fix(libraries): filter content-type-less Jellyfin roots
This commit is contained in:
@@ -767,7 +767,7 @@ class _LibraryBrowseTabState extends BaseLibraryTabState<MediaItem, LibraryBrows
|
|||||||
limit: size,
|
limit: size,
|
||||||
);
|
);
|
||||||
final query =
|
final query =
|
||||||
baseQuery.kind == null &&
|
(baseQuery.kind == null || baseQuery.kind == MediaKind.folder) &&
|
||||||
baseQuery.includeKinds.isEmpty &&
|
baseQuery.includeKinds.isEmpty &&
|
||||||
_selectedGrouping == browseGroupingAll &&
|
_selectedGrouping == browseGroupingAll &&
|
||||||
widget.library.defaultBrowseKinds.isNotEmpty
|
widget.library.defaultBrowseKinds.isNotEmpty
|
||||||
|
|||||||
@@ -268,12 +268,13 @@ class JellyfinMappers {
|
|||||||
final id = view['Id'] as String?;
|
final id = view['Id'] as String?;
|
||||||
if (id == null || id.isEmpty) return null;
|
if (id == null || id.isEmpty) return null;
|
||||||
final collectionType = view['CollectionType'] as String?;
|
final collectionType = view['CollectionType'] as String?;
|
||||||
|
final type = view['Type'] as String?;
|
||||||
return MediaLibrary(
|
return MediaLibrary(
|
||||||
id: id,
|
id: id,
|
||||||
backend: MediaBackend.jellyfin,
|
backend: MediaBackend.jellyfin,
|
||||||
title: view['Name'] as String? ?? t.libraries.fallbackTitle,
|
title: view['Name'] as String? ?? t.libraries.fallbackTitle,
|
||||||
kind: _libraryKindFromCollectionType(collectionType, view['Type'] as String?),
|
kind: _libraryKindFromCollectionType(collectionType, type),
|
||||||
defaultBrowseKinds: _defaultBrowseKindsFromCollectionType(collectionType),
|
defaultBrowseKinds: _defaultBrowseKindsFromCollectionType(collectionType, type),
|
||||||
updatedAt: jellyfinIsoToEpochSeconds(view['DateLastSaved'] as String? ?? view['DateModified'] as String?),
|
updatedAt: jellyfinIsoToEpochSeconds(view['DateLastSaved'] as String? ?? view['DateModified'] as String?),
|
||||||
createdAt: jellyfinIsoToEpochSeconds(view['DateCreated'] as String?),
|
createdAt: jellyfinIsoToEpochSeconds(view['DateCreated'] as String?),
|
||||||
hidden: false,
|
hidden: false,
|
||||||
@@ -317,8 +318,8 @@ class JellyfinMappers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static MediaKind _libraryKindFromCollectionType(String? collectionType, String? type) {
|
static MediaKind _libraryKindFromCollectionType(String? collectionType, String? type) {
|
||||||
final ct = collectionType?.toLowerCase();
|
final ct = collectionType?.trim().toLowerCase();
|
||||||
if (ct != null) {
|
if (ct != null && ct.isNotEmpty) {
|
||||||
return switch (ct) {
|
return switch (ct) {
|
||||||
'movies' => MediaKind.movie,
|
'movies' => MediaKind.movie,
|
||||||
'tvshows' => MediaKind.show,
|
'tvshows' => MediaKind.show,
|
||||||
@@ -328,15 +329,17 @@ class JellyfinMappers {
|
|||||||
'photos' => MediaKind.photo,
|
'photos' => MediaKind.photo,
|
||||||
'boxsets' => MediaKind.collection,
|
'boxsets' => MediaKind.collection,
|
||||||
'playlists' => MediaKind.playlist,
|
'playlists' => MediaKind.playlist,
|
||||||
'mixed' => MediaKind.unknown,
|
|
||||||
_ => MediaKind.unknown,
|
_ => MediaKind.unknown,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return MediaKind.fromString(type);
|
return MediaKind.fromString(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<MediaKind> _defaultBrowseKindsFromCollectionType(String? collectionType) {
|
static List<MediaKind> _defaultBrowseKindsFromCollectionType(String? collectionType, String? type) {
|
||||||
return collectionType?.toLowerCase() == 'mixed' ? const [MediaKind.movie, MediaKind.show] : const <MediaKind>[];
|
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) {
|
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/state_messages.dart';
|
||||||
import 'package:plezy/screens/libraries/tabs/library_browse_tab.dart';
|
import 'package:plezy/screens/libraries/tabs/library_browse_tab.dart';
|
||||||
import 'package:plezy/services/data_aggregation_service.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/multi_server_manager.dart';
|
||||||
import 'package:plezy/services/settings_service.dart';
|
import 'package:plezy/services/settings_service.dart';
|
||||||
import 'package:plezy/services/storage_service.dart';
|
import 'package:plezy/services/storage_service.dart';
|
||||||
@@ -137,20 +138,19 @@ void main() {
|
|||||||
final client = _BrowseClient('server-a', 'Mixed');
|
final client = _BrowseClient('server-a', 'Mixed');
|
||||||
final harness = _BrowseHarness(clientA: client);
|
final harness = _BrowseHarness(clientA: client);
|
||||||
addTearDown(harness.dispose);
|
addTearDown(harness.dispose);
|
||||||
harness.selectedLibrary.value = MediaLibrary(
|
harness.selectedLibrary.value = JellyfinMappers.library({
|
||||||
id: 'mixed-library',
|
'Id': 'mixed-library',
|
||||||
backend: MediaBackend.jellyfin,
|
'Name': 'Mixed',
|
||||||
title: 'Mixed',
|
'Type': 'CollectionFolder',
|
||||||
defaultBrowseKinds: const [MediaKind.movie, MediaKind.show],
|
'IsFolder': true,
|
||||||
serverId: client.serverId,
|
}, serverId: client.serverId)!;
|
||||||
);
|
|
||||||
|
|
||||||
await _pumpHarness(tester, harness);
|
await _pumpHarness(tester, harness);
|
||||||
|
|
||||||
expect(client.pageQueries, hasLength(1));
|
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.pageQueries.single.includeKinds, const [MediaKind.movie, MediaKind.show]);
|
||||||
expect(client.pageLibraryKinds.single, MediaKind.unknown);
|
expect(client.pageLibraryKinds.single, MediaKind.folder);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -474,18 +474,20 @@ void main() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('maps mixed collections to a movie and show root browse', () {
|
test('maps content-type-less collection folders to a movie and show root browse', () {
|
||||||
final mixed = JellyfinMappers.library({
|
for (final view in [
|
||||||
'Id': 'view-mixed',
|
{'Id': 'view-missing-type', 'Name': 'Mixed', 'Type': 'CollectionFolder', 'IsFolder': true},
|
||||||
'Name': 'Mixed',
|
{'Id': 'view-empty-type', 'Name': 'Mixed', 'Type': 'CollectionFolder', 'CollectionType': '', 'IsFolder': true},
|
||||||
'CollectionType': 'mixed',
|
]) {
|
||||||
}, serverId: ServerId(_serverId))!;
|
final mixed = JellyfinMappers.library(view, serverId: ServerId(_serverId))!;
|
||||||
expect(mixed.kind, MediaKind.unknown);
|
expect(mixed.kind, MediaKind.folder);
|
||||||
expect(mixed.defaultBrowseKinds, const [MediaKind.movie, MediaKind.show]);
|
expect(mixed.defaultBrowseKinds, const [MediaKind.movie, MediaKind.show]);
|
||||||
|
}
|
||||||
|
|
||||||
final unrecognised = JellyfinMappers.library({
|
final unrecognised = JellyfinMappers.library({
|
||||||
'Id': 'view-books',
|
'Id': 'view-books',
|
||||||
'Name': 'Books',
|
'Name': 'Books',
|
||||||
|
'Type': 'CollectionFolder',
|
||||||
'CollectionType': 'books',
|
'CollectionType': 'books',
|
||||||
}, serverId: ServerId(_serverId))!;
|
}, serverId: ServerId(_serverId))!;
|
||||||
expect(unrecognised.kind, MediaKind.unknown);
|
expect(unrecognised.kind, MediaKind.unknown);
|
||||||
|
|||||||
Reference in New Issue
Block a user