fix(libraries): filter content-type-less Jellyfin roots

This commit is contained in:
edde746
2026-07-25 17:38:09 +02:00
parent c1cfb9609e
commit 96fd47a160
4 changed files with 30 additions and 25 deletions
@@ -767,7 +767,7 @@ class _LibraryBrowseTabState extends BaseLibraryTabState<MediaItem, LibraryBrows
limit: size,
);
final query =
baseQuery.kind == null &&
(baseQuery.kind == null || baseQuery.kind == MediaKind.folder) &&
baseQuery.includeKinds.isEmpty &&
_selectedGrouping == browseGroupingAll &&
widget.library.defaultBrowseKinds.isNotEmpty
+10 -7
View File
@@ -268,12 +268,13 @@ class JellyfinMappers {
final id = view['Id'] as String?;
if (id == null || id.isEmpty) return null;
final collectionType = view['CollectionType'] as String?;
final type = view['Type'] as String?;
return MediaLibrary(
id: id,
backend: MediaBackend.jellyfin,
title: view['Name'] as String? ?? t.libraries.fallbackTitle,
kind: _libraryKindFromCollectionType(collectionType, view['Type'] as String?),
defaultBrowseKinds: _defaultBrowseKindsFromCollectionType(collectionType),
kind: _libraryKindFromCollectionType(collectionType, type),
defaultBrowseKinds: _defaultBrowseKindsFromCollectionType(collectionType, type),
updatedAt: jellyfinIsoToEpochSeconds(view['DateLastSaved'] as String? ?? view['DateModified'] as String?),
createdAt: jellyfinIsoToEpochSeconds(view['DateCreated'] as String?),
hidden: false,
@@ -317,8 +318,8 @@ class JellyfinMappers {
}
static MediaKind _libraryKindFromCollectionType(String? collectionType, String? type) {
final ct = collectionType?.toLowerCase();
if (ct != null) {
final ct = collectionType?.trim().toLowerCase();
if (ct != null && ct.isNotEmpty) {
return switch (ct) {
'movies' => MediaKind.movie,
'tvshows' => MediaKind.show,
@@ -328,15 +329,17 @@ class JellyfinMappers {
'photos' => MediaKind.photo,
'boxsets' => MediaKind.collection,
'playlists' => MediaKind.playlist,
'mixed' => MediaKind.unknown,
_ => MediaKind.unknown,
};
}
return MediaKind.fromString(type);
}
static List<MediaKind> _defaultBrowseKindsFromCollectionType(String? collectionType) {
return collectionType?.toLowerCase() == 'mixed' ? const [MediaKind.movie, MediaKind.show] : const <MediaKind>[];
static List<MediaKind> _defaultBrowseKindsFromCollectionType(String? collectionType, String? type) {
final ct = collectionType?.trim();
return (ct == null || ct.isEmpty) && type?.toLowerCase() == 'collectionfolder'
? const [MediaKind.movie, MediaKind.show]
: const <MediaKind>[];
}
static Map<String, dynamic>? _userData(Map<String, dynamic> item) {
@@ -20,6 +20,7 @@ import 'package:plezy/providers/multi_server_provider.dart';
import 'package:plezy/screens/libraries/state_messages.dart';
import 'package:plezy/screens/libraries/tabs/library_browse_tab.dart';
import 'package:plezy/services/data_aggregation_service.dart';
import 'package:plezy/services/jellyfin_mappers.dart';
import 'package:plezy/services/multi_server_manager.dart';
import 'package:plezy/services/settings_service.dart';
import 'package:plezy/services/storage_service.dart';
@@ -137,20 +138,19 @@ void main() {
final client = _BrowseClient('server-a', 'Mixed');
final harness = _BrowseHarness(clientA: client);
addTearDown(harness.dispose);
harness.selectedLibrary.value = MediaLibrary(
id: 'mixed-library',
backend: MediaBackend.jellyfin,
title: 'Mixed',
defaultBrowseKinds: const [MediaKind.movie, MediaKind.show],
serverId: client.serverId,
);
harness.selectedLibrary.value = JellyfinMappers.library({
'Id': 'mixed-library',
'Name': 'Mixed',
'Type': 'CollectionFolder',
'IsFolder': true,
}, serverId: client.serverId)!;
await _pumpHarness(tester, harness);
expect(client.pageQueries, hasLength(1));
expect(client.pageQueries.single.kind, isNull);
expect(client.pageQueries.single.kind, MediaKind.folder);
expect(client.pageQueries.single.includeKinds, const [MediaKind.movie, MediaKind.show]);
expect(client.pageLibraryKinds.single, MediaKind.unknown);
expect(client.pageLibraryKinds.single, MediaKind.folder);
});
}
+9 -7
View File
@@ -474,18 +474,20 @@ void main() {
}
});
test('maps mixed collections to a movie and show root browse', () {
final mixed = JellyfinMappers.library({
'Id': 'view-mixed',
'Name': 'Mixed',
'CollectionType': 'mixed',
}, serverId: ServerId(_serverId))!;
expect(mixed.kind, MediaKind.unknown);
test('maps content-type-less collection folders to a movie and show root browse', () {
for (final view in [
{'Id': 'view-missing-type', 'Name': 'Mixed', 'Type': 'CollectionFolder', 'IsFolder': true},
{'Id': 'view-empty-type', 'Name': 'Mixed', 'Type': 'CollectionFolder', 'CollectionType': '', 'IsFolder': true},
]) {
final mixed = JellyfinMappers.library(view, serverId: ServerId(_serverId))!;
expect(mixed.kind, MediaKind.folder);
expect(mixed.defaultBrowseKinds, const [MediaKind.movie, MediaKind.show]);
}
final unrecognised = JellyfinMappers.library({
'Id': 'view-books',
'Name': 'Books',
'Type': 'CollectionFolder',
'CollectionType': 'books',
}, serverId: ServerId(_serverId))!;
expect(unrecognised.kind, MediaKind.unknown);