fix(libraries): add Plex TV date added sort

close #1369
This commit is contained in:
edde746
2026-06-18 09:05:09 +02:00
parent d9b03160f0
commit 52d70dd97d
2 changed files with 26 additions and 15 deletions
+16 -10
View File
@@ -1791,16 +1791,18 @@ class PlexClient
/// Append sort options that Plex honors via the `sort=` parameter but does not
/// advertise in `/library/sections/{id}/sorts`.
///
/// Plays (`viewCount`) and the signed-in user's rating (`userRating`) both
/// sort correctly on movie/show libraries, so we surface them client-side
/// (mirroring how the Jellyfin sort list is built). De-duped by key so we
/// never double up if a future Plex version starts advertising them.
/// Date Added (`addedAt`), plays (`viewCount`), and the signed-in user's
/// rating (`userRating`) sort correctly on movie/show libraries, so we
/// surface them client-side (mirroring how the Jellyfin sort list is built).
/// De-duped by key so we never double up if a future Plex version starts
/// advertising them.
List<MediaSort> _withExtraSorts(List<MediaSort> base, String? libraryType) {
final type = libraryType?.toLowerCase();
if (type != 'movie' && type != 'show') return base;
final keys = base.map((s) => s.key).toSet();
final extras = [
_dateAddedSort(),
MediaSort(
key: 'viewCount',
descKey: 'viewCount:desc',
@@ -1818,18 +1820,22 @@ class PlexClient
return [...base, ...extras];
}
MediaSort _dateAddedSort() {
return MediaSort(
key: 'addedAt',
descKey: 'addedAt:desc',
title: t.libraries.sortLabels.dateAdded,
defaultDirection: 'desc',
);
}
/// Build fallback sort options based on library type.
///
/// If [libraryType] is null, returns generic sorts without the show-specific options.
List<MediaSort> _getFallbackSorts(String? libraryType) {
final fallbackSorts = <MediaSort>[
MediaSort(key: 'titleSort', title: t.libraries.sortLabels.title, defaultDirection: 'asc'),
MediaSort(
key: 'addedAt',
descKey: 'addedAt:desc',
title: t.libraries.sortLabels.dateAdded,
defaultDirection: 'desc',
),
_dateAddedSort(),
];
// Add "Latest Episode Air Date" only for TV show libraries
+10 -5
View File
@@ -77,7 +77,7 @@ void main() {
]);
});
test('appends Plays and User Rating sorts only for movie/show libraries', () async {
test('appends Date Added, Plays, and User Rating sorts only for movie/show libraries', () async {
PlexClient clientReturning() => makeClient((request) async {
if (request.url.path == '/library/sections/1/sorts') {
return http.Response(
@@ -99,7 +99,11 @@ void main() {
final client = clientReturning();
addTearDown(client.close);
final sorts = await client.fetchSortOptions('1', libraryType: type);
expect(sorts.map((s) => s.key), ['titleSort', 'viewCount', 'userRating'], reason: type);
expect(sorts.map((s) => s.key), ['titleSort', 'addedAt', 'viewCount', 'userRating'], reason: type);
final dateAdded = sorts.singleWhere((s) => s.key == 'addedAt');
expect(dateAdded.descKey, 'addedAt:desc', reason: type);
expect(dateAdded.defaultDirection, 'desc', reason: type);
}
// Other library types (e.g. music) are left as the server returned them.
@@ -109,7 +113,7 @@ void main() {
expect(musicSorts.map((s) => s.key), ['titleSort']);
});
test('does not duplicate Plays/User Rating when the server already advertises them', () async {
test('does not duplicate Date Added/Plays when the server already advertises them', () async {
final client = makeClient((request) async {
if (request.url.path == '/library/sections/1/sorts') {
return http.Response(
@@ -117,6 +121,7 @@ void main() {
'MediaContainer': {
'Directory': [
{'key': 'titleSort', 'title': 'Title', 'defaultDirection': 'asc'},
{'key': 'addedAt', 'title': 'Date Added', 'defaultDirection': 'desc'},
{'key': 'viewCount', 'title': 'Plays', 'defaultDirection': 'desc'},
],
},
@@ -130,8 +135,8 @@ void main() {
addTearDown(client.close);
final sorts = await client.fetchSortOptions('1', libraryType: 'movie');
// viewCount already advertised -> not duplicated; userRating still appended.
expect(sorts.map((s) => s.key), ['titleSort', 'viewCount', 'userRating']);
// addedAt/viewCount already advertised -> not duplicated; userRating still appended.
expect(sorts.map((s) => s.key), ['titleSort', 'addedAt', 'viewCount', 'userRating']);
});
test('library content stamps known section when Plex omits librarySectionID on rows', () async {