feat(jellyfin): add unwatched library filter

close #1116
This commit is contained in:
edde746
2026-05-25 22:43:39 +02:00
parent 50be8565d9
commit 366ae67341
33 changed files with 130 additions and 38 deletions
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "Genre",
"year": "År",
"contentRating": "Aldersvurdering",
"tag": "Tag"
"tag": "Tag",
"unwatched": "Usete"
},
"sortLabels": {
"title": "Titel",
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "Genre",
"year": "Jahr",
"contentRating": "Altersfreigabe",
"tag": "Tag"
"tag": "Tag",
"unwatched": "Ungesehene"
},
"sortLabels": {
"title": "Titel",
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "Genre",
"year": "Year",
"contentRating": "Content Rating",
"tag": "Tag"
"tag": "Tag",
"unwatched": "Unwatched"
},
"sortLabels": {
"title": "Title",
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "Género",
"year": "Año",
"contentRating": "Clasificación",
"tag": "Etiqueta"
"tag": "Etiqueta",
"unwatched": "No vistos"
},
"sortLabels": {
"title": "Título",
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "Genre",
"year": "Année",
"contentRating": "Classification",
"tag": "Tag"
"tag": "Tag",
"unwatched": "Non vus"
},
"sortLabels": {
"title": "Titre",
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "Genere",
"year": "Anno",
"contentRating": "Classificazione",
"tag": "Tag"
"tag": "Tag",
"unwatched": "Non visti"
},
"sortLabels": {
"title": "Titolo",
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "ジャンル",
"year": "年",
"contentRating": "視聴年齢区分",
"tag": "タグ"
"tag": "タグ",
"unwatched": "未視聴"
},
"sortLabels": {
"title": "タイトル",
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "장르",
"year": "연도",
"contentRating": "시청 등급",
"tag": "태그"
"tag": "태그",
"unwatched": "미시청"
},
"sortLabels": {
"title": "제목",
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "Sjanger",
"year": "År",
"contentRating": "Aldersgrense",
"tag": "Tag"
"tag": "Tag",
"unwatched": "Usette"
},
"sortLabels": {
"title": "Tittel",
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "Genre",
"year": "Jaar",
"contentRating": "Leeftijdsclassificatie",
"tag": "Tag"
"tag": "Tag",
"unwatched": "Onbekeken"
},
"sortLabels": {
"title": "Titel",
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "Gatunek",
"year": "Rok",
"contentRating": "Klasyfikacja wiekowa",
"tag": "Tag"
"tag": "Tag",
"unwatched": "Nieobejrzane"
},
"sortLabels": {
"title": "Tytuł",
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "Gênero",
"year": "Ano",
"contentRating": "Classificação",
"tag": "Tag"
"tag": "Tag",
"unwatched": "Não assistidos"
},
"sortLabels": {
"title": "Título",
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "Жанр",
"year": "Год",
"contentRating": "Возрастной рейтинг",
"tag": "Тег"
"tag": "Тег",
"unwatched": "Непросмотренные"
},
"sortLabels": {
"title": "Название",
+1 -1
View File
@@ -4,7 +4,7 @@
/// To regenerate, run: `dart run slang`
///
/// Locales: 15
/// Strings: 17565 (1171 per locale)
/// Strings: 17580 (1172 per locale)
// coverage:ignore-file
// ignore_for_file: type=lint, unused_import
+3 -1
View File
@@ -1621,6 +1621,7 @@ class _TranslationsLibrariesFilterCategoriesDa extends TranslationsLibrariesFilt
@override String get year => 'År';
@override String get contentRating => 'Aldersvurdering';
@override String get tag => 'Tag';
@override String get unwatched => 'Usete';
}
// Path: libraries.sortLabels
@@ -2453,6 +2454,7 @@ extension on TranslationsDa {
'libraries.filterCategories.year' => 'År',
'libraries.filterCategories.contentRating' => 'Aldersvurdering',
'libraries.filterCategories.tag' => 'Tag',
'libraries.filterCategories.unwatched' => 'Usete',
'libraries.sortLabels.title' => 'Titel',
'libraries.sortLabels.dateAdded' => 'Tilføjet dato',
'libraries.sortLabels.releaseDate' => 'Udgivelsesdato',
@@ -2825,9 +2827,9 @@ extension on TranslationsDa {
'metadataEdit.summary' => 'Resumé',
'metadataEdit.poster' => 'Plakat',
'metadataEdit.background' => 'Baggrund',
'metadataEdit.logo' => 'Logo',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => 'Logo',
'metadataEdit.squareArt' => 'Kvadratisk billede',
'metadataEdit.selectPoster' => 'Vælg plakat',
'metadataEdit.selectBackground' => 'Vælg baggrund',
+3 -1
View File
@@ -1621,6 +1621,7 @@ class _TranslationsLibrariesFilterCategoriesDe extends TranslationsLibrariesFilt
@override String get year => 'Jahr';
@override String get contentRating => 'Altersfreigabe';
@override String get tag => 'Tag';
@override String get unwatched => 'Ungesehene';
}
// Path: libraries.sortLabels
@@ -2453,6 +2454,7 @@ extension on TranslationsDe {
'libraries.filterCategories.year' => 'Jahr',
'libraries.filterCategories.contentRating' => 'Altersfreigabe',
'libraries.filterCategories.tag' => 'Tag',
'libraries.filterCategories.unwatched' => 'Ungesehene',
'libraries.sortLabels.title' => 'Titel',
'libraries.sortLabels.dateAdded' => 'Hinzugefügt am',
'libraries.sortLabels.releaseDate' => 'Erscheinungsdatum',
@@ -2825,9 +2827,9 @@ extension on TranslationsDe {
'metadataEdit.summary' => 'Zusammenfassung',
'metadataEdit.poster' => 'Poster',
'metadataEdit.background' => 'Hintergrund',
'metadataEdit.logo' => 'Logo',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => 'Logo',
'metadataEdit.squareArt' => 'Quadratisches Bild',
'metadataEdit.selectPoster' => 'Poster auswählen',
'metadataEdit.selectBackground' => 'Hintergrund auswählen',
+5 -1
View File
@@ -3775,6 +3775,9 @@ class TranslationsLibrariesFilterCategoriesEn {
/// en: 'Tag'
String get tag => 'Tag';
/// en: 'Unwatched'
String get unwatched => 'Unwatched';
}
// Path: libraries.sortLabels
@@ -4801,6 +4804,7 @@ extension on Translations {
'libraries.filterCategories.year' => 'Year',
'libraries.filterCategories.contentRating' => 'Content Rating',
'libraries.filterCategories.tag' => 'Tag',
'libraries.filterCategories.unwatched' => 'Unwatched',
'libraries.sortLabels.title' => 'Title',
'libraries.sortLabels.dateAdded' => 'Date Added',
'libraries.sortLabels.releaseDate' => 'Release Date',
@@ -5173,9 +5177,9 @@ extension on Translations {
'metadataEdit.summary' => 'Summary',
'metadataEdit.poster' => 'Poster',
'metadataEdit.background' => 'Background',
'metadataEdit.logo' => 'Logo',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => 'Logo',
'metadataEdit.squareArt' => 'Square Art',
'metadataEdit.selectPoster' => 'Select Poster',
'metadataEdit.selectBackground' => 'Select Background',
+3 -1
View File
@@ -1621,6 +1621,7 @@ class _TranslationsLibrariesFilterCategoriesEs extends TranslationsLibrariesFilt
@override String get year => 'Año';
@override String get contentRating => 'Clasificación';
@override String get tag => 'Etiqueta';
@override String get unwatched => 'No vistos';
}
// Path: libraries.sortLabels
@@ -2453,6 +2454,7 @@ extension on TranslationsEs {
'libraries.filterCategories.year' => 'Año',
'libraries.filterCategories.contentRating' => 'Clasificación',
'libraries.filterCategories.tag' => 'Etiqueta',
'libraries.filterCategories.unwatched' => 'No vistos',
'libraries.sortLabels.title' => 'Título',
'libraries.sortLabels.dateAdded' => 'Fecha de adición',
'libraries.sortLabels.releaseDate' => 'Fecha de estreno',
@@ -2825,9 +2827,9 @@ extension on TranslationsEs {
'metadataEdit.summary' => 'Resumen',
'metadataEdit.poster' => 'Póster',
'metadataEdit.background' => 'Fondo',
'metadataEdit.logo' => 'Logo',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => 'Logo',
'metadataEdit.squareArt' => 'Imagen cuadrada',
'metadataEdit.selectPoster' => 'Seleccionar póster',
'metadataEdit.selectBackground' => 'Seleccionar fondo',
+3 -1
View File
@@ -1621,6 +1621,7 @@ class _TranslationsLibrariesFilterCategoriesFr extends TranslationsLibrariesFilt
@override String get year => 'Année';
@override String get contentRating => 'Classification';
@override String get tag => 'Tag';
@override String get unwatched => 'Non vus';
}
// Path: libraries.sortLabels
@@ -2453,6 +2454,7 @@ extension on TranslationsFr {
'libraries.filterCategories.year' => 'Année',
'libraries.filterCategories.contentRating' => 'Classification',
'libraries.filterCategories.tag' => 'Tag',
'libraries.filterCategories.unwatched' => 'Non vus',
'libraries.sortLabels.title' => 'Titre',
'libraries.sortLabels.dateAdded' => 'Date d\'ajout',
'libraries.sortLabels.releaseDate' => 'Date de sortie',
@@ -2825,9 +2827,9 @@ extension on TranslationsFr {
'metadataEdit.summary' => 'Résumé',
'metadataEdit.poster' => 'Affiche',
'metadataEdit.background' => 'Arrière-plan',
'metadataEdit.logo' => 'Logo',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => 'Logo',
'metadataEdit.squareArt' => 'Image carrée',
'metadataEdit.selectPoster' => 'Sélectionner l\'affiche',
'metadataEdit.selectBackground' => 'Sélectionner l\'arrière-plan',
+3 -1
View File
@@ -1621,6 +1621,7 @@ class _TranslationsLibrariesFilterCategoriesIt extends TranslationsLibrariesFilt
@override String get year => 'Anno';
@override String get contentRating => 'Classificazione';
@override String get tag => 'Tag';
@override String get unwatched => 'Non visti';
}
// Path: libraries.sortLabels
@@ -2453,6 +2454,7 @@ extension on TranslationsIt {
'libraries.filterCategories.year' => 'Anno',
'libraries.filterCategories.contentRating' => 'Classificazione',
'libraries.filterCategories.tag' => 'Tag',
'libraries.filterCategories.unwatched' => 'Non visti',
'libraries.sortLabels.title' => 'Titolo',
'libraries.sortLabels.dateAdded' => 'Data di aggiunta',
'libraries.sortLabels.releaseDate' => 'Data di uscita',
@@ -2825,9 +2827,9 @@ extension on TranslationsIt {
'metadataEdit.summary' => 'Trama',
'metadataEdit.poster' => 'Poster',
'metadataEdit.background' => 'Sfondo',
'metadataEdit.logo' => 'Logo',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => 'Logo',
'metadataEdit.squareArt' => 'Immagine quadrata',
'metadataEdit.selectPoster' => 'Seleziona poster',
'metadataEdit.selectBackground' => 'Seleziona sfondo',
+3 -1
View File
@@ -1621,6 +1621,7 @@ class _TranslationsLibrariesFilterCategoriesJa extends TranslationsLibrariesFilt
@override String get year => '';
@override String get contentRating => '視聴年齢区分';
@override String get tag => 'タグ';
@override String get unwatched => '未視聴';
}
// Path: libraries.sortLabels
@@ -2453,6 +2454,7 @@ extension on TranslationsJa {
'libraries.filterCategories.year' => '',
'libraries.filterCategories.contentRating' => '視聴年齢区分',
'libraries.filterCategories.tag' => 'タグ',
'libraries.filterCategories.unwatched' => '未視聴',
'libraries.sortLabels.title' => 'タイトル',
'libraries.sortLabels.dateAdded' => '追加日',
'libraries.sortLabels.releaseDate' => 'リリース日',
@@ -2825,9 +2827,9 @@ extension on TranslationsJa {
'metadataEdit.summary' => 'あらすじ',
'metadataEdit.poster' => 'ポスター',
'metadataEdit.background' => '背景',
'metadataEdit.logo' => 'ロゴ',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => 'ロゴ',
'metadataEdit.squareArt' => '正方形アート',
'metadataEdit.selectPoster' => 'ポスターを選択',
'metadataEdit.selectBackground' => '背景を選択',
+3 -1
View File
@@ -1621,6 +1621,7 @@ class _TranslationsLibrariesFilterCategoriesKo extends TranslationsLibrariesFilt
@override String get year => '연도';
@override String get contentRating => '시청 등급';
@override String get tag => '태그';
@override String get unwatched => '미시청';
}
// Path: libraries.sortLabels
@@ -2453,6 +2454,7 @@ extension on TranslationsKo {
'libraries.filterCategories.year' => '연도',
'libraries.filterCategories.contentRating' => '시청 등급',
'libraries.filterCategories.tag' => '태그',
'libraries.filterCategories.unwatched' => '미시청',
'libraries.sortLabels.title' => '제목',
'libraries.sortLabels.dateAdded' => '추가된 날짜',
'libraries.sortLabels.releaseDate' => '출시일',
@@ -2825,9 +2827,9 @@ extension on TranslationsKo {
'metadataEdit.summary' => '줄거리',
'metadataEdit.poster' => '포스터',
'metadataEdit.background' => '배경',
'metadataEdit.logo' => '로고',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => '로고',
'metadataEdit.squareArt' => '정사각형 아트',
'metadataEdit.selectPoster' => '포스터 선택',
'metadataEdit.selectBackground' => '배경 선택',
+3 -1
View File
@@ -1621,6 +1621,7 @@ class _TranslationsLibrariesFilterCategoriesNb extends TranslationsLibrariesFilt
@override String get year => 'År';
@override String get contentRating => 'Aldersgrense';
@override String get tag => 'Tag';
@override String get unwatched => 'Usette';
}
// Path: libraries.sortLabels
@@ -2453,6 +2454,7 @@ extension on TranslationsNb {
'libraries.filterCategories.year' => 'År',
'libraries.filterCategories.contentRating' => 'Aldersgrense',
'libraries.filterCategories.tag' => 'Tag',
'libraries.filterCategories.unwatched' => 'Usette',
'libraries.sortLabels.title' => 'Tittel',
'libraries.sortLabels.dateAdded' => 'Lagt til-dato',
'libraries.sortLabels.releaseDate' => 'Utgivelsesdato',
@@ -2825,9 +2827,9 @@ extension on TranslationsNb {
'metadataEdit.summary' => 'Sammendrag',
'metadataEdit.poster' => 'Plakat',
'metadataEdit.background' => 'Bakgrunn',
'metadataEdit.logo' => 'Logo',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => 'Logo',
'metadataEdit.squareArt' => 'Kvadratisk bilde',
'metadataEdit.selectPoster' => 'Velg plakat',
'metadataEdit.selectBackground' => 'Velg bakgrunn',
+3 -1
View File
@@ -1621,6 +1621,7 @@ class _TranslationsLibrariesFilterCategoriesNl extends TranslationsLibrariesFilt
@override String get year => 'Jaar';
@override String get contentRating => 'Leeftijdsclassificatie';
@override String get tag => 'Tag';
@override String get unwatched => 'Onbekeken';
}
// Path: libraries.sortLabels
@@ -2453,6 +2454,7 @@ extension on TranslationsNl {
'libraries.filterCategories.year' => 'Jaar',
'libraries.filterCategories.contentRating' => 'Leeftijdsclassificatie',
'libraries.filterCategories.tag' => 'Tag',
'libraries.filterCategories.unwatched' => 'Onbekeken',
'libraries.sortLabels.title' => 'Titel',
'libraries.sortLabels.dateAdded' => 'Toegevoegd op',
'libraries.sortLabels.releaseDate' => 'Uitgavedatum',
@@ -2825,9 +2827,9 @@ extension on TranslationsNl {
'metadataEdit.summary' => 'Samenvatting',
'metadataEdit.poster' => 'Poster',
'metadataEdit.background' => 'Achtergrond',
'metadataEdit.logo' => 'Logo',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => 'Logo',
'metadataEdit.squareArt' => 'Vierkante afbeelding',
'metadataEdit.selectPoster' => 'Poster selecteren',
'metadataEdit.selectBackground' => 'Achtergrond selecteren',
+3 -1
View File
@@ -1621,6 +1621,7 @@ class _TranslationsLibrariesFilterCategoriesPl extends TranslationsLibrariesFilt
@override String get year => 'Rok';
@override String get contentRating => 'Klasyfikacja wiekowa';
@override String get tag => 'Tag';
@override String get unwatched => 'Nieobejrzane';
}
// Path: libraries.sortLabels
@@ -2453,6 +2454,7 @@ extension on TranslationsPl {
'libraries.filterCategories.year' => 'Rok',
'libraries.filterCategories.contentRating' => 'Klasyfikacja wiekowa',
'libraries.filterCategories.tag' => 'Tag',
'libraries.filterCategories.unwatched' => 'Nieobejrzane',
'libraries.sortLabels.title' => 'Tytuł',
'libraries.sortLabels.dateAdded' => 'Data dodania',
'libraries.sortLabels.releaseDate' => 'Data premiery',
@@ -2825,9 +2827,9 @@ extension on TranslationsPl {
'metadataEdit.summary' => 'Opis',
'metadataEdit.poster' => 'Plakat',
'metadataEdit.background' => 'Tło',
'metadataEdit.logo' => 'Logo',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => 'Logo',
'metadataEdit.squareArt' => 'Kwadratowy obraz',
'metadataEdit.selectPoster' => 'Wybierz plakat',
'metadataEdit.selectBackground' => 'Wybierz tło',
+3 -1
View File
@@ -1621,6 +1621,7 @@ class _TranslationsLibrariesFilterCategoriesPt extends TranslationsLibrariesFilt
@override String get year => 'Ano';
@override String get contentRating => 'Classificação';
@override String get tag => 'Tag';
@override String get unwatched => 'Não assistidos';
}
// Path: libraries.sortLabels
@@ -2453,6 +2454,7 @@ extension on TranslationsPt {
'libraries.filterCategories.year' => 'Ano',
'libraries.filterCategories.contentRating' => 'Classificação',
'libraries.filterCategories.tag' => 'Tag',
'libraries.filterCategories.unwatched' => 'Não assistidos',
'libraries.sortLabels.title' => 'Título',
'libraries.sortLabels.dateAdded' => 'Data de adição',
'libraries.sortLabels.releaseDate' => 'Data de lançamento',
@@ -2825,9 +2827,9 @@ extension on TranslationsPt {
'metadataEdit.summary' => 'Sinopse',
'metadataEdit.poster' => 'Poster',
'metadataEdit.background' => 'Plano de Fundo',
'metadataEdit.logo' => 'Logo',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => 'Logo',
'metadataEdit.squareArt' => 'Imagem Quadrada',
'metadataEdit.selectPoster' => 'Selecionar Poster',
'metadataEdit.selectBackground' => 'Selecionar Plano de Fundo',
+3 -1
View File
@@ -1621,6 +1621,7 @@ class _TranslationsLibrariesFilterCategoriesRu extends TranslationsLibrariesFilt
@override String get year => 'Год';
@override String get contentRating => 'Возрастной рейтинг';
@override String get tag => 'Тег';
@override String get unwatched => 'Непросмотренные';
}
// Path: libraries.sortLabels
@@ -2453,6 +2454,7 @@ extension on TranslationsRu {
'libraries.filterCategories.year' => 'Год',
'libraries.filterCategories.contentRating' => 'Возрастной рейтинг',
'libraries.filterCategories.tag' => 'Тег',
'libraries.filterCategories.unwatched' => 'Непросмотренные',
'libraries.sortLabels.title' => 'Название',
'libraries.sortLabels.dateAdded' => 'Дата добавления',
'libraries.sortLabels.releaseDate' => 'Дата выхода',
@@ -2825,9 +2827,9 @@ extension on TranslationsRu {
'metadataEdit.summary' => 'Описание',
'metadataEdit.poster' => 'Постер',
'metadataEdit.background' => 'Фон',
'metadataEdit.logo' => 'Логотип',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => 'Логотип',
'metadataEdit.squareArt' => 'Квадратное изображение',
'metadataEdit.selectPoster' => 'Выбрать постер',
'metadataEdit.selectBackground' => 'Выбрать фон',
+3 -1
View File
@@ -1621,6 +1621,7 @@ class _TranslationsLibrariesFilterCategoriesSv extends TranslationsLibrariesFilt
@override String get year => 'År';
@override String get contentRating => 'Åldersgräns';
@override String get tag => 'Tagg';
@override String get unwatched => 'Osedda';
}
// Path: libraries.sortLabels
@@ -2453,6 +2454,7 @@ extension on TranslationsSv {
'libraries.filterCategories.year' => 'År',
'libraries.filterCategories.contentRating' => 'Åldersgräns',
'libraries.filterCategories.tag' => 'Tagg',
'libraries.filterCategories.unwatched' => 'Osedda',
'libraries.sortLabels.title' => 'Titel',
'libraries.sortLabels.dateAdded' => 'Tillagd',
'libraries.sortLabels.releaseDate' => 'Releasedatum',
@@ -2825,9 +2827,9 @@ extension on TranslationsSv {
'metadataEdit.summary' => 'Sammanfattning',
'metadataEdit.poster' => 'Poster',
'metadataEdit.background' => 'Bakgrund',
'metadataEdit.logo' => 'Logotyp',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => 'Logotyp',
'metadataEdit.squareArt' => 'Kvadratisk bild',
'metadataEdit.selectPoster' => 'Välj poster',
'metadataEdit.selectBackground' => 'Välj bakgrund',
+3 -1
View File
@@ -1621,6 +1621,7 @@ class _TranslationsLibrariesFilterCategoriesZh extends TranslationsLibrariesFilt
@override String get year => '年份';
@override String get contentRating => '内容分级';
@override String get tag => '标签';
@override String get unwatched => '未观看';
}
// Path: libraries.sortLabels
@@ -2453,6 +2454,7 @@ extension on TranslationsZh {
'libraries.filterCategories.year' => '年份',
'libraries.filterCategories.contentRating' => '内容分级',
'libraries.filterCategories.tag' => '标签',
'libraries.filterCategories.unwatched' => '未观看',
'libraries.sortLabels.title' => '标题',
'libraries.sortLabels.dateAdded' => '添加日期',
'libraries.sortLabels.releaseDate' => '发行日期',
@@ -2825,9 +2827,9 @@ extension on TranslationsZh {
'metadataEdit.summary' => '简介',
'metadataEdit.poster' => '海报',
'metadataEdit.background' => '背景',
'metadataEdit.logo' => '标志',
_ => null,
} ?? switch (path) {
'metadataEdit.logo' => '标志',
'metadataEdit.squareArt' => '方形图片',
'metadataEdit.selectPoster' => '选择海报',
'metadataEdit.selectBackground' => '选择背景',
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "Genre",
"year": "År",
"contentRating": "Åldersgräns",
"tag": "Tagg"
"tag": "Tagg",
"unwatched": "Osedda"
},
"sortLabels": {
"title": "Titel",
+2 -1
View File
@@ -705,7 +705,8 @@
"genre": "类型",
"year": "年份",
"contentRating": "内容分级",
"tag": "标签"
"tag": "标签",
"unwatched": "未观看"
},
"sortLabels": {
"title": "标题",
+17 -7
View File
@@ -127,15 +127,26 @@ mixin _JellyfinBrowseMethods on MediaServerCacheMixin {
}
/// Jellyfin's `/Items/Filters` returns Genres / OfficialRatings / Tags /
/// Categories + values from `/Items/Filters` in a single call. Keys are
/// translated to Plex's filter naming so the existing filter-param map
/// round-trips through `_buildFilterParams` unchanged; the synthesised
/// `MediaFilter.key` is prefixed `jellyfin:` so FiltersBottomSheet can
/// recognise it as cached and skip the per-category value fetch.
/// Categories + values from `/Items/Filters` in a single call. The unwatched
/// boolean is synthetic because Jellyfin exposes it as an `/Items` query
/// filter, not a filter-listing category. Keys are translated to Plex's
/// filter naming so the existing filter-param map round-trips through
/// `_buildFilterParams` unchanged; the synthesised `MediaFilter.key` is
/// prefixed `jellyfin:` so FiltersBottomSheet can recognise it as cached and
/// skip the per-category value fetch.
@override
Future<LibraryFilterResult> fetchLibraryFiltersWithValues(String libraryId) async {
final filters = <MediaFilter>[
MediaFilter(
filter: 'unwatched',
filterType: 'boolean',
key: 'jellyfin:unwatched',
title: t.libraries.filterCategories.unwatched,
type: 'filter',
),
];
final data = await _safeFetchFilterPayload(libraryId);
if (data == null) return LibraryFilterResult.empty;
if (data == null) return LibraryFilterResult(filters: filters, cachedValues: const {});
List<String> stringList(Object? raw) {
if (raw is! List) return const [];
return raw.whereType<String>().where((s) => s.isNotEmpty).toList();
@@ -157,7 +168,6 @@ mixin _JellyfinBrowseMethods on MediaServerCacheMixin {
'contentRating': t.libraries.filterCategories.contentRating,
'tag': t.libraries.filterCategories.tag,
};
final filters = <MediaFilter>[];
final values = <String, List<MediaFilterValue>>{};
for (final key in order) {
final entries = raw[key];
@@ -1343,6 +1343,41 @@ void main() {
expect(captured!.queryParameters['ImageTypeLimit'], '1');
});
test('fetchLibraryFiltersWithValues adds unwatched boolean filter', () async {
Uri? captured;
final scoped = JellyfinClient.forTesting(
connection: _conn(),
httpClient: MockClient((req) async {
captured = req.url;
return http.Response(
jsonEncode({
'Genres': ['Drama', 'Action'],
'OfficialRatings': ['PG-13'],
'Tags': ['Holiday'],
'Years': [2024, 1999],
}),
200,
headers: {'content-type': 'application/json'},
);
}),
);
addTearDown(scoped.close);
final result = await scoped.fetchLibraryFiltersWithValues('lib-1');
expect(captured, isNotNull);
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.first.filterType, 'boolean');
expect(result.filters.first.key, 'jellyfin:unwatched');
expect(result.filters.first.title, 'Unwatched');
expect(result.cachedValues.containsKey('unwatched'), isFalse);
expect(result.cachedValues['genre']!.map((value) => value.key), ['Action', 'Drama']);
expect(result.cachedValues['year']!.map((value) => value.key), ['2024', '1999']);
});
test('fetchLibraryContent uses sentinel total fallback when server omits total', () async {
final scoped = JellyfinClient.forTesting(
connection: _conn(),