feat: metadata editing

close #338
This commit is contained in:
edde746
2026-02-22 17:56:13 +01:00
parent 03fc1c1109
commit 4eb55885f7
28 changed files with 3033 additions and 10 deletions
+62 -1
View File
@@ -1,7 +1,7 @@
{
"app": {
"title": "Plezy"
},
},
"auth": {
"signInWithPlex": "Mit Plex anmelden",
"showQRCode": "QR-Code anzeigen",
@@ -831,5 +831,66 @@
"launchFailed": "Externer Player konnte nicht geöffnet werden",
"appNotInstalled": "${name} ist nicht installiert",
"playInExternalPlayer": "In externem Player abspielen"
},
"metadataEdit": {
"editMetadata": "Bearbeiten...",
"screenTitle": "Metadaten bearbeiten",
"basicInfo": "Grundlegende Infos",
"artwork": "Artwork",
"advancedSettings": "Erweiterte Einstellungen",
"title": "Titel",
"sortTitle": "Sortiertitel",
"originalTitle": "Originaltitel",
"releaseDate": "Erscheinungsdatum",
"contentRating": "Altersfreigabe",
"studio": "Studio",
"tagline": "Tagline",
"summary": "Zusammenfassung",
"poster": "Poster",
"background": "Hintergrund",
"selectPoster": "Poster auswählen",
"selectBackground": "Hintergrund auswählen",
"fromUrl": "Von URL",
"uploadFile": "Datei hochladen",
"enterImageUrl": "Bild-URL eingeben",
"imageUrl": "Bild-URL",
"metadataUpdated": "Metadaten aktualisiert",
"metadataUpdateFailed": "Metadaten konnten nicht aktualisiert werden",
"artworkUpdated": "Artwork aktualisiert",
"artworkUpdateFailed": "Artwork konnte nicht aktualisiert werden",
"noArtworkAvailable": "Kein Artwork verfügbar",
"notSet": "Nicht festgelegt",
"libraryDefault": "Bibliotheksstandard",
"accountDefault": "Kontostandard",
"seriesDefault": "Serienstandard",
"episodeSorting": "Episodensortierung",
"oldestFirst": "Älteste zuerst",
"newestFirst": "Neueste zuerst",
"keep": "Behalten",
"allEpisodes": "Alle Episoden",
"latestEpisodes": "${count} neueste Episoden",
"latestEpisode": "Neueste Episode",
"episodesAddedPastDays": "Episoden der letzten ${count} Tage",
"deleteAfterPlaying": "Episoden nach Wiedergabe löschen",
"never": "Nie",
"afterADay": "Nach einem Tag",
"afterAWeek": "Nach einer Woche",
"afterAMonth": "Nach einem Monat",
"onNextRefresh": "Bei nächster Aktualisierung",
"seasons": "Staffeln",
"show": "Anzeigen",
"hide": "Ausblenden",
"episodeOrdering": "Episodenreihenfolge",
"tmdbAiring": "The Movie Database (Ausgestrahlt)",
"tvdbAiring": "TheTVDB (Ausgestrahlt)",
"tvdbAbsolute": "TheTVDB (Absolut)",
"metadataLanguage": "Metadaten-Sprache",
"useOriginalTitle": "Originaltitel verwenden",
"preferredAudioLanguage": "Bevorzugte Audiosprache",
"preferredSubtitleLanguage": "Bevorzugte Untertitelsprache",
"subtitleMode": "Automatische Untertitelauswahl",
"manuallySelected": "Manuell ausgewählt",
"shownWithForeignAudio": "Bei fremdsprachigem Audio anzeigen",
"alwaysEnabled": "Immer aktiviert"
}
}
+61
View File
@@ -831,5 +831,66 @@
"launchFailed": "Failed to open external player",
"appNotInstalled": "${name} is not installed",
"playInExternalPlayer": "Play in External Player"
},
"metadataEdit": {
"editMetadata": "Edit...",
"screenTitle": "Edit Metadata",
"basicInfo": "Basic Info",
"artwork": "Artwork",
"advancedSettings": "Advanced Settings",
"title": "Title",
"sortTitle": "Sort Title",
"originalTitle": "Original Title",
"releaseDate": "Release Date",
"contentRating": "Content Rating",
"studio": "Studio",
"tagline": "Tagline",
"summary": "Summary",
"poster": "Poster",
"background": "Background",
"selectPoster": "Select Poster",
"selectBackground": "Select Background",
"fromUrl": "From URL",
"uploadFile": "Upload File",
"enterImageUrl": "Enter image URL",
"imageUrl": "Image URL",
"metadataUpdated": "Metadata updated",
"metadataUpdateFailed": "Failed to update metadata",
"artworkUpdated": "Artwork updated",
"artworkUpdateFailed": "Failed to update artwork",
"noArtworkAvailable": "No artwork available",
"notSet": "Not set",
"libraryDefault": "Library default",
"accountDefault": "Account default",
"seriesDefault": "Series default",
"episodeSorting": "Episode Sorting",
"oldestFirst": "Oldest first",
"newestFirst": "Newest first",
"keep": "Keep",
"allEpisodes": "All episodes",
"latestEpisodes": "${count} latest episodes",
"latestEpisode": "Latest episode",
"episodesAddedPastDays": "Episodes added in the past ${count} days",
"deleteAfterPlaying": "Delete Episodes After Playing",
"never": "Never",
"afterADay": "After a day",
"afterAWeek": "After a week",
"afterAMonth": "After a month",
"onNextRefresh": "On next refresh",
"seasons": "Seasons",
"show": "Show",
"hide": "Hide",
"episodeOrdering": "Episode Ordering",
"tmdbAiring": "The Movie Database (Aired)",
"tvdbAiring": "TheTVDB (Aired)",
"tvdbAbsolute": "TheTVDB (Absolute)",
"metadataLanguage": "Metadata Language",
"useOriginalTitle": "Use Original Title",
"preferredAudioLanguage": "Preferred Audio Language",
"preferredSubtitleLanguage": "Preferred Subtitle Language",
"subtitleMode": "Auto-Select Subtitle Mode",
"manuallySelected": "Manually selected",
"shownWithForeignAudio": "Shown with foreign audio",
"alwaysEnabled": "Always enabled"
}
}
+62 -1
View File
@@ -1,7 +1,7 @@
{
"app": {
"title": "Plezy"
},
},
"auth": {
"signInWithPlex": "Inicia sesión con Plex",
"showQRCode": "Mostrar código QR",
@@ -831,5 +831,66 @@
"launchFailed": "No se pudo abrir el reproductor externo",
"appNotInstalled": "${name} no está instalado",
"playInExternalPlayer": "Reproducir en reproductor externo"
},
"metadataEdit": {
"editMetadata": "Editar...",
"screenTitle": "Editar metadatos",
"basicInfo": "Información básica",
"artwork": "Artwork",
"advancedSettings": "Ajustes avanzados",
"title": "Título",
"sortTitle": "Título de ordenación",
"originalTitle": "Título original",
"releaseDate": "Fecha de estreno",
"contentRating": "Clasificación de contenido",
"studio": "Estudio",
"tagline": "Eslogan",
"summary": "Resumen",
"poster": "Póster",
"background": "Fondo",
"selectPoster": "Seleccionar póster",
"selectBackground": "Seleccionar fondo",
"fromUrl": "Desde URL",
"uploadFile": "Subir archivo",
"enterImageUrl": "Introducir URL de imagen",
"imageUrl": "URL de imagen",
"metadataUpdated": "Metadatos actualizados",
"metadataUpdateFailed": "Error al actualizar los metadatos",
"artworkUpdated": "Artwork actualizado",
"artworkUpdateFailed": "Error al actualizar el artwork",
"noArtworkAvailable": "No hay artwork disponible",
"notSet": "No establecido",
"libraryDefault": "Predeterminado de biblioteca",
"accountDefault": "Predeterminado de cuenta",
"seriesDefault": "Predeterminado de serie",
"episodeSorting": "Orden de episodios",
"oldestFirst": "Más antiguos primero",
"newestFirst": "Más recientes primero",
"keep": "Conservar",
"allEpisodes": "Todos los episodios",
"latestEpisodes": "${count} episodios más recientes",
"latestEpisode": "Episodio más reciente",
"episodesAddedPastDays": "Episodios añadidos en los últimos ${count} días",
"deleteAfterPlaying": "Eliminar episodios después de reproducir",
"never": "Nunca",
"afterADay": "Después de un día",
"afterAWeek": "Después de una semana",
"afterAMonth": "Después de un mes",
"onNextRefresh": "En la próxima actualización",
"seasons": "Temporadas",
"show": "Mostrar",
"hide": "Ocultar",
"episodeOrdering": "Orden de episodios",
"tmdbAiring": "The Movie Database (Emisión)",
"tvdbAiring": "TheTVDB (Emisión)",
"tvdbAbsolute": "TheTVDB (Absoluto)",
"metadataLanguage": "Idioma de metadatos",
"useOriginalTitle": "Usar título original",
"preferredAudioLanguage": "Idioma de audio preferido",
"preferredSubtitleLanguage": "Idioma de subtítulos preferido",
"subtitleMode": "Selección automática de subtítulos",
"manuallySelected": "Seleccionado manualmente",
"shownWithForeignAudio": "Mostrar con audio extranjero",
"alwaysEnabled": "Siempre activado"
}
}
+62 -1
View File
@@ -1,7 +1,7 @@
{
"app": {
"title": "Plezy"
},
},
"auth": {
"signInWithPlex": "S'inscrire avec Plex",
"showQRCode": "Afficher le QR Code",
@@ -831,5 +831,66 @@
"launchFailed": "Impossible d'ouvrir le lecteur externe",
"appNotInstalled": "${name} n'est pas installé",
"playInExternalPlayer": "Lire dans un lecteur externe"
},
"metadataEdit": {
"editMetadata": "Modifier...",
"screenTitle": "Modifier les métadonnées",
"basicInfo": "Informations de base",
"artwork": "Artwork",
"advancedSettings": "Paramètres avancés",
"title": "Titre",
"sortTitle": "Titre de tri",
"originalTitle": "Titre original",
"releaseDate": "Date de sortie",
"contentRating": "Classification",
"studio": "Studio",
"tagline": "Slogan",
"summary": "Résumé",
"poster": "Affiche",
"background": "Arrière-plan",
"selectPoster": "Sélectionner l'affiche",
"selectBackground": "Sélectionner l'arrière-plan",
"fromUrl": "Depuis une URL",
"uploadFile": "Importer un fichier",
"enterImageUrl": "Entrer l'URL de l'image",
"imageUrl": "URL de l'image",
"metadataUpdated": "Métadonnées mises à jour",
"metadataUpdateFailed": "Échec de la mise à jour des métadonnées",
"artworkUpdated": "Artwork mis à jour",
"artworkUpdateFailed": "Échec de la mise à jour de l'artwork",
"noArtworkAvailable": "Aucun artwork disponible",
"notSet": "Non défini",
"libraryDefault": "Par défaut de la bibliothèque",
"accountDefault": "Par défaut du compte",
"seriesDefault": "Par défaut de la série",
"episodeSorting": "Tri des épisodes",
"oldestFirst": "Plus anciens en premier",
"newestFirst": "Plus récents en premier",
"keep": "Conserver",
"allEpisodes": "Tous les épisodes",
"latestEpisodes": "${count} derniers épisodes",
"latestEpisode": "Dernier épisode",
"episodesAddedPastDays": "Épisodes ajoutés ces ${count} derniers jours",
"deleteAfterPlaying": "Supprimer les épisodes après lecture",
"never": "Jamais",
"afterADay": "Après un jour",
"afterAWeek": "Après une semaine",
"afterAMonth": "Après un mois",
"onNextRefresh": "Au prochain rafraîchissement",
"seasons": "Saisons",
"show": "Afficher",
"hide": "Masquer",
"episodeOrdering": "Ordre des épisodes",
"tmdbAiring": "The Movie Database (Diffusion)",
"tvdbAiring": "TheTVDB (Diffusion)",
"tvdbAbsolute": "TheTVDB (Absolu)",
"metadataLanguage": "Langue des métadonnées",
"useOriginalTitle": "Utiliser le titre original",
"preferredAudioLanguage": "Langue audio préférée",
"preferredSubtitleLanguage": "Langue de sous-titres préférée",
"subtitleMode": "Sélection automatique des sous-titres",
"manuallySelected": "Sélectionné manuellement",
"shownWithForeignAudio": "Affichés avec audio étranger",
"alwaysEnabled": "Toujours activé"
}
}
+62 -1
View File
@@ -1,7 +1,7 @@
{
"app": {
"title": "Plezy"
},
},
"auth": {
"signInWithPlex": "Accedi con Plex",
"showQRCode": "Mostra QR Code",
@@ -831,5 +831,66 @@
"launchFailed": "Impossibile aprire il lettore esterno",
"appNotInstalled": "${name} non è installato",
"playInExternalPlayer": "Riproduci in lettore esterno"
},
"metadataEdit": {
"editMetadata": "Modifica...",
"screenTitle": "Modifica metadati",
"basicInfo": "Informazioni di base",
"artwork": "Artwork",
"advancedSettings": "Impostazioni avanzate",
"title": "Titolo",
"sortTitle": "Titolo di ordinamento",
"originalTitle": "Titolo originale",
"releaseDate": "Data di uscita",
"contentRating": "Classificazione",
"studio": "Studio",
"tagline": "Tagline",
"summary": "Trama",
"poster": "Poster",
"background": "Sfondo",
"selectPoster": "Seleziona poster",
"selectBackground": "Seleziona sfondo",
"fromUrl": "Da URL",
"uploadFile": "Carica file",
"enterImageUrl": "Inserisci URL immagine",
"imageUrl": "URL immagine",
"metadataUpdated": "Metadati aggiornati",
"metadataUpdateFailed": "Aggiornamento metadati non riuscito",
"artworkUpdated": "Artwork aggiornato",
"artworkUpdateFailed": "Aggiornamento artwork non riuscito",
"noArtworkAvailable": "Nessun artwork disponibile",
"notSet": "Non impostato",
"libraryDefault": "Predefinito libreria",
"accountDefault": "Predefinito account",
"seriesDefault": "Predefinito serie",
"episodeSorting": "Ordinamento episodi",
"oldestFirst": "Più vecchi prima",
"newestFirst": "Più recenti prima",
"keep": "Conserva",
"allEpisodes": "Tutti gli episodi",
"latestEpisodes": "${count} episodi più recenti",
"latestEpisode": "Episodio più recente",
"episodesAddedPastDays": "Episodi aggiunti negli ultimi ${count} giorni",
"deleteAfterPlaying": "Elimina episodi dopo la riproduzione",
"never": "Mai",
"afterADay": "Dopo un giorno",
"afterAWeek": "Dopo una settimana",
"afterAMonth": "Dopo un mese",
"onNextRefresh": "Al prossimo aggiornamento",
"seasons": "Stagioni",
"show": "Mostra",
"hide": "Nascondi",
"episodeOrdering": "Ordine episodi",
"tmdbAiring": "The Movie Database (In onda)",
"tvdbAiring": "TheTVDB (In onda)",
"tvdbAbsolute": "TheTVDB (Assoluto)",
"metadataLanguage": "Lingua metadati",
"useOriginalTitle": "Usa titolo originale",
"preferredAudioLanguage": "Lingua audio preferita",
"preferredSubtitleLanguage": "Lingua sottotitoli preferita",
"subtitleMode": "Selezione automatica sottotitoli",
"manuallySelected": "Selezionato manualmente",
"shownWithForeignAudio": "Mostrati con audio straniero",
"alwaysEnabled": "Sempre attivo"
}
}
+62 -1
View File
@@ -1,7 +1,7 @@
{
"app": {
"title": "Plezy"
},
},
"auth": {
"signInWithPlex": "Plex 계정으로 로그인",
"showQRCode": "QR 코드",
@@ -831,5 +831,66 @@
"launchFailed": "외부 플레이어를 열 수 없습니다",
"appNotInstalled": "${name}이(가) 설치되어 있지 않습니다",
"playInExternalPlayer": "외부 플레이어에서 재생"
},
"metadataEdit": {
"editMetadata": "편집...",
"screenTitle": "메타데이터 편집",
"basicInfo": "기본 정보",
"artwork": "아트워크",
"advancedSettings": "고급 설정",
"title": "제목",
"sortTitle": "정렬 제목",
"originalTitle": "원제",
"releaseDate": "출시일",
"contentRating": "콘텐츠 등급",
"studio": "스튜디오",
"tagline": "태그라인",
"summary": "줄거리",
"poster": "포스터",
"background": "배경",
"selectPoster": "포스터 선택",
"selectBackground": "배경 선택",
"fromUrl": "URL에서",
"uploadFile": "파일 업로드",
"enterImageUrl": "이미지 URL 입력",
"imageUrl": "이미지 URL",
"metadataUpdated": "메타데이터가 업데이트되었습니다",
"metadataUpdateFailed": "메타데이터 업데이트 실패",
"artworkUpdated": "아트워크가 업데이트되었습니다",
"artworkUpdateFailed": "아트워크 업데이트 실패",
"noArtworkAvailable": "사용 가능한 아트워크 없음",
"notSet": "설정되지 않음",
"libraryDefault": "라이브러리 기본값",
"accountDefault": "계정 기본값",
"seriesDefault": "시리즈 기본값",
"episodeSorting": "에피소드 정렬",
"oldestFirst": "오래된 순",
"newestFirst": "최신 순",
"keep": "유지",
"allEpisodes": "모든 에피소드",
"latestEpisodes": "최신 에피소드 ${count}개",
"latestEpisode": "최신 에피소드",
"episodesAddedPastDays": "최근 ${count}일 내 추가된 에피소드",
"deleteAfterPlaying": "재생 후 에피소드 삭제",
"never": "안 함",
"afterADay": "하루 후",
"afterAWeek": "일주일 후",
"afterAMonth": "한 달 후",
"onNextRefresh": "다음 새로고침 시",
"seasons": "시즌",
"show": "표시",
"hide": "숨기기",
"episodeOrdering": "에피소드 순서",
"tmdbAiring": "The Movie Database (방영순)",
"tvdbAiring": "TheTVDB (방영순)",
"tvdbAbsolute": "TheTVDB (절대순)",
"metadataLanguage": "메타데이터 언어",
"useOriginalTitle": "원제 사용",
"preferredAudioLanguage": "선호 오디오 언어",
"preferredSubtitleLanguage": "선호 자막 언어",
"subtitleMode": "자막 자동 선택 모드",
"manuallySelected": "수동 선택",
"shownWithForeignAudio": "외국어 오디오 시 표시",
"alwaysEnabled": "항상 활성화"
}
}
+62 -1
View File
@@ -1,7 +1,7 @@
{
"app": {
"title": "Plezy"
},
},
"auth": {
"signInWithPlex": "Inloggen met Plex",
"showQRCode": "Toon QR-code",
@@ -831,5 +831,66 @@
"launchFailed": "Kan externe speler niet openen",
"appNotInstalled": "${name} is niet geïnstalleerd",
"playInExternalPlayer": "Afspelen in externe speler"
},
"metadataEdit": {
"editMetadata": "Bewerken...",
"screenTitle": "Metadata bewerken",
"basicInfo": "Basisinformatie",
"artwork": "Artwork",
"advancedSettings": "Geavanceerde instellingen",
"title": "Titel",
"sortTitle": "Sorteertitel",
"originalTitle": "Oorspronkelijke titel",
"releaseDate": "Releasedatum",
"contentRating": "Leeftijdsclassificatie",
"studio": "Studio",
"tagline": "Tagline",
"summary": "Samenvatting",
"poster": "Poster",
"background": "Achtergrond",
"selectPoster": "Poster selecteren",
"selectBackground": "Achtergrond selecteren",
"fromUrl": "Vanaf URL",
"uploadFile": "Bestand uploaden",
"enterImageUrl": "Voer afbeeldings-URL in",
"imageUrl": "Afbeeldings-URL",
"metadataUpdated": "Metadata bijgewerkt",
"metadataUpdateFailed": "Metadata bijwerken mislukt",
"artworkUpdated": "Artwork bijgewerkt",
"artworkUpdateFailed": "Artwork bijwerken mislukt",
"noArtworkAvailable": "Geen artwork beschikbaar",
"notSet": "Niet ingesteld",
"libraryDefault": "Bibliotheekstandaard",
"accountDefault": "Accountstandaard",
"seriesDefault": "Seriestandaard",
"episodeSorting": "Afleveringen sorteren",
"oldestFirst": "Oudste eerst",
"newestFirst": "Nieuwste eerst",
"keep": "Bewaren",
"allEpisodes": "Alle afleveringen",
"latestEpisodes": "${count} nieuwste afleveringen",
"latestEpisode": "Nieuwste aflevering",
"episodesAddedPastDays": "Afleveringen toegevoegd in de afgelopen ${count} dagen",
"deleteAfterPlaying": "Afleveringen verwijderen na afspelen",
"never": "Nooit",
"afterADay": "Na een dag",
"afterAWeek": "Na een week",
"afterAMonth": "Na een maand",
"onNextRefresh": "Bij volgende verversing",
"seasons": "Seizoenen",
"show": "Tonen",
"hide": "Verbergen",
"episodeOrdering": "Afleveringsvolgorde",
"tmdbAiring": "The Movie Database (Uitgezonden)",
"tvdbAiring": "TheTVDB (Uitgezonden)",
"tvdbAbsolute": "TheTVDB (Absoluut)",
"metadataLanguage": "Metadatataal",
"useOriginalTitle": "Oorspronkelijke titel gebruiken",
"preferredAudioLanguage": "Voorkeurstaal audio",
"preferredSubtitleLanguage": "Voorkeurstaal ondertiteling",
"subtitleMode": "Automatische ondertitelselectie",
"manuallySelected": "Handmatig geselecteerd",
"shownWithForeignAudio": "Weergeven bij anderstalig geluid",
"alwaysEnabled": "Altijd ingeschakeld"
}
}
+2 -2
View File
@@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang`
///
/// Locales: 9
/// Strings: 6705 (745 per locale)
/// Strings: 7236 (804 per locale)
///
/// Built on 2026-02-20 at 23:08 UTC
/// Built on 2026-02-22 at 16:11 UTC
// coverage:ignore-file
// ignore_for_file: type=lint, unused_import
+128
View File
@@ -74,6 +74,7 @@ class TranslationsDe with BaseTranslations<AppLocale, Translations> implements T
@override late final _TranslationsCompanionRemoteDe companionRemote = _TranslationsCompanionRemoteDe._(_root);
@override late final _TranslationsVideoSettingsDe videoSettings = _TranslationsVideoSettingsDe._(_root);
@override late final _TranslationsExternalPlayerDe externalPlayer = _TranslationsExternalPlayerDe._(_root);
@override late final _TranslationsMetadataEditDe metadataEdit = _TranslationsMetadataEditDe._(_root);
}
// Path: app
@@ -1050,6 +1051,74 @@ class _TranslationsExternalPlayerDe implements TranslationsExternalPlayerEn {
@override String get playInExternalPlayer => 'In externem Player abspielen';
}
// Path: metadataEdit
class _TranslationsMetadataEditDe implements TranslationsMetadataEditEn {
_TranslationsMetadataEditDe._(this._root);
final TranslationsDe _root; // ignore: unused_field
// Translations
@override String get editMetadata => 'Bearbeiten...';
@override String get screenTitle => 'Metadaten bearbeiten';
@override String get basicInfo => 'Grundlegende Infos';
@override String get artwork => 'Artwork';
@override String get advancedSettings => 'Erweiterte Einstellungen';
@override String get title => 'Titel';
@override String get sortTitle => 'Sortiertitel';
@override String get originalTitle => 'Originaltitel';
@override String get releaseDate => 'Erscheinungsdatum';
@override String get contentRating => 'Altersfreigabe';
@override String get studio => 'Studio';
@override String get tagline => 'Tagline';
@override String get summary => 'Zusammenfassung';
@override String get poster => 'Poster';
@override String get background => 'Hintergrund';
@override String get selectPoster => 'Poster auswählen';
@override String get selectBackground => 'Hintergrund auswählen';
@override String get fromUrl => 'Von URL';
@override String get uploadFile => 'Datei hochladen';
@override String get enterImageUrl => 'Bild-URL eingeben';
@override String get imageUrl => 'Bild-URL';
@override String get metadataUpdated => 'Metadaten aktualisiert';
@override String get metadataUpdateFailed => 'Metadaten konnten nicht aktualisiert werden';
@override String get artworkUpdated => 'Artwork aktualisiert';
@override String get artworkUpdateFailed => 'Artwork konnte nicht aktualisiert werden';
@override String get noArtworkAvailable => 'Kein Artwork verfügbar';
@override String get notSet => 'Nicht festgelegt';
@override String get libraryDefault => 'Bibliotheksstandard';
@override String get accountDefault => 'Kontostandard';
@override String get seriesDefault => 'Serienstandard';
@override String get episodeSorting => 'Episodensortierung';
@override String get oldestFirst => 'Älteste zuerst';
@override String get newestFirst => 'Neueste zuerst';
@override String get keep => 'Behalten';
@override String get allEpisodes => 'Alle Episoden';
@override String latestEpisodes({required Object count}) => '${count} neueste Episoden';
@override String get latestEpisode => 'Neueste Episode';
@override String episodesAddedPastDays({required Object count}) => 'Episoden der letzten ${count} Tage';
@override String get deleteAfterPlaying => 'Episoden nach Wiedergabe löschen';
@override String get never => 'Nie';
@override String get afterADay => 'Nach einem Tag';
@override String get afterAWeek => 'Nach einer Woche';
@override String get afterAMonth => 'Nach einem Monat';
@override String get onNextRefresh => 'Bei nächster Aktualisierung';
@override String get seasons => 'Staffeln';
@override String get show => 'Anzeigen';
@override String get hide => 'Ausblenden';
@override String get episodeOrdering => 'Episodenreihenfolge';
@override String get tmdbAiring => 'The Movie Database (Ausgestrahlt)';
@override String get tvdbAiring => 'TheTVDB (Ausgestrahlt)';
@override String get tvdbAbsolute => 'TheTVDB (Absolut)';
@override String get metadataLanguage => 'Metadaten-Sprache';
@override String get useOriginalTitle => 'Originaltitel verwenden';
@override String get preferredAudioLanguage => 'Bevorzugte Audiosprache';
@override String get preferredSubtitleLanguage => 'Bevorzugte Untertitelsprache';
@override String get subtitleMode => 'Automatische Untertitelauswahl';
@override String get manuallySelected => 'Manuell ausgewählt';
@override String get shownWithForeignAudio => 'Bei fremdsprachigem Audio anzeigen';
@override String get alwaysEnabled => 'Immer aktiviert';
}
// Path: hotkeys.actions
class _TranslationsHotkeysActionsDe implements TranslationsHotkeysActionsEn {
_TranslationsHotkeysActionsDe._(this._root);
@@ -1979,6 +2048,65 @@ extension on TranslationsDe {
'externalPlayer.launchFailed' => 'Externer Player konnte nicht geöffnet werden',
'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} ist nicht installiert',
'externalPlayer.playInExternalPlayer' => 'In externem Player abspielen',
'metadataEdit.editMetadata' => 'Bearbeiten...',
'metadataEdit.screenTitle' => 'Metadaten bearbeiten',
'metadataEdit.basicInfo' => 'Grundlegende Infos',
'metadataEdit.artwork' => 'Artwork',
'metadataEdit.advancedSettings' => 'Erweiterte Einstellungen',
'metadataEdit.title' => 'Titel',
'metadataEdit.sortTitle' => 'Sortiertitel',
'metadataEdit.originalTitle' => 'Originaltitel',
'metadataEdit.releaseDate' => 'Erscheinungsdatum',
'metadataEdit.contentRating' => 'Altersfreigabe',
'metadataEdit.studio' => 'Studio',
'metadataEdit.tagline' => 'Tagline',
'metadataEdit.summary' => 'Zusammenfassung',
'metadataEdit.poster' => 'Poster',
'metadataEdit.background' => 'Hintergrund',
'metadataEdit.selectPoster' => 'Poster auswählen',
'metadataEdit.selectBackground' => 'Hintergrund auswählen',
'metadataEdit.fromUrl' => 'Von URL',
'metadataEdit.uploadFile' => 'Datei hochladen',
'metadataEdit.enterImageUrl' => 'Bild-URL eingeben',
'metadataEdit.imageUrl' => 'Bild-URL',
'metadataEdit.metadataUpdated' => 'Metadaten aktualisiert',
'metadataEdit.metadataUpdateFailed' => 'Metadaten konnten nicht aktualisiert werden',
'metadataEdit.artworkUpdated' => 'Artwork aktualisiert',
'metadataEdit.artworkUpdateFailed' => 'Artwork konnte nicht aktualisiert werden',
'metadataEdit.noArtworkAvailable' => 'Kein Artwork verfügbar',
'metadataEdit.notSet' => 'Nicht festgelegt',
'metadataEdit.libraryDefault' => 'Bibliotheksstandard',
'metadataEdit.accountDefault' => 'Kontostandard',
'metadataEdit.seriesDefault' => 'Serienstandard',
'metadataEdit.episodeSorting' => 'Episodensortierung',
'metadataEdit.oldestFirst' => 'Älteste zuerst',
'metadataEdit.newestFirst' => 'Neueste zuerst',
'metadataEdit.keep' => 'Behalten',
'metadataEdit.allEpisodes' => 'Alle Episoden',
'metadataEdit.latestEpisodes' => ({required Object count}) => '${count} neueste Episoden',
'metadataEdit.latestEpisode' => 'Neueste Episode',
'metadataEdit.episodesAddedPastDays' => ({required Object count}) => 'Episoden der letzten ${count} Tage',
'metadataEdit.deleteAfterPlaying' => 'Episoden nach Wiedergabe löschen',
'metadataEdit.never' => 'Nie',
'metadataEdit.afterADay' => 'Nach einem Tag',
'metadataEdit.afterAWeek' => 'Nach einer Woche',
'metadataEdit.afterAMonth' => 'Nach einem Monat',
'metadataEdit.onNextRefresh' => 'Bei nächster Aktualisierung',
'metadataEdit.seasons' => 'Staffeln',
'metadataEdit.show' => 'Anzeigen',
'metadataEdit.hide' => 'Ausblenden',
'metadataEdit.episodeOrdering' => 'Episodenreihenfolge',
'metadataEdit.tmdbAiring' => 'The Movie Database (Ausgestrahlt)',
'metadataEdit.tvdbAiring' => 'TheTVDB (Ausgestrahlt)',
'metadataEdit.tvdbAbsolute' => 'TheTVDB (Absolut)',
'metadataEdit.metadataLanguage' => 'Metadaten-Sprache',
'metadataEdit.useOriginalTitle' => 'Originaltitel verwenden',
'metadataEdit.preferredAudioLanguage' => 'Bevorzugte Audiosprache',
'metadataEdit.preferredSubtitleLanguage' => 'Bevorzugte Untertitelsprache',
'metadataEdit.subtitleMode' => 'Automatische Untertitelauswahl',
'metadataEdit.manuallySelected' => 'Manuell ausgewählt',
'metadataEdit.shownWithForeignAudio' => 'Bei fremdsprachigem Audio anzeigen',
'metadataEdit.alwaysEnabled' => 'Immer aktiviert',
_ => null,
};
}
+246
View File
@@ -77,6 +77,7 @@ class Translations with BaseTranslations<AppLocale, Translations> {
late final TranslationsCompanionRemoteEn companionRemote = TranslationsCompanionRemoteEn._(_root);
late final TranslationsVideoSettingsEn videoSettings = TranslationsVideoSettingsEn._(_root);
late final TranslationsExternalPlayerEn externalPlayer = TranslationsExternalPlayerEn._(_root);
late final TranslationsMetadataEditEn metadataEdit = TranslationsMetadataEditEn._(_root);
}
// Path: app
@@ -2325,6 +2326,192 @@ class TranslationsExternalPlayerEn {
String get playInExternalPlayer => 'Play in External Player';
}
// Path: metadataEdit
class TranslationsMetadataEditEn {
TranslationsMetadataEditEn._(this._root);
final Translations _root; // ignore: unused_field
// Translations
/// en: 'Edit...'
String get editMetadata => 'Edit...';
/// en: 'Edit Metadata'
String get screenTitle => 'Edit Metadata';
/// en: 'Basic Info'
String get basicInfo => 'Basic Info';
/// en: 'Artwork'
String get artwork => 'Artwork';
/// en: 'Advanced Settings'
String get advancedSettings => 'Advanced Settings';
/// en: 'Title'
String get title => 'Title';
/// en: 'Sort Title'
String get sortTitle => 'Sort Title';
/// en: 'Original Title'
String get originalTitle => 'Original Title';
/// en: 'Release Date'
String get releaseDate => 'Release Date';
/// en: 'Content Rating'
String get contentRating => 'Content Rating';
/// en: 'Studio'
String get studio => 'Studio';
/// en: 'Tagline'
String get tagline => 'Tagline';
/// en: 'Summary'
String get summary => 'Summary';
/// en: 'Poster'
String get poster => 'Poster';
/// en: 'Background'
String get background => 'Background';
/// en: 'Select Poster'
String get selectPoster => 'Select Poster';
/// en: 'Select Background'
String get selectBackground => 'Select Background';
/// en: 'From URL'
String get fromUrl => 'From URL';
/// en: 'Upload File'
String get uploadFile => 'Upload File';
/// en: 'Enter image URL'
String get enterImageUrl => 'Enter image URL';
/// en: 'Image URL'
String get imageUrl => 'Image URL';
/// en: 'Metadata updated'
String get metadataUpdated => 'Metadata updated';
/// en: 'Failed to update metadata'
String get metadataUpdateFailed => 'Failed to update metadata';
/// en: 'Artwork updated'
String get artworkUpdated => 'Artwork updated';
/// en: 'Failed to update artwork'
String get artworkUpdateFailed => 'Failed to update artwork';
/// en: 'No artwork available'
String get noArtworkAvailable => 'No artwork available';
/// en: 'Not set'
String get notSet => 'Not set';
/// en: 'Library default'
String get libraryDefault => 'Library default';
/// en: 'Account default'
String get accountDefault => 'Account default';
/// en: 'Series default'
String get seriesDefault => 'Series default';
/// en: 'Episode Sorting'
String get episodeSorting => 'Episode Sorting';
/// en: 'Oldest first'
String get oldestFirst => 'Oldest first';
/// en: 'Newest first'
String get newestFirst => 'Newest first';
/// en: 'Keep'
String get keep => 'Keep';
/// en: 'All episodes'
String get allEpisodes => 'All episodes';
/// en: '${count} latest episodes'
String latestEpisodes({required Object count}) => '${count} latest episodes';
/// en: 'Latest episode'
String get latestEpisode => 'Latest episode';
/// en: 'Episodes added in the past ${count} days'
String episodesAddedPastDays({required Object count}) => 'Episodes added in the past ${count} days';
/// en: 'Delete Episodes After Playing'
String get deleteAfterPlaying => 'Delete Episodes After Playing';
/// en: 'Never'
String get never => 'Never';
/// en: 'After a day'
String get afterADay => 'After a day';
/// en: 'After a week'
String get afterAWeek => 'After a week';
/// en: 'After a month'
String get afterAMonth => 'After a month';
/// en: 'On next refresh'
String get onNextRefresh => 'On next refresh';
/// en: 'Seasons'
String get seasons => 'Seasons';
/// en: 'Show'
String get show => 'Show';
/// en: 'Hide'
String get hide => 'Hide';
/// en: 'Episode Ordering'
String get episodeOrdering => 'Episode Ordering';
/// en: 'The Movie Database (Aired)'
String get tmdbAiring => 'The Movie Database (Aired)';
/// en: 'TheTVDB (Aired)'
String get tvdbAiring => 'TheTVDB (Aired)';
/// en: 'TheTVDB (Absolute)'
String get tvdbAbsolute => 'TheTVDB (Absolute)';
/// en: 'Metadata Language'
String get metadataLanguage => 'Metadata Language';
/// en: 'Use Original Title'
String get useOriginalTitle => 'Use Original Title';
/// en: 'Preferred Audio Language'
String get preferredAudioLanguage => 'Preferred Audio Language';
/// en: 'Preferred Subtitle Language'
String get preferredSubtitleLanguage => 'Preferred Subtitle Language';
/// en: 'Auto-Select Subtitle Mode'
String get subtitleMode => 'Auto-Select Subtitle Mode';
/// en: 'Manually selected'
String get manuallySelected => 'Manually selected';
/// en: 'Shown with foreign audio'
String get shownWithForeignAudio => 'Shown with foreign audio';
/// en: 'Always enabled'
String get alwaysEnabled => 'Always enabled';
}
// Path: hotkeys.actions
class TranslationsHotkeysActionsEn {
TranslationsHotkeysActionsEn._(this._root);
@@ -3476,6 +3663,65 @@ extension on Translations {
'externalPlayer.launchFailed' => 'Failed to open external player',
'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} is not installed',
'externalPlayer.playInExternalPlayer' => 'Play in External Player',
'metadataEdit.editMetadata' => 'Edit...',
'metadataEdit.screenTitle' => 'Edit Metadata',
'metadataEdit.basicInfo' => 'Basic Info',
'metadataEdit.artwork' => 'Artwork',
'metadataEdit.advancedSettings' => 'Advanced Settings',
'metadataEdit.title' => 'Title',
'metadataEdit.sortTitle' => 'Sort Title',
'metadataEdit.originalTitle' => 'Original Title',
'metadataEdit.releaseDate' => 'Release Date',
'metadataEdit.contentRating' => 'Content Rating',
'metadataEdit.studio' => 'Studio',
'metadataEdit.tagline' => 'Tagline',
'metadataEdit.summary' => 'Summary',
'metadataEdit.poster' => 'Poster',
'metadataEdit.background' => 'Background',
'metadataEdit.selectPoster' => 'Select Poster',
'metadataEdit.selectBackground' => 'Select Background',
'metadataEdit.fromUrl' => 'From URL',
'metadataEdit.uploadFile' => 'Upload File',
'metadataEdit.enterImageUrl' => 'Enter image URL',
'metadataEdit.imageUrl' => 'Image URL',
'metadataEdit.metadataUpdated' => 'Metadata updated',
'metadataEdit.metadataUpdateFailed' => 'Failed to update metadata',
'metadataEdit.artworkUpdated' => 'Artwork updated',
'metadataEdit.artworkUpdateFailed' => 'Failed to update artwork',
'metadataEdit.noArtworkAvailable' => 'No artwork available',
'metadataEdit.notSet' => 'Not set',
'metadataEdit.libraryDefault' => 'Library default',
'metadataEdit.accountDefault' => 'Account default',
'metadataEdit.seriesDefault' => 'Series default',
'metadataEdit.episodeSorting' => 'Episode Sorting',
'metadataEdit.oldestFirst' => 'Oldest first',
'metadataEdit.newestFirst' => 'Newest first',
'metadataEdit.keep' => 'Keep',
'metadataEdit.allEpisodes' => 'All episodes',
'metadataEdit.latestEpisodes' => ({required Object count}) => '${count} latest episodes',
'metadataEdit.latestEpisode' => 'Latest episode',
'metadataEdit.episodesAddedPastDays' => ({required Object count}) => 'Episodes added in the past ${count} days',
'metadataEdit.deleteAfterPlaying' => 'Delete Episodes After Playing',
'metadataEdit.never' => 'Never',
'metadataEdit.afterADay' => 'After a day',
'metadataEdit.afterAWeek' => 'After a week',
'metadataEdit.afterAMonth' => 'After a month',
'metadataEdit.onNextRefresh' => 'On next refresh',
'metadataEdit.seasons' => 'Seasons',
'metadataEdit.show' => 'Show',
'metadataEdit.hide' => 'Hide',
'metadataEdit.episodeOrdering' => 'Episode Ordering',
'metadataEdit.tmdbAiring' => 'The Movie Database (Aired)',
'metadataEdit.tvdbAiring' => 'TheTVDB (Aired)',
'metadataEdit.tvdbAbsolute' => 'TheTVDB (Absolute)',
'metadataEdit.metadataLanguage' => 'Metadata Language',
'metadataEdit.useOriginalTitle' => 'Use Original Title',
'metadataEdit.preferredAudioLanguage' => 'Preferred Audio Language',
'metadataEdit.preferredSubtitleLanguage' => 'Preferred Subtitle Language',
'metadataEdit.subtitleMode' => 'Auto-Select Subtitle Mode',
'metadataEdit.manuallySelected' => 'Manually selected',
'metadataEdit.shownWithForeignAudio' => 'Shown with foreign audio',
'metadataEdit.alwaysEnabled' => 'Always enabled',
_ => null,
};
}
+128
View File
@@ -74,6 +74,7 @@ class TranslationsEs with BaseTranslations<AppLocale, Translations> implements T
@override late final _TranslationsCompanionRemoteEs companionRemote = _TranslationsCompanionRemoteEs._(_root);
@override late final _TranslationsVideoSettingsEs videoSettings = _TranslationsVideoSettingsEs._(_root);
@override late final _TranslationsExternalPlayerEs externalPlayer = _TranslationsExternalPlayerEs._(_root);
@override late final _TranslationsMetadataEditEs metadataEdit = _TranslationsMetadataEditEs._(_root);
}
// Path: app
@@ -1050,6 +1051,74 @@ class _TranslationsExternalPlayerEs implements TranslationsExternalPlayerEn {
@override String get playInExternalPlayer => 'Reproducir en reproductor externo';
}
// Path: metadataEdit
class _TranslationsMetadataEditEs implements TranslationsMetadataEditEn {
_TranslationsMetadataEditEs._(this._root);
final TranslationsEs _root; // ignore: unused_field
// Translations
@override String get editMetadata => 'Editar...';
@override String get screenTitle => 'Editar metadatos';
@override String get basicInfo => 'Información básica';
@override String get artwork => 'Artwork';
@override String get advancedSettings => 'Ajustes avanzados';
@override String get title => 'Título';
@override String get sortTitle => 'Título de ordenación';
@override String get originalTitle => 'Título original';
@override String get releaseDate => 'Fecha de estreno';
@override String get contentRating => 'Clasificación de contenido';
@override String get studio => 'Estudio';
@override String get tagline => 'Eslogan';
@override String get summary => 'Resumen';
@override String get poster => 'Póster';
@override String get background => 'Fondo';
@override String get selectPoster => 'Seleccionar póster';
@override String get selectBackground => 'Seleccionar fondo';
@override String get fromUrl => 'Desde URL';
@override String get uploadFile => 'Subir archivo';
@override String get enterImageUrl => 'Introducir URL de imagen';
@override String get imageUrl => 'URL de imagen';
@override String get metadataUpdated => 'Metadatos actualizados';
@override String get metadataUpdateFailed => 'Error al actualizar los metadatos';
@override String get artworkUpdated => 'Artwork actualizado';
@override String get artworkUpdateFailed => 'Error al actualizar el artwork';
@override String get noArtworkAvailable => 'No hay artwork disponible';
@override String get notSet => 'No establecido';
@override String get libraryDefault => 'Predeterminado de biblioteca';
@override String get accountDefault => 'Predeterminado de cuenta';
@override String get seriesDefault => 'Predeterminado de serie';
@override String get episodeSorting => 'Orden de episodios';
@override String get oldestFirst => 'Más antiguos primero';
@override String get newestFirst => 'Más recientes primero';
@override String get keep => 'Conservar';
@override String get allEpisodes => 'Todos los episodios';
@override String latestEpisodes({required Object count}) => '${count} episodios más recientes';
@override String get latestEpisode => 'Episodio más reciente';
@override String episodesAddedPastDays({required Object count}) => 'Episodios añadidos en los últimos ${count} días';
@override String get deleteAfterPlaying => 'Eliminar episodios después de reproducir';
@override String get never => 'Nunca';
@override String get afterADay => 'Después de un día';
@override String get afterAWeek => 'Después de una semana';
@override String get afterAMonth => 'Después de un mes';
@override String get onNextRefresh => 'En la próxima actualización';
@override String get seasons => 'Temporadas';
@override String get show => 'Mostrar';
@override String get hide => 'Ocultar';
@override String get episodeOrdering => 'Orden de episodios';
@override String get tmdbAiring => 'The Movie Database (Emisión)';
@override String get tvdbAiring => 'TheTVDB (Emisión)';
@override String get tvdbAbsolute => 'TheTVDB (Absoluto)';
@override String get metadataLanguage => 'Idioma de metadatos';
@override String get useOriginalTitle => 'Usar título original';
@override String get preferredAudioLanguage => 'Idioma de audio preferido';
@override String get preferredSubtitleLanguage => 'Idioma de subtítulos preferido';
@override String get subtitleMode => 'Selección automática de subtítulos';
@override String get manuallySelected => 'Seleccionado manualmente';
@override String get shownWithForeignAudio => 'Mostrar con audio extranjero';
@override String get alwaysEnabled => 'Siempre activado';
}
// Path: hotkeys.actions
class _TranslationsHotkeysActionsEs implements TranslationsHotkeysActionsEn {
_TranslationsHotkeysActionsEs._(this._root);
@@ -1979,6 +2048,65 @@ extension on TranslationsEs {
'externalPlayer.launchFailed' => 'No se pudo abrir el reproductor externo',
'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} no está instalado',
'externalPlayer.playInExternalPlayer' => 'Reproducir en reproductor externo',
'metadataEdit.editMetadata' => 'Editar...',
'metadataEdit.screenTitle' => 'Editar metadatos',
'metadataEdit.basicInfo' => 'Información básica',
'metadataEdit.artwork' => 'Artwork',
'metadataEdit.advancedSettings' => 'Ajustes avanzados',
'metadataEdit.title' => 'Título',
'metadataEdit.sortTitle' => 'Título de ordenación',
'metadataEdit.originalTitle' => 'Título original',
'metadataEdit.releaseDate' => 'Fecha de estreno',
'metadataEdit.contentRating' => 'Clasificación de contenido',
'metadataEdit.studio' => 'Estudio',
'metadataEdit.tagline' => 'Eslogan',
'metadataEdit.summary' => 'Resumen',
'metadataEdit.poster' => 'Póster',
'metadataEdit.background' => 'Fondo',
'metadataEdit.selectPoster' => 'Seleccionar póster',
'metadataEdit.selectBackground' => 'Seleccionar fondo',
'metadataEdit.fromUrl' => 'Desde URL',
'metadataEdit.uploadFile' => 'Subir archivo',
'metadataEdit.enterImageUrl' => 'Introducir URL de imagen',
'metadataEdit.imageUrl' => 'URL de imagen',
'metadataEdit.metadataUpdated' => 'Metadatos actualizados',
'metadataEdit.metadataUpdateFailed' => 'Error al actualizar los metadatos',
'metadataEdit.artworkUpdated' => 'Artwork actualizado',
'metadataEdit.artworkUpdateFailed' => 'Error al actualizar el artwork',
'metadataEdit.noArtworkAvailable' => 'No hay artwork disponible',
'metadataEdit.notSet' => 'No establecido',
'metadataEdit.libraryDefault' => 'Predeterminado de biblioteca',
'metadataEdit.accountDefault' => 'Predeterminado de cuenta',
'metadataEdit.seriesDefault' => 'Predeterminado de serie',
'metadataEdit.episodeSorting' => 'Orden de episodios',
'metadataEdit.oldestFirst' => 'Más antiguos primero',
'metadataEdit.newestFirst' => 'Más recientes primero',
'metadataEdit.keep' => 'Conservar',
'metadataEdit.allEpisodes' => 'Todos los episodios',
'metadataEdit.latestEpisodes' => ({required Object count}) => '${count} episodios más recientes',
'metadataEdit.latestEpisode' => 'Episodio más reciente',
'metadataEdit.episodesAddedPastDays' => ({required Object count}) => 'Episodios añadidos en los últimos ${count} días',
'metadataEdit.deleteAfterPlaying' => 'Eliminar episodios después de reproducir',
'metadataEdit.never' => 'Nunca',
'metadataEdit.afterADay' => 'Después de un día',
'metadataEdit.afterAWeek' => 'Después de una semana',
'metadataEdit.afterAMonth' => 'Después de un mes',
'metadataEdit.onNextRefresh' => 'En la próxima actualización',
'metadataEdit.seasons' => 'Temporadas',
'metadataEdit.show' => 'Mostrar',
'metadataEdit.hide' => 'Ocultar',
'metadataEdit.episodeOrdering' => 'Orden de episodios',
'metadataEdit.tmdbAiring' => 'The Movie Database (Emisión)',
'metadataEdit.tvdbAiring' => 'TheTVDB (Emisión)',
'metadataEdit.tvdbAbsolute' => 'TheTVDB (Absoluto)',
'metadataEdit.metadataLanguage' => 'Idioma de metadatos',
'metadataEdit.useOriginalTitle' => 'Usar título original',
'metadataEdit.preferredAudioLanguage' => 'Idioma de audio preferido',
'metadataEdit.preferredSubtitleLanguage' => 'Idioma de subtítulos preferido',
'metadataEdit.subtitleMode' => 'Selección automática de subtítulos',
'metadataEdit.manuallySelected' => 'Seleccionado manualmente',
'metadataEdit.shownWithForeignAudio' => 'Mostrar con audio extranjero',
'metadataEdit.alwaysEnabled' => 'Siempre activado',
_ => null,
};
}
+128
View File
@@ -74,6 +74,7 @@ class TranslationsFr with BaseTranslations<AppLocale, Translations> implements T
@override late final _TranslationsCompanionRemoteFr companionRemote = _TranslationsCompanionRemoteFr._(_root);
@override late final _TranslationsVideoSettingsFr videoSettings = _TranslationsVideoSettingsFr._(_root);
@override late final _TranslationsExternalPlayerFr externalPlayer = _TranslationsExternalPlayerFr._(_root);
@override late final _TranslationsMetadataEditFr metadataEdit = _TranslationsMetadataEditFr._(_root);
}
// Path: app
@@ -1050,6 +1051,74 @@ class _TranslationsExternalPlayerFr implements TranslationsExternalPlayerEn {
@override String get playInExternalPlayer => 'Lire dans un lecteur externe';
}
// Path: metadataEdit
class _TranslationsMetadataEditFr implements TranslationsMetadataEditEn {
_TranslationsMetadataEditFr._(this._root);
final TranslationsFr _root; // ignore: unused_field
// Translations
@override String get editMetadata => 'Modifier...';
@override String get screenTitle => 'Modifier les métadonnées';
@override String get basicInfo => 'Informations de base';
@override String get artwork => 'Artwork';
@override String get advancedSettings => 'Paramètres avancés';
@override String get title => 'Titre';
@override String get sortTitle => 'Titre de tri';
@override String get originalTitle => 'Titre original';
@override String get releaseDate => 'Date de sortie';
@override String get contentRating => 'Classification';
@override String get studio => 'Studio';
@override String get tagline => 'Slogan';
@override String get summary => 'Résumé';
@override String get poster => 'Affiche';
@override String get background => 'Arrière-plan';
@override String get selectPoster => 'Sélectionner l\'affiche';
@override String get selectBackground => 'Sélectionner l\'arrière-plan';
@override String get fromUrl => 'Depuis une URL';
@override String get uploadFile => 'Importer un fichier';
@override String get enterImageUrl => 'Entrer l\'URL de l\'image';
@override String get imageUrl => 'URL de l\'image';
@override String get metadataUpdated => 'Métadonnées mises à jour';
@override String get metadataUpdateFailed => 'Échec de la mise à jour des métadonnées';
@override String get artworkUpdated => 'Artwork mis à jour';
@override String get artworkUpdateFailed => 'Échec de la mise à jour de l\'artwork';
@override String get noArtworkAvailable => 'Aucun artwork disponible';
@override String get notSet => 'Non défini';
@override String get libraryDefault => 'Par défaut de la bibliothèque';
@override String get accountDefault => 'Par défaut du compte';
@override String get seriesDefault => 'Par défaut de la série';
@override String get episodeSorting => 'Tri des épisodes';
@override String get oldestFirst => 'Plus anciens en premier';
@override String get newestFirst => 'Plus récents en premier';
@override String get keep => 'Conserver';
@override String get allEpisodes => 'Tous les épisodes';
@override String latestEpisodes({required Object count}) => '${count} derniers épisodes';
@override String get latestEpisode => 'Dernier épisode';
@override String episodesAddedPastDays({required Object count}) => 'Épisodes ajoutés ces ${count} derniers jours';
@override String get deleteAfterPlaying => 'Supprimer les épisodes après lecture';
@override String get never => 'Jamais';
@override String get afterADay => 'Après un jour';
@override String get afterAWeek => 'Après une semaine';
@override String get afterAMonth => 'Après un mois';
@override String get onNextRefresh => 'Au prochain rafraîchissement';
@override String get seasons => 'Saisons';
@override String get show => 'Afficher';
@override String get hide => 'Masquer';
@override String get episodeOrdering => 'Ordre des épisodes';
@override String get tmdbAiring => 'The Movie Database (Diffusion)';
@override String get tvdbAiring => 'TheTVDB (Diffusion)';
@override String get tvdbAbsolute => 'TheTVDB (Absolu)';
@override String get metadataLanguage => 'Langue des métadonnées';
@override String get useOriginalTitle => 'Utiliser le titre original';
@override String get preferredAudioLanguage => 'Langue audio préférée';
@override String get preferredSubtitleLanguage => 'Langue de sous-titres préférée';
@override String get subtitleMode => 'Sélection automatique des sous-titres';
@override String get manuallySelected => 'Sélectionné manuellement';
@override String get shownWithForeignAudio => 'Affichés avec audio étranger';
@override String get alwaysEnabled => 'Toujours activé';
}
// Path: hotkeys.actions
class _TranslationsHotkeysActionsFr implements TranslationsHotkeysActionsEn {
_TranslationsHotkeysActionsFr._(this._root);
@@ -1979,6 +2048,65 @@ extension on TranslationsFr {
'externalPlayer.launchFailed' => 'Impossible d\'ouvrir le lecteur externe',
'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} n\'est pas installé',
'externalPlayer.playInExternalPlayer' => 'Lire dans un lecteur externe',
'metadataEdit.editMetadata' => 'Modifier...',
'metadataEdit.screenTitle' => 'Modifier les métadonnées',
'metadataEdit.basicInfo' => 'Informations de base',
'metadataEdit.artwork' => 'Artwork',
'metadataEdit.advancedSettings' => 'Paramètres avancés',
'metadataEdit.title' => 'Titre',
'metadataEdit.sortTitle' => 'Titre de tri',
'metadataEdit.originalTitle' => 'Titre original',
'metadataEdit.releaseDate' => 'Date de sortie',
'metadataEdit.contentRating' => 'Classification',
'metadataEdit.studio' => 'Studio',
'metadataEdit.tagline' => 'Slogan',
'metadataEdit.summary' => 'Résumé',
'metadataEdit.poster' => 'Affiche',
'metadataEdit.background' => 'Arrière-plan',
'metadataEdit.selectPoster' => 'Sélectionner l\'affiche',
'metadataEdit.selectBackground' => 'Sélectionner l\'arrière-plan',
'metadataEdit.fromUrl' => 'Depuis une URL',
'metadataEdit.uploadFile' => 'Importer un fichier',
'metadataEdit.enterImageUrl' => 'Entrer l\'URL de l\'image',
'metadataEdit.imageUrl' => 'URL de l\'image',
'metadataEdit.metadataUpdated' => 'Métadonnées mises à jour',
'metadataEdit.metadataUpdateFailed' => 'Échec de la mise à jour des métadonnées',
'metadataEdit.artworkUpdated' => 'Artwork mis à jour',
'metadataEdit.artworkUpdateFailed' => 'Échec de la mise à jour de l\'artwork',
'metadataEdit.noArtworkAvailable' => 'Aucun artwork disponible',
'metadataEdit.notSet' => 'Non défini',
'metadataEdit.libraryDefault' => 'Par défaut de la bibliothèque',
'metadataEdit.accountDefault' => 'Par défaut du compte',
'metadataEdit.seriesDefault' => 'Par défaut de la série',
'metadataEdit.episodeSorting' => 'Tri des épisodes',
'metadataEdit.oldestFirst' => 'Plus anciens en premier',
'metadataEdit.newestFirst' => 'Plus récents en premier',
'metadataEdit.keep' => 'Conserver',
'metadataEdit.allEpisodes' => 'Tous les épisodes',
'metadataEdit.latestEpisodes' => ({required Object count}) => '${count} derniers épisodes',
'metadataEdit.latestEpisode' => 'Dernier épisode',
'metadataEdit.episodesAddedPastDays' => ({required Object count}) => 'Épisodes ajoutés ces ${count} derniers jours',
'metadataEdit.deleteAfterPlaying' => 'Supprimer les épisodes après lecture',
'metadataEdit.never' => 'Jamais',
'metadataEdit.afterADay' => 'Après un jour',
'metadataEdit.afterAWeek' => 'Après une semaine',
'metadataEdit.afterAMonth' => 'Après un mois',
'metadataEdit.onNextRefresh' => 'Au prochain rafraîchissement',
'metadataEdit.seasons' => 'Saisons',
'metadataEdit.show' => 'Afficher',
'metadataEdit.hide' => 'Masquer',
'metadataEdit.episodeOrdering' => 'Ordre des épisodes',
'metadataEdit.tmdbAiring' => 'The Movie Database (Diffusion)',
'metadataEdit.tvdbAiring' => 'TheTVDB (Diffusion)',
'metadataEdit.tvdbAbsolute' => 'TheTVDB (Absolu)',
'metadataEdit.metadataLanguage' => 'Langue des métadonnées',
'metadataEdit.useOriginalTitle' => 'Utiliser le titre original',
'metadataEdit.preferredAudioLanguage' => 'Langue audio préférée',
'metadataEdit.preferredSubtitleLanguage' => 'Langue de sous-titres préférée',
'metadataEdit.subtitleMode' => 'Sélection automatique des sous-titres',
'metadataEdit.manuallySelected' => 'Sélectionné manuellement',
'metadataEdit.shownWithForeignAudio' => 'Affichés avec audio étranger',
'metadataEdit.alwaysEnabled' => 'Toujours activé',
_ => null,
};
}
+128
View File
@@ -74,6 +74,7 @@ class TranslationsIt with BaseTranslations<AppLocale, Translations> implements T
@override late final _TranslationsCompanionRemoteIt companionRemote = _TranslationsCompanionRemoteIt._(_root);
@override late final _TranslationsVideoSettingsIt videoSettings = _TranslationsVideoSettingsIt._(_root);
@override late final _TranslationsExternalPlayerIt externalPlayer = _TranslationsExternalPlayerIt._(_root);
@override late final _TranslationsMetadataEditIt metadataEdit = _TranslationsMetadataEditIt._(_root);
}
// Path: app
@@ -1050,6 +1051,74 @@ class _TranslationsExternalPlayerIt implements TranslationsExternalPlayerEn {
@override String get playInExternalPlayer => 'Riproduci in lettore esterno';
}
// Path: metadataEdit
class _TranslationsMetadataEditIt implements TranslationsMetadataEditEn {
_TranslationsMetadataEditIt._(this._root);
final TranslationsIt _root; // ignore: unused_field
// Translations
@override String get editMetadata => 'Modifica...';
@override String get screenTitle => 'Modifica metadati';
@override String get basicInfo => 'Informazioni di base';
@override String get artwork => 'Artwork';
@override String get advancedSettings => 'Impostazioni avanzate';
@override String get title => 'Titolo';
@override String get sortTitle => 'Titolo di ordinamento';
@override String get originalTitle => 'Titolo originale';
@override String get releaseDate => 'Data di uscita';
@override String get contentRating => 'Classificazione';
@override String get studio => 'Studio';
@override String get tagline => 'Tagline';
@override String get summary => 'Trama';
@override String get poster => 'Poster';
@override String get background => 'Sfondo';
@override String get selectPoster => 'Seleziona poster';
@override String get selectBackground => 'Seleziona sfondo';
@override String get fromUrl => 'Da URL';
@override String get uploadFile => 'Carica file';
@override String get enterImageUrl => 'Inserisci URL immagine';
@override String get imageUrl => 'URL immagine';
@override String get metadataUpdated => 'Metadati aggiornati';
@override String get metadataUpdateFailed => 'Aggiornamento metadati non riuscito';
@override String get artworkUpdated => 'Artwork aggiornato';
@override String get artworkUpdateFailed => 'Aggiornamento artwork non riuscito';
@override String get noArtworkAvailable => 'Nessun artwork disponibile';
@override String get notSet => 'Non impostato';
@override String get libraryDefault => 'Predefinito libreria';
@override String get accountDefault => 'Predefinito account';
@override String get seriesDefault => 'Predefinito serie';
@override String get episodeSorting => 'Ordinamento episodi';
@override String get oldestFirst => 'Più vecchi prima';
@override String get newestFirst => 'Più recenti prima';
@override String get keep => 'Conserva';
@override String get allEpisodes => 'Tutti gli episodi';
@override String latestEpisodes({required Object count}) => '${count} episodi più recenti';
@override String get latestEpisode => 'Episodio più recente';
@override String episodesAddedPastDays({required Object count}) => 'Episodi aggiunti negli ultimi ${count} giorni';
@override String get deleteAfterPlaying => 'Elimina episodi dopo la riproduzione';
@override String get never => 'Mai';
@override String get afterADay => 'Dopo un giorno';
@override String get afterAWeek => 'Dopo una settimana';
@override String get afterAMonth => 'Dopo un mese';
@override String get onNextRefresh => 'Al prossimo aggiornamento';
@override String get seasons => 'Stagioni';
@override String get show => 'Mostra';
@override String get hide => 'Nascondi';
@override String get episodeOrdering => 'Ordine episodi';
@override String get tmdbAiring => 'The Movie Database (In onda)';
@override String get tvdbAiring => 'TheTVDB (In onda)';
@override String get tvdbAbsolute => 'TheTVDB (Assoluto)';
@override String get metadataLanguage => 'Lingua metadati';
@override String get useOriginalTitle => 'Usa titolo originale';
@override String get preferredAudioLanguage => 'Lingua audio preferita';
@override String get preferredSubtitleLanguage => 'Lingua sottotitoli preferita';
@override String get subtitleMode => 'Selezione automatica sottotitoli';
@override String get manuallySelected => 'Selezionato manualmente';
@override String get shownWithForeignAudio => 'Mostrati con audio straniero';
@override String get alwaysEnabled => 'Sempre attivo';
}
// Path: hotkeys.actions
class _TranslationsHotkeysActionsIt implements TranslationsHotkeysActionsEn {
_TranslationsHotkeysActionsIt._(this._root);
@@ -1979,6 +2048,65 @@ extension on TranslationsIt {
'externalPlayer.launchFailed' => 'Impossibile aprire il lettore esterno',
'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} non è installato',
'externalPlayer.playInExternalPlayer' => 'Riproduci in lettore esterno',
'metadataEdit.editMetadata' => 'Modifica...',
'metadataEdit.screenTitle' => 'Modifica metadati',
'metadataEdit.basicInfo' => 'Informazioni di base',
'metadataEdit.artwork' => 'Artwork',
'metadataEdit.advancedSettings' => 'Impostazioni avanzate',
'metadataEdit.title' => 'Titolo',
'metadataEdit.sortTitle' => 'Titolo di ordinamento',
'metadataEdit.originalTitle' => 'Titolo originale',
'metadataEdit.releaseDate' => 'Data di uscita',
'metadataEdit.contentRating' => 'Classificazione',
'metadataEdit.studio' => 'Studio',
'metadataEdit.tagline' => 'Tagline',
'metadataEdit.summary' => 'Trama',
'metadataEdit.poster' => 'Poster',
'metadataEdit.background' => 'Sfondo',
'metadataEdit.selectPoster' => 'Seleziona poster',
'metadataEdit.selectBackground' => 'Seleziona sfondo',
'metadataEdit.fromUrl' => 'Da URL',
'metadataEdit.uploadFile' => 'Carica file',
'metadataEdit.enterImageUrl' => 'Inserisci URL immagine',
'metadataEdit.imageUrl' => 'URL immagine',
'metadataEdit.metadataUpdated' => 'Metadati aggiornati',
'metadataEdit.metadataUpdateFailed' => 'Aggiornamento metadati non riuscito',
'metadataEdit.artworkUpdated' => 'Artwork aggiornato',
'metadataEdit.artworkUpdateFailed' => 'Aggiornamento artwork non riuscito',
'metadataEdit.noArtworkAvailable' => 'Nessun artwork disponibile',
'metadataEdit.notSet' => 'Non impostato',
'metadataEdit.libraryDefault' => 'Predefinito libreria',
'metadataEdit.accountDefault' => 'Predefinito account',
'metadataEdit.seriesDefault' => 'Predefinito serie',
'metadataEdit.episodeSorting' => 'Ordinamento episodi',
'metadataEdit.oldestFirst' => 'Più vecchi prima',
'metadataEdit.newestFirst' => 'Più recenti prima',
'metadataEdit.keep' => 'Conserva',
'metadataEdit.allEpisodes' => 'Tutti gli episodi',
'metadataEdit.latestEpisodes' => ({required Object count}) => '${count} episodi più recenti',
'metadataEdit.latestEpisode' => 'Episodio più recente',
'metadataEdit.episodesAddedPastDays' => ({required Object count}) => 'Episodi aggiunti negli ultimi ${count} giorni',
'metadataEdit.deleteAfterPlaying' => 'Elimina episodi dopo la riproduzione',
'metadataEdit.never' => 'Mai',
'metadataEdit.afterADay' => 'Dopo un giorno',
'metadataEdit.afterAWeek' => 'Dopo una settimana',
'metadataEdit.afterAMonth' => 'Dopo un mese',
'metadataEdit.onNextRefresh' => 'Al prossimo aggiornamento',
'metadataEdit.seasons' => 'Stagioni',
'metadataEdit.show' => 'Mostra',
'metadataEdit.hide' => 'Nascondi',
'metadataEdit.episodeOrdering' => 'Ordine episodi',
'metadataEdit.tmdbAiring' => 'The Movie Database (In onda)',
'metadataEdit.tvdbAiring' => 'TheTVDB (In onda)',
'metadataEdit.tvdbAbsolute' => 'TheTVDB (Assoluto)',
'metadataEdit.metadataLanguage' => 'Lingua metadati',
'metadataEdit.useOriginalTitle' => 'Usa titolo originale',
'metadataEdit.preferredAudioLanguage' => 'Lingua audio preferita',
'metadataEdit.preferredSubtitleLanguage' => 'Lingua sottotitoli preferita',
'metadataEdit.subtitleMode' => 'Selezione automatica sottotitoli',
'metadataEdit.manuallySelected' => 'Selezionato manualmente',
'metadataEdit.shownWithForeignAudio' => 'Mostrati con audio straniero',
'metadataEdit.alwaysEnabled' => 'Sempre attivo',
_ => null,
};
}
+128
View File
@@ -74,6 +74,7 @@ class TranslationsKo with BaseTranslations<AppLocale, Translations> implements T
@override late final _TranslationsCompanionRemoteKo companionRemote = _TranslationsCompanionRemoteKo._(_root);
@override late final _TranslationsVideoSettingsKo videoSettings = _TranslationsVideoSettingsKo._(_root);
@override late final _TranslationsExternalPlayerKo externalPlayer = _TranslationsExternalPlayerKo._(_root);
@override late final _TranslationsMetadataEditKo metadataEdit = _TranslationsMetadataEditKo._(_root);
}
// Path: app
@@ -1050,6 +1051,74 @@ class _TranslationsExternalPlayerKo implements TranslationsExternalPlayerEn {
@override String get playInExternalPlayer => '외부 플레이어에서 재생';
}
// Path: metadataEdit
class _TranslationsMetadataEditKo implements TranslationsMetadataEditEn {
_TranslationsMetadataEditKo._(this._root);
final TranslationsKo _root; // ignore: unused_field
// Translations
@override String get editMetadata => '편집...';
@override String get screenTitle => '메타데이터 편집';
@override String get basicInfo => '기본 정보';
@override String get artwork => '아트워크';
@override String get advancedSettings => '고급 설정';
@override String get title => '제목';
@override String get sortTitle => '정렬 제목';
@override String get originalTitle => '원제';
@override String get releaseDate => '출시일';
@override String get contentRating => '콘텐츠 등급';
@override String get studio => '스튜디오';
@override String get tagline => '태그라인';
@override String get summary => '줄거리';
@override String get poster => '포스터';
@override String get background => '배경';
@override String get selectPoster => '포스터 선택';
@override String get selectBackground => '배경 선택';
@override String get fromUrl => 'URL에서';
@override String get uploadFile => '파일 업로드';
@override String get enterImageUrl => '이미지 URL 입력';
@override String get imageUrl => '이미지 URL';
@override String get metadataUpdated => '메타데이터가 업데이트되었습니다';
@override String get metadataUpdateFailed => '메타데이터 업데이트 실패';
@override String get artworkUpdated => '아트워크가 업데이트되었습니다';
@override String get artworkUpdateFailed => '아트워크 업데이트 실패';
@override String get noArtworkAvailable => '사용 가능한 아트워크 없음';
@override String get notSet => '설정되지 않음';
@override String get libraryDefault => '라이브러리 기본값';
@override String get accountDefault => '계정 기본값';
@override String get seriesDefault => '시리즈 기본값';
@override String get episodeSorting => '에피소드 정렬';
@override String get oldestFirst => '오래된 순';
@override String get newestFirst => '최신 순';
@override String get keep => '유지';
@override String get allEpisodes => '모든 에피소드';
@override String latestEpisodes({required Object count}) => '최신 에피소드 ${count}';
@override String get latestEpisode => '최신 에피소드';
@override String episodesAddedPastDays({required Object count}) => '최근 ${count}일 내 추가된 에피소드';
@override String get deleteAfterPlaying => '재생 후 에피소드 삭제';
@override String get never => '안 함';
@override String get afterADay => '하루 후';
@override String get afterAWeek => '일주일 후';
@override String get afterAMonth => '한 달 후';
@override String get onNextRefresh => '다음 새로고침 시';
@override String get seasons => '시즌';
@override String get show => '표시';
@override String get hide => '숨기기';
@override String get episodeOrdering => '에피소드 순서';
@override String get tmdbAiring => 'The Movie Database (방영순)';
@override String get tvdbAiring => 'TheTVDB (방영순)';
@override String get tvdbAbsolute => 'TheTVDB (절대순)';
@override String get metadataLanguage => '메타데이터 언어';
@override String get useOriginalTitle => '원제 사용';
@override String get preferredAudioLanguage => '선호 오디오 언어';
@override String get preferredSubtitleLanguage => '선호 자막 언어';
@override String get subtitleMode => '자막 자동 선택 모드';
@override String get manuallySelected => '수동 선택';
@override String get shownWithForeignAudio => '외국어 오디오 시 표시';
@override String get alwaysEnabled => '항상 활성화';
}
// Path: hotkeys.actions
class _TranslationsHotkeysActionsKo implements TranslationsHotkeysActionsEn {
_TranslationsHotkeysActionsKo._(this._root);
@@ -1979,6 +2048,65 @@ extension on TranslationsKo {
'externalPlayer.launchFailed' => '외부 플레이어를 열 수 없습니다',
'externalPlayer.appNotInstalled' => ({required Object name}) => '${name}이(가) 설치되어 있지 않습니다',
'externalPlayer.playInExternalPlayer' => '외부 플레이어에서 재생',
'metadataEdit.editMetadata' => '편집...',
'metadataEdit.screenTitle' => '메타데이터 편집',
'metadataEdit.basicInfo' => '기본 정보',
'metadataEdit.artwork' => '아트워크',
'metadataEdit.advancedSettings' => '고급 설정',
'metadataEdit.title' => '제목',
'metadataEdit.sortTitle' => '정렬 제목',
'metadataEdit.originalTitle' => '원제',
'metadataEdit.releaseDate' => '출시일',
'metadataEdit.contentRating' => '콘텐츠 등급',
'metadataEdit.studio' => '스튜디오',
'metadataEdit.tagline' => '태그라인',
'metadataEdit.summary' => '줄거리',
'metadataEdit.poster' => '포스터',
'metadataEdit.background' => '배경',
'metadataEdit.selectPoster' => '포스터 선택',
'metadataEdit.selectBackground' => '배경 선택',
'metadataEdit.fromUrl' => 'URL에서',
'metadataEdit.uploadFile' => '파일 업로드',
'metadataEdit.enterImageUrl' => '이미지 URL 입력',
'metadataEdit.imageUrl' => '이미지 URL',
'metadataEdit.metadataUpdated' => '메타데이터가 업데이트되었습니다',
'metadataEdit.metadataUpdateFailed' => '메타데이터 업데이트 실패',
'metadataEdit.artworkUpdated' => '아트워크가 업데이트되었습니다',
'metadataEdit.artworkUpdateFailed' => '아트워크 업데이트 실패',
'metadataEdit.noArtworkAvailable' => '사용 가능한 아트워크 없음',
'metadataEdit.notSet' => '설정되지 않음',
'metadataEdit.libraryDefault' => '라이브러리 기본값',
'metadataEdit.accountDefault' => '계정 기본값',
'metadataEdit.seriesDefault' => '시리즈 기본값',
'metadataEdit.episodeSorting' => '에피소드 정렬',
'metadataEdit.oldestFirst' => '오래된 순',
'metadataEdit.newestFirst' => '최신 순',
'metadataEdit.keep' => '유지',
'metadataEdit.allEpisodes' => '모든 에피소드',
'metadataEdit.latestEpisodes' => ({required Object count}) => '최신 에피소드 ${count}',
'metadataEdit.latestEpisode' => '최신 에피소드',
'metadataEdit.episodesAddedPastDays' => ({required Object count}) => '최근 ${count}일 내 추가된 에피소드',
'metadataEdit.deleteAfterPlaying' => '재생 후 에피소드 삭제',
'metadataEdit.never' => '안 함',
'metadataEdit.afterADay' => '하루 후',
'metadataEdit.afterAWeek' => '일주일 후',
'metadataEdit.afterAMonth' => '한 달 후',
'metadataEdit.onNextRefresh' => '다음 새로고침 시',
'metadataEdit.seasons' => '시즌',
'metadataEdit.show' => '표시',
'metadataEdit.hide' => '숨기기',
'metadataEdit.episodeOrdering' => '에피소드 순서',
'metadataEdit.tmdbAiring' => 'The Movie Database (방영순)',
'metadataEdit.tvdbAiring' => 'TheTVDB (방영순)',
'metadataEdit.tvdbAbsolute' => 'TheTVDB (절대순)',
'metadataEdit.metadataLanguage' => '메타데이터 언어',
'metadataEdit.useOriginalTitle' => '원제 사용',
'metadataEdit.preferredAudioLanguage' => '선호 오디오 언어',
'metadataEdit.preferredSubtitleLanguage' => '선호 자막 언어',
'metadataEdit.subtitleMode' => '자막 자동 선택 모드',
'metadataEdit.manuallySelected' => '수동 선택',
'metadataEdit.shownWithForeignAudio' => '외국어 오디오 시 표시',
'metadataEdit.alwaysEnabled' => '항상 활성화',
_ => null,
};
}
+128
View File
@@ -74,6 +74,7 @@ class TranslationsNl with BaseTranslations<AppLocale, Translations> implements T
@override late final _TranslationsCompanionRemoteNl companionRemote = _TranslationsCompanionRemoteNl._(_root);
@override late final _TranslationsVideoSettingsNl videoSettings = _TranslationsVideoSettingsNl._(_root);
@override late final _TranslationsExternalPlayerNl externalPlayer = _TranslationsExternalPlayerNl._(_root);
@override late final _TranslationsMetadataEditNl metadataEdit = _TranslationsMetadataEditNl._(_root);
}
// Path: app
@@ -1050,6 +1051,74 @@ class _TranslationsExternalPlayerNl implements TranslationsExternalPlayerEn {
@override String get playInExternalPlayer => 'Afspelen in externe speler';
}
// Path: metadataEdit
class _TranslationsMetadataEditNl implements TranslationsMetadataEditEn {
_TranslationsMetadataEditNl._(this._root);
final TranslationsNl _root; // ignore: unused_field
// Translations
@override String get editMetadata => 'Bewerken...';
@override String get screenTitle => 'Metadata bewerken';
@override String get basicInfo => 'Basisinformatie';
@override String get artwork => 'Artwork';
@override String get advancedSettings => 'Geavanceerde instellingen';
@override String get title => 'Titel';
@override String get sortTitle => 'Sorteertitel';
@override String get originalTitle => 'Oorspronkelijke titel';
@override String get releaseDate => 'Releasedatum';
@override String get contentRating => 'Leeftijdsclassificatie';
@override String get studio => 'Studio';
@override String get tagline => 'Tagline';
@override String get summary => 'Samenvatting';
@override String get poster => 'Poster';
@override String get background => 'Achtergrond';
@override String get selectPoster => 'Poster selecteren';
@override String get selectBackground => 'Achtergrond selecteren';
@override String get fromUrl => 'Vanaf URL';
@override String get uploadFile => 'Bestand uploaden';
@override String get enterImageUrl => 'Voer afbeeldings-URL in';
@override String get imageUrl => 'Afbeeldings-URL';
@override String get metadataUpdated => 'Metadata bijgewerkt';
@override String get metadataUpdateFailed => 'Metadata bijwerken mislukt';
@override String get artworkUpdated => 'Artwork bijgewerkt';
@override String get artworkUpdateFailed => 'Artwork bijwerken mislukt';
@override String get noArtworkAvailable => 'Geen artwork beschikbaar';
@override String get notSet => 'Niet ingesteld';
@override String get libraryDefault => 'Bibliotheekstandaard';
@override String get accountDefault => 'Accountstandaard';
@override String get seriesDefault => 'Seriestandaard';
@override String get episodeSorting => 'Afleveringen sorteren';
@override String get oldestFirst => 'Oudste eerst';
@override String get newestFirst => 'Nieuwste eerst';
@override String get keep => 'Bewaren';
@override String get allEpisodes => 'Alle afleveringen';
@override String latestEpisodes({required Object count}) => '${count} nieuwste afleveringen';
@override String get latestEpisode => 'Nieuwste aflevering';
@override String episodesAddedPastDays({required Object count}) => 'Afleveringen toegevoegd in de afgelopen ${count} dagen';
@override String get deleteAfterPlaying => 'Afleveringen verwijderen na afspelen';
@override String get never => 'Nooit';
@override String get afterADay => 'Na een dag';
@override String get afterAWeek => 'Na een week';
@override String get afterAMonth => 'Na een maand';
@override String get onNextRefresh => 'Bij volgende verversing';
@override String get seasons => 'Seizoenen';
@override String get show => 'Tonen';
@override String get hide => 'Verbergen';
@override String get episodeOrdering => 'Afleveringsvolgorde';
@override String get tmdbAiring => 'The Movie Database (Uitgezonden)';
@override String get tvdbAiring => 'TheTVDB (Uitgezonden)';
@override String get tvdbAbsolute => 'TheTVDB (Absoluut)';
@override String get metadataLanguage => 'Metadatataal';
@override String get useOriginalTitle => 'Oorspronkelijke titel gebruiken';
@override String get preferredAudioLanguage => 'Voorkeurstaal audio';
@override String get preferredSubtitleLanguage => 'Voorkeurstaal ondertiteling';
@override String get subtitleMode => 'Automatische ondertitelselectie';
@override String get manuallySelected => 'Handmatig geselecteerd';
@override String get shownWithForeignAudio => 'Weergeven bij anderstalig geluid';
@override String get alwaysEnabled => 'Altijd ingeschakeld';
}
// Path: hotkeys.actions
class _TranslationsHotkeysActionsNl implements TranslationsHotkeysActionsEn {
_TranslationsHotkeysActionsNl._(this._root);
@@ -1979,6 +2048,65 @@ extension on TranslationsNl {
'externalPlayer.launchFailed' => 'Kan externe speler niet openen',
'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} is niet geïnstalleerd',
'externalPlayer.playInExternalPlayer' => 'Afspelen in externe speler',
'metadataEdit.editMetadata' => 'Bewerken...',
'metadataEdit.screenTitle' => 'Metadata bewerken',
'metadataEdit.basicInfo' => 'Basisinformatie',
'metadataEdit.artwork' => 'Artwork',
'metadataEdit.advancedSettings' => 'Geavanceerde instellingen',
'metadataEdit.title' => 'Titel',
'metadataEdit.sortTitle' => 'Sorteertitel',
'metadataEdit.originalTitle' => 'Oorspronkelijke titel',
'metadataEdit.releaseDate' => 'Releasedatum',
'metadataEdit.contentRating' => 'Leeftijdsclassificatie',
'metadataEdit.studio' => 'Studio',
'metadataEdit.tagline' => 'Tagline',
'metadataEdit.summary' => 'Samenvatting',
'metadataEdit.poster' => 'Poster',
'metadataEdit.background' => 'Achtergrond',
'metadataEdit.selectPoster' => 'Poster selecteren',
'metadataEdit.selectBackground' => 'Achtergrond selecteren',
'metadataEdit.fromUrl' => 'Vanaf URL',
'metadataEdit.uploadFile' => 'Bestand uploaden',
'metadataEdit.enterImageUrl' => 'Voer afbeeldings-URL in',
'metadataEdit.imageUrl' => 'Afbeeldings-URL',
'metadataEdit.metadataUpdated' => 'Metadata bijgewerkt',
'metadataEdit.metadataUpdateFailed' => 'Metadata bijwerken mislukt',
'metadataEdit.artworkUpdated' => 'Artwork bijgewerkt',
'metadataEdit.artworkUpdateFailed' => 'Artwork bijwerken mislukt',
'metadataEdit.noArtworkAvailable' => 'Geen artwork beschikbaar',
'metadataEdit.notSet' => 'Niet ingesteld',
'metadataEdit.libraryDefault' => 'Bibliotheekstandaard',
'metadataEdit.accountDefault' => 'Accountstandaard',
'metadataEdit.seriesDefault' => 'Seriestandaard',
'metadataEdit.episodeSorting' => 'Afleveringen sorteren',
'metadataEdit.oldestFirst' => 'Oudste eerst',
'metadataEdit.newestFirst' => 'Nieuwste eerst',
'metadataEdit.keep' => 'Bewaren',
'metadataEdit.allEpisodes' => 'Alle afleveringen',
'metadataEdit.latestEpisodes' => ({required Object count}) => '${count} nieuwste afleveringen',
'metadataEdit.latestEpisode' => 'Nieuwste aflevering',
'metadataEdit.episodesAddedPastDays' => ({required Object count}) => 'Afleveringen toegevoegd in de afgelopen ${count} dagen',
'metadataEdit.deleteAfterPlaying' => 'Afleveringen verwijderen na afspelen',
'metadataEdit.never' => 'Nooit',
'metadataEdit.afterADay' => 'Na een dag',
'metadataEdit.afterAWeek' => 'Na een week',
'metadataEdit.afterAMonth' => 'Na een maand',
'metadataEdit.onNextRefresh' => 'Bij volgende verversing',
'metadataEdit.seasons' => 'Seizoenen',
'metadataEdit.show' => 'Tonen',
'metadataEdit.hide' => 'Verbergen',
'metadataEdit.episodeOrdering' => 'Afleveringsvolgorde',
'metadataEdit.tmdbAiring' => 'The Movie Database (Uitgezonden)',
'metadataEdit.tvdbAiring' => 'TheTVDB (Uitgezonden)',
'metadataEdit.tvdbAbsolute' => 'TheTVDB (Absoluut)',
'metadataEdit.metadataLanguage' => 'Metadatataal',
'metadataEdit.useOriginalTitle' => 'Oorspronkelijke titel gebruiken',
'metadataEdit.preferredAudioLanguage' => 'Voorkeurstaal audio',
'metadataEdit.preferredSubtitleLanguage' => 'Voorkeurstaal ondertiteling',
'metadataEdit.subtitleMode' => 'Automatische ondertitelselectie',
'metadataEdit.manuallySelected' => 'Handmatig geselecteerd',
'metadataEdit.shownWithForeignAudio' => 'Weergeven bij anderstalig geluid',
'metadataEdit.alwaysEnabled' => 'Altijd ingeschakeld',
_ => null,
};
}
+128
View File
@@ -74,6 +74,7 @@ class TranslationsSv with BaseTranslations<AppLocale, Translations> implements T
@override late final _TranslationsCompanionRemoteSv companionRemote = _TranslationsCompanionRemoteSv._(_root);
@override late final _TranslationsVideoSettingsSv videoSettings = _TranslationsVideoSettingsSv._(_root);
@override late final _TranslationsExternalPlayerSv externalPlayer = _TranslationsExternalPlayerSv._(_root);
@override late final _TranslationsMetadataEditSv metadataEdit = _TranslationsMetadataEditSv._(_root);
}
// Path: app
@@ -1050,6 +1051,74 @@ class _TranslationsExternalPlayerSv implements TranslationsExternalPlayerEn {
@override String get playInExternalPlayer => 'Spela i extern spelare';
}
// Path: metadataEdit
class _TranslationsMetadataEditSv implements TranslationsMetadataEditEn {
_TranslationsMetadataEditSv._(this._root);
final TranslationsSv _root; // ignore: unused_field
// Translations
@override String get editMetadata => 'Redigera...';
@override String get screenTitle => 'Redigera metadata';
@override String get basicInfo => 'Grundläggande info';
@override String get artwork => 'Artwork';
@override String get advancedSettings => 'Avancerade inställningar';
@override String get title => 'Titel';
@override String get sortTitle => 'Sorteringstitel';
@override String get originalTitle => 'Originaltitel';
@override String get releaseDate => 'Utgivningsdatum';
@override String get contentRating => 'Åldersgräns';
@override String get studio => 'Studio';
@override String get tagline => 'Tagline';
@override String get summary => 'Sammanfattning';
@override String get poster => 'Poster';
@override String get background => 'Bakgrund';
@override String get selectPoster => 'Välj poster';
@override String get selectBackground => 'Välj bakgrund';
@override String get fromUrl => 'Från URL';
@override String get uploadFile => 'Ladda upp fil';
@override String get enterImageUrl => 'Ange bild-URL';
@override String get imageUrl => 'Bild-URL';
@override String get metadataUpdated => 'Metadata uppdaterad';
@override String get metadataUpdateFailed => 'Kunde inte uppdatera metadata';
@override String get artworkUpdated => 'Artwork uppdaterad';
@override String get artworkUpdateFailed => 'Kunde inte uppdatera artwork';
@override String get noArtworkAvailable => 'Ingen artwork tillgänglig';
@override String get notSet => 'Inte angiven';
@override String get libraryDefault => 'Biblioteksstandard';
@override String get accountDefault => 'Kontostandard';
@override String get seriesDefault => 'Seriestandard';
@override String get episodeSorting => 'Avsnittsortering';
@override String get oldestFirst => 'Äldst först';
@override String get newestFirst => 'Nyast först';
@override String get keep => 'Behåll';
@override String get allEpisodes => 'Alla avsnitt';
@override String latestEpisodes({required Object count}) => '${count} senaste avsnitten';
@override String get latestEpisode => 'Senaste avsnittet';
@override String episodesAddedPastDays({required Object count}) => 'Avsnitt tillagda de senaste ${count} dagarna';
@override String get deleteAfterPlaying => 'Ta bort avsnitt efter uppspelning';
@override String get never => 'Aldrig';
@override String get afterADay => 'Efter en dag';
@override String get afterAWeek => 'Efter en vecka';
@override String get afterAMonth => 'Efter en månad';
@override String get onNextRefresh => 'Vid nästa uppdatering';
@override String get seasons => 'Säsonger';
@override String get show => 'Visa';
@override String get hide => 'Dölj';
@override String get episodeOrdering => 'Avsnittsordning';
@override String get tmdbAiring => 'The Movie Database (Sändning)';
@override String get tvdbAiring => 'TheTVDB (Sändning)';
@override String get tvdbAbsolute => 'TheTVDB (Absolut)';
@override String get metadataLanguage => 'Metadataspråk';
@override String get useOriginalTitle => 'Använd originaltitel';
@override String get preferredAudioLanguage => 'Föredraget ljudspråk';
@override String get preferredSubtitleLanguage => 'Föredraget undertextspråk';
@override String get subtitleMode => 'Automatiskt val av undertexter';
@override String get manuallySelected => 'Manuellt vald';
@override String get shownWithForeignAudio => 'Visas vid främmande ljud';
@override String get alwaysEnabled => 'Alltid aktiverad';
}
// Path: hotkeys.actions
class _TranslationsHotkeysActionsSv implements TranslationsHotkeysActionsEn {
_TranslationsHotkeysActionsSv._(this._root);
@@ -1979,6 +2048,65 @@ extension on TranslationsSv {
'externalPlayer.launchFailed' => 'Kunde inte öppna extern spelare',
'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} är inte installerad',
'externalPlayer.playInExternalPlayer' => 'Spela i extern spelare',
'metadataEdit.editMetadata' => 'Redigera...',
'metadataEdit.screenTitle' => 'Redigera metadata',
'metadataEdit.basicInfo' => 'Grundläggande info',
'metadataEdit.artwork' => 'Artwork',
'metadataEdit.advancedSettings' => 'Avancerade inställningar',
'metadataEdit.title' => 'Titel',
'metadataEdit.sortTitle' => 'Sorteringstitel',
'metadataEdit.originalTitle' => 'Originaltitel',
'metadataEdit.releaseDate' => 'Utgivningsdatum',
'metadataEdit.contentRating' => 'Åldersgräns',
'metadataEdit.studio' => 'Studio',
'metadataEdit.tagline' => 'Tagline',
'metadataEdit.summary' => 'Sammanfattning',
'metadataEdit.poster' => 'Poster',
'metadataEdit.background' => 'Bakgrund',
'metadataEdit.selectPoster' => 'Välj poster',
'metadataEdit.selectBackground' => 'Välj bakgrund',
'metadataEdit.fromUrl' => 'Från URL',
'metadataEdit.uploadFile' => 'Ladda upp fil',
'metadataEdit.enterImageUrl' => 'Ange bild-URL',
'metadataEdit.imageUrl' => 'Bild-URL',
'metadataEdit.metadataUpdated' => 'Metadata uppdaterad',
'metadataEdit.metadataUpdateFailed' => 'Kunde inte uppdatera metadata',
'metadataEdit.artworkUpdated' => 'Artwork uppdaterad',
'metadataEdit.artworkUpdateFailed' => 'Kunde inte uppdatera artwork',
'metadataEdit.noArtworkAvailable' => 'Ingen artwork tillgänglig',
'metadataEdit.notSet' => 'Inte angiven',
'metadataEdit.libraryDefault' => 'Biblioteksstandard',
'metadataEdit.accountDefault' => 'Kontostandard',
'metadataEdit.seriesDefault' => 'Seriestandard',
'metadataEdit.episodeSorting' => 'Avsnittsortering',
'metadataEdit.oldestFirst' => 'Äldst först',
'metadataEdit.newestFirst' => 'Nyast först',
'metadataEdit.keep' => 'Behåll',
'metadataEdit.allEpisodes' => 'Alla avsnitt',
'metadataEdit.latestEpisodes' => ({required Object count}) => '${count} senaste avsnitten',
'metadataEdit.latestEpisode' => 'Senaste avsnittet',
'metadataEdit.episodesAddedPastDays' => ({required Object count}) => 'Avsnitt tillagda de senaste ${count} dagarna',
'metadataEdit.deleteAfterPlaying' => 'Ta bort avsnitt efter uppspelning',
'metadataEdit.never' => 'Aldrig',
'metadataEdit.afterADay' => 'Efter en dag',
'metadataEdit.afterAWeek' => 'Efter en vecka',
'metadataEdit.afterAMonth' => 'Efter en månad',
'metadataEdit.onNextRefresh' => 'Vid nästa uppdatering',
'metadataEdit.seasons' => 'Säsonger',
'metadataEdit.show' => 'Visa',
'metadataEdit.hide' => 'Dölj',
'metadataEdit.episodeOrdering' => 'Avsnittsordning',
'metadataEdit.tmdbAiring' => 'The Movie Database (Sändning)',
'metadataEdit.tvdbAiring' => 'TheTVDB (Sändning)',
'metadataEdit.tvdbAbsolute' => 'TheTVDB (Absolut)',
'metadataEdit.metadataLanguage' => 'Metadataspråk',
'metadataEdit.useOriginalTitle' => 'Använd originaltitel',
'metadataEdit.preferredAudioLanguage' => 'Föredraget ljudspråk',
'metadataEdit.preferredSubtitleLanguage' => 'Föredraget undertextspråk',
'metadataEdit.subtitleMode' => 'Automatiskt val av undertexter',
'metadataEdit.manuallySelected' => 'Manuellt vald',
'metadataEdit.shownWithForeignAudio' => 'Visas vid främmande ljud',
'metadataEdit.alwaysEnabled' => 'Alltid aktiverad',
_ => null,
};
}
+128
View File
@@ -74,6 +74,7 @@ class TranslationsZh with BaseTranslations<AppLocale, Translations> implements T
@override late final _TranslationsCompanionRemoteZh companionRemote = _TranslationsCompanionRemoteZh._(_root);
@override late final _TranslationsVideoSettingsZh videoSettings = _TranslationsVideoSettingsZh._(_root);
@override late final _TranslationsExternalPlayerZh externalPlayer = _TranslationsExternalPlayerZh._(_root);
@override late final _TranslationsMetadataEditZh metadataEdit = _TranslationsMetadataEditZh._(_root);
}
// Path: app
@@ -1050,6 +1051,74 @@ class _TranslationsExternalPlayerZh implements TranslationsExternalPlayerEn {
@override String get playInExternalPlayer => '在外部播放器中播放';
}
// Path: metadataEdit
class _TranslationsMetadataEditZh implements TranslationsMetadataEditEn {
_TranslationsMetadataEditZh._(this._root);
final TranslationsZh _root; // ignore: unused_field
// Translations
@override String get editMetadata => '编辑...';
@override String get screenTitle => '编辑元数据';
@override String get basicInfo => '基本信息';
@override String get artwork => '封面图片';
@override String get advancedSettings => '高级设置';
@override String get title => '标题';
@override String get sortTitle => '排序标题';
@override String get originalTitle => '原始标题';
@override String get releaseDate => '上映日期';
@override String get contentRating => '内容分级';
@override String get studio => '制片厂';
@override String get tagline => '标语';
@override String get summary => '简介';
@override String get poster => '海报';
@override String get background => '背景';
@override String get selectPoster => '选择海报';
@override String get selectBackground => '选择背景';
@override String get fromUrl => '从 URL';
@override String get uploadFile => '上传文件';
@override String get enterImageUrl => '输入图片 URL';
@override String get imageUrl => '图片 URL';
@override String get metadataUpdated => '元数据已更新';
@override String get metadataUpdateFailed => '元数据更新失败';
@override String get artworkUpdated => '封面图片已更新';
@override String get artworkUpdateFailed => '封面图片更新失败';
@override String get noArtworkAvailable => '没有可用的封面图片';
@override String get notSet => '未设置';
@override String get libraryDefault => '媒体库默认';
@override String get accountDefault => '账户默认';
@override String get seriesDefault => '剧集默认';
@override String get episodeSorting => '剧集排序';
@override String get oldestFirst => '最旧优先';
@override String get newestFirst => '最新优先';
@override String get keep => '保留';
@override String get allEpisodes => '所有剧集';
@override String latestEpisodes({required Object count}) => '最新 ${count}';
@override String get latestEpisode => '最新一集';
@override String episodesAddedPastDays({required Object count}) => '过去 ${count} 天内添加的剧集';
@override String get deleteAfterPlaying => '播放后删除剧集';
@override String get never => '从不';
@override String get afterADay => '一天后';
@override String get afterAWeek => '一周后';
@override String get afterAMonth => '一个月后';
@override String get onNextRefresh => '下次刷新时';
@override String get seasons => '';
@override String get show => '显示';
@override String get hide => '隐藏';
@override String get episodeOrdering => '剧集排列顺序';
@override String get tmdbAiring => 'The Movie Database(播出顺序)';
@override String get tvdbAiring => 'TheTVDB(播出顺序)';
@override String get tvdbAbsolute => 'TheTVDB(绝对顺序)';
@override String get metadataLanguage => '元数据语言';
@override String get useOriginalTitle => '使用原始标题';
@override String get preferredAudioLanguage => '首选音频语言';
@override String get preferredSubtitleLanguage => '首选字幕语言';
@override String get subtitleMode => '自动选择字幕模式';
@override String get manuallySelected => '手动选择';
@override String get shownWithForeignAudio => '外语音频时显示';
@override String get alwaysEnabled => '始终启用';
}
// Path: hotkeys.actions
class _TranslationsHotkeysActionsZh implements TranslationsHotkeysActionsEn {
_TranslationsHotkeysActionsZh._(this._root);
@@ -1979,6 +2048,65 @@ extension on TranslationsZh {
'externalPlayer.launchFailed' => '无法打开外部播放器',
'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} 未安装',
'externalPlayer.playInExternalPlayer' => '在外部播放器中播放',
'metadataEdit.editMetadata' => '编辑...',
'metadataEdit.screenTitle' => '编辑元数据',
'metadataEdit.basicInfo' => '基本信息',
'metadataEdit.artwork' => '封面图片',
'metadataEdit.advancedSettings' => '高级设置',
'metadataEdit.title' => '标题',
'metadataEdit.sortTitle' => '排序标题',
'metadataEdit.originalTitle' => '原始标题',
'metadataEdit.releaseDate' => '上映日期',
'metadataEdit.contentRating' => '内容分级',
'metadataEdit.studio' => '制片厂',
'metadataEdit.tagline' => '标语',
'metadataEdit.summary' => '简介',
'metadataEdit.poster' => '海报',
'metadataEdit.background' => '背景',
'metadataEdit.selectPoster' => '选择海报',
'metadataEdit.selectBackground' => '选择背景',
'metadataEdit.fromUrl' => '从 URL',
'metadataEdit.uploadFile' => '上传文件',
'metadataEdit.enterImageUrl' => '输入图片 URL',
'metadataEdit.imageUrl' => '图片 URL',
'metadataEdit.metadataUpdated' => '元数据已更新',
'metadataEdit.metadataUpdateFailed' => '元数据更新失败',
'metadataEdit.artworkUpdated' => '封面图片已更新',
'metadataEdit.artworkUpdateFailed' => '封面图片更新失败',
'metadataEdit.noArtworkAvailable' => '没有可用的封面图片',
'metadataEdit.notSet' => '未设置',
'metadataEdit.libraryDefault' => '媒体库默认',
'metadataEdit.accountDefault' => '账户默认',
'metadataEdit.seriesDefault' => '剧集默认',
'metadataEdit.episodeSorting' => '剧集排序',
'metadataEdit.oldestFirst' => '最旧优先',
'metadataEdit.newestFirst' => '最新优先',
'metadataEdit.keep' => '保留',
'metadataEdit.allEpisodes' => '所有剧集',
'metadataEdit.latestEpisodes' => ({required Object count}) => '最新 ${count}',
'metadataEdit.latestEpisode' => '最新一集',
'metadataEdit.episodesAddedPastDays' => ({required Object count}) => '过去 ${count} 天内添加的剧集',
'metadataEdit.deleteAfterPlaying' => '播放后删除剧集',
'metadataEdit.never' => '从不',
'metadataEdit.afterADay' => '一天后',
'metadataEdit.afterAWeek' => '一周后',
'metadataEdit.afterAMonth' => '一个月后',
'metadataEdit.onNextRefresh' => '下次刷新时',
'metadataEdit.seasons' => '',
'metadataEdit.show' => '显示',
'metadataEdit.hide' => '隐藏',
'metadataEdit.episodeOrdering' => '剧集排列顺序',
'metadataEdit.tmdbAiring' => 'The Movie Database(播出顺序)',
'metadataEdit.tvdbAiring' => 'TheTVDB(播出顺序)',
'metadataEdit.tvdbAbsolute' => 'TheTVDB(绝对顺序)',
'metadataEdit.metadataLanguage' => '元数据语言',
'metadataEdit.useOriginalTitle' => '使用原始标题',
'metadataEdit.preferredAudioLanguage' => '首选音频语言',
'metadataEdit.preferredSubtitleLanguage' => '首选字幕语言',
'metadataEdit.subtitleMode' => '自动选择字幕模式',
'metadataEdit.manuallySelected' => '手动选择',
'metadataEdit.shownWithForeignAudio' => '外语音频时显示',
'metadataEdit.alwaysEnabled' => '始终启用',
_ => null,
};
}
+62 -1
View File
@@ -1,7 +1,7 @@
{
"app": {
"title": "Plezy"
},
},
"auth": {
"signInWithPlex": "Logga in med Plex",
"showQRCode": "Visa QR-kod",
@@ -831,5 +831,66 @@
"launchFailed": "Kunde inte öppna extern spelare",
"appNotInstalled": "${name} är inte installerad",
"playInExternalPlayer": "Spela i extern spelare"
},
"metadataEdit": {
"editMetadata": "Redigera...",
"screenTitle": "Redigera metadata",
"basicInfo": "Grundläggande info",
"artwork": "Artwork",
"advancedSettings": "Avancerade inställningar",
"title": "Titel",
"sortTitle": "Sorteringstitel",
"originalTitle": "Originaltitel",
"releaseDate": "Utgivningsdatum",
"contentRating": "Åldersgräns",
"studio": "Studio",
"tagline": "Tagline",
"summary": "Sammanfattning",
"poster": "Poster",
"background": "Bakgrund",
"selectPoster": "Välj poster",
"selectBackground": "Välj bakgrund",
"fromUrl": "Från URL",
"uploadFile": "Ladda upp fil",
"enterImageUrl": "Ange bild-URL",
"imageUrl": "Bild-URL",
"metadataUpdated": "Metadata uppdaterad",
"metadataUpdateFailed": "Kunde inte uppdatera metadata",
"artworkUpdated": "Artwork uppdaterad",
"artworkUpdateFailed": "Kunde inte uppdatera artwork",
"noArtworkAvailable": "Ingen artwork tillgänglig",
"notSet": "Inte angiven",
"libraryDefault": "Biblioteksstandard",
"accountDefault": "Kontostandard",
"seriesDefault": "Seriestandard",
"episodeSorting": "Avsnittsortering",
"oldestFirst": "Äldst först",
"newestFirst": "Nyast först",
"keep": "Behåll",
"allEpisodes": "Alla avsnitt",
"latestEpisodes": "${count} senaste avsnitten",
"latestEpisode": "Senaste avsnittet",
"episodesAddedPastDays": "Avsnitt tillagda de senaste ${count} dagarna",
"deleteAfterPlaying": "Ta bort avsnitt efter uppspelning",
"never": "Aldrig",
"afterADay": "Efter en dag",
"afterAWeek": "Efter en vecka",
"afterAMonth": "Efter en månad",
"onNextRefresh": "Vid nästa uppdatering",
"seasons": "Säsonger",
"show": "Visa",
"hide": "Dölj",
"episodeOrdering": "Avsnittsordning",
"tmdbAiring": "The Movie Database (Sändning)",
"tvdbAiring": "TheTVDB (Sändning)",
"tvdbAbsolute": "TheTVDB (Absolut)",
"metadataLanguage": "Metadataspråk",
"useOriginalTitle": "Använd originaltitel",
"preferredAudioLanguage": "Föredraget ljudspråk",
"preferredSubtitleLanguage": "Föredraget undertextspråk",
"subtitleMode": "Automatiskt val av undertexter",
"manuallySelected": "Manuellt vald",
"shownWithForeignAudio": "Visas vid främmande ljud",
"alwaysEnabled": "Alltid aktiverad"
}
}
+62 -1
View File
@@ -1,7 +1,7 @@
{
"app": {
"title": "Plezy"
},
},
"auth": {
"signInWithPlex": "使用 Plex 登录",
"showQRCode": "显示二维码",
@@ -831,5 +831,66 @@
"launchFailed": "无法打开外部播放器",
"appNotInstalled": "${name} 未安装",
"playInExternalPlayer": "在外部播放器中播放"
},
"metadataEdit": {
"editMetadata": "编辑...",
"screenTitle": "编辑元数据",
"basicInfo": "基本信息",
"artwork": "封面图片",
"advancedSettings": "高级设置",
"title": "标题",
"sortTitle": "排序标题",
"originalTitle": "原始标题",
"releaseDate": "上映日期",
"contentRating": "内容分级",
"studio": "制片厂",
"tagline": "标语",
"summary": "简介",
"poster": "海报",
"background": "背景",
"selectPoster": "选择海报",
"selectBackground": "选择背景",
"fromUrl": "从 URL",
"uploadFile": "上传文件",
"enterImageUrl": "输入图片 URL",
"imageUrl": "图片 URL",
"metadataUpdated": "元数据已更新",
"metadataUpdateFailed": "元数据更新失败",
"artworkUpdated": "封面图片已更新",
"artworkUpdateFailed": "封面图片更新失败",
"noArtworkAvailable": "没有可用的封面图片",
"notSet": "未设置",
"libraryDefault": "媒体库默认",
"accountDefault": "账户默认",
"seriesDefault": "剧集默认",
"episodeSorting": "剧集排序",
"oldestFirst": "最旧优先",
"newestFirst": "最新优先",
"keep": "保留",
"allEpisodes": "所有剧集",
"latestEpisodes": "最新 ${count} 集",
"latestEpisode": "最新一集",
"episodesAddedPastDays": "过去 ${count} 天内添加的剧集",
"deleteAfterPlaying": "播放后删除剧集",
"never": "从不",
"afterADay": "一天后",
"afterAWeek": "一周后",
"afterAMonth": "一个月后",
"onNextRefresh": "下次刷新时",
"seasons": "季",
"show": "显示",
"hide": "隐藏",
"episodeOrdering": "剧集排列顺序",
"tmdbAiring": "The Movie Database(播出顺序)",
"tvdbAiring": "TheTVDB(播出顺序)",
"tvdbAbsolute": "TheTVDB(绝对顺序)",
"metadataLanguage": "元数据语言",
"useOriginalTitle": "使用原始标题",
"preferredAudioLanguage": "首选音频语言",
"preferredSubtitleLanguage": "首选字幕语言",
"subtitleMode": "自动选择字幕模式",
"manuallySelected": "手动选择",
"shownWithForeignAudio": "外语音频时显示",
"alwaysEnabled": "始终启用"
}
}
+20
View File
@@ -33,6 +33,18 @@ enum PlexMediaType {
/// Whether this type can be played directly
bool get isPlayable => isVideo || this == track;
/// Plex API type number for metadata editing endpoints
int get typeNumber => switch (this) {
PlexMediaType.movie => 1,
PlexMediaType.show => 2,
PlexMediaType.season => 3,
PlexMediaType.episode => 4,
PlexMediaType.artist => 8,
PlexMediaType.album => 9,
PlexMediaType.track => 10,
_ => 0,
};
}
@JsonSerializable()
@@ -81,6 +93,8 @@ class PlexMetadata with MultiServerFields {
final int? librarySectionID; // Library section ID this item belongs to
final String? ratingImage; // Rating source URI (e.g. rottentomatoes://image.rating.ripe)
final String? audienceRatingImage; // Audience rating source URI
final String? tagline;
final String? originalTitle;
final String? subtype; // Clip subtype: "trailer", "behindTheScenes", "deleted", etc.
final int? extraType; // Numeric extra type identifier
final String? primaryExtraKey; // Points to main trailer (e.g., "/library/metadata/52601")
@@ -161,6 +175,8 @@ class PlexMetadata with MultiServerFields {
this.librarySectionID,
this.ratingImage,
this.audienceRatingImage,
this.tagline,
this.originalTitle,
this.subtype,
this.extraType,
this.primaryExtraKey,
@@ -214,6 +230,8 @@ class PlexMetadata with MultiServerFields {
int? librarySectionID,
String? ratingImage,
String? audienceRatingImage,
String? tagline,
String? originalTitle,
String? subtype,
int? extraType,
String? primaryExtraKey,
@@ -265,6 +283,8 @@ class PlexMetadata with MultiServerFields {
librarySectionID: librarySectionID ?? this.librarySectionID,
ratingImage: ratingImage ?? this.ratingImage,
audienceRatingImage: audienceRatingImage ?? this.audienceRatingImage,
tagline: tagline ?? this.tagline,
originalTitle: originalTitle ?? this.originalTitle,
subtype: subtype ?? this.subtype,
extraType: extraType ?? this.extraType,
primaryExtraKey: primaryExtraKey ?? this.primaryExtraKey,
+4
View File
@@ -50,6 +50,8 @@ PlexMetadata _$PlexMetadataFromJson(Map<String, dynamic> json) => PlexMetadata(
librarySectionID: (json['librarySectionID'] as num?)?.toInt(),
ratingImage: json['ratingImage'] as String?,
audienceRatingImage: json['audienceRatingImage'] as String?,
tagline: json['tagline'] as String?,
originalTitle: json['originalTitle'] as String?,
subtype: json['subtype'] as String?,
extraType: (json['extraType'] as num?)?.toInt(),
primaryExtraKey: json['primaryExtraKey'] as String?,
@@ -100,6 +102,8 @@ Map<String, dynamic> _$PlexMetadataToJson(PlexMetadata instance) => <String, dyn
'librarySectionID': instance.librarySectionID,
'ratingImage': instance.ratingImage,
'audienceRatingImage': instance.audienceRatingImage,
'tagline': instance.tagline,
'originalTitle': instance.originalTitle,
'subtype': instance.subtype,
'extraType': instance.extraType,
'primaryExtraKey': instance.primaryExtraKey,
+20
View File
@@ -47,6 +47,7 @@ import '../mixins/watch_state_aware.dart';
import '../mixins/deletion_aware.dart';
import '../utils/watch_state_notifier.dart';
import '../utils/deletion_notifier.dart';
import 'metadata_edit_screen.dart';
import 'season_detail_screen.dart';
class MediaDetailScreen extends StatefulWidget {
@@ -703,6 +704,25 @@ class _MediaDetailScreenState extends State<MediaDetailScreen> with WatchStateAw
iconSize: 20,
style: IconButton.styleFrom(minimumSize: const Size(48, 48), maximumSize: const Size(48, 48)),
),
// Edit metadata button (hidden in offline mode)
if (!widget.isOffline) ...[
const SizedBox(width: 12),
IconButton.filledTonal(
onPressed: () async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MetadataEditScreen(metadata: metadata)),
);
if (result == true && mounted) {
_loadFullMetadata();
}
},
icon: const AppIcon(Symbols.edit_rounded, fill: 1),
tooltip: t.metadataEdit.editMetadata,
iconSize: 20,
style: IconButton.styleFrom(minimumSize: const Size(48, 48), maximumSize: const Size(48, 48)),
),
],
],
),
);
+717
View File
@@ -0,0 +1,717 @@
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/symbols.dart';
import '../focus/focusable_button.dart';
import '../i18n/strings.g.dart';
import '../models/plex_metadata.dart';
import '../services/plex_client.dart';
import '../utils/dialogs.dart';
import '../utils/language_codes.dart';
import '../utils/provider_extensions.dart';
import '../utils/snackbar_helper.dart';
import '../widgets/app_icon.dart';
import '../widgets/artwork_picker_dialog.dart';
import '../widgets/focusable_list_tile.dart';
import '../widgets/focused_scroll_scaffold.dart';
import '../widgets/plex_optimized_image.dart';
class MetadataEditScreen extends StatefulWidget {
final PlexMetadata metadata;
const MetadataEditScreen({super.key, required this.metadata});
@override
State<MetadataEditScreen> createState() => _MetadataEditScreenState();
}
class _MetadataEditScreenState extends State<MetadataEditScreen> {
late PlexClient _client;
PlexMetadata? _fullMetadata;
bool _isLoading = true;
bool _isSaving = false;
// Text field values
String? _title;
String? _titleSort;
String? _originalTitle;
String? _originallyAvailableAt;
String? _contentRating;
String? _studio;
String? _tagline;
String? _summary;
// Original values for change detection
String? _origTitle;
String? _origTitleSort;
String? _origOriginalTitle;
String? _origOriginallyAvailableAt;
String? _origContentRating;
String? _origStudio;
String? _origTagline;
String? _origSummary;
// Advanced prefs (loaded from metadata JSON)
final Map<String, String> _currentPrefs = {};
bool get _hasChanges =>
_title != _origTitle ||
_titleSort != _origTitleSort ||
_originalTitle != _origOriginalTitle ||
_originallyAvailableAt != _origOriginallyAvailableAt ||
_contentRating != _origContentRating ||
_studio != _origStudio ||
_tagline != _origTagline ||
_summary != _origSummary;
PlexMediaType get _mediaType => widget.metadata.mediaType;
@override
void initState() {
super.initState();
_client = context.getClientWithFallback(widget.metadata.serverId);
_loadMetadata();
}
Future<void> _loadMetadata() async {
try {
final meta = await _client.getMetadataWithImages(widget.metadata.ratingKey);
if (!mounted) return;
if (meta != null) {
_fullMetadata = meta;
_initFieldsFromMetadata(meta);
} else {
_initFieldsFromMetadata(widget.metadata);
}
setState(() => _isLoading = false);
} catch (e) {
if (!mounted) return;
_initFieldsFromMetadata(widget.metadata);
setState(() => _isLoading = false);
}
}
void _initFieldsFromMetadata(PlexMetadata meta) {
_title = meta.title;
_titleSort = meta.titleSort ?? '';
_originalTitle = meta.originalTitle ?? '';
_originallyAvailableAt = meta.originallyAvailableAt ?? '';
_contentRating = meta.contentRating ?? '';
_studio = meta.studio ?? '';
_tagline = meta.tagline ?? '';
_summary = meta.summary ?? '';
_origTitle = _title;
_origTitleSort = _titleSort;
_origOriginalTitle = _originalTitle;
_origOriginallyAvailableAt = _originallyAvailableAt;
_origContentRating = _contentRating;
_origStudio = _studio;
_origTagline = _tagline;
_origSummary = _summary;
}
Future<void> _save() async {
if (!_hasChanges || _isSaving) return;
final sectionId = _fullMetadata?.librarySectionID ?? widget.metadata.librarySectionID;
if (sectionId == null) {
if (mounted) showErrorSnackBar(context, t.metadataEdit.metadataUpdateFailed);
return;
}
setState(() => _isSaving = true);
final success = await _client.updateMetadata(
sectionId: sectionId,
ratingKey: widget.metadata.ratingKey,
typeNumber: _mediaType.typeNumber,
title: _title != _origTitle ? _title : null,
titleSort: _titleSort != _origTitleSort ? _titleSort : null,
originalTitle: _originalTitle != _origOriginalTitle ? _originalTitle : null,
originallyAvailableAt: _originallyAvailableAt != _origOriginallyAvailableAt ? _originallyAvailableAt : null,
contentRating: _contentRating != _origContentRating ? _contentRating : null,
studio: _studio != _origStudio ? _studio : null,
tagline: _tagline != _origTagline ? _tagline : null,
summary: _summary != _origSummary ? _summary : null,
);
if (!mounted) return;
setState(() => _isSaving = false);
if (success) {
showSuccessSnackBar(context, t.metadataEdit.metadataUpdated);
Navigator.pop(context, true);
} else {
showErrorSnackBar(context, t.metadataEdit.metadataUpdateFailed);
}
}
Future<void> _editTextField({
required String title,
required String label,
required String? currentValue,
required ValueChanged<String> onChanged,
bool multiline = false,
}) async {
final String? result;
if (multiline) {
result = await showMultilineTextInputDialog(
context,
title: title,
labelText: label,
initialValue: currentValue,
);
} else {
result = await showTextInputDialog(
context,
title: title,
labelText: label,
hintText: '',
initialValue: currentValue,
);
}
if (result != null && mounted) {
final value = result;
setState(() => onChanged(value));
}
}
Future<void> _editDate() async {
DateTime initial = DateTime.now();
if (_originallyAvailableAt != null && _originallyAvailableAt!.isNotEmpty) {
final parsed = DateTime.tryParse(_originallyAvailableAt!);
if (parsed != null) initial = parsed;
}
final picked = await showDatePicker(
context: context,
initialDate: initial,
firstDate: DateTime(1800),
lastDate: DateTime(2200),
);
if (picked != null && mounted) {
setState(() {
_originallyAvailableAt =
'${picked.year}-${picked.month.toString().padLeft(2, '0')}-${picked.day.toString().padLeft(2, '0')}';
});
}
}
Future<void> _openArtworkPicker(String element) async {
final result = await showDialog<bool>(
context: context,
builder: (context) => ArtworkPickerDialog(
client: _client,
ratingKey: widget.metadata.ratingKey,
element: element,
),
);
if (result == true && mounted) {
// Reload metadata to get updated artwork paths
_loadMetadata();
}
}
Future<void> _showAdvancedSettingDialog({
required String title,
required String prefKey,
required List<({String value, String label})> options,
}) async {
// Determine current value from metadata or default
final currentValue = _currentPrefs[prefKey] ?? _getMetadataPrefValue(prefKey);
final result = await showDialog<String>(
context: context,
builder: (dialogContext) {
String? selected = currentValue;
return StatefulBuilder(
builder: (context, setDialogState) {
return AlertDialog(
title: Text(title),
content: SizedBox(
width: double.maxFinite,
child: ListView(
shrinkWrap: true,
children: options.map((option) {
return FocusableRadioListTile<String>(
title: Text(option.label),
value: option.value,
groupValue: selected,
onChanged: (val) {
setDialogState(() => selected = val);
Navigator.pop(dialogContext, val);
},
);
}).toList(),
),
),
actions: [
FocusableButton(
autofocus: true,
onPressed: () => Navigator.pop(dialogContext),
child: TextButton(
onPressed: () => Navigator.pop(dialogContext),
child: Text(t.common.cancel),
),
),
],
);
},
);
},
);
if (result != null && mounted) {
setState(() => _currentPrefs[prefKey] = result);
await _client.updateMetadataPrefs(widget.metadata.ratingKey, {prefKey: result});
}
}
String _getMetadataPrefValue(String key) {
// These prefs appear as keys on the raw metadata JSON when non-default.
// Since we use typed models, we check known fields.
final meta = _fullMetadata ?? widget.metadata;
switch (key) {
case 'audioLanguage':
return meta.audioLanguage ?? '';
case 'subtitleLanguage':
return meta.subtitleLanguage ?? '';
default:
return '';
}
}
String _getDisplayValueForPref(String prefKey, List<({String value, String label})> options) {
final val = _currentPrefs[prefKey] ?? _getMetadataPrefValue(prefKey);
for (final option in options) {
if (option.value == val) return option.label;
}
return options.first.label;
}
// ===== Field visibility =====
bool get _showSortTitle => _mediaType != PlexMediaType.season;
bool get _showOriginalTitle => _mediaType == PlexMediaType.movie || _mediaType == PlexMediaType.show;
bool get _showReleaseDate => _mediaType != PlexMediaType.season;
bool get _showContentRating => _mediaType != PlexMediaType.season;
bool get _showStudio => _mediaType == PlexMediaType.movie || _mediaType == PlexMediaType.show;
bool get _showTagline => _mediaType == PlexMediaType.movie || _mediaType == PlexMediaType.show;
bool get _showBackground =>
_mediaType == PlexMediaType.movie || _mediaType == PlexMediaType.show || _mediaType == PlexMediaType.episode;
bool get _showAdvanced => _mediaType != PlexMediaType.episode;
@override
Widget build(BuildContext context) {
if (_isLoading) {
return FocusedScrollScaffold(
title: Text(t.metadataEdit.screenTitle),
slivers: [const SliverFillRemaining(child: Center(child: CircularProgressIndicator()))],
);
}
return FocusedScrollScaffold(
title: Text(t.metadataEdit.screenTitle),
actions: [
if (_isSaving)
const Padding(
padding: EdgeInsets.all(12),
child: SizedBox(width: 24, height: 24, child: CircularProgressIndicator(strokeWidth: 2)),
)
else
IconButton(
onPressed: _hasChanges ? _save : null,
icon: const AppIcon(Symbols.check_rounded, fill: 1),
),
],
slivers: [
SliverPadding(
padding: const EdgeInsets.all(16),
sliver: SliverList(
delegate: SliverChildListDelegate([
_buildBasicInfoCard(),
const SizedBox(height: 16),
_buildArtworkCard(),
if (_showAdvanced) ...[
const SizedBox(height: 16),
_buildAdvancedSettingsCard(),
],
]),
),
),
],
);
}
Widget _buildBasicInfoCard() {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Text(
t.metadataEdit.basicInfo,
style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
),
),
_buildFieldTile(
label: t.metadataEdit.title,
value: _title,
onTap: () => _editTextField(
title: t.metadataEdit.title,
label: t.metadataEdit.title,
currentValue: _title,
onChanged: (v) => _title = v,
),
),
if (_showSortTitle)
_buildFieldTile(
label: t.metadataEdit.sortTitle,
value: _titleSort,
onTap: () => _editTextField(
title: t.metadataEdit.sortTitle,
label: t.metadataEdit.sortTitle,
currentValue: _titleSort,
onChanged: (v) => _titleSort = v,
),
),
if (_showOriginalTitle)
_buildFieldTile(
label: t.metadataEdit.originalTitle,
value: _originalTitle,
onTap: () => _editTextField(
title: t.metadataEdit.originalTitle,
label: t.metadataEdit.originalTitle,
currentValue: _originalTitle,
onChanged: (v) => _originalTitle = v,
),
),
if (_showReleaseDate)
_buildFieldTile(
label: t.metadataEdit.releaseDate,
value: _originallyAvailableAt,
onTap: _editDate,
),
if (_showContentRating)
_buildFieldTile(
label: t.metadataEdit.contentRating,
value: _contentRating,
onTap: () => _editTextField(
title: t.metadataEdit.contentRating,
label: t.metadataEdit.contentRating,
currentValue: _contentRating,
onChanged: (v) => _contentRating = v,
),
),
if (_showStudio)
_buildFieldTile(
label: t.metadataEdit.studio,
value: _studio,
onTap: () => _editTextField(
title: t.metadataEdit.studio,
label: t.metadataEdit.studio,
currentValue: _studio,
onChanged: (v) => _studio = v,
),
),
if (_showTagline)
_buildFieldTile(
label: t.metadataEdit.tagline,
value: _tagline,
onTap: () => _editTextField(
title: t.metadataEdit.tagline,
label: t.metadataEdit.tagline,
currentValue: _tagline,
onChanged: (v) => _tagline = v,
),
),
_buildFieldTile(
label: t.metadataEdit.summary,
value: _summary,
onTap: () => _editTextField(
title: t.metadataEdit.summary,
label: t.metadataEdit.summary,
currentValue: _summary,
onChanged: (v) => _summary = v,
multiline: true,
),
),
],
),
);
}
Widget _buildFieldTile({required String label, String? value, required VoidCallback onTap}) {
final displayValue = (value == null || value.isEmpty) ? t.metadataEdit.notSet : value;
final isNotSet = value == null || value.isEmpty;
return ListTile(
title: Text(label),
subtitle: Text(
displayValue,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: isNotSet ? TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.5)) : null,
),
trailing: const AppIcon(Symbols.chevron_right_rounded),
onTap: onTap,
);
}
Widget _buildArtworkCard() {
final meta = _fullMetadata ?? widget.metadata;
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Text(
t.metadataEdit.artwork,
style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
),
),
ListTile(
leading: SizedBox(
width: 40,
height: 60,
child: ClipRRect(
borderRadius: BorderRadius.circular(4),
child: PlexOptimizedImage(
client: _client,
imagePath: meta.thumb,
width: 40,
height: 60,
fit: BoxFit.cover,
),
),
),
title: Text(t.metadataEdit.poster),
trailing: const AppIcon(Symbols.chevron_right_rounded),
onTap: () => _openArtworkPicker('posters'),
),
if (_showBackground)
ListTile(
leading: SizedBox(
width: 80,
height: 45,
child: ClipRRect(
borderRadius: BorderRadius.circular(4),
child: PlexOptimizedImage(
client: _client,
imagePath: meta.art,
width: 80,
height: 45,
fit: BoxFit.cover,
),
),
),
title: Text(t.metadataEdit.background),
trailing: const AppIcon(Symbols.chevron_right_rounded),
onTap: () => _openArtworkPicker('arts'),
),
],
),
);
}
Widget _buildAdvancedSettingsCard() {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Text(
t.metadataEdit.advancedSettings,
style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
),
),
if (_mediaType == PlexMediaType.show) ..._buildShowAdvancedSettings(),
if (_mediaType == PlexMediaType.movie) ..._buildMovieAdvancedSettings(),
if (_mediaType == PlexMediaType.season) ..._buildSeasonAdvancedSettings(),
],
),
);
}
List<Widget> _buildShowAdvancedSettings() {
return [
_buildAdvancedTile(
title: t.metadataEdit.episodeSorting,
prefKey: 'episodeSort',
options: [
(value: '-1', label: t.metadataEdit.libraryDefault),
(value: '0', label: t.metadataEdit.oldestFirst),
(value: '1', label: t.metadataEdit.newestFirst),
],
),
_buildAdvancedTile(
title: t.metadataEdit.keep,
prefKey: 'autoDeletionItemPolicyUnwatchedLibrary',
options: [
(value: '0', label: t.metadataEdit.allEpisodes),
(value: '5', label: t.metadataEdit.latestEpisodes(count: '5')),
(value: '3', label: t.metadataEdit.latestEpisodes(count: '3')),
(value: '1', label: t.metadataEdit.latestEpisode),
(value: '-3', label: t.metadataEdit.episodesAddedPastDays(count: '3')),
(value: '-7', label: t.metadataEdit.episodesAddedPastDays(count: '7')),
(value: '-30', label: t.metadataEdit.episodesAddedPastDays(count: '30')),
],
),
_buildAdvancedTile(
title: t.metadataEdit.deleteAfterPlaying,
prefKey: 'autoDeletionItemPolicyWatchedLibrary',
options: [
(value: '0', label: t.metadataEdit.never),
(value: '1', label: t.metadataEdit.afterADay),
(value: '7', label: t.metadataEdit.afterAWeek),
(value: '30', label: t.metadataEdit.afterAMonth),
(value: '100', label: t.metadataEdit.onNextRefresh),
],
),
_buildAdvancedTile(
title: t.metadataEdit.seasons,
prefKey: 'flattenSeasons',
options: [
(value: '-1', label: t.metadataEdit.libraryDefault),
(value: '0', label: t.metadataEdit.show),
(value: '1', label: t.metadataEdit.hide),
],
),
_buildAdvancedTile(
title: t.metadataEdit.episodeOrdering,
prefKey: 'showOrdering',
options: [
(value: '', label: t.metadataEdit.libraryDefault),
(value: 'tmdbAiring', label: t.metadataEdit.tmdbAiring),
(value: 'tvdbAiring', label: t.metadataEdit.tvdbAiring),
(value: 'tvdbAbsolute', label: t.metadataEdit.tvdbAbsolute),
],
),
_buildAdvancedTile(
title: t.metadataEdit.metadataLanguage,
prefKey: 'languageOverride',
options: _metadataLanguageOptions(t.metadataEdit.libraryDefault),
),
_buildAdvancedTile(
title: t.metadataEdit.useOriginalTitle,
prefKey: 'useOriginalTitle',
options: [
(value: '-1', label: t.metadataEdit.libraryDefault),
(value: '0', label: t.common.no),
(value: '1', label: t.common.yes),
],
),
_buildAdvancedTile(
title: t.metadataEdit.preferredAudioLanguage,
prefKey: 'audioLanguage',
options: _audioSubtitleLanguageOptions(t.metadataEdit.accountDefault),
),
_buildAdvancedTile(
title: t.metadataEdit.preferredSubtitleLanguage,
prefKey: 'subtitleLanguage',
options: _audioSubtitleLanguageOptions(t.metadataEdit.accountDefault),
),
_buildAdvancedTile(
title: t.metadataEdit.subtitleMode,
prefKey: 'subtitleMode',
options: [
(value: '-1', label: t.metadataEdit.accountDefault),
(value: '0', label: t.metadataEdit.manuallySelected),
(value: '1', label: t.metadataEdit.shownWithForeignAudio),
(value: '2', label: t.metadataEdit.alwaysEnabled),
],
),
];
}
List<Widget> _buildMovieAdvancedSettings() {
return [
_buildAdvancedTile(
title: t.metadataEdit.metadataLanguage,
prefKey: 'languageOverride',
options: _metadataLanguageOptions(t.metadataEdit.libraryDefault),
),
_buildAdvancedTile(
title: t.metadataEdit.useOriginalTitle,
prefKey: 'useOriginalTitle',
options: [
(value: '-1', label: t.metadataEdit.libraryDefault),
(value: '0', label: t.common.no),
(value: '1', label: t.common.yes),
],
),
];
}
List<Widget> _buildSeasonAdvancedSettings() {
return [
_buildAdvancedTile(
title: t.metadataEdit.preferredAudioLanguage,
prefKey: 'audioLanguage',
options: _audioSubtitleLanguageOptions(t.metadataEdit.seriesDefault),
),
_buildAdvancedTile(
title: t.metadataEdit.preferredSubtitleLanguage,
prefKey: 'subtitleLanguage',
options: _audioSubtitleLanguageOptions(t.metadataEdit.seriesDefault),
),
_buildAdvancedTile(
title: t.metadataEdit.subtitleMode,
prefKey: 'subtitleMode',
options: [
(value: '-1', label: t.metadataEdit.seriesDefault),
(value: '0', label: t.metadataEdit.manuallySelected),
(value: '1', label: t.metadataEdit.shownWithForeignAudio),
(value: '2', label: t.metadataEdit.alwaysEnabled),
],
),
];
}
Widget _buildAdvancedTile({
required String title,
required String prefKey,
required List<({String value, String label})> options,
}) {
return ListTile(
title: Text(title),
subtitle: Text(_getDisplayValueForPref(prefKey, options)),
trailing: const AppIcon(Symbols.chevron_right_rounded),
onTap: () => _showAdvancedSettingDialog(title: title, prefKey: prefKey, options: options),
);
}
}
// ===== Language option lists =====
// Plex locale codes for metadata agent language.
const _plexLocaleCodes = [
'ar-SA', 'bg-BG', 'ca-ES', 'zh-CN', 'zh-HK', 'zh-TW', 'hr-HR', 'cs-CZ',
'da-DK', 'nl-NL', 'en-US', 'en-AU', 'en-CA', 'en-GB', 'et-EE', 'fi-FI',
'fr-FR', 'fr-CA', 'de-DE', 'el-GR', 'he-IL', 'hi-IN', 'hu-HU', 'is-IS',
'id-ID', 'it-IT', 'ja-JP', 'ko-KR', 'lv-LV', 'lt-LT', 'nb-NO', 'fa-IR',
'pl-PL', 'pt-BR', 'pt-PT', 'ro-RO', 'ru-RU', 'sk-SK', 'es-ES', 'es-MX',
'sv-SE', 'th-TH', 'tr-TR', 'uk-UA', 'vi-VN',
];
// Common 2-letter codes shown at the top of audio/subtitle pickers.
const _commonAudioSubtitleCodes = ['en', 'ja', 'fr', 'de', 'it', 'es', 'pt', 'ru', 'ar'];
List<({String value, String label})> _buildLanguageOptions(String defaultLabel, List<String> codes) {
return [
(value: '', label: defaultLabel),
...codes.map((c) => (value: c, label: LanguageCodes.getDisplayName(c))),
];
}
List<({String value, String label})> _metadataLanguageOptions(String defaultLabel) =>
_buildLanguageOptions(defaultLabel, _plexLocaleCodes);
List<({String value, String label})> _audioSubtitleLanguageOptions(String defaultLabel) =>
_buildLanguageOptions(defaultLabel, [..._commonAudioSubtitleCodes, ..._plexLocaleCodes]);
+88
View File
@@ -1565,6 +1565,94 @@ class PlexClient {
);
}
// ============================================================================
// Metadata Editing Methods
// ============================================================================
/// Update metadata fields for a media item
Future<bool> updateMetadata({
required int sectionId,
required String ratingKey,
required int typeNumber,
String? title,
String? titleSort,
String? originalTitle,
String? originallyAvailableAt,
String? contentRating,
String? studio,
String? tagline,
String? summary,
}) {
final queryParams = <String, dynamic>{
'type': typeNumber,
'id': ratingKey,
};
void addField(String name, String? value) {
if (value != null) {
queryParams['$name.value'] = value;
queryParams['$name.locked'] = '1';
}
}
addField('title', title);
addField('titleSort', titleSort);
addField('originalTitle', originalTitle);
addField('originallyAvailableAt', originallyAvailableAt);
addField('contentRating', contentRating);
addField('studio', studio);
addField('tagline', tagline);
addField('summary', summary);
return _wrapBoolApiCall(
() => _dio.put('/library/sections/$sectionId/all', queryParameters: queryParams),
'Failed to update metadata',
);
}
/// Get available artwork (posters or backgrounds) for a media item
Future<List<Map<String, dynamic>>> getAvailableArtwork(String ratingKey, String element) async {
try {
final response = await _dio.get('/library/metadata/$ratingKey/$element');
final container = _getMediaContainer(response);
if (container != null && container['Metadata'] != null) {
return (container['Metadata'] as List).cast<Map<String, dynamic>>();
}
return [];
} catch (e) {
appLogger.e('Failed to get available artwork', error: e);
return [];
}
}
/// Set artwork from a URL (can be a Plex internal path or external URL)
Future<bool> setArtworkFromUrl(String ratingKey, String element, String url) {
return _wrapBoolApiCall(
() => _dio.post('/library/metadata/$ratingKey/$element', queryParameters: {'url': url}),
'Failed to set artwork from URL',
);
}
/// Upload artwork from binary data
Future<bool> uploadArtwork(String ratingKey, String element, List<int> bytes) {
return _wrapBoolApiCall(
() => _dio.post(
'/library/metadata/$ratingKey/$element',
data: bytes,
options: Options(headers: {'Content-Length': bytes.length}),
),
'Failed to upload artwork',
);
}
/// Update per-media advanced preferences
Future<bool> updateMetadataPrefs(String ratingKey, Map<String, String> prefs) {
return _wrapBoolApiCall(
() => _dio.put('/library/metadata/$ratingKey/prefs', queryParameters: prefs),
'Failed to update metadata preferences',
);
}
// ============================================================================
// Collection Methods
// ============================================================================
+75
View File
@@ -135,6 +135,81 @@ Future<String?> showTextInputDialog(
);
}
/// Shows a multiline text input dialog for editing longer text like summaries.
/// Returns the entered text, or null if cancelled.
/// Allows empty text to be submitted (for clearing fields).
Future<String?> showMultilineTextInputDialog(
BuildContext context, {
required String title,
required String labelText,
String? initialValue,
}) {
return showDialog<String>(
context: context,
builder: (context) => _MultilineTextInputDialog(title: title, labelText: labelText, initialValue: initialValue),
);
}
class _MultilineTextInputDialog extends StatefulWidget {
final String title;
final String labelText;
final String? initialValue;
const _MultilineTextInputDialog({required this.title, required this.labelText, this.initialValue});
@override
State<_MultilineTextInputDialog> createState() => _MultilineTextInputDialogState();
}
class _MultilineTextInputDialogState extends State<_MultilineTextInputDialog> {
late final TextEditingController _controller;
final _saveFocusNode = FocusNode();
@override
void initState() {
super.initState();
_controller = TextEditingController(text: widget.initialValue);
}
@override
void dispose() {
_controller.dispose();
_saveFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(widget.title),
content: SizedBox(
width: 400,
child: TextField(
controller: _controller,
autofocus: true,
decoration: InputDecoration(labelText: widget.labelText),
maxLines: 8,
minLines: 3,
),
),
actions: [
FocusableButton(
onPressed: () => Navigator.pop(context),
child: TextButton(onPressed: () => Navigator.pop(context), child: Text(t.common.cancel)),
),
FocusableButton(
focusNode: _saveFocusNode,
onPressed: () => Navigator.pop(context, _controller.text),
child: TextButton(
onPressed: () => Navigator.pop(context, _controller.text),
child: Text(t.common.save),
),
),
],
);
}
}
class _TextInputDialog extends StatefulWidget {
final String title;
final String labelText;
+32
View File
@@ -70,6 +70,38 @@ class LanguageCodes {
return variations.toList();
}
/// Get a display name for a language/locale code.
/// Handles plain codes ("en" → "English") and locale codes ("en-US" → "English",
/// "en-AU" → "English (Australia)").
/// Uses [_regionNames] for the country qualifier on non-primary variants.
static String getDisplayName(String code) {
if (code.isEmpty) return code;
// Plain language code (e.g. "en", "ja")
if (!code.contains('-')) {
return getLanguageName(code) ?? code;
}
// Locale code (e.g. "en-US", "zh-TW")
final parts = code.split('-');
final langName = getLanguageName(parts[0]) ?? parts[0];
final region = parts.length > 1 ? _regionNames[parts[1]] : null;
return region != null ? '$langName ($region)' : langName;
}
// Region qualifiers for Plex locale codes that differ from the primary variant.
// Only entries where Plex shows a country qualifier in its UI are listed.
static const _regionNames = <String, String>{
'AU': 'Australia',
'BR': 'Brazil',
'CA': 'Canada',
'GB': 'UK',
'HK': 'Hong Kong',
'MX': 'Mexico',
'PT': 'Portugal',
'TW': 'Taiwan',
};
/// Get the English name of a language from its code
static String? getLanguageName(String languageCode) {
if (_codes == null) return null;
+226
View File
@@ -0,0 +1,226 @@
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/symbols.dart';
import '../focus/focusable_button.dart';
import '../focus/focusable_wrapper.dart';
import '../i18n/strings.g.dart';
import '../services/plex_client.dart';
import '../utils/dialogs.dart';
import '../utils/snackbar_helper.dart';
import '../widgets/app_icon.dart';
import '../widgets/plex_optimized_image.dart';
class ArtworkPickerDialog extends StatefulWidget {
final PlexClient client;
final String ratingKey;
final String element; // "posters" or "arts"
const ArtworkPickerDialog({
super.key,
required this.client,
required this.ratingKey,
required this.element,
});
@override
State<ArtworkPickerDialog> createState() => _ArtworkPickerDialogState();
}
class _ArtworkPickerDialogState extends State<ArtworkPickerDialog> {
List<Map<String, dynamic>>? _artworkList;
bool _isLoading = true;
bool _isApplying = false;
bool get _isPosters => widget.element == 'posters';
@override
void initState() {
super.initState();
_loadArtwork();
}
Future<void> _loadArtwork() async {
final artwork = await widget.client.getAvailableArtwork(widget.ratingKey, widget.element);
if (!mounted) return;
setState(() {
_artworkList = artwork;
_isLoading = false;
});
}
Future<void> _selectArtwork(Map<String, dynamic> artwork) async {
final key = artwork['key'] as String?;
if (key == null || _isApplying) return;
setState(() => _isApplying = true);
final success = await widget.client.setArtworkFromUrl(widget.ratingKey, widget.element, key);
if (!mounted) return;
setState(() => _isApplying = false);
if (success) {
showSuccessSnackBar(context, t.metadataEdit.artworkUpdated);
Navigator.pop(context, true);
} else {
showErrorSnackBar(context, t.metadataEdit.artworkUpdateFailed);
}
}
Future<void> _addFromUrl() async {
final url = await showTextInputDialog(
context,
title: t.metadataEdit.fromUrl,
labelText: t.metadataEdit.imageUrl,
hintText: t.metadataEdit.enterImageUrl,
);
if (url == null || url.isEmpty || !mounted) return;
setState(() => _isApplying = true);
final success = await widget.client.setArtworkFromUrl(widget.ratingKey, widget.element, url);
if (!mounted) return;
setState(() => _isApplying = false);
if (success) {
showSuccessSnackBar(context, t.metadataEdit.artworkUpdated);
Navigator.pop(context, true);
} else {
showErrorSnackBar(context, t.metadataEdit.artworkUpdateFailed);
}
}
Future<void> _uploadFile() async {
final result = await FilePicker.platform.pickFiles(
type: FileType.image,
withData: true,
);
if (result == null || result.files.isEmpty || !mounted) return;
final bytes = result.files.first.bytes;
if (bytes == null) return;
setState(() => _isApplying = true);
final success = await widget.client.uploadArtwork(widget.ratingKey, widget.element, bytes);
if (!mounted) return;
setState(() => _isApplying = false);
if (success) {
showSuccessSnackBar(context, t.metadataEdit.artworkUpdated);
Navigator.pop(context, true);
} else {
showErrorSnackBar(context, t.metadataEdit.artworkUpdateFailed);
}
}
@override
Widget build(BuildContext context) {
final title = _isPosters ? t.metadataEdit.selectPoster : t.metadataEdit.selectBackground;
return AlertDialog(
title: Text(title),
content: SizedBox(
width: 500,
height: 400,
child: _isLoading
? const Center(child: CircularProgressIndicator())
: _artworkList == null || _artworkList!.isEmpty
? Center(child: Text(t.metadataEdit.noArtworkAvailable))
: _buildGrid(),
),
actions: [
if (_isApplying)
const Padding(
padding: EdgeInsets.all(8),
child: SizedBox(width: 24, height: 24, child: CircularProgressIndicator(strokeWidth: 2)),
),
FocusableButton(
onPressed: _addFromUrl,
child: TextButton.icon(
onPressed: _addFromUrl,
icon: const AppIcon(Symbols.link_rounded, size: 18),
label: Text(t.metadataEdit.fromUrl),
),
),
FocusableButton(
onPressed: _uploadFile,
child: TextButton.icon(
onPressed: _uploadFile,
icon: const AppIcon(Symbols.upload_rounded, size: 18),
label: Text(t.metadataEdit.uploadFile),
),
),
FocusableButton(
autofocus: true,
onPressed: () => Navigator.pop(context),
child: TextButton(
onPressed: () => Navigator.pop(context),
child: Text(t.common.cancel),
),
),
],
);
}
Widget _buildGrid() {
final crossAxisCount = _isPosters ? 3 : 2;
final aspectRatio = _isPosters ? 2.0 / 3.0 : 16.0 / 9.0;
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
childAspectRatio: aspectRatio,
),
itemCount: _artworkList!.length,
itemBuilder: (context, index) {
final artwork = _artworkList![index];
final thumbUrl = artwork['thumb'] as String?;
final isSelected = artwork['selected'] == true;
return FocusableWrapper(
borderRadius: 8,
onSelect: () => _selectArtwork(artwork),
child: Stack(
fit: StackFit.expand,
children: [
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(8),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: PlexOptimizedImage(
client: widget.client,
imagePath: thumbUrl,
fit: BoxFit.contain,
),
),
),
if (isSelected)
Positioned(
right: 6,
bottom: 6,
child: Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary,
shape: BoxShape.circle,
),
child: Icon(Symbols.check_rounded, size: 16, color: Theme.of(context).colorScheme.onPrimary),
),
),
],
),
);
},
);
}
}
+22
View File
@@ -20,6 +20,7 @@ import '../services/external_player_service.dart';
import '../focus/focusable_button.dart';
import '../focus/dpad_navigator.dart';
import '../screens/media_detail_screen.dart';
import '../screens/metadata_edit_screen.dart';
import '../screens/season_detail_screen.dart';
import '../utils/smart_deletion_handler.dart';
import '../utils/deletion_notifier.dart';
@@ -199,6 +200,16 @@ class MediaContextMenuState extends State<MediaContextMenu> {
);
}
// Edit Metadata (for movies, shows, seasons, and episodes)
if (mediaType == PlexMediaType.movie ||
mediaType == PlexMediaType.show ||
mediaType == PlexMediaType.season ||
mediaType == PlexMediaType.episode) {
menuActions.add(
_MenuAction(value: 'edit_metadata', icon: Symbols.edit_rounded, label: t.metadataEdit.editMetadata),
);
}
// Remove from Collection (only when viewing items within a collection)
if (widget.collectionId != null) {
menuActions.add(
@@ -415,6 +426,17 @@ class MediaContextMenuState extends State<MediaContextMenu> {
}
break;
case 'edit_metadata':
didNavigate = true;
if (context.mounted) {
await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MetadataEditScreen(metadata: metadata!)),
);
widget.onRefresh?.call(metadata!.ratingKey);
}
break;
case 'remove_from_collection':
await _handleRemoveFromCollection(context, metadata!);
break;