feat(jellyfin): favorites library filter + heart favorite in the rate sheet
close #1485
This commit is contained in:
@@ -1598,11 +1598,22 @@ void main() {
|
||||
expect(captured!.path, '/Items/Filters');
|
||||
expect(captured!.queryParameters['ParentId'], 'lib-1');
|
||||
expect(captured!.queryParameters['userId'], 'user-1');
|
||||
expect(result.filters.map((filter) => filter.filter), ['unwatched', 'genre', 'year', 'contentRating', 'tag']);
|
||||
expect(result.filters.map((filter) => filter.filter), [
|
||||
'unwatched',
|
||||
'favorite',
|
||||
'genre',
|
||||
'year',
|
||||
'contentRating',
|
||||
'tag',
|
||||
]);
|
||||
expect(result.filters.first.filterType, 'boolean');
|
||||
expect(result.filters.first.key, 'jellyfin:unwatched');
|
||||
expect(result.filters.first.title, 'Unwatched');
|
||||
expect(result.filters[1].filterType, 'boolean');
|
||||
expect(result.filters[1].key, 'jellyfin:favorite');
|
||||
expect(result.filters[1].title, 'Favorites');
|
||||
expect(result.cachedValues.containsKey('unwatched'), isFalse);
|
||||
expect(result.cachedValues.containsKey('favorite'), isFalse);
|
||||
expect(result.cachedValues['genre']!.map((value) => value.key), ['Action', 'Drama']);
|
||||
expect(result.cachedValues['year']!.map((value) => value.key), ['2024', '1999']);
|
||||
});
|
||||
|
||||
@@ -100,6 +100,32 @@ void main() {
|
||||
expect(item.isWatched, isFalse);
|
||||
});
|
||||
|
||||
test('maps UserData.IsFavorite and ignores the legacy Likes flag', () {
|
||||
final json = {
|
||||
'Id': 'fav-1',
|
||||
'Name': 'Favorited Movie',
|
||||
'Type': 'Movie',
|
||||
'UserData': {'IsFavorite': true, 'Likes': true},
|
||||
};
|
||||
|
||||
final item = JellyfinMappers.mediaItem(json, serverId: ServerId(_serverId), absolutizer: null)!;
|
||||
|
||||
expect(item.isFavorite, isTrue);
|
||||
// Likes used to map to userRating 10.0/0.0; the rate sheet now uses
|
||||
// IsFavorite for Jellyfin, so Likes must no longer surface anywhere.
|
||||
expect(item.userRating, isNull);
|
||||
});
|
||||
|
||||
test('missing UserData leaves isFavorite null', () {
|
||||
final item = JellyfinMappers.mediaItem(
|
||||
{'Id': 'no-userdata', 'Name': 'No UserData', 'Type': 'Movie'},
|
||||
serverId: ServerId(_serverId),
|
||||
absolutizer: null,
|
||||
)!;
|
||||
|
||||
expect(item.isFavorite, isNull);
|
||||
});
|
||||
|
||||
test('maps generic Jellyfin video types to playable clips', () {
|
||||
final video = JellyfinMappers.mediaItem(
|
||||
{'Id': 'home-video', 'Name': 'Home Video', 'Type': 'Video'},
|
||||
|
||||
@@ -57,6 +57,10 @@ void main() {
|
||||
expect(params['unwatched'], '1');
|
||||
});
|
||||
|
||||
test('favoritesOnly is ignored (Plex has no favorites)', () {
|
||||
expect(translator.toQueryParameters(const LibraryQuery(favoritesOnly: true)), isEmpty);
|
||||
});
|
||||
|
||||
test('arbitrary filter clauses pass through verbatim', () {
|
||||
final params = translator.toQueryParameters(
|
||||
const LibraryQuery(
|
||||
@@ -210,6 +214,16 @@ void main() {
|
||||
expect(params['Filters'], 'IsUnplayed');
|
||||
});
|
||||
|
||||
test('favoritesOnly sets Filters=IsFavorite', () {
|
||||
final params = translator.toQueryParameters(const LibraryQuery(favoritesOnly: true));
|
||||
expect(params['Filters'], 'IsFavorite');
|
||||
});
|
||||
|
||||
test('unwatched + favorites combine into a comma-separated Filters list', () {
|
||||
final params = translator.toQueryParameters(const LibraryQuery(includeWatched: false, favoritesOnly: true));
|
||||
expect(params['Filters'], 'IsUnplayed,IsFavorite');
|
||||
});
|
||||
|
||||
test('search puts text in SearchTerm', () {
|
||||
final params = translator.toQueryParameters(const LibraryQuery(search: 'matrix'));
|
||||
expect(params['SearchTerm'], 'matrix');
|
||||
@@ -298,6 +312,14 @@ void main() {
|
||||
expect(roundTrip(input)['director'], '12345');
|
||||
});
|
||||
|
||||
test('favorite=1 maps to favoritesOnly, not a generic filter entry', () {
|
||||
// Jellyfin-only key; the Plex translator deliberately drops it, so it
|
||||
// must not leak into the verbatim-pass-through filters bucket either.
|
||||
final query = libraryQueryFromPlexMap(map: {'favorite': '1'});
|
||||
expect(query.favoritesOnly, isTrue);
|
||||
expect(query.filters, isEmpty);
|
||||
});
|
||||
|
||||
test('libraryKind argument overrides any type entry in the map', () {
|
||||
// The browse tab always passes the library's actual kind; map's `type`
|
||||
// is dropped if the explicit arg is present.
|
||||
|
||||
Reference in New Issue
Block a user