feat: platform service selection and media type filters for artist posts (v2.0.4)

This commit is contained in:
2026-09-03 18:36:23 +03:00
parent 5ae802f89c
commit 1f624fc020
9 changed files with 327 additions and 87 deletions
@@ -47,6 +47,7 @@ abstract class TagMetadataProvider {
abstract class ArtistProvider {
Future<List<ArtistProfile>> listArtists({
String? service,
List<String>? services,
String? query,
int page = 1,
int limit = 30,
@@ -55,6 +56,7 @@ abstract class ArtistProvider {
Future<List<ArtistProfile>> searchArtists(
String query, {
String? service,
List<String>? services,
int page = 1,
int limit = 30,
});
+21 -31
View File
@@ -91,66 +91,56 @@ class KemonoProvider
@override
Future<List<ArtistProfile>> listArtists({
String? service,
List<String>? services,
String? query,
int page = 1,
int limit = 30,
}) async {
final searchText = query?.trim() ?? '';
if (searchText.isNotEmpty) {
try {
final response = await _creatorDio.get<dynamic>(
_creatorPath(),
queryParameters: {
'keyword': searchText,
'page': page,
'itemsPerPage': limit.clamp(1, 100),
},
);
final artists = _rankArtists(
_artistsFromResponse(response.data)
.where((artist) =>
service == null ||
service.isEmpty ||
artist.service == service)
.toList(growable: false),
searchText,
);
if (artists.isNotEmpty) return artists;
} catch (_) {
// Fall through to the indexed creator endpoints.
}
}
final effectiveService =
services != null && services.length == 1 ? services.first : service;
List<ArtistProfile> list;
try {
final response = await _creatorDio.get<dynamic>(
service == null || service.isEmpty
effectiveService == null || effectiveService.isEmpty
? _creatorPath()
: '${_creatorPath()}/$service',
: '${_creatorPath()}/$effectiveService',
queryParameters: {
'page': page,
'itemsPerPage': limit.clamp(1, 100),
if (query != null && query.trim().isNotEmpty) 'keyword': query.trim(),
},
);
return _rankArtists(_artistsFromResponse(response.data), query ?? '');
list = _rankArtists(_artistsFromResponse(response.data), query ?? '');
} catch (_) {
return _listArtistsFromPublicApi(
service: service,
list = await _listArtistsFromPublicApi(
service: effectiveService,
query: query,
page: page,
limit: limit,
);
}
if (services != null && services.isNotEmpty) {
final sSet = services.map((s) => s.toLowerCase()).toSet();
list = list.where((a) => sSet.contains(a.service.toLowerCase())).toList();
}
return list;
}
@override
Future<List<ArtistProfile>> searchArtists(
String query, {
String? service,
List<String>? services,
int page = 1,
int limit = 30,
}) {
return listArtists(
service: service, query: query, page: page, limit: limit);
service: service,
services: services,
query: query,
page: page,
limit: limit,
);
}
@override
+12 -3
View File
@@ -122,16 +122,23 @@ class PawchiveProvider
@override
Future<List<ArtistProfile>> listArtists({
String? service,
List<String>? services,
String? query,
int page = 1,
int limit = 30,
}) async {
final allArtists = await _ensureArtistsLoaded();
final queryText = (query ?? '').trim().toLowerCase();
final activeServices = services != null && services.isNotEmpty
? services.map((s) => s.trim().toLowerCase()).toSet()
: null;
final filtered = allArtists.where((artist) {
final matchService = service == null ||
service.isEmpty ||
artist.service.toLowerCase() == service.toLowerCase();
final artistService = artist.service.toLowerCase();
final matchService = activeServices != null
? activeServices.contains(artistService)
: service == null ||
service.isEmpty ||
artistService == service.toLowerCase();
if (!matchService) return false;
if (queryText.isEmpty) return true;
return artist.displayName.toLowerCase().contains(queryText) ||
@@ -147,11 +154,13 @@ class PawchiveProvider
Future<List<ArtistProfile>> searchArtists(
String query, {
String? service,
List<String>? services,
int page = 1,
int limit = 30,
}) {
return listArtists(
service: service,
services: services,
query: query,
page: page,
limit: limit,