feat: complete e621 integration with API key auth, comics/pools, post variations, and server sync (v3.7.0)
This commit is contained in:
@@ -2,6 +2,7 @@ import 'package:dio/dio.dart';
|
||||
|
||||
import '../../core/http/dio_client.dart';
|
||||
import '../mappers/e621_mapper.dart';
|
||||
import '../models/e621_pool.dart';
|
||||
import '../models/post.dart';
|
||||
import '../models/post_comment.dart';
|
||||
import '../models/provider_health.dart';
|
||||
@@ -33,6 +34,24 @@ class E621Provider
|
||||
final Dio _dio;
|
||||
final Map<String, String> _queryParameters;
|
||||
|
||||
static DateTime _lastRequestTime = DateTime.fromMillisecondsSinceEpoch(0);
|
||||
|
||||
static Future<void> _throttle() async {
|
||||
final now = DateTime.now();
|
||||
final diff = now.difference(_lastRequestTime);
|
||||
if (diff.inMilliseconds < 500) {
|
||||
final waitMs = 500 - diff.inMilliseconds;
|
||||
await Future<void>.delayed(Duration(milliseconds: waitMs));
|
||||
}
|
||||
_lastRequestTime = DateTime.now();
|
||||
}
|
||||
|
||||
bool get isAuthorized =>
|
||||
_queryParameters.containsKey('login') ||
|
||||
_dio.options.headers.containsKey('Authorization');
|
||||
|
||||
String? get login => _queryParameters['login'];
|
||||
|
||||
@override
|
||||
String postPageUrl(Post post) => '$baseUrl/posts/${post.id}';
|
||||
|
||||
@@ -44,6 +63,7 @@ class E621Provider
|
||||
String? rating,
|
||||
TopPeriodFilter topPeriod = TopPeriodFilter.none,
|
||||
}) async {
|
||||
await _throttle();
|
||||
final response = await _dio.get<dynamic>(
|
||||
'/posts.json',
|
||||
queryParameters: {
|
||||
@@ -66,6 +86,7 @@ class E621Provider
|
||||
|
||||
@override
|
||||
Future<Post?> getPost(String id) async {
|
||||
await _throttle();
|
||||
final response = await _dio.get<dynamic>(
|
||||
'/posts/$id.json',
|
||||
queryParameters: _queryParameters,
|
||||
@@ -78,6 +99,63 @@ class E621Provider
|
||||
return posts.isEmpty ? null : posts.first;
|
||||
}
|
||||
|
||||
Future<E621Pool?> getPool(String poolId) async {
|
||||
await _throttle();
|
||||
try {
|
||||
final response = await _dio.get<dynamic>(
|
||||
'/pools/$poolId.json',
|
||||
queryParameters: _queryParameters,
|
||||
);
|
||||
if (response.data is Map) {
|
||||
return E621Pool.fromJson(Map<String, dynamic>.from(response.data as Map));
|
||||
}
|
||||
} catch (_) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<bool> votePost(String postId, int score) async {
|
||||
await _throttle();
|
||||
try {
|
||||
final response = await _dio.post<dynamic>(
|
||||
'/posts/$postId/votes.json',
|
||||
data: {'score': score, 'no_unvote': 'true'},
|
||||
queryParameters: _queryParameters,
|
||||
options: Options(contentType: Headers.formUrlEncodedContentType),
|
||||
);
|
||||
return response.statusCode == 200 || response.statusCode == 201;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> addFavorite(String postId) async {
|
||||
await _throttle();
|
||||
try {
|
||||
final response = await _dio.post<dynamic>(
|
||||
'/favorites.json',
|
||||
data: {'post_id': postId},
|
||||
queryParameters: _queryParameters,
|
||||
options: Options(contentType: Headers.formUrlEncodedContentType),
|
||||
);
|
||||
return response.statusCode == 200 || response.statusCode == 201;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> removeFavorite(String postId) async {
|
||||
await _throttle();
|
||||
try {
|
||||
final response = await _dio.delete<dynamic>(
|
||||
'/favorites/$postId.json',
|
||||
queryParameters: _queryParameters,
|
||||
);
|
||||
return response.statusCode == 200 || response.statusCode == 204;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ProviderHealth> checkHealth() async {
|
||||
final startedAt = DateTime.now();
|
||||
@@ -109,6 +187,7 @@ class E621Provider
|
||||
Future<List<TagSuggestion>> suggestTags(String query,
|
||||
{int limit = 20}) async {
|
||||
if (query.trim().isEmpty) return const [];
|
||||
await _throttle();
|
||||
final response = await _dio.get<dynamic>(
|
||||
'/tags.json',
|
||||
queryParameters: {
|
||||
@@ -136,6 +215,7 @@ class E621Provider
|
||||
|
||||
@override
|
||||
Future<List<PostComment>> getComments(String postId) async {
|
||||
await _throttle();
|
||||
final response = await _dio.get<dynamic>(
|
||||
'/comments.json',
|
||||
queryParameters: {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import '../../core/http/dio_client.dart';
|
||||
import '../models/content_provider_config.dart';
|
||||
import 'content_provider.dart';
|
||||
@@ -20,6 +22,17 @@ class ProviderFactory {
|
||||
if (entry.key.startsWith('query.') && entry.value.trim().isNotEmpty)
|
||||
entry.key.substring('query.'.length): entry.value.trim(),
|
||||
};
|
||||
|
||||
if (config.apiType.toLowerCase() == 'e621') {
|
||||
final login = queryParameters['login'] ?? headers['login'];
|
||||
final apiKey = queryParameters['api_key'] ?? headers['api_key'];
|
||||
if (login != null && apiKey != null && login.isNotEmpty && apiKey.isNotEmpty) {
|
||||
final basicAuth = base64Encode(utf8.encode('$login:$apiKey'));
|
||||
headers['Authorization'] = 'Basic $basicAuth';
|
||||
headers['User-Agent'] = 'Prisma/3.6.6 (by $login on e621)';
|
||||
}
|
||||
}
|
||||
|
||||
final client = DioClient(
|
||||
baseUrl: config.baseUrl,
|
||||
timeout: Duration(seconds: config.timeoutSeconds),
|
||||
|
||||
@@ -144,6 +144,14 @@ class ProviderManager {
|
||||
});
|
||||
}
|
||||
|
||||
Future<ContentProvider?> getProviderInstance(String id) async {
|
||||
final result = await _repository.getProvider(id);
|
||||
if (result is Success<ContentProviderConfig?> && result.data != null) {
|
||||
return _factory.create(result.data!);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<Result<List<ProviderHealth>>> checkAll({int concurrency = 3}) async {
|
||||
final providersResult = await activeProviders();
|
||||
if (providersResult is Error<List<ContentProvider>>) {
|
||||
|
||||
Reference in New Issue
Block a user