feat: release v2.0.6 with full Pawchive API integration (global feed, tags, links, announcements, server media filter)
This commit is contained in:
@@ -4,6 +4,9 @@ export 'models/content_provider_config.dart';
|
||||
export 'models/app_update_info.dart';
|
||||
export 'models/artist_profile.dart';
|
||||
export 'models/artist_work_query.dart';
|
||||
export 'models/artist_tag.dart';
|
||||
export 'models/artist_link.dart';
|
||||
export 'models/artist_announcement.dart';
|
||||
export 'models/download_task.dart';
|
||||
export 'models/downloaded_media.dart';
|
||||
export 'models/favorite.dart';
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
class ArtistAnnouncement {
|
||||
const ArtistAnnouncement({
|
||||
required this.service,
|
||||
required this.userId,
|
||||
required this.content,
|
||||
this.hash,
|
||||
this.added,
|
||||
});
|
||||
|
||||
final String service;
|
||||
final String userId;
|
||||
final String content;
|
||||
final String? hash;
|
||||
final DateTime? added;
|
||||
|
||||
factory ArtistAnnouncement.fromJson(Map<String, dynamic> json) {
|
||||
return ArtistAnnouncement(
|
||||
service: (json['service'] ?? '').toString(),
|
||||
userId: (json['user_id'] ?? '').toString(),
|
||||
content: (json['content'] ?? '').toString(),
|
||||
hash: json['hash']?.toString(),
|
||||
added: json['added'] != null
|
||||
? DateTime.tryParse(json['added'].toString())
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'service': service,
|
||||
'user_id': userId,
|
||||
'content': content,
|
||||
if (hash != null) 'hash': hash,
|
||||
if (added != null) 'added': added?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
class ArtistLink {
|
||||
const ArtistLink({
|
||||
required this.id,
|
||||
required this.service,
|
||||
required this.name,
|
||||
this.publicId,
|
||||
this.indexed,
|
||||
this.updated,
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String service;
|
||||
final String name;
|
||||
final String? publicId;
|
||||
final DateTime? indexed;
|
||||
final DateTime? updated;
|
||||
|
||||
factory ArtistLink.fromJson(Map<String, dynamic> json) {
|
||||
return ArtistLink(
|
||||
id: (json['id'] ?? '').toString(),
|
||||
service: (json['service'] ?? '').toString(),
|
||||
name: (json['name'] ?? '').toString(),
|
||||
publicId: json['public_id']?.toString(),
|
||||
indexed: json['indexed'] != null
|
||||
? DateTime.tryParse(json['indexed'].toString())
|
||||
: null,
|
||||
updated: json['updated'] != null
|
||||
? DateTime.tryParse(json['updated'].toString())
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'service': service,
|
||||
'name': name,
|
||||
if (publicId != null) 'public_id': publicId,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
class ArtistTag {
|
||||
const ArtistTag({
|
||||
required this.tag,
|
||||
required this.postCount,
|
||||
});
|
||||
|
||||
final String tag;
|
||||
final int postCount;
|
||||
|
||||
factory ArtistTag.fromJson(Map<String, dynamic> json) {
|
||||
return ArtistTag(
|
||||
tag: (json['tag'] ?? '').toString(),
|
||||
postCount: (json['post_count'] as num?)?.toInt() ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'tag': tag,
|
||||
'post_count': postCount,
|
||||
};
|
||||
}
|
||||
@@ -4,12 +4,34 @@ class ArtistWorkQuery {
|
||||
required this.service,
|
||||
required this.artistId,
|
||||
required this.artistName,
|
||||
this.queryText,
|
||||
this.tagFilter,
|
||||
});
|
||||
|
||||
final String providerId;
|
||||
final String service;
|
||||
final String artistId;
|
||||
final String artistName;
|
||||
final String? queryText;
|
||||
final String? tagFilter;
|
||||
|
||||
ArtistWorkQuery copyWith({
|
||||
String? providerId,
|
||||
String? service,
|
||||
String? artistId,
|
||||
String? artistName,
|
||||
String? queryText,
|
||||
String? tagFilter,
|
||||
}) {
|
||||
return ArtistWorkQuery(
|
||||
providerId: providerId ?? this.providerId,
|
||||
service: service ?? this.service,
|
||||
artistId: artistId ?? this.artistId,
|
||||
artistName: artistName ?? this.artistName,
|
||||
queryText: queryText ?? this.queryText,
|
||||
tagFilter: tagFilter ?? this.tagFilter,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
@@ -17,9 +39,18 @@ class ArtistWorkQuery {
|
||||
other.providerId == providerId &&
|
||||
other.service == service &&
|
||||
other.artistId == artistId &&
|
||||
other.artistName == artistName;
|
||||
other.artistName == artistName &&
|
||||
other.queryText == queryText &&
|
||||
other.tagFilter == tagFilter;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(providerId, service, artistId, artistName);
|
||||
int get hashCode => Object.hash(
|
||||
providerId,
|
||||
service,
|
||||
artistId,
|
||||
artistName,
|
||||
queryText,
|
||||
tagFilter,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import '../models/artist_announcement.dart';
|
||||
import '../models/artist_link.dart';
|
||||
import '../models/artist_profile.dart';
|
||||
import '../models/artist_tag.dart';
|
||||
import '../models/artist_work_query.dart';
|
||||
import '../models/post.dart';
|
||||
import '../models/post_comment.dart';
|
||||
import '../models/provider_health.dart';
|
||||
import '../models/tag_suggestion.dart';
|
||||
import '../models/top_period_filter.dart';
|
||||
import '../models/artist_profile.dart';
|
||||
import '../models/artist_work_query.dart';
|
||||
|
||||
abstract class ContentProvider {
|
||||
String get id;
|
||||
@@ -72,4 +75,15 @@ abstract class ArtistProvider {
|
||||
String artistId,
|
||||
String postId,
|
||||
);
|
||||
|
||||
Future<List<ArtistTag>> getArtistTags(String service, String artistId) async =>
|
||||
const [];
|
||||
|
||||
Future<List<ArtistLink>> getArtistLinks(
|
||||
String service, String artistId) async =>
|
||||
const [];
|
||||
|
||||
Future<List<ArtistAnnouncement>> getArtistAnnouncements(
|
||||
String service, String artistId) async =>
|
||||
const [];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import '../../core/http/dio_client.dart';
|
||||
import '../models/artist_announcement.dart';
|
||||
import '../models/artist_link.dart';
|
||||
import '../models/artist_profile.dart';
|
||||
import '../models/artist_tag.dart';
|
||||
import '../models/artist_work_query.dart';
|
||||
import '../models/post.dart';
|
||||
import '../models/post_comment.dart';
|
||||
@@ -214,6 +217,21 @@ class KemonoProvider
|
||||
return getArtistPostComments(parts[0], parts[1], parts[2]);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ArtistTag>> getArtistTags(
|
||||
String service, String artistId) async =>
|
||||
const [];
|
||||
|
||||
@override
|
||||
Future<List<ArtistLink>> getArtistLinks(
|
||||
String service, String artistId) async =>
|
||||
const [];
|
||||
|
||||
@override
|
||||
Future<List<ArtistAnnouncement>> getArtistAnnouncements(
|
||||
String service, String artistId) async =>
|
||||
const [];
|
||||
|
||||
String _creatorPath() => _isCoomer ? '/coomer' : '/kemono';
|
||||
|
||||
List<ArtistProfile> _artistsFromResponse(dynamic data) {
|
||||
|
||||
@@ -3,7 +3,10 @@ import 'dart:async';
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import '../../core/http/dio_client.dart';
|
||||
import '../models/artist_announcement.dart';
|
||||
import '../models/artist_link.dart';
|
||||
import '../models/artist_profile.dart';
|
||||
import '../models/artist_tag.dart';
|
||||
import '../models/artist_work_query.dart';
|
||||
import '../models/post.dart';
|
||||
import '../models/post_comment.dart';
|
||||
@@ -42,7 +45,34 @@ class PawchiveProvider
|
||||
String? rating,
|
||||
TopPeriodFilter topPeriod = TopPeriodFilter.none,
|
||||
}) async {
|
||||
return const [];
|
||||
final offset = (page - 1).clamp(0, 999999) * 50;
|
||||
final queryText = tags.join(' ').trim();
|
||||
try {
|
||||
final response = await _dio.get<dynamic>(
|
||||
'/api/v1/posts',
|
||||
queryParameters: {
|
||||
if (queryText.isNotEmpty) 'q': queryText,
|
||||
'o': offset,
|
||||
},
|
||||
);
|
||||
final posts = _postItems(response.data);
|
||||
final mapped = <Post>[];
|
||||
for (final post in posts.whereType<Map>()) {
|
||||
final json = Map<String, dynamic>.from(post);
|
||||
final service = (json['service'] ?? 'fanbox').toString();
|
||||
final userId = (json['user'] ?? '').toString();
|
||||
final dummyQuery = ArtistWorkQuery(
|
||||
providerId: id,
|
||||
service: service,
|
||||
artistId: userId,
|
||||
artistName: userId,
|
||||
);
|
||||
mapped.addAll(_postsFromArtistPost(json, query: dummyQuery));
|
||||
}
|
||||
return mapped;
|
||||
} catch (_) {
|
||||
return const [];
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -178,7 +208,13 @@ class PawchiveProvider
|
||||
try {
|
||||
final response = await _dio.get<dynamic>(
|
||||
path,
|
||||
queryParameters: {'o': offset},
|
||||
queryParameters: {
|
||||
'o': offset,
|
||||
if (query.tagFilter != null && query.tagFilter!.isNotEmpty)
|
||||
'tag': query.tagFilter,
|
||||
if (query.queryText != null && query.queryText!.isNotEmpty)
|
||||
'q': query.queryText,
|
||||
},
|
||||
);
|
||||
final posts = _postItems(response.data);
|
||||
final mapped = <Post>[];
|
||||
@@ -216,6 +252,72 @@ class PawchiveProvider
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ArtistTag>> getArtistTags(String service, String artistId) async {
|
||||
try {
|
||||
final response = await _dio.get<dynamic>(
|
||||
'/api/v1/$service/user/$artistId/tags',
|
||||
options: Options(
|
||||
receiveTimeout: const Duration(seconds: 15),
|
||||
sendTimeout: const Duration(seconds: 10),
|
||||
),
|
||||
);
|
||||
final items = response.data;
|
||||
if (items is List) {
|
||||
return items
|
||||
.whereType<Map>()
|
||||
.map((item) => ArtistTag.fromJson(Map<String, dynamic>.from(item)))
|
||||
.toList(growable: false);
|
||||
}
|
||||
} catch (_) {}
|
||||
return const [];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ArtistLink>> getArtistLinks(
|
||||
String service, String artistId) async {
|
||||
try {
|
||||
final response = await _dio.get<dynamic>(
|
||||
'/api/v1/$service/user/$artistId/links',
|
||||
options: Options(
|
||||
receiveTimeout: const Duration(seconds: 15),
|
||||
sendTimeout: const Duration(seconds: 10),
|
||||
),
|
||||
);
|
||||
final items = response.data;
|
||||
if (items is List) {
|
||||
return items
|
||||
.whereType<Map>()
|
||||
.map((item) => ArtistLink.fromJson(Map<String, dynamic>.from(item)))
|
||||
.toList(growable: false);
|
||||
}
|
||||
} catch (_) {}
|
||||
return const [];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ArtistAnnouncement>> getArtistAnnouncements(
|
||||
String service, String artistId) async {
|
||||
try {
|
||||
final response = await _dio.get<dynamic>(
|
||||
'/api/v1/$service/user/$artistId/announcements',
|
||||
options: Options(
|
||||
receiveTimeout: const Duration(seconds: 15),
|
||||
sendTimeout: const Duration(seconds: 10),
|
||||
),
|
||||
);
|
||||
final items = response.data;
|
||||
if (items is List) {
|
||||
return items
|
||||
.whereType<Map>()
|
||||
.map((item) =>
|
||||
ArtistAnnouncement.fromJson(Map<String, dynamic>.from(item)))
|
||||
.toList(growable: false);
|
||||
}
|
||||
} catch (_) {}
|
||||
return const [];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<PostComment>> getComments(String postId) async {
|
||||
final parts = postId.split(':');
|
||||
|
||||
Reference in New Issue
Block a user