feat: add trailers and extras support

Adds support for viewing and playing trailers and bonus content from Plex.

- Add getExtras() API method to fetch extras from Plex
- Add trailer/extras metadata fields (subtype, extraType, primaryExtraKey)
- Add play trailer button with film reel icon on media detail screen
- Add "Trailers & Extras" section below cast with horizontal scroll
- Support offline mode via cache fallback
- Preserve serverId/serverName for multi-server setups
This commit is contained in:
Matt Vogel
2026-02-15 15:09:45 -05:00
parent 04438c8e45
commit 0bbcd854e4
24 changed files with 674 additions and 1166 deletions
+6 -2
View File
@@ -421,6 +421,7 @@ class _TranslationsTooltipsEs implements TranslationsTooltipsEn {
// Translations
@override String get shufflePlay => 'Reproducción aleatoria';
@override String get playTrailer => 'Reproducir tráiler';
@override String get markAsWatched => 'Marcar como visto';
@override String get markAsUnwatched => 'Marcar como no visto';
}
@@ -610,6 +611,7 @@ class _TranslationsDiscoverEs implements TranslationsDiscoverEn {
@override String playEpisode({required Object season, required Object episode}) => 'T${season}E${episode}';
@override String get overview => 'Resumen';
@override String get cast => 'Reparto';
@override String get extras => 'Tráilers y Extras';
@override String get seasons => 'Temporadas';
@override String get studio => 'Estudio';
@override String get rating => 'Calificación';
@@ -1465,6 +1467,7 @@ extension on TranslationsEs {
'accessibility.mediaCardUnwatched' => 'no visto',
'accessibility.tapToPlay' => 'Toca para reproducir',
'tooltips.shufflePlay' => 'Reproducción aleatoria',
'tooltips.playTrailer' => 'Reproducir tráiler',
'tooltips.markAsWatched' => 'Marcar como visto',
'tooltips.markAsUnwatched' => 'Marcar como no visto',
'videoControls.audioLabel' => 'Audio',
@@ -1595,6 +1598,7 @@ extension on TranslationsEs {
'discover.playEpisode' => ({required Object season, required Object episode}) => 'T${season}E${episode}',
'discover.overview' => 'Resumen',
'discover.cast' => 'Reparto',
'discover.extras' => 'Tráilers y Extras',
'discover.seasons' => 'Temporadas',
'discover.studio' => 'Estudio',
'discover.rating' => 'Calificación',
@@ -1727,10 +1731,10 @@ extension on TranslationsEs {
'collections.empty' => 'La colección está vacía',
'collections.unknownLibrarySection' => 'No se puede eliminar: Sección de biblioteca desconocida',
'collections.deleteCollection' => 'Eliminar Colección',
'collections.deleteConfirm' => ({required Object title}) => '¿Estás seguro de que quieres eliminar "${title}"? Esta acción no se puede deshacer.',
'collections.deleted' => 'Colección eliminada',
_ => null,
} ?? switch (path) {
'collections.deleteConfirm' => ({required Object title}) => '¿Estás seguro de que quieres eliminar "${title}"? Esta acción no se puede deshacer.',
'collections.deleted' => 'Colección eliminada',
'collections.deleteFailed' => 'Error al eliminar la colección',
'collections.deleteFailedWithError' => ({required Object error}) => 'Error al eliminar la colección: ${error}',
'collections.failedToLoadItems' => ({required Object error}) => 'Error al cargar los elementos de la colección: ${error}',