From 5e58df6fe21b19020ec86d48917c47540bd9b354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Guerre?= Date: Mon, 30 Sep 2024 15:41:56 +0000 Subject: [PATCH 01/18] Translated using Weblate (French) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fr/ --- src/strings/fr.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/strings/fr.json b/src/strings/fr.json index 5d651781b9..44bbbd4008 100644 --- a/src/strings/fr.json +++ b/src/strings/fr.json @@ -1930,5 +1930,10 @@ "EnableHi10p": "Active le profil H.264 High 10", "EnableHi10pHelp": "Activer pour éviter l'encodage des vidéos H.264 10-bits. Désactiver cette option si la vidéo affiche des images vides.", "AlwaysRemuxFlacAudioFilesHelp": "Si votre navigateur refuse de lire des fichiers ou s'il calcule incorrectement l'horodatage, activer ceci en guise d'alternative.", - "AlwaysRemuxMp3AudioFilesHelp": "Si votre navigateur calcule incorrectement l'horodatage de certains fichiers, activer ceci en guise d'alternative." + "AlwaysRemuxMp3AudioFilesHelp": "Si votre navigateur calcule incorrectement l'horodatage de certains fichiers, activer ceci en guise d'alternative.", + "DateModified": "Date modifiée", + "FallbackMaxStreamingBitrateHelp": "Le débit maximum de streaming est utilisé par défaut quand ffprobe ne peut pas déterminer le débit du flux source. Cela aide à éviter que les clients demandent un débit de transcodage excessivement élevé, ce qui pourrait mener le lecteur à échouer et surcharger l'encodeur.", + "LabelAlwaysRemuxFlacAudioFiles": "Toujours remultiplexer les fichiers audio FLAC", + "LabelAlwaysRemuxMp3AudioFiles": "Toujours remultiplexer les fichiers audio MP3", + "LabelAllowStreamSharing": "Autoriser le partage de flux" } From aac5fe2f495d50198bbd4f27867552733adbab81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9on?= Date: Tue, 1 Oct 2024 03:40:00 +0000 Subject: [PATCH 02/18] Translated using Weblate (French) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fr/ --- src/strings/fr.json | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/strings/fr.json b/src/strings/fr.json index 44bbbd4008..7187a3c4c8 100644 --- a/src/strings/fr.json +++ b/src/strings/fr.json @@ -1267,7 +1267,7 @@ "OnWakeFromSleep": "À la sortie de veille", "WeeklyAt": "{0} à {1}", "DailyAt": "Tous les jours à {0}", - "LastSeen": "Vu {0}", + "LastSeen": "Dernière connexion {0}", "PersonRole": "est {0}", "ListPaging": "{0}-{1} de {2}", "WriteAccessRequired": "Jellyfin a besoin d'un accès en écriture à ce dossier. Merci de vérifier les permissions de ce-dernier puis de réessayer.", @@ -1935,5 +1935,36 @@ "FallbackMaxStreamingBitrateHelp": "Le débit maximum de streaming est utilisé par défaut quand ffprobe ne peut pas déterminer le débit du flux source. Cela aide à éviter que les clients demandent un débit de transcodage excessivement élevé, ce qui pourrait mener le lecteur à échouer et surcharger l'encodeur.", "LabelAlwaysRemuxFlacAudioFiles": "Toujours remultiplexer les fichiers audio FLAC", "LabelAlwaysRemuxMp3AudioFiles": "Toujours remultiplexer les fichiers audio MP3", - "LabelAllowStreamSharing": "Autoriser le partage de flux" + "LabelAllowStreamSharing": "Autoriser le partage de flux", + "MessageCancelSeriesTimerError": "Une erreur est survenue lors de l'annulation du minuteur de série", + "AllowStreamSharingHelp": "Autoriser Jellyfin à dupliquer le flux mpegts provenant du tuner et à partager ce flux dupliqué avec ses clients. Cela est utile lorsque le tuner a une limite de nombre total de flux, mais peut également causer des problèmes de lecture.", + "Reset": "Réinitialiser", + "UseCustomTagDelimitersHelp": "Diviser les balises d'artiste/genre avec des caractères personnalisés.", + "HeaderAudioAdvanced": "Audio Avancé", + "LabelAudioTagSettings": "Paramètres des balises audio", + "LabelCustomTagDelimiters": "Délimiteur de balise personnalisé", + "LabelCustomTagDelimitersHelp": "Caractères à traiter comme délimiteurs pour séparer les balises.", + "LabelLyricDownloaders": "Téléchargeurs de Lyrics", + "LabelDelimiterWhitelist": "Liste blanche des délimiteurs", + "LabelDelimiterWhitelistHelp": "Éléments à exclure de la division des balises. Un élément par ligne.", + "LabelDisableVbrAudioEncoding": "Désactiver l'encodage audio VBR", + "LabelSaveTrickplayLocally": "Enregistrer les images trickplay au même emplacement que les médias", + "LabelSaveTrickplayLocallyHelp": "Enregistrer les images trickplay dans les dossiers de médias les placera à côté de vos médias pour une migration et un accès faciles.", + "MediaInfoRotation": "Rotation", + "RenderPgsSubtitle": "Rendu expérimental des sous-titres PGS", + "ReplaceTrickplayImages": "Remplacer les images trickplay existantes", + "LibraryInvalidItemIdError": "La bibliothèque est dans un état invalide et ne peut pas être modifiée. Vous rencontrez probablement un bug : le chemin dans la base de données n'est pas le bon chemin sur le système de fichiers.", + "MessageCancelTimerError": "Une erreur est survenue lors de l'annulation du minuteur", + "MessageSplitVersionsError": "Une erreur s'est produite lors de la division des versions", + "PreferNonstandardArtistsTag": "Préférer la balise ARTISTS si disponible", + "PreferNonstandardArtistsTagHelp": "Utiliser la balise non standard ARTISTS au lieu de la balise ARTIST lorsqu'elle est disponible.", + "RenderPgsSubtitleHelp": "Détermine si le client doit rendre les sous-titres PGS au lieu d'utiliser des sous-titres incrustés. Cela peut éviter le transcodage côté serveur au profit de la performance de rendu côté client.", + "UseCustomTagDelimiters": "Utiliser un délimiteur de balise personnalisé", + "VideoCodecTagNotSupported": "La balise de codec vidéo n'est pas prise en charge", + "LabelFallbackMaxStreamingBitrate": "Bitrate de flux maximum de repli (Mbps)", + "LyricDownloadersHelp": "Activez et classez vos téléchargeurs de sous-titres préférés par ordre de priorité.", + "LabelAllowFmp4TranscodingContainer": "Autoriser le conteneur de transcodage fMP4", + "AllowTonemappingSoftwareHelp": "Le tone-mapping peut transformer la plage dynamique d'une vidéo de HDR à SDR tout en conservant les détails et les couleurs de l'image, qui sont des informations très importantes pour représenter la scène originale. Fonctionne uniquement avec les vidéos 10 bits HDR10, HLG et DoVi.", + "LabelTrickplayKeyFrameOnlyExtraction": "Générer uniquement des images à partir des images clés", + "LabelTrickplayKeyFrameOnlyExtractionHelp": "Extraire uniquement les images clés pour un traitement beaucoup plus rapide avec un minutage moins précis. Si le décodeur matériel configuré ne prend pas en charge ce mode, il utilisera le décodeur logiciel à la place." } From 0dbde712415af8e7f7b1424c47e47b569f1779ce Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 1 Oct 2024 17:02:50 +0800 Subject: [PATCH 03/18] Only add gain node when normalization enabled --- src/plugins/htmlAudioPlayer/plugin.js | 11 +++++++++-- src/strings/en-us.json | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/plugins/htmlAudioPlayer/plugin.js b/src/plugins/htmlAudioPlayer/plugin.js index 067d94c48c..99ecb2b4c9 100644 --- a/src/plugins/htmlAudioPlayer/plugin.js +++ b/src/plugins/htmlAudioPlayer/plugin.js @@ -121,6 +121,13 @@ class HtmlAudioPlayer { normalizationGain = options.mediaSource.albumNormalizationGain ?? options.item.NormalizationGain; + } else { + console.debug('normalization disabled') + return; + } + + if (!self.gainNode) { + addGainElement(elem); } if (normalizationGain) { @@ -276,7 +283,7 @@ class HtmlAudioPlayer { self._mediaElement = elem; - addGainElement(elem); + // addGainElement(elem); return elem; } @@ -317,7 +324,7 @@ class HtmlAudioPlayer { function onVolumeChange() { if (!self._isFadingOut) { htmlMediaHelper.saveVolume(this.volume); - if (browser.safari) { + if (browser.safari && self.gainNode) { self.gainNode.gain.value = this.volume * self.normalizationGain; } Events.trigger(self, 'volumechange'); diff --git a/src/strings/en-us.json b/src/strings/en-us.json index d2e32a1ff4..5cd78810ef 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -156,7 +156,7 @@ "ChannelNumber": "Channel number", "Channels": "Channels", "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.", - "SelectAudioNormalizationHelp": "Track gain - adjusts the volume of each track so they playback with the same loudness. Album gain - adjusts the volume of all the tracks in an album only, keeping the album's dynamic range.", + "SelectAudioNormalizationHelp": "Track gain - adjusts the volume of each track so they playback with the same loudness. Album gain - adjusts the volume of all the tracks in an album only, keeping the album's dynamic range. Switching between \"Off\" and other options requires restarting the current playback.", "ClearQueue": "Clear queue", "ClientSettings": "Client Settings", "Collections": "Collections", From 6b52358b57ec80bb822838b764194709d65273be Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 1 Oct 2024 17:13:52 +0800 Subject: [PATCH 04/18] Remove commented code --- src/plugins/htmlAudioPlayer/plugin.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/htmlAudioPlayer/plugin.js b/src/plugins/htmlAudioPlayer/plugin.js index 99ecb2b4c9..2be98b40aa 100644 --- a/src/plugins/htmlAudioPlayer/plugin.js +++ b/src/plugins/htmlAudioPlayer/plugin.js @@ -283,8 +283,6 @@ class HtmlAudioPlayer { self._mediaElement = elem; - // addGainElement(elem); - return elem; } From 75d21a81403bc76ee5a61d09333230122df3b705 Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 1 Oct 2024 17:18:26 +0800 Subject: [PATCH 05/18] Fix lint Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/plugins/htmlAudioPlayer/plugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/htmlAudioPlayer/plugin.js b/src/plugins/htmlAudioPlayer/plugin.js index 2be98b40aa..a211aba276 100644 --- a/src/plugins/htmlAudioPlayer/plugin.js +++ b/src/plugins/htmlAudioPlayer/plugin.js @@ -122,7 +122,7 @@ class HtmlAudioPlayer { options.mediaSource.albumNormalizationGain ?? options.item.NormalizationGain; } else { - console.debug('normalization disabled') + console.debug('normalization disabled'); return; } From 24c30dc96d577610cd4650f397c995bd6b2116c7 Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 1 Oct 2024 18:25:09 +0800 Subject: [PATCH 06/18] Handle addGainElement failure Co-authored-by: Dmitry Lyzo <56478732+dmitrylyzo@users.noreply.github.com> --- src/plugins/htmlAudioPlayer/plugin.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/htmlAudioPlayer/plugin.js b/src/plugins/htmlAudioPlayer/plugin.js index a211aba276..029cdeca82 100644 --- a/src/plugins/htmlAudioPlayer/plugin.js +++ b/src/plugins/htmlAudioPlayer/plugin.js @@ -128,6 +128,7 @@ class HtmlAudioPlayer { if (!self.gainNode) { addGainElement(elem); + if (!self.gainNode) return; } if (normalizationGain) { From 2442dc6b527d25ed29b3d2657ad14839193e847c Mon Sep 17 00:00:00 2001 From: Andi Chandler Date: Tue, 1 Oct 2024 10:02:03 +0000 Subject: [PATCH 07/18] Translated using Weblate (English (United Kingdom)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/en_GB/ --- src/strings/en-gb.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/strings/en-gb.json b/src/strings/en-gb.json index 92fa5b43a8..f54f367915 100644 --- a/src/strings/en-gb.json +++ b/src/strings/en-gb.json @@ -1963,5 +1963,9 @@ "PreferNonstandardArtistsTag": "Prefer ARTISTS tag if available", "PreferNonstandardArtistsTagHelp": "Use the non-standard ARTISTS tag instead of ARTIST tag when available.", "UseCustomTagDelimiters": "Use custom tag delimiter", - "UseCustomTagDelimitersHelp": "Split artist/genre tags with custom characters." + "UseCustomTagDelimitersHelp": "Split artist/genre tags with custom characters.", + "DateModified": "Date modified", + "MessageCancelSeriesTimerError": "An error occurred while cancelling the series timer", + "MessageCancelTimerError": "An error occurred while cancelling the timer", + "MessageSplitVersionsError": "An error occurred while splitting versions" } From 5888962e3f3fd389cfa54b502df1217717b4d140 Mon Sep 17 00:00:00 2001 From: hoanghuy309 Date: Tue, 1 Oct 2024 16:37:19 +0000 Subject: [PATCH 08/18] Translated using Weblate (Vietnamese) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/vi/ --- src/strings/vi.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/strings/vi.json b/src/strings/vi.json index ddd7bd5b73..5c8fb2a9b9 100644 --- a/src/strings/vi.json +++ b/src/strings/vi.json @@ -1960,5 +1960,9 @@ "ReplaceTrickplayImages": "Thay thế ảnh tua nhanh hiện có", "LabelAlwaysRemuxMp3AudioFiles": "Luôn làm lại các tập tin âm thanh MP3", "LabelSaveTrickplayLocally": "Lưu ảnh tua nhanh bên cạnh phương tiện", - "LabelSaveTrickplayLocallyHelp": "Việc lưu ảnh tua anh vào thư mục phương tiện sẽ đặt chúng kế bên phương tiện của bạn để dễ di chuyển và truy cập." + "LabelSaveTrickplayLocallyHelp": "Việc lưu ảnh tua anh vào thư mục phương tiện sẽ đặt chúng kế bên phương tiện của bạn để dễ di chuyển và truy cập.", + "DateModified": "Ngày sửa đổi", + "MessageCancelSeriesTimerError": "Đã xảy ra lỗi khi hủy bộ hẹn giờ chuỗi", + "MessageCancelTimerError": "Đã xảy ra lỗi khi hủy bộ hẹn giờ", + "MessageSplitVersionsError": "Đã xảy ra lỗi khi chia nhỏ các phiên bản" } From 26f7f281cd1c6e3b0ee596f8c0cda9c098d06267 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Tue, 1 Oct 2024 13:41:40 -0400 Subject: [PATCH 09/18] Add playback subscriber abstraction --- .../constants/playbackManagerEvent.ts | 14 +++ .../playback/constants/playerEvent.ts | 23 ++++ .../features/playback/types/callbacks.ts | 33 ++++++ .../features/playback/types/streamInfo.ts | 34 ++++++ .../playback/utils/playbackSubscriber.ts | 101 ++++++++++++++++++ src/components/playback/playbackmanager.js | 2 +- src/types/playTarget.ts | 3 + 7 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 src/apps/stable/features/playback/constants/playbackManagerEvent.ts create mode 100644 src/apps/stable/features/playback/constants/playerEvent.ts create mode 100644 src/apps/stable/features/playback/types/callbacks.ts create mode 100644 src/apps/stable/features/playback/types/streamInfo.ts create mode 100644 src/apps/stable/features/playback/utils/playbackSubscriber.ts diff --git a/src/apps/stable/features/playback/constants/playbackManagerEvent.ts b/src/apps/stable/features/playback/constants/playbackManagerEvent.ts new file mode 100644 index 0000000000..2200c833b5 --- /dev/null +++ b/src/apps/stable/features/playback/constants/playbackManagerEvent.ts @@ -0,0 +1,14 @@ +/** + * Events triggered by PlaybackManager. + */ +export enum PlaybackManagerEvent { + Pairing = 'pairing', + Paired = 'paired', + PairError = 'pairerror', + PlaybackCancelled = 'playbackcancelled', + PlaybackError = 'playbackerror', + PlaybackStart = 'playbackstart', + PlaybackStop = 'playbackstop', + PlayerChange = 'playerchange', + ReportPlayback = 'reportplayback' +} diff --git a/src/apps/stable/features/playback/constants/playerEvent.ts b/src/apps/stable/features/playback/constants/playerEvent.ts new file mode 100644 index 0000000000..a02a7caaf1 --- /dev/null +++ b/src/apps/stable/features/playback/constants/playerEvent.ts @@ -0,0 +1,23 @@ +/** + * Events triggered by media player plugins. + * NOTE: This list is incomplete + */ +export enum PlayerEvent { + Error = 'error', + FullscreenChange = 'fullscreenchange', + ItemStarted = 'itemstarted', + ItemStopped = 'itemstopped', + MediaStreamsChange = 'mediastreamschange', + Pause = 'pause', + PlaybackStart = 'playbackstart', + PlaybackStop = 'playbackstop', + PlaylistItemAdd = 'playlistitemadd', + PlaylistItemMove = 'playlistitemmove', + PlaylistItemRemove = 'playlistitemremove', + RepeatModeChange = 'repeatmodechange', + ShuffleModeChange = 'shufflequeuemodechange', + Stopped = 'stopped', + TimeUpdate = 'timeupdate', + Unpause = 'unpause', + VolumeChange = 'volumechange' +} diff --git a/src/apps/stable/features/playback/types/callbacks.ts b/src/apps/stable/features/playback/types/callbacks.ts new file mode 100644 index 0000000000..1bede1b2c0 --- /dev/null +++ b/src/apps/stable/features/playback/types/callbacks.ts @@ -0,0 +1,33 @@ +import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'; +import type { MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client/models/media-source-info'; +import type { MediaType } from '@jellyfin/sdk/lib/generated-client/models/media-type'; + +import type { StreamInfo } from './streamInfo'; + +export interface ManagedPlayerStopInfo { + item: BaseItemDto + mediaSource: MediaSourceInfo + nextItem?: BaseItemDto | null + nextMediaType?: MediaType | null + positionMs?: number +} + +export interface MovedItem { + newIndex: number + playlistItemId: string +} + +export type PlayerErrorCode = string; + +export interface PlayerStopInfo { + src?: URL | BaseItemDto +} + +export interface PlayerError { + streamInfo?: StreamInfo + type: MediaError | string +} + +export interface RemovedItems { + playlistItemIds: string[] +} diff --git a/src/apps/stable/features/playback/types/streamInfo.ts b/src/apps/stable/features/playback/types/streamInfo.ts new file mode 100644 index 0000000000..0fe54210f3 --- /dev/null +++ b/src/apps/stable/features/playback/types/streamInfo.ts @@ -0,0 +1,34 @@ +import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'; +import type { MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client/models/media-source-info'; +import type { MediaType } from '@jellyfin/sdk/lib/generated-client/models/media-type'; +import type { PlayMethod } from '@jellyfin/sdk/lib/generated-client/models/play-method'; + +export interface StreamInfo { + ended?: boolean + fullscreen?: boolean + item?: BaseItemDto + lastMediaInfoQuery?: number + liveStreamId?: string + mediaSource?: MediaSourceInfo + mediaType?: MediaType + mimeType?: string + playMethod?: PlayMethod + playSessionId?: string + playbackStartTimeTicks?: number + playerStartPositionTicks?: number + resetSubtitleOffset?: boolean + started?: boolean + textTracks?: TrackInfo[] + title?: string + tracks?: TrackInfo[] + transcodingOffsetTicks?: number + url?: string +} + +interface TrackInfo { + url: string + language: string + isDefault: boolean + index: number + format: string +} diff --git a/src/apps/stable/features/playback/utils/playbackSubscriber.ts b/src/apps/stable/features/playback/utils/playbackSubscriber.ts new file mode 100644 index 0000000000..54ff9d94fc --- /dev/null +++ b/src/apps/stable/features/playback/utils/playbackSubscriber.ts @@ -0,0 +1,101 @@ +import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'; +import type { MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client/models/media-source-info'; + +import type { PlaybackManager } from 'components/playback/playbackmanager'; +import type { MediaError } from 'types/mediaError'; +import type { PlayTarget } from 'types/playTarget'; +import type { PlaybackStopInfo, PlayerState } from 'types/playbackStopInfo'; +import type { Plugin } from 'types/plugin'; +import Events, { type Event } from 'utils/events'; + +import { PlaybackManagerEvent } from '../constants/playbackManagerEvent'; +import { PlayerEvent } from '../constants/playerEvent'; +import type { ManagedPlayerStopInfo, MovedItem, PlayerError, PlayerErrorCode, PlayerStopInfo, RemovedItems } from '../types/callbacks'; + +export interface PlaybackSubscriber { + onPlaybackCancelled?(e: Event): void + onPlaybackError?(e: Event, errorType: MediaError): void + onPlaybackStart?(e: Event, player: Plugin, state: PlayerState): void + onPlaybackStop?(e: Event, info: PlaybackStopInfo): void + onPlayerChange?(e: Event, player: Plugin, target: PlayTarget, previousPlayer: Plugin): void + onPlayerError?(e: Event, error: PlayerError): void + onPlayerFullscreenChange?(e: Event): void + onPlayerItemStarted?(e: Event, item?: BaseItemDto, mediaSource?: MediaSourceInfo): void + onPlayerItemStopped?(e: Event, info: ManagedPlayerStopInfo): void + onPlayerMediaStreamsChange?(e: Event): void + onPlayerPause?(e: Event): void + onPlayerPlaybackStart?(e: Event, state: PlayerState): void + onPlayerPlaybackStop?(e: Event, state: PlayerState): void + onPlayerPlaylistItemAdd?(e: Event): void + onPlayerPlaylistItemMove?(e: Event, item: MovedItem): void + onPlayerPlaylistItemRemove?(e: Event, items?: RemovedItems): void + onPlayerRepeatModeChange?(e: Event): void + onPlayerShuffleModeChange?(e: Event): void + onPlayerStopped?(e: Event, info?: PlayerStopInfo | PlayerErrorCode): void + onPlayerTimeUpdate?(e: Event): void + onPlayerUnpause?(e: Event): void + onPlayerVolumeChange?(e: Event): void + onReportPlayback?(e: Event, isServerItem: boolean): void +} + +export abstract class PlaybackSubscriber { + private player: Plugin | undefined; + + private playbackManagerEvents = { + [PlaybackManagerEvent.PlaybackCancelled]: this.onPlaybackCancelled, + [PlaybackManagerEvent.PlaybackError]: this.onPlaybackError, + [PlaybackManagerEvent.PlaybackStart]: this.onPlaybackStart, + [PlaybackManagerEvent.PlaybackStop]: this.onPlaybackStop, + [PlaybackManagerEvent.PlayerChange]: this.onPlayerChange, + [PlaybackManagerEvent.ReportPlayback]: this.onReportPlayback + }; + + private playerEvents = { + [PlayerEvent.Error]: this.onPlayerError, + [PlayerEvent.FullscreenChange]: this.onPlayerFullscreenChange, + [PlayerEvent.ItemStarted]: this.onPlayerItemStarted, + [PlayerEvent.ItemStopped]: this.onPlayerItemStopped, + [PlayerEvent.MediaStreamsChange]: this.onPlayerMediaStreamsChange, + [PlayerEvent.Pause]: this.onPlayerPause, + [PlayerEvent.PlaybackStart]: this.onPlayerPlaybackStart, + [PlayerEvent.PlaybackStop]: this.onPlayerPlaybackStop, + [PlayerEvent.PlaylistItemAdd]: this.onPlayerPlaylistItemAdd, + [PlayerEvent.PlaylistItemMove]: this.onPlayerPlaylistItemMove, + [PlayerEvent.PlaylistItemRemove]: this.onPlayerPlaylistItemRemove, + [PlayerEvent.RepeatModeChange]: this.onPlayerRepeatModeChange, + [PlayerEvent.ShuffleModeChange]: this.onPlayerShuffleModeChange, + [PlayerEvent.Stopped]: this.onPlayerStopped, + [PlayerEvent.TimeUpdate]: this.onPlayerTimeUpdate, + [PlayerEvent.Unpause]: this.onPlayerUnpause, + [PlayerEvent.VolumeChange]: this.onPlayerVolumeChange + }; + + constructor( + protected readonly playbackManager: PlaybackManager + ) { + Object.entries(this.playbackManagerEvents).forEach(([event, handler]) => { + if (handler) Events.on(playbackManager, event, handler); + }); + + this.bindPlayerEvents(); + Events.on(playbackManager, PlaybackManagerEvent.PlayerChange, this.bindPlayerEvents.bind(this)); + } + + private bindPlayerEvents() { + const newPlayer = this.playbackManager.getCurrentPlayer(); + if (this.player === newPlayer) return; + + if (this.player) { + Object.entries(this.playerEvents).forEach(([event, handler]) => { + if (handler) Events.off(this.player, event, handler); + }); + } + + this.player = newPlayer; + if (!this.player) return; + + Object.entries(this.playerEvents).forEach(([event, handler]) => { + if (handler) Events.on(this.player, event, handler); + }); + } +} diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index b51046d340..e90aff609f 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -687,7 +687,7 @@ function sortPlayerTargets(a, b) { return aVal.localeCompare(bVal); } -class PlaybackManager { +export class PlaybackManager { constructor() { const self = this; diff --git a/src/types/playTarget.ts b/src/types/playTarget.ts index 33353137d5..b2f0f6a284 100644 --- a/src/types/playTarget.ts +++ b/src/types/playTarget.ts @@ -1,3 +1,4 @@ +import type { MediaType } from '@jellyfin/sdk/lib/generated-client/models/media-type'; import type { UserDto } from '@jellyfin/sdk/lib/generated-client/models/user-dto'; export interface PlayTarget { @@ -7,5 +8,7 @@ export interface PlayTarget { playerName?: string deviceType?: string isLocalPlayer?: boolean + playableMediaTypes: MediaType[] + supportedCommands?: string[] user?: UserDto } From 8acf8fb5506fd19c18da1d8eafb5eb35d5254a9b Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Tue, 1 Oct 2024 14:01:54 -0400 Subject: [PATCH 10/18] Mark event handler maps as readonly --- src/apps/stable/features/playback/utils/playbackSubscriber.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/apps/stable/features/playback/utils/playbackSubscriber.ts b/src/apps/stable/features/playback/utils/playbackSubscriber.ts index 54ff9d94fc..dfc79360a2 100644 --- a/src/apps/stable/features/playback/utils/playbackSubscriber.ts +++ b/src/apps/stable/features/playback/utils/playbackSubscriber.ts @@ -41,7 +41,7 @@ export interface PlaybackSubscriber { export abstract class PlaybackSubscriber { private player: Plugin | undefined; - private playbackManagerEvents = { + private readonly playbackManagerEvents = { [PlaybackManagerEvent.PlaybackCancelled]: this.onPlaybackCancelled, [PlaybackManagerEvent.PlaybackError]: this.onPlaybackError, [PlaybackManagerEvent.PlaybackStart]: this.onPlaybackStart, @@ -50,7 +50,7 @@ export abstract class PlaybackSubscriber { [PlaybackManagerEvent.ReportPlayback]: this.onReportPlayback }; - private playerEvents = { + private readonly playerEvents = { [PlayerEvent.Error]: this.onPlayerError, [PlayerEvent.FullscreenChange]: this.onPlayerFullscreenChange, [PlayerEvent.ItemStarted]: this.onPlayerItemStarted, From f4687e115798f4bf3166bada6b87606d458dbd52 Mon Sep 17 00:00:00 2001 From: stanol Date: Tue, 1 Oct 2024 18:31:21 +0000 Subject: [PATCH 11/18] Translated using Weblate (Ukrainian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/uk/ --- src/strings/uk.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/strings/uk.json b/src/strings/uk.json index b34ef8960a..66f2dc6a5b 100644 --- a/src/strings/uk.json +++ b/src/strings/uk.json @@ -1960,5 +1960,9 @@ "PreferNonstandardArtistsTag": "Надавати перевагу тегу ARTISTS, якщо він доступний", "PreferNonstandardArtistsTagHelp": "Використовувати нестандартний тег ARTISTS замість тега ARTIST, якщо він доступний.", "UseCustomTagDelimiters": "Використовувати власний роздільник тегів", - "UseCustomTagDelimitersHelp": "Розділіть теги виконавця/жанру за допомогою спеціальних символів." + "UseCustomTagDelimitersHelp": "Розділіть теги виконавця/жанру за допомогою спеціальних символів.", + "DateModified": "Дату змінено", + "MessageCancelSeriesTimerError": "Виникла помилка під час скасування таймера серіалу", + "MessageCancelTimerError": "Виникла помилка під час скасування таймера", + "MessageSplitVersionsError": "Виникла помилка під час розділення версій" } From 6a6766f998b861ed7c5080597224a66e552952da Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Tue, 1 Oct 2024 16:00:48 -0400 Subject: [PATCH 12/18] Change NOTE to TODO --- src/apps/stable/features/playback/constants/playerEvent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/stable/features/playback/constants/playerEvent.ts b/src/apps/stable/features/playback/constants/playerEvent.ts index a02a7caaf1..c236475383 100644 --- a/src/apps/stable/features/playback/constants/playerEvent.ts +++ b/src/apps/stable/features/playback/constants/playerEvent.ts @@ -1,6 +1,6 @@ /** * Events triggered by media player plugins. - * NOTE: This list is incomplete + * TODO: This list is incomplete */ export enum PlayerEvent { Error = 'error', From 443b5cf895f9128669b5429bfd621b3059b2a4eb Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 2 Oct 2024 02:07:24 -0400 Subject: [PATCH 13/18] Use renovate for unstable sdk updates --- .github/renovate.json | 9 +++++- .github/workflows/update-sdk.yml | 52 -------------------------------- 2 files changed, 8 insertions(+), 53 deletions(-) delete mode 100644 .github/workflows/update-sdk.yml diff --git a/.github/renovate.json b/.github/renovate.json index 9bfb15c5e3..0a3b7bd9c1 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -2,7 +2,14 @@ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "github>jellyfin/.github//renovate-presets/nodejs", - ":semanticCommitsDisabled", ":dependencyDashboard" + ], + "packageRules": [ + { + "matchPackageNames": [ "@jellyfin/sdk" ], + "followTag": "unstable", + "minimumReleaseAge": 0, + "schedule": [ "after 7:00 am" ] + } ] } diff --git a/.github/workflows/update-sdk.yml b/.github/workflows/update-sdk.yml deleted file mode 100644 index c76d34729e..0000000000 --- a/.github/workflows/update-sdk.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Update the Jellyfin SDK - -on: - schedule: - - cron: '0 7 * * *' - workflow_dispatch: - -concurrency: - group: unstable-sdk-pr - cancel-in-progress: true - -jobs: - update: - runs-on: ubuntu-latest - if: ${{ github.repository == 'jellyfin/jellyfin-web' }} - - steps: - - name: Check out Git repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - with: - ref: master - token: ${{ secrets.JF_BOT_TOKEN }} - - - name: Set up Node.js - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 - with: - node-version: 20 - check-latest: true - cache: npm - - - name: Install latest unstable SDK - run: | - npm i --save @jellyfin/sdk@unstable - VERSION=$(jq -r '.dependencies["@jellyfin/sdk"]' package.json) - echo "JF_SDK_VERSION=${VERSION}" >> $GITHUB_ENV - - - name: Open a pull request - uses: peter-evans/create-pull-request@8867c4aba1b742c39f8d0ba35429c2dfa4b6cb20 # v7.0.1 - with: - token: ${{ secrets.JF_BOT_TOKEN }} - commit-message: Update @jellyfin/sdk to ${{env.JF_SDK_VERSION}} - committer: jellyfin-bot - author: jellyfin-bot - branch: update-jf-sdk - delete-branch: true - title: Update @jellyfin/sdk to ${{env.JF_SDK_VERSION}} - body: | - **Changes** - Updates to the latest unstable @jellyfin/sdk build - labels: | - dependencies - npm From b7a32c6aeea5e3edebcb2142cb299e9ea33cee3c Mon Sep 17 00:00:00 2001 From: BromTeque Date: Wed, 2 Oct 2024 10:18:44 +0000 Subject: [PATCH 14/18] =?UTF-8?q?Translated=20using=20Weblate=20(Norwegian?= =?UTF-8?q?=20Bokm=C3=A5l)=20Translation:=20Jellyfin/Jellyfin=20Web=20Tran?= =?UTF-8?q?slate-URL:=20https://translate.jellyfin.org/projects/jellyfin/j?= =?UTF-8?q?ellyfin-web/nb=5FNO/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/strings/nb.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/strings/nb.json b/src/strings/nb.json index d0e1dee15d..987f622dfe 100644 --- a/src/strings/nb.json +++ b/src/strings/nb.json @@ -1958,5 +1958,9 @@ "PreferNonstandardArtistsTag": "Foretrekk ARTISTER-tag om tilgjengelig", "PreferNonstandardArtistsTagHelp": "Bruk ikke-standard ARTISTS-taggen istedenfor ARTIST-taggen når den er tilgjengelig.", "UseCustomTagDelimiters": "Bruk egendefinert skilletegn for tagger", - "UseCustomTagDelimitersHelp": "Del artist- og sjanger-tagger med egendefinert tegn." + "UseCustomTagDelimitersHelp": "Del artist- og sjanger-tagger med egendefinert tegn.", + "DateModified": "Data modifisert", + "MessageCancelSeriesTimerError": "Det oppstod en feil under avbryting av serietidtakeren", + "MessageCancelTimerError": "Det oppstod en feil under avbryting av tidtakeren", + "MessageSplitVersionsError": "Det oppsto en feil under oppdeling av versjoner" } From f1e5b409e7d4b503b10bd09b2a92f9caadc6c78b Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 2 Oct 2024 07:57:58 -0400 Subject: [PATCH 15/18] Fix minimum release age type in renovate config --- .github/renovate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/renovate.json b/.github/renovate.json index 0a3b7bd9c1..200d5e43e7 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -8,7 +8,7 @@ { "matchPackageNames": [ "@jellyfin/sdk" ], "followTag": "unstable", - "minimumReleaseAge": 0, + "minimumReleaseAge": null, "schedule": [ "after 7:00 am" ] } ] From 00844cee032fe89f94ffefb118257ab16f071e74 Mon Sep 17 00:00:00 2001 From: Bas <44002186+854562@users.noreply.github.com> Date: Wed, 2 Oct 2024 12:36:06 +0000 Subject: [PATCH 16/18] Translated using Weblate (Dutch) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/nl/ --- src/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/nl.json b/src/strings/nl.json index cebcb545cd..6033a8b8c9 100644 --- a/src/strings/nl.json +++ b/src/strings/nl.json @@ -1776,7 +1776,7 @@ "BackdropScreensaver": "Schermbeveiliging met achtergronden", "LogoScreensaver": "Schermbeveiliging met logo", "LabelIsHearingImpaired": "Voor slechthorenden (ODS)", - "SelectAudioNormalizationHelp": "Nummerversterking regelt het volume van elk individueel nummer zodat alle nummers even luid afspelen. Albumversterking regelt het volume van alle nummers op een album, zodat het dynamische bereik van het album behouden blijft.", + "SelectAudioNormalizationHelp": "Nummerversterking regelt het volume van elk individueel nummer zodat alle nummers even luid afspelen. Albumversterking regelt het volume van alle nummers op een album, waarbij het dynamische bereik van het album behouden blijft. Na het wisselen tussen deze opties moet het afspelen herstart worden.", "LabelAlbumGain": "Albumversterking", "LabelSelectAudioNormalization": "Geluidsnormalisatie", "LabelTrackGain": "Nummerversterking", From e3cec3168216ffdefbc72f35441444210dc73d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9A=87=E7=94=AB=E6=9C=9D=E4=BA=91?= Date: Wed, 2 Oct 2024 13:08:27 +0000 Subject: [PATCH 17/18] Translated using Weblate (Chinese (Simplified Han script)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/zh_Hans/ --- src/strings/zh-cn.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strings/zh-cn.json b/src/strings/zh-cn.json index 3969b117f4..f32fc318d6 100644 --- a/src/strings/zh-cn.json +++ b/src/strings/zh-cn.json @@ -1019,7 +1019,7 @@ "SortName": "排序名称", "Sports": "体育", "StopRecording": "停止录制", - "Studios": "制片发行商", + "Studios": "工作室", "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "这些设置也会被应用于任何通过此设备发起的 Google Cast 播放。", "SubtitleAppearanceSettingsDisclaimer": "以下设置不适用于上述图形字幕或嵌入其自身样式的 ASS/SSA 字幕。", "SubtitleDownloadersHelp": "按优先顺序启用并排列您的首选字幕下载程序。", @@ -1728,7 +1728,7 @@ "MenuOpen": "打开菜单", "MenuClose": "关闭菜单", "UserMenu": "用户菜单", - "Studio": "制片发行商", + "Studio": "工作室", "AllowCollectionManagement": "允许该用户管理收藏夹", "EnableAudioNormalizationHelp": "音频标准化将添加一个恒定的增益,以保持平均音量在所需的级别(-18dB)。", "EnableAudioNormalization": "音频标准化", @@ -1779,7 +1779,7 @@ "LabelIsHearingImpaired": "用于听障/聋哑人士", "SearchResultsEmpty": "抱歉!未找到与\"{0}\"相关的结果", "LabelTrackGain": "音轨增益", - "SelectAudioNormalizationHelp": "音轨增益 - 调整每个音轨的音量,使它们播放时具有相同的响度。专辑增益 - 只调整专辑中所有音轨的音量,保持专辑的动态范围。", + "SelectAudioNormalizationHelp": "音轨增益 - 调整每个音轨的音量,使它们播放时具有相同的响度。专辑增益 - 只调整专辑中所有音轨的音量,保持专辑的动态范围。在“关闭”和其他选项之间切换后需要重新启动当前播放。", "LabelAlbumGain": "专辑增益", "LabelSelectAudioNormalization": "音频标准化", "HeaderAllRecordings": "所有录制的节目", From d301f323ac995ea5071a9f2ed80335fc962a3694 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 14:16:23 +0000 Subject: [PATCH 18/18] Update dependency @jellyfin/sdk to v0.0.0-unstable.202410020501 --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index aa0e5591f3..355a5821d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@fontsource/noto-sans-sc": "5.1.0", "@fontsource/noto-sans-tc": "5.1.0", "@jellyfin/libass-wasm": "4.2.3", - "@jellyfin/sdk": "0.0.0-unstable.202409260501", + "@jellyfin/sdk": "0.0.0-unstable.202410020501", "@mui/icons-material": "5.16.7", "@mui/material": "5.16.7", "@mui/x-date-pickers": "7.18.0", @@ -5068,9 +5068,9 @@ "license": "LGPL-2.1-or-later AND (FTL OR GPL-2.0-or-later) AND MIT AND MIT-Modern-Variant AND ISC AND NTP AND Zlib AND BSL-1.0" }, "node_modules/@jellyfin/sdk": { - "version": "0.0.0-unstable.202409260501", - "resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202409260501.tgz", - "integrity": "sha512-3W/J15A/jELTMJPrPiGvfkO8xsUaxKh4P/f+kVAxOSCYkPp+vvZxmRCGV7M1+1947O19iJ/l7ypD08L3YVf39g==", + "version": "0.0.0-unstable.202410020501", + "resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202410020501.tgz", + "integrity": "sha512-Tl+bE4GoGDf5qmzYiauNLFclAYF4cPFVX3HldKl/KuwEarzRdQfudGNFCu0KmDbJGiZ6HtDlec6LoUaYeXmvng==", "license": "MPL-2.0", "peerDependencies": { "axios": "^1.3.4" @@ -29306,9 +29306,9 @@ "integrity": "sha512-C0OlBxIr9NdeFESMTA/OVDqNSWtog6Mi7wwzwH12xbZpxsMD0RgCupUcIP7zZgcpTNecW3fZq5d6xVo7Q8HEJw==" }, "@jellyfin/sdk": { - "version": "0.0.0-unstable.202409260501", - "resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202409260501.tgz", - "integrity": "sha512-3W/J15A/jELTMJPrPiGvfkO8xsUaxKh4P/f+kVAxOSCYkPp+vvZxmRCGV7M1+1947O19iJ/l7ypD08L3YVf39g==", + "version": "0.0.0-unstable.202410020501", + "resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202410020501.tgz", + "integrity": "sha512-Tl+bE4GoGDf5qmzYiauNLFclAYF4cPFVX3HldKl/KuwEarzRdQfudGNFCu0KmDbJGiZ6HtDlec6LoUaYeXmvng==", "requires": {} }, "@jridgewell/gen-mapping": { diff --git a/package.json b/package.json index 47063fda6f..fb62f4be96 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "@fontsource/noto-sans-sc": "5.1.0", "@fontsource/noto-sans-tc": "5.1.0", "@jellyfin/libass-wasm": "4.2.3", - "@jellyfin/sdk": "0.0.0-unstable.202409260501", + "@jellyfin/sdk": "0.0.0-unstable.202410020501", "@mui/icons-material": "5.16.7", "@mui/material": "5.16.7", "@mui/x-date-pickers": "7.18.0",