From 185d0ee97f04edbff66bf95551c49a8a39fa9e1b Mon Sep 17 00:00:00 2001 From: photonconvergence <116527579+photonconvergence@users.noreply.github.com> Date: Thu, 27 Oct 2022 18:02:21 -0700 Subject: [PATCH 01/65] Fix extra subtext display Translation strings added for two extra types. --- src/strings/en-us.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/strings/en-us.json b/src/strings/en-us.json index 4fa437b462..f2e0cd0bfc 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -1642,7 +1642,9 @@ "UnknownAudioStreamInfo": "The audio stream info is unknown", "DirectPlayError": "There was an error starting direct playback", "SelectAll": "Select All", - "Clip": "Featurette", + "Featurette": "Featurette", + "Short": "Short", + "Clip": "Clip", "Trailer": "Trailer", "BehindTheScenes": "Behind the Scenes", "DeletedScene": "Deleted Scene", From 85d9d515f527224f7cec7d2b7308cca6e08e3607 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 3 Nov 2022 22:11:49 +0000 Subject: [PATCH 02/65] Update fedora Docker tag to v38 --- deployment/Dockerfile.fedora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/Dockerfile.fedora b/deployment/Dockerfile.fedora index da3537327f..9248c209d7 100644 --- a/deployment/Dockerfile.fedora +++ b/deployment/Dockerfile.fedora @@ -1,4 +1,4 @@ -FROM fedora:37 +FROM fedora:38 # Docker build arguments ARG SOURCE_DIR=/jellyfin From f2fd96aced6cfd9f14d55d997b4228dd56ea6ba2 Mon Sep 17 00:00:00 2001 From: Ivan Schurawel Date: Sun, 12 Feb 2023 17:16:20 -0500 Subject: [PATCH 03/65] fix: clear stuck subtitle track cues --- src/plugins/htmlVideoPlayer/plugin.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index f2a2b8d30b..8902b9cf25 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -620,6 +620,28 @@ function tryRemoveElement(elem) { return relativeOffset; } + /** + * @private + * These browsers will not clear the existing active cue when setting an offset + * for native TextTracks. + * Any previous text tracks that are on the screen when the offset changes will + * remain next to the new tracks until they reach the new offset's instance of the track. + */ + requiresHidingActiveCuesOnOffsetChange() { + return !!browser.firefox; + } + + /** + * @private + */ + hideTextTrackActiveCues(currentTrack) { + if (currentTrack.activeCues) { + Array.from(currentTrack.activeCues).forEach((cue) => { + cue.text = ''; + }); + } + } + /** * @private */ @@ -629,6 +651,9 @@ function tryRemoveElement(elem) { if (offsetValue === 0) { return; } + if (this.requiresHidingActiveCuesOnOffsetChange()) { + this.hideTextTrackActiveCues(currentTrack); + } Array.from(currentTrack.cues) .forEach(function (cue) { cue.startTime -= offsetValue; From f20ee0b2ea0c486b97dcc1c197ed76b813013e29 Mon Sep 17 00:00:00 2001 From: Ivan Schurawel Date: Tue, 14 Feb 2023 18:43:19 -0500 Subject: [PATCH 04/65] fix: disable track mode to force clear active cues --- src/plugins/htmlVideoPlayer/plugin.js | 48 ++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index 8902b9cf25..695829ca2b 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -245,6 +245,12 @@ function tryRemoveElement(elem) { * @type {any | null | undefined} */ #currentSecondaryTrackEvents; + /** + * Used to temporarily store the text track when + * force-clearing the `activeCue` for certain browsers + * @type {TextTrack | null | undefined} + */ + #currentTextTrack; /** * @type {string[] | undefined} */ @@ -624,8 +630,8 @@ function tryRemoveElement(elem) { * @private * These browsers will not clear the existing active cue when setting an offset * for native TextTracks. - * Any previous text tracks that are on the screen when the offset changes will - * remain next to the new tracks until they reach the new offset's instance of the track. + * Any previous text tracks that are on the screen when the offset changes will remain next + * to the new tracks until they reach the end time of the new offset's instance of the track. */ requiresHidingActiveCuesOnOffsetChange() { return !!browser.firefox; @@ -634,11 +640,30 @@ function tryRemoveElement(elem) { /** * @private */ - hideTextTrackActiveCues(currentTrack) { + hideTextTrackWithActiveCues(currentTrack) { if (currentTrack.activeCues) { - Array.from(currentTrack.activeCues).forEach((cue) => { - cue.text = ''; - }); + currentTrack.mode = 'hidden'; + } + } + + /** + * Forces the active cue to clear by disabling then re-enabling the track. + * The track mode is reverted inside of a 0ms timeout to free up the track + * and allow it to disable and clear the active cue. + * The track needs to be temporarily stored in order for us to access it + * inside the timeout. The stored value is reset after it is used. + * @private + */ + forceClearTextTrackActiveCues(currentTrack) { + if (currentTrack.activeCues) { + this.#currentTextTrack = currentTrack; + currentTrack.mode = 'disabled'; + setTimeout(() => { + if (this.#currentTextTrack) { + this.#currentTextTrack.mode = 'showing'; + this.#currentTextTrack = null; + } + }, 0); } } @@ -651,14 +676,21 @@ function tryRemoveElement(elem) { if (offsetValue === 0) { return; } - if (this.requiresHidingActiveCuesOnOffsetChange()) { - this.hideTextTrackActiveCues(currentTrack); + + const shouldClearActiveCues = this.requiresClearingActiveCuesOnOffsetChange(); + if (shouldClearActiveCues) { + this.hideTextTrackWithActiveCues(currentTrack); } + Array.from(currentTrack.cues) .forEach(function (cue) { cue.startTime -= offsetValue; cue.endTime -= offsetValue; }); + + if (shouldClearActiveCues) { + this.forceClearTextTrackActiveCues(currentTrack); + } } } From 2caa2851b9b9a08cafa607cd5d5582a27c3cc5e6 Mon Sep 17 00:00:00 2001 From: Ivan Schurawel <30599893+is343@users.noreply.github.com> Date: Fri, 17 Feb 2023 09:43:04 -0500 Subject: [PATCH 05/65] fix: use correct name Co-authored-by: Dmitry Lyzo <56478732+dmitrylyzo@users.noreply.github.com> --- src/plugins/htmlVideoPlayer/plugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index 695829ca2b..aaf22f759b 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -677,7 +677,7 @@ function tryRemoveElement(elem) { return; } - const shouldClearActiveCues = this.requiresClearingActiveCuesOnOffsetChange(); + const shouldClearActiveCues = this.requiresHidingActiveCuesOnOffsetChange(); if (shouldClearActiveCues) { this.hideTextTrackWithActiveCues(currentTrack); } From 032d03d20135d0cdb357ad6f2dda1603af5ede1e Mon Sep 17 00:00:00 2001 From: Ivan Schurawel Date: Sun, 19 Feb 2023 10:56:10 -0500 Subject: [PATCH 06/65] fix: don't set temp variable --- src/plugins/htmlVideoPlayer/plugin.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index aaf22f759b..7936067145 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -245,12 +245,6 @@ function tryRemoveElement(elem) { * @type {any | null | undefined} */ #currentSecondaryTrackEvents; - /** - * Used to temporarily store the text track when - * force-clearing the `activeCue` for certain browsers - * @type {TextTrack | null | undefined} - */ - #currentTextTrack; /** * @type {string[] | undefined} */ @@ -650,19 +644,13 @@ function tryRemoveElement(elem) { * Forces the active cue to clear by disabling then re-enabling the track. * The track mode is reverted inside of a 0ms timeout to free up the track * and allow it to disable and clear the active cue. - * The track needs to be temporarily stored in order for us to access it - * inside the timeout. The stored value is reset after it is used. * @private */ forceClearTextTrackActiveCues(currentTrack) { if (currentTrack.activeCues) { - this.#currentTextTrack = currentTrack; currentTrack.mode = 'disabled'; setTimeout(() => { - if (this.#currentTextTrack) { - this.#currentTextTrack.mode = 'showing'; - this.#currentTextTrack = null; - } + currentTrack.mode = 'showing'; }, 0); } } From acdbf59b50e7a6d2b0114d490048aee337cfaa1b Mon Sep 17 00:00:00 2001 From: Ivan Schurawel Date: Sun, 19 Feb 2023 17:29:34 -0500 Subject: [PATCH 07/65] chore: add debounce to setSubtitleOffset --- src/plugins/htmlVideoPlayer/plugin.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index 7936067145..cef47fe119 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -32,6 +32,7 @@ import { getIncludeCorsCredentials } from '../../scripts/settings/webSettings'; import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../components/backdrop/backdrop'; import Events from '../../utils/events.ts'; import { includesAny } from '../../utils/container.ts'; +import debounce from 'lodash-es/debounce'; /** * Returns resolved URL. @@ -571,7 +572,12 @@ function tryRemoveElement(elem) { } } - setSubtitleOffset(offset) { + setSubtitleOffset = debounce(this._setSubtitleOffset, 500); + + /** + * @private + */ + _setSubtitleOffset(offset) { const offsetValue = parseFloat(offset); // if .ass currently rendering From 4c71de481547f61fbb46e5065b895b6ce5a6895b Mon Sep 17 00:00:00 2001 From: Ivan Schurawel Date: Mon, 20 Feb 2023 15:26:17 -0500 Subject: [PATCH 08/65] chore: use smaller debounce time --- src/plugins/htmlVideoPlayer/plugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index cef47fe119..4e120e5f78 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -572,7 +572,7 @@ function tryRemoveElement(elem) { } } - setSubtitleOffset = debounce(this._setSubtitleOffset, 500); + setSubtitleOffset = debounce(this._setSubtitleOffset, 100); /** * @private From c0fc93dedcbdf87c49cef6f4d72817bb5cd57172 Mon Sep 17 00:00:00 2001 From: Ivan Schurawel Date: Tue, 21 Feb 2023 09:12:39 -0500 Subject: [PATCH 09/65] fix: cancel debounce on player unmount --- src/plugins/htmlVideoPlayer/plugin.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index 4e120e5f78..8b5afd90d5 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -822,6 +822,8 @@ function tryRemoveElement(elem) { } destroy() { + this.setSubtitleOffset.cancel(); + destroyHlsPlayer(this); destroyFlvPlayer(this); From 12d2fb471ce6407389738a211198520e5215cbed Mon Sep 17 00:00:00 2001 From: Niels van Velzen Date: Sat, 4 Mar 2023 16:29:45 +0100 Subject: [PATCH 10/65] Support markdown in item descriptions --- src/controllers/itemDetails/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controllers/itemDetails/index.js b/src/controllers/itemDetails/index.js index c06043e472..05bfb8ee50 100644 --- a/src/controllers/itemDetails/index.js +++ b/src/controllers/itemDetails/index.js @@ -1,5 +1,6 @@ import { intervalToDuration } from 'date-fns'; import DOMPurify from 'dompurify'; +import { marked } from 'marked'; import escapeHtml from 'escape-html'; import isEqual from 'lodash-es/isEqual'; @@ -877,7 +878,7 @@ function renderOverview(page, item) { const overviewElements = page.querySelectorAll('.overview'); if (overviewElements.length > 0) { - const overview = DOMPurify.sanitize(item.Overview || ''); + const overview = DOMPurify.sanitize(marked(item.Overview || '')); if (overview) { for (const overviewElemnt of overviewElements) { From 1c5f17d73871c5a95db4adccb6c4a46174d30011 Mon Sep 17 00:00:00 2001 From: robert-hamilton36 Date: Mon, 6 Mar 2023 14:05:41 +1300 Subject: [PATCH 11/65] Edit CSS to avoid text overflow --- src/components/upnextdialog/upnextdialog.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/upnextdialog/upnextdialog.scss b/src/components/upnextdialog/upnextdialog.scss index 08c4904bb5..fd2ae8d054 100644 --- a/src/components/upnextdialog/upnextdialog.scss +++ b/src/components/upnextdialog/upnextdialog.scss @@ -28,9 +28,9 @@ .upNextDialog-countdownText { font-weight: 500; + white-space: nowrap; } -.upNextDialog-nextVideoText, .upNextDialog-title { width: 25.5em; white-space: nowrap; From 7106611f9de01b1669a0d2e803621d8bf891608e Mon Sep 17 00:00:00 2001 From: WontTell Date: Mon, 6 Mar 2023 03:24:40 +0000 Subject: [PATCH 12/65] Translated using Weblate (Spanish (Latin America)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/es_419/ --- src/strings/es_419.json | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/strings/es_419.json b/src/strings/es_419.json index 707713eeea..db7ec1884c 100644 --- a/src/strings/es_419.json +++ b/src/strings/es_419.json @@ -16,7 +16,7 @@ "Books": "Libros", "Artists": "Artistas", "Albums": "Álbumes", - "TabLatest": "Recientes", + "TabLatest": "Agregado recientemente", "HeaderUser": "Usuario", "AlbumArtist": "Artista del álbum", "Album": "Álbum", @@ -309,7 +309,7 @@ "LibraryAccessHelp": "Selecciona las bibliotecas que deseas compartir con este usuario. Los administradores podrán editar todas las carpetas utilizando el gestor de metadatos.", "LeaveBlankToNotSetAPassword": "Puedes dejar este campo en blanco para no establecer ninguna contraseña.", "LearnHowYouCanContribute": "Aprende cómo puedes contribuir.", - "LatestFromLibrary": "Últimas - {0}", + "LatestFromLibrary": "Agregado recientemente en {0}", "Large": "Grande", "LanNetworksHelp": "Lista separada por comas de direcciones IP o entradas de IP/máscara de red para las redes que se considerarán en la red local al aplicar las restricciones de ancho de banda. Si se establecen, todas las demás direcciones IP se considerarán como parte de la red externa y estarán sujetas a las restricciones de ancho de banda externa. Si se deja en blanco, solo se considera a la subred del servidor estar en la red local.", "LabelffmpegPathHelp": "La ruta hacia el archivo ejecutable FFmpeg, o la carpeta que contenga FFmpeg.", @@ -875,7 +875,7 @@ "HttpsRequiresCert": "Para habilitar las conexiones seguras, necesitarás proporcionar un certificado SSL de confianza, como el de Let's Encrypt. Por favor, proporciona un certificado o desactiva las conexiones seguras.", "Horizontal": "Horizontal", "Home": "Inicio", - "HideWatchedContentFromLatestMedia": "Ocultar contenido ya visto de «Últimos medios»", + "HideWatchedContentFromLatestMedia": "Ocultar contenido ya visto de «Medios agregados recientemente»", "Hide": "Ocultar", "Help": "Ayuda", "HeaderYears": "Años", @@ -970,11 +970,11 @@ "HeaderLibraryFolders": "Carpetas de bibliotecas", "HeaderLibraryAccess": "Acceso a bibliotecas", "HeaderLibraries": "Bibliotecas", - "HeaderLatestRecordings": "Últimas grabaciones", - "HeaderLatestMusic": "Última música", - "HeaderLatestMovies": "Últimas películas", - "HeaderLatestMedia": "Últimos medios", - "HeaderLatestEpisodes": "Últimos episodios", + "HeaderLatestRecordings": "Grabaciones agregadas recientemente", + "HeaderLatestMusic": "Música agregada recientemente", + "HeaderLatestMovies": "Películas agregadas recientemente", + "HeaderLatestMedia": "Medios agregados recientemente", + "HeaderLatestEpisodes": "Episodios agregados recientemente", "HeaderKodiMetadataHelp": "Para habilitar o deshabilitar los metadatos NFO, edita una biblioteca y ubica la sección de 'Grabadores de metadatos'.", "HeaderKeepSeries": "Conservar serie", "HeaderKeepRecording": "Conservar grabación", @@ -1022,7 +1022,7 @@ "LabelLibraryPageSize": "Tamaño de las páginas de las bibliotecas:", "LabelLanguage": "Idioma:", "LabelLanNetworks": "Redes LAN:", - "LabelKodiMetadataUserHelp": "Guarda los datos de visto en archivos NFO para que otras aplicaciones los utilicen.", + "LabelKodiMetadataUserHelp": "Guarda los datos de visualización en los archivos NFO para que otras aplicaciones lo usen.", "LabelKodiMetadataUser": "Guardar los datos de visto del usuario en archivos NFO para:", "LabelKodiMetadataSaveImagePathsHelp": "Esto se recomienda si tienes nombres de imágenes que no se ajustan a los lineamientos de Kodi.", "LabelKodiMetadataSaveImagePaths": "Guardar las rutas de las imágenes en los archivos NFO", @@ -1166,7 +1166,7 @@ "DisplayModeHelp": "Selecciona el estilo de diseño que desea para la interfaz.", "DisplayMissingEpisodesWithinSeasonsHelp": "Esto también debe estar habilitado para las bibliotecas de TV en la configuración del servidor.", "DisplayMissingEpisodesWithinSeasons": "Mostrar episodios faltantes en las temporadas", - "DisplayInOtherHomeScreenSections": "Mostrar en las secciones de la pantalla de inicio como «Recientes» o «Continuar viendo»", + "DisplayInOtherHomeScreenSections": "Mostrar en las secciones de la pantalla de inicio como «Medios agregados recientemente» o «Continuar viendo»", "DisplayInMyMedia": "Mostrar en la pantalla de inicio", "Display": "Pantalla", "Disconnect": "Desconectar", @@ -1564,5 +1564,15 @@ "LabelSyncPlaySettingsSyncCorrection": "Corrección de sincronización", "LabelSyncPlaySettingsExtraTimeOffset": "Desfase de tiempo extra:", "LabelSyncPlaySettingsMinDelaySpeedToSync": "Retraso mínimo de SpeedToSync:", - "LabelOriginalName": "Nombre original:" + "LabelOriginalName": "Nombre original:", + "Experimental": "Experimental", + "HeaderRecordingMetadataSaving": "Metadatos de grabación", + "LabelStereoDownmixAlgorithm": "Algoritmo de downmix estéreo", + "LabelDummyChapterDuration": "Intervalo:", + "LabelDummyChapterCountHelp": "El máximo número de imágenes de capítulos que serán extraídas por cada archivo de medios.", + "HeaderDummyChapter": "Imágenes de capítulos", + "LabelDummyChapterDurationHelp": "El intervalo de la extracción de las imágenes de los capítulos, en segundos.", + "LabelDummyChapterCount": "Límite:", + "LabelChapterImageResolution": "Resolución:", + "LabelChapterImageResolutionHelp": "La resolución de las imágenes de capítulos extraídas." } From 52363c59d9556cbaf6178a448ad7d823cb107336 Mon Sep 17 00:00:00 2001 From: knackebrot Date: Mon, 6 Mar 2023 10:02:38 +0100 Subject: [PATCH 13/65] Update hls.js to 1.3.4 --- package-lock.json | 38 ++++++++------------------- package.json | 2 +- src/plugins/htmlAudioPlayer/plugin.js | 3 +++ src/plugins/htmlVideoPlayer/plugin.js | 3 +++ webpack.common.js | 1 + 5 files changed, 19 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index 97116e92d6..dcc6fb05f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,7 @@ "flv.js": "1.6.2", "headroom.js": "0.12.0", "history": "5.3.0", - "hls.js": "0.14.17", + "hls.js": "1.3.4", "intersection-observer": "0.12.2", "jellyfin-apiclient": "1.10.0", "jquery": "3.6.3", @@ -7301,7 +7301,8 @@ "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true }, "node_modules/events": { "version": "3.3.0", @@ -8467,13 +8468,9 @@ } }, "node_modules/hls.js": { - "version": "0.14.17", - "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-0.14.17.tgz", - "integrity": "sha512-25A7+m6qqp6UVkuzUQ//VVh2EEOPYlOBg32ypr34bcPO7liBMOkKFvbjbCBfiPAOTA/7BSx1Dujft3Th57WyFg==", - "dependencies": { - "eventemitter3": "^4.0.3", - "url-toolkit": "^2.1.6" - } + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.3.4.tgz", + "integrity": "sha512-iFEwVqtEDk6sKotcTwtJ5OMo/nuDTk9PrpB8FI2J2WYf8EriTVfR4FaK0aNyYtwbYeRSWCXJKlz23xeREdlNYg==" }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", @@ -18229,11 +18226,6 @@ "deprecated": "Please see https://github.com/lydell/urix#deprecated", "dev": true }, - "node_modules/url-toolkit": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.2.3.tgz", - "integrity": "sha512-Da75SQoxsZ+2wXS56CZBrj2nukQ4nlGUZUP/dqUBG5E1su5GKThgT94Q00x81eVII7AyS1Pn+CtTTZ4Z0pLUtQ==" - }, "node_modules/use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -24492,7 +24484,8 @@ "eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true }, "events": { "version": "3.3.0", @@ -25405,13 +25398,9 @@ } }, "hls.js": { - "version": "0.14.17", - "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-0.14.17.tgz", - "integrity": "sha512-25A7+m6qqp6UVkuzUQ//VVh2EEOPYlOBg32ypr34bcPO7liBMOkKFvbjbCBfiPAOTA/7BSx1Dujft3Th57WyFg==", - "requires": { - "eventemitter3": "^4.0.3", - "url-toolkit": "^2.1.6" - } + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.3.4.tgz", + "integrity": "sha512-iFEwVqtEDk6sKotcTwtJ5OMo/nuDTk9PrpB8FI2J2WYf8EriTVfR4FaK0aNyYtwbYeRSWCXJKlz23xeREdlNYg==" }, "hoist-non-react-statics": { "version": "3.3.2", @@ -32698,11 +32687,6 @@ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "dev": true }, - "url-toolkit": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.2.3.tgz", - "integrity": "sha512-Da75SQoxsZ+2wXS56CZBrj2nukQ4nlGUZUP/dqUBG5E1su5GKThgT94Q00x81eVII7AyS1Pn+CtTTZ4Z0pLUtQ==" - }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", diff --git a/package.json b/package.json index 3d25ed4276..bc19c04a9e 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "flv.js": "1.6.2", "headroom.js": "0.12.0", "history": "5.3.0", - "hls.js": "0.14.17", + "hls.js": "1.3.4", "intersection-observer": "0.12.2", "jellyfin-apiclient": "1.10.0", "jquery": "3.6.3", diff --git a/src/plugins/htmlAudioPlayer/plugin.js b/src/plugins/htmlAudioPlayer/plugin.js index b5d3c8bd02..a1cad660fe 100644 --- a/src/plugins/htmlAudioPlayer/plugin.js +++ b/src/plugins/htmlAudioPlayer/plugin.js @@ -48,6 +48,9 @@ function supportsFade() { function requireHlsPlayer(callback) { import('hls.js').then(({ default: hls }) => { + hls.DefaultConfig.lowLatencyMode = false; + hls.DefaultConfig.backBufferLength = Infinity; + hls.DefaultConfig.liveBackBufferLength = 90; window.Hls = hls; callback(); }); diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index f2a2b8d30b..388cb4caad 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -106,6 +106,9 @@ function tryRemoveElement(elem) { function requireHlsPlayer(callback) { import('hls.js').then(({default: hls}) => { + hls.DefaultConfig.lowLatencyMode = false; + hls.DefaultConfig.backBufferLength = Infinity; + hls.DefaultConfig.liveBackBufferLength = 90; window.Hls = hls; callback(); }); diff --git a/webpack.common.js b/webpack.common.js index eebd423d98..1b5d41fc42 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -158,6 +158,7 @@ const config = { path.resolve(__dirname, 'node_modules/dom7'), path.resolve(__dirname, 'node_modules/epubjs'), path.resolve(__dirname, 'node_modules/flv.js'), + path.resolve(__dirname, 'node_modules/hls.js'), path.resolve(__dirname, 'node_modules/libarchive.js'), path.resolve(__dirname, 'node_modules/marked'), path.resolve(__dirname, 'node_modules/react-router'), From 2681d5c4ca781b9304ba1699b7d42edc94d6beb9 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Mon, 6 Mar 2023 09:00:02 +0000 Subject: [PATCH 14/65] Translated using Weblate (German) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/de/ --- src/strings/de.json | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/strings/de.json b/src/strings/de.json index 89856057b3..dedc1dfdc3 100644 --- a/src/strings/de.json +++ b/src/strings/de.json @@ -121,7 +121,7 @@ "DeleteMedia": "Medien löschen", "DeleteUser": "Benutzer löschen", "DeleteUserConfirmation": "Bist du dir sicher, dass du diesen Benutzer löschen willst?", - "Depressed": "gedrückt", + "Depressed": "Gedrückt", "Descending": "Absteigend", "DetectingDevices": "Suche Geräte", "DeviceAccessHelp": "Dies wird nur auf Geräte angewendet, die eindeutig identifiziert werden können, und verhindert nicht den Web-Zugriff. Gefilterter Zugriff auf Geräte verhindert die Nutzung neuer Geräte solange, bis der Zugriff für diese freigegeben wird.", @@ -279,11 +279,11 @@ "HeaderKeepRecording": "Aufnahme behalten", "HeaderKeepSeries": "Serie behalten", "HeaderKodiMetadataHelp": "Um NFO-Metadaten zu aktivieren oder zu deaktivieren, bearbeite eine Bibliothek und finde den Abschnitt zum Speichern von Metadaten.", - "HeaderLatestEpisodes": "Neueste Episoden", - "HeaderLatestMedia": "Neueste Medien", - "HeaderLatestMovies": "Neueste Filme", - "HeaderLatestMusic": "Neueste Musik", - "HeaderLatestRecordings": "Neueste Aufnahmen", + "HeaderLatestEpisodes": "Kürzlich hinzugefügte Episoden", + "HeaderLatestMedia": "Kürzlich hinzugefügte Medien", + "HeaderLatestMovies": "Kürzlich hinzugefügte Filme", + "HeaderLatestMusic": "Kürzlich hinzugefügte Musik", + "HeaderLatestRecordings": "Kürzlich hinzugefügte Aufnahmen", "HeaderLibraries": "Bibliotheken", "HeaderLibraryAccess": "Bibliothekszugriff", "HeaderLibraryFolders": "Bibliotheksverzeichnisse", @@ -301,7 +301,7 @@ "HeaderMyMediaSmall": "Meine Medien (Klein)", "HeaderNewApiKey": "Neuer API-Schlüssel", "HeaderNewDevices": "Neue Geräte", - "HeaderNextEpisodePlayingInValue": "Nächste Episode wird abgespielt in {0}", + "HeaderNextEpisodePlayingInValue": "Nächste Episode in {0}", "HeaderNextVideoPlayingInValue": "Nächstes Video wird abgespielt in {0}", "HeaderOnNow": "Gerade läuft", "HeaderOtherItems": "Andere Inhalte", @@ -696,7 +696,7 @@ "LabelffmpegPathHelp": "Verzeichnis zur FFmpeg-Applikationsdatei oder zum Ordner, der FFmpeg enthält.", "LanNetworksHelp": "Komma separierte Liste von IP-Adressen oder IP/Netzmasken die als lokale Netzwerke behandelt werden sollen, um Bandbreitenlimitationen auszusetzen. Wenn gesetzt, werden alle anderen IP-Adressen als extern behandelt und unterliegen den Bandbreitenlimitationen für externe Verbindungen. Wenn leer, wird nur das Subnetz des Servers als lokales Netzwerk behandelt.", "Large": "Groß", - "LatestFromLibrary": "Neueste {0}", + "LatestFromLibrary": "Kürzlich hinzugefügt in {0}", "LearnHowYouCanContribute": "Erfahre, wie du unterstützen kannst.", "LibraryAccessHelp": "Wähle die Bibliotheken aus, die du mit diesem Benutzer teilen möchtest. Administratoren können den Metadaten-Manager verwenden um alle Ordner zu bearbeiten.", "List": "Liste", @@ -1023,7 +1023,7 @@ "TabContainers": "Container", "TabDashboard": "Übersicht", "TabDirectPlay": "Direktwiedergabe", - "TabLatest": "Neueste", + "TabLatest": "Kürzlich hinzugefügt", "TabMusic": "Musik", "TabMyPlugins": "Meine Plugins", "TabNetworks": "Fernsehsender", @@ -1704,5 +1704,15 @@ "LabelDummyChapterCount": "Limit:", "LabelDummyChapterCountHelp": "Die maximale Anzahl von Kapitelbildern, die für jede Mediendatei extrahiert werden.", "LabelChapterImageResolution": "Auflösung:", - "LabelChapterImageResolutionHelp": "Die Auflösung der extrahierten Kapitelbilder." + "LabelChapterImageResolutionHelp": "Die Auflösung der extrahierten Kapitelbilder.", + "SubtitleBlack": "Schwarz", + "SubtitleBlue": "Blau", + "SubtitleCyan": "Cyan", + "SubtitleGray": "Grau", + "SubtitleGreen": "Grün", + "SubtitleLightGray": "Hellgrau", + "SubtitleMagenta": "Magenta", + "SubtitleRed": "Rot", + "SubtitleWhite": "Weiß", + "SubtitleYellow": "Gelb" } From bd9d3e5f65b805bc2d041b7b48e79fb3207de813 Mon Sep 17 00:00:00 2001 From: James Raspass Date: Thu, 2 Mar 2023 13:24:46 +0000 Subject: [PATCH 15/65] Remove old Emby (3.x) version checks As per https://trello.com/c/sA25wd46/8-remove-old-emby-3x-version-checks --- src/components/playback/playbackmanager.js | 6 ------ src/controllers/dashboard/devices/devices.js | 19 +++++++------------ src/controllers/itemDetails/index.js | 7 +------ 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 2b8bd21280..ffcd0e4d91 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -3423,12 +3423,6 @@ class PlaybackManager { streamInfo.lastMediaInfoQuery = new Date().getTime(); - const apiClient = ServerConnections.getApiClient(serverId); - - if (!apiClient.isMinServerVersion('3.2.70.7')) { - return; - } - ServerConnections.getApiClient(serverId).getLiveStreamMediaInfo(liveStreamId).then(function (info) { mediaSource.MediaStreams = info.MediaStreams; Events.trigger(player, 'mediastreamschange'); diff --git a/src/controllers/dashboard/devices/devices.js b/src/controllers/dashboard/devices/devices.js index 3c3a039745..537e842d90 100644 --- a/src/controllers/dashboard/devices/devices.js +++ b/src/controllers/dashboard/devices/devices.js @@ -54,15 +54,11 @@ import confirm from '../../../components/confirm/confirm'; } function showDeviceMenu(view, btn, deviceId) { - const menuItems = []; - - if (canEdit) { - menuItems.push({ - name: globalize.translate('Edit'), - id: 'open', - icon: 'mode_edit' - }); - } + const menuItems = [{ + name: globalize.translate('Edit'), + id: 'open', + icon: 'mode_edit' + }]; if (canDelete(deviceId)) { menuItems.push({ @@ -100,7 +96,7 @@ import confirm from '../../../components/confirm/confirm'; deviceHtml += '
'; deviceHtml += ''; deviceHtml += '
'; - if (canEdit || canDelete(device.Id)) { + if (canDelete(device.Id)) { if (globalize.getIsRTL()) deviceHtml += '
'; else @@ -155,7 +151,6 @@ import confirm from '../../../components/confirm/confirm'; }); } - const canEdit = ApiClient.isMinServerVersion('3.4.1.31'); export default function (view) { view.querySelector('.devicesList').addEventListener('click', function (e) { const btnDeviceMenu = dom.parentWithClass(e.target, 'btnDeviceMenu'); diff --git a/src/controllers/itemDetails/index.js b/src/controllers/itemDetails/index.js index c06043e472..478b6be23a 100644 --- a/src/controllers/itemDetails/index.js +++ b/src/controllers/itemDetails/index.js @@ -1156,12 +1156,7 @@ function renderMoreFromArtist(view, item, apiClient) { const section = view.querySelector('.moreFromArtistSection'); if (section) { - if (item.Type === 'MusicArtist') { - if (!apiClient.isMinServerVersion('3.4.1.19')) { - section.classList.add('hide'); - return; - } - } else if (item.Type !== 'MusicAlbum' || !item.AlbumArtists || !item.AlbumArtists.length) { + if (item.Type !== 'MusicArtist' && (item.Type !== 'MusicAlbum' || !item.AlbumArtists || !item.AlbumArtists.length)) { section.classList.add('hide'); return; } From e4d6ba2de6e1079366605d6ad6f989fc5063c3f2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Mar 2023 00:56:24 +0000 Subject: [PATCH 16/65] Update dependency react-router-dom to v6.8.2 --- package-lock.json | 50 +++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0f909a9694..bd0707b57a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,7 @@ "pdfjs-dist": "2.16.105", "react": "17.0.2", "react-dom": "17.0.2", - "react-router-dom": "6.8.1", + "react-router-dom": "6.8.2", "resize-observer-polyfill": "1.5.1", "screenfull": "6.0.2", "sortablejs": "1.15.0", @@ -2767,9 +2767,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.2.tgz", - "integrity": "sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.3.tgz", + "integrity": "sha512-YRHie1yQEj0kqqCTCJEfHqYSSNlZQ696QJG+MMiW4mxSl9I0ojz/eRhJS4fs88Z5i6D1SmoF9d3K99/QOhI8/w==", "engines": { "node": ">=14" } @@ -13122,11 +13122,11 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-router": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.1.tgz", - "integrity": "sha512-Jgi8BzAJQ8MkPt8ipXnR73rnD7EmZ0HFFb7jdQU24TynGW1Ooqin2KVDN9voSC+7xhqbbCd2cjGUepb6RObnyg==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.2.tgz", + "integrity": "sha512-lF7S0UmXI5Pd8bmHvMdPKI4u4S5McxmHnzJhrYi9ZQ6wE+DA8JN5BzVC5EEBuduWWDaiJ8u6YhVOCmThBli+rw==", "dependencies": { - "@remix-run/router": "1.3.2" + "@remix-run/router": "1.3.3" }, "engines": { "node": ">=14" @@ -13136,12 +13136,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.1.tgz", - "integrity": "sha512-67EXNfkQgf34P7+PSb6VlBuaacGhkKn3kpE51+P6zYSG2kiRoumXEL6e27zTa9+PGF2MNXbgIUHTVlleLbIcHQ==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.2.tgz", + "integrity": "sha512-N/oAF1Shd7g4tWy+75IIufCGsHBqT74tnzHQhbiUTYILYF0Blk65cg+HPZqwC+6SqEyx033nKqU7by38v3lBZg==", "dependencies": { - "@remix-run/router": "1.3.2", - "react-router": "6.8.1" + "@remix-run/router": "1.3.3", + "react-router": "6.8.2" }, "engines": { "node": ">=14" @@ -21045,9 +21045,9 @@ } }, "@remix-run/router": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.2.tgz", - "integrity": "sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA==" + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.3.tgz", + "integrity": "sha512-YRHie1yQEj0kqqCTCJEfHqYSSNlZQ696QJG+MMiW4mxSl9I0ojz/eRhJS4fs88Z5i6D1SmoF9d3K99/QOhI8/w==" }, "@rollup/plugin-babel": { "version": "5.3.1", @@ -28721,20 +28721,20 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "react-router": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.1.tgz", - "integrity": "sha512-Jgi8BzAJQ8MkPt8ipXnR73rnD7EmZ0HFFb7jdQU24TynGW1Ooqin2KVDN9voSC+7xhqbbCd2cjGUepb6RObnyg==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.2.tgz", + "integrity": "sha512-lF7S0UmXI5Pd8bmHvMdPKI4u4S5McxmHnzJhrYi9ZQ6wE+DA8JN5BzVC5EEBuduWWDaiJ8u6YhVOCmThBli+rw==", "requires": { - "@remix-run/router": "1.3.2" + "@remix-run/router": "1.3.3" } }, "react-router-dom": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.1.tgz", - "integrity": "sha512-67EXNfkQgf34P7+PSb6VlBuaacGhkKn3kpE51+P6zYSG2kiRoumXEL6e27zTa9+PGF2MNXbgIUHTVlleLbIcHQ==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.2.tgz", + "integrity": "sha512-N/oAF1Shd7g4tWy+75IIufCGsHBqT74tnzHQhbiUTYILYF0Blk65cg+HPZqwC+6SqEyx033nKqU7by38v3lBZg==", "requires": { - "@remix-run/router": "1.3.2", - "react-router": "6.8.1" + "@remix-run/router": "1.3.3", + "react-router": "6.8.2" } }, "read-file-stdin": { diff --git a/package.json b/package.json index f8c9f45023..5bc2a3b78f 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "pdfjs-dist": "2.16.105", "react": "17.0.2", "react-dom": "17.0.2", - "react-router-dom": "6.8.1", + "react-router-dom": "6.8.2", "resize-observer-polyfill": "1.5.1", "screenfull": "6.0.2", "sortablejs": "1.15.0", From b55a3751f236ebbf4b73ce6e8721a1155571b555 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Mar 2023 00:56:50 +0000 Subject: [PATCH 17/65] Update Linters to v5.54.0 --- package-lock.json | 164 +++++++++++++++++++++++----------------------- package.json | 4 +- 2 files changed, 84 insertions(+), 84 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0f909a9694..a00e6750f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,8 +68,8 @@ "@types/lodash-es": "4.17.6", "@types/react": "17.0.53", "@types/react-dom": "17.0.19", - "@typescript-eslint/eslint-plugin": "5.53.0", - "@typescript-eslint/parser": "5.53.0", + "@typescript-eslint/eslint-plugin": "5.54.0", + "@typescript-eslint/parser": "5.54.0", "@uupaa/dynamic-import-polyfill": "1.0.2", "autoprefixer": "10.4.13", "babel-loader": "9.1.2", @@ -3200,14 +3200,14 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.53.0.tgz", - "integrity": "sha512-alFpFWNucPLdUOySmXCJpzr6HKC3bu7XooShWM+3w/EL6J2HIoB2PFxpLnq4JauWVk6DiVeNKzQlFEaE+X9sGw==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.0.tgz", + "integrity": "sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.53.0", - "@typescript-eslint/type-utils": "5.53.0", - "@typescript-eslint/utils": "5.53.0", + "@typescript-eslint/scope-manager": "5.54.0", + "@typescript-eslint/type-utils": "5.54.0", + "@typescript-eslint/utils": "5.54.0", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", @@ -3249,14 +3249,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.53.0.tgz", - "integrity": "sha512-MKBw9i0DLYlmdOb3Oq/526+al20AJZpANdT6Ct9ffxcV8nKCHz63t/S0IhlTFNsBIHJv+GY5SFJ0XfqVeydQrQ==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.0.tgz", + "integrity": "sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.53.0", - "@typescript-eslint/types": "5.53.0", - "@typescript-eslint/typescript-estree": "5.53.0", + "@typescript-eslint/scope-manager": "5.54.0", + "@typescript-eslint/types": "5.54.0", + "@typescript-eslint/typescript-estree": "5.54.0", "debug": "^4.3.4" }, "engines": { @@ -3276,13 +3276,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.53.0.tgz", - "integrity": "sha512-Opy3dqNsp/9kBBeCPhkCNR7fmdSQqA+47r21hr9a14Bx0xnkElEQmhoHga+VoaoQ6uDHjDKmQPIYcUcKJifS7w==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.54.0.tgz", + "integrity": "sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.53.0", - "@typescript-eslint/visitor-keys": "5.53.0" + "@typescript-eslint/types": "5.54.0", + "@typescript-eslint/visitor-keys": "5.54.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3293,13 +3293,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.53.0.tgz", - "integrity": "sha512-HO2hh0fmtqNLzTAme/KnND5uFNwbsdYhCZghK2SoxGp3Ifn2emv+hi0PBUjzzSh0dstUIFqOj3bp0AwQlK4OWw==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.54.0.tgz", + "integrity": "sha512-WI+WMJ8+oS+LyflqsD4nlXMsVdzTMYTxl16myXPaCXnSgc7LWwMsjxQFZCK/rVmTZ3FN71Ct78ehO9bRC7erYQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.53.0", - "@typescript-eslint/utils": "5.53.0", + "@typescript-eslint/typescript-estree": "5.54.0", + "@typescript-eslint/utils": "5.54.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -3320,9 +3320,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.53.0.tgz", - "integrity": "sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.54.0.tgz", + "integrity": "sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3333,13 +3333,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.53.0.tgz", - "integrity": "sha512-eKmipH7QyScpHSkhbptBBYh9v8FxtngLquq292YTEQ1pxVs39yFBlLC1xeIZcPPz1RWGqb7YgERJRGkjw8ZV7w==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.0.tgz", + "integrity": "sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.53.0", - "@typescript-eslint/visitor-keys": "5.53.0", + "@typescript-eslint/types": "5.54.0", + "@typescript-eslint/visitor-keys": "5.54.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3404,16 +3404,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.53.0.tgz", - "integrity": "sha512-VUOOtPv27UNWLxFwQK/8+7kvxVC+hPHNsJjzlJyotlaHjLSIgOCKj9I0DBUjwOOA64qjBwx5afAPjksqOxMO0g==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.54.0.tgz", + "integrity": "sha512-cuwm8D/Z/7AuyAeJ+T0r4WZmlnlxQ8wt7C7fLpFlKMR+dY6QO79Cq1WpJhvZbMA4ZeZGHiRWnht7ZJ8qkdAunw==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.53.0", - "@typescript-eslint/types": "5.53.0", - "@typescript-eslint/typescript-estree": "5.53.0", + "@typescript-eslint/scope-manager": "5.54.0", + "@typescript-eslint/types": "5.54.0", + "@typescript-eslint/typescript-estree": "5.54.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -3445,12 +3445,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.53.0.tgz", - "integrity": "sha512-JqNLnX3leaHFZEN0gCh81sIvgrp/2GOACZNgO4+Tkf64u51kTpAyWFOY8XHx8XuXr3N2C9zgPPHtcpMg6z1g0w==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.0.tgz", + "integrity": "sha512-xu4wT7aRCakGINTLGeyGqDn+78BwFlggwBjnHa1ar/KaGagnmwLYmlrXIrgAaQ3AE1Vd6nLfKASm7LrFHNbKGA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.53.0", + "@typescript-eslint/types": "5.54.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -21445,14 +21445,14 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.53.0.tgz", - "integrity": "sha512-alFpFWNucPLdUOySmXCJpzr6HKC3bu7XooShWM+3w/EL6J2HIoB2PFxpLnq4JauWVk6DiVeNKzQlFEaE+X9sGw==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.0.tgz", + "integrity": "sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.53.0", - "@typescript-eslint/type-utils": "5.53.0", - "@typescript-eslint/utils": "5.53.0", + "@typescript-eslint/scope-manager": "5.54.0", + "@typescript-eslint/type-utils": "5.54.0", + "@typescript-eslint/utils": "5.54.0", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", @@ -21474,53 +21474,53 @@ } }, "@typescript-eslint/parser": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.53.0.tgz", - "integrity": "sha512-MKBw9i0DLYlmdOb3Oq/526+al20AJZpANdT6Ct9ffxcV8nKCHz63t/S0IhlTFNsBIHJv+GY5SFJ0XfqVeydQrQ==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.0.tgz", + "integrity": "sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.53.0", - "@typescript-eslint/types": "5.53.0", - "@typescript-eslint/typescript-estree": "5.53.0", + "@typescript-eslint/scope-manager": "5.54.0", + "@typescript-eslint/types": "5.54.0", + "@typescript-eslint/typescript-estree": "5.54.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.53.0.tgz", - "integrity": "sha512-Opy3dqNsp/9kBBeCPhkCNR7fmdSQqA+47r21hr9a14Bx0xnkElEQmhoHga+VoaoQ6uDHjDKmQPIYcUcKJifS7w==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.54.0.tgz", + "integrity": "sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.53.0", - "@typescript-eslint/visitor-keys": "5.53.0" + "@typescript-eslint/types": "5.54.0", + "@typescript-eslint/visitor-keys": "5.54.0" } }, "@typescript-eslint/type-utils": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.53.0.tgz", - "integrity": "sha512-HO2hh0fmtqNLzTAme/KnND5uFNwbsdYhCZghK2SoxGp3Ifn2emv+hi0PBUjzzSh0dstUIFqOj3bp0AwQlK4OWw==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.54.0.tgz", + "integrity": "sha512-WI+WMJ8+oS+LyflqsD4nlXMsVdzTMYTxl16myXPaCXnSgc7LWwMsjxQFZCK/rVmTZ3FN71Ct78ehO9bRC7erYQ==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.53.0", - "@typescript-eslint/utils": "5.53.0", + "@typescript-eslint/typescript-estree": "5.54.0", + "@typescript-eslint/utils": "5.54.0", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.53.0.tgz", - "integrity": "sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.54.0.tgz", + "integrity": "sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.53.0.tgz", - "integrity": "sha512-eKmipH7QyScpHSkhbptBBYh9v8FxtngLquq292YTEQ1pxVs39yFBlLC1xeIZcPPz1RWGqb7YgERJRGkjw8ZV7w==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.0.tgz", + "integrity": "sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.53.0", - "@typescript-eslint/visitor-keys": "5.53.0", + "@typescript-eslint/types": "5.54.0", + "@typescript-eslint/visitor-keys": "5.54.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -21560,16 +21560,16 @@ } }, "@typescript-eslint/utils": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.53.0.tgz", - "integrity": "sha512-VUOOtPv27UNWLxFwQK/8+7kvxVC+hPHNsJjzlJyotlaHjLSIgOCKj9I0DBUjwOOA64qjBwx5afAPjksqOxMO0g==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.54.0.tgz", + "integrity": "sha512-cuwm8D/Z/7AuyAeJ+T0r4WZmlnlxQ8wt7C7fLpFlKMR+dY6QO79Cq1WpJhvZbMA4ZeZGHiRWnht7ZJ8qkdAunw==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.53.0", - "@typescript-eslint/types": "5.53.0", - "@typescript-eslint/typescript-estree": "5.53.0", + "@typescript-eslint/scope-manager": "5.54.0", + "@typescript-eslint/types": "5.54.0", + "@typescript-eslint/typescript-estree": "5.54.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -21587,12 +21587,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.53.0.tgz", - "integrity": "sha512-JqNLnX3leaHFZEN0gCh81sIvgrp/2GOACZNgO4+Tkf64u51kTpAyWFOY8XHx8XuXr3N2C9zgPPHtcpMg6z1g0w==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.0.tgz", + "integrity": "sha512-xu4wT7aRCakGINTLGeyGqDn+78BwFlggwBjnHa1ar/KaGagnmwLYmlrXIrgAaQ3AE1Vd6nLfKASm7LrFHNbKGA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.53.0", + "@typescript-eslint/types": "5.54.0", "eslint-visitor-keys": "^3.3.0" }, "dependencies": { diff --git a/package.json b/package.json index f8c9f45023..ad691b532d 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "@types/lodash-es": "4.17.6", "@types/react": "17.0.53", "@types/react-dom": "17.0.19", - "@typescript-eslint/eslint-plugin": "5.53.0", - "@typescript-eslint/parser": "5.53.0", + "@typescript-eslint/eslint-plugin": "5.54.0", + "@typescript-eslint/parser": "5.54.0", "@uupaa/dynamic-import-polyfill": "1.0.2", "autoprefixer": "10.4.13", "babel-loader": "9.1.2", From 5e51616e18e9565719906e39d8608ae5a56e68a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3bert=20=C3=96rn=20Ketilsson?= Date: Tue, 7 Mar 2023 23:52:07 +0000 Subject: [PATCH 18/65] Translated using Weblate (Icelandic) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/is/ --- src/strings/is-is.json | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/strings/is-is.json b/src/strings/is-is.json index b4b01a1fda..585b335c18 100644 --- a/src/strings/is-is.json +++ b/src/strings/is-is.json @@ -447,6 +447,13 @@ "Mute": "Þagga", "MusicArtist": "Tónlistarmaður", "MusicAlbum": "Tónlistaralbúm", - "ButtonCast": "Senda efni út í tæki", - "AddToFavorites": "Bæta við eftirlæti" + "ButtonCast": "Senda út í tæki", + "AddToFavorites": "Bæta við eftirlæti", + "ButtonPlayer": "Spilari", + "AgeValue": "({0} ára)", + "ApiKeysCaption": "Listi yfir núverandi virkum API lyklum", + "ButtonActivate": "Virkja", + "ButtonClose": "Loka", + "ButtonSpace": "Bil", + "Authorize": "Heimila" } From 47c13444ccef523bbfa192cbcdb685babe76f76c Mon Sep 17 00:00:00 2001 From: Pier-Luc Ducharme Date: Fri, 30 Dec 2022 10:24:09 -0500 Subject: [PATCH 19/65] Add eslint max-params rule with a max of 7 --- .eslintrc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.js b/.eslintrc.js index 53dd01ff25..e2811f35a9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -46,6 +46,7 @@ module.exports = { 'keyword-spacing': ['error'], 'no-throw-literal': ['error'], 'max-statements-per-line': ['error'], + 'max-params': ['error', 7], 'no-duplicate-imports': ['error'], 'no-empty-function': ['error'], 'no-floating-decimal': ['error'], From dc5ab265f694beaf09d888767bc1d8cbb47adfa2 Mon Sep 17 00:00:00 2001 From: Pier-Luc Ducharme Date: Fri, 30 Dec 2022 10:40:20 -0500 Subject: [PATCH 20/65] Refactor cardBuilder to follow max-params rule --- src/components/cardbuilder/cardBuilder.js | 40 ++++++++++------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/components/cardbuilder/cardBuilder.js b/src/components/cardbuilder/cardBuilder.js index 658837df83..657a4102d9 100644 --- a/src/components/cardbuilder/cardBuilder.js +++ b/src/components/cardbuilder/cardBuilder.js @@ -773,27 +773,24 @@ import { appRouter } from '../appRouter'; * @param {Object} item - Item used to generate the footer text. * @param {Object} apiClient - API client instance. * @param {Object} options - Options used to generate the footer text. - * @param {string} showTitle - Flag to show the title in the footer. - * @param {boolean} forceName - Flag to force showing the name of the item. - * @param {boolean} overlayText - Flag to show overlay text. - * @param {Object} imgUrl - Object representing the card's image URL. * @param {string} footerClass - CSS classes of the footer element. * @param {string} progressHtml - HTML markup of the progress bar element. - * @param {string} logoUrl - URL of the logo for the item. - * @param {boolean} isOuterFooter - Flag to mark the text as outer footer. + * @param {Object} flags - Various flags for the footer + * @param {Object} urls - Various urls for the footer * @returns {string} HTML markup of the card's footer text element. */ - function getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerClass, progressHtml, logoUrl, isOuterFooter) { + function getCardFooterText(item, apiClient, options, footerClass, progressHtml, flags, urls) { item = item.ProgramInfo || item; let html = ''; - if (logoUrl) { - html += ''; + if (urls.logoUrl) { + html += ''; } - const showOtherText = isOuterFooter ? !overlayText : overlayText; + const showTitle = options.showTitle === 'auto' ? true : (options.showTitle || item.Type === 'PhotoAlbum' || item.Type === 'Folder'); + const showOtherText = flags.isOuterFooter ? !flags.overlayText : flags.overlayText; - if (isOuterFooter && options.cardLayout && layoutManager.mobile && options.cardFooterAside !== 'none') { + if (flags.isOuterFooter && options.cardLayout && layoutManager.mobile && options.cardFooterAside !== 'none') { html += ``; } @@ -805,7 +802,7 @@ import { appRouter } from '../appRouter'; let titleAdded; if (showOtherText && (options.showParentTitle || options.showParentTitleOrTitle) && !parentTitleUnderneath) { - if (isOuterFooter && item.Type === 'Episode' && item.SeriesName) { + if (flags.isOuterFooter && item.Type === 'Episode' && item.SeriesName) { if (item.SeriesId) { lines.push(getTextActionButton({ Id: item.SeriesId, @@ -835,7 +832,7 @@ import { appRouter } from '../appRouter'; } let showMediaTitle = (showTitle && !titleAdded) || (options.showParentTitleOrTitle && !lines.length); - if (!showMediaTitle && !titleAdded && (showTitle || forceName)) { + if (!showMediaTitle && !titleAdded && (showTitle || flags.forceName)) { showMediaTitle = true; } @@ -856,7 +853,7 @@ import { appRouter } from '../appRouter'; if (showOtherText) { if (options.showParentTitle && parentTitleUnderneath) { - if (isOuterFooter && item.AlbumArtists && item.AlbumArtists.length) { + if (flags.isOuterFooter && item.AlbumArtists && item.AlbumArtists.length) { item.AlbumArtists[0].Type = 'MusicArtist'; item.AlbumArtists[0].IsFolder = true; lines.push(getTextActionButton(item.AlbumArtists[0], null, serverId)); @@ -991,23 +988,23 @@ import { appRouter } from '../appRouter'; } } - if ((showTitle || !imgUrl) && forceName && overlayText && lines.length === 1) { + if ((showTitle || !urls.imgUrl) && flags.forceName && flags.overlayText && lines.length === 1) { lines = []; } - if (overlayText && showTitle) { + if (flags.overlayText && showTitle) { lines = [escapeHtml(item.Name)]; } - const addRightTextMargin = isOuterFooter && options.cardLayout && !options.centerText && options.cardFooterAside !== 'none' && layoutManager.mobile; + const addRightTextMargin = flags.isOuterFooter && options.cardLayout && !options.centerText && options.cardFooterAside !== 'none' && layoutManager.mobile; - html += getCardTextLines(lines, cssClass, !options.overlayText, isOuterFooter, options.cardLayout, addRightTextMargin, options.lines); + html += getCardTextLines(lines, cssClass, !options.overlayText, flags.isOuterFooter, options.cardLayout, addRightTextMargin, options.lines); if (progressHtml) { html += progressHtml; } - if (html && (!isOuterFooter || logoUrl || options.cardLayout)) { + if (html && (!flags.isOuterFooter || urls.logoUrl || options.cardLayout)) { html = '
' + html; //cardFooter @@ -1217,7 +1214,6 @@ import { appRouter } from '../appRouter'; const forceName = imgInfo.forceName; - const showTitle = options.showTitle === 'auto' ? true : (options.showTitle || item.Type === 'PhotoAlbum' || item.Type === 'Folder'); const overlayText = options.overlayText; let cardImageContainerClass = 'cardImageContainer'; @@ -1265,7 +1261,7 @@ import { appRouter } from '../appRouter'; logoUrl = null; footerCssClass = progressHtml ? 'innerCardFooter fullInnerCardFooter' : 'innerCardFooter'; - innerCardFooter += getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, logoUrl, false); + innerCardFooter += getCardFooterText(item, apiClient, options, footerCssClass, progressHtml, {forceName: forceName, overlayText: overlayText, isOuterFooter: false}, {imgUrl: imgUrl, logoUrl: logoUrl}); footerOverlayed = true; } else if (progressHtml) { innerCardFooter += '
'; @@ -1292,7 +1288,7 @@ import { appRouter } from '../appRouter'; logoUrl = null; } - outerCardFooter = getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, logoUrl, true); + outerCardFooter = getCardFooterText(item, apiClient, options, footerCssClass, progressHtml, {forceName: forceName, overlayText: overlayText, isOuterFooter: true}, {imgUrl: imgUrl, logoUrl: logoUrl}); } if (outerCardFooter && !options.cardLayout) { From 5e5988c1077451b44c44d403394fc2b3726bd43e Mon Sep 17 00:00:00 2001 From: Pier-Luc Ducharme Date: Fri, 30 Dec 2022 12:55:07 -0500 Subject: [PATCH 21/65] Refactor guide to follow max-params rule --- src/components/guide/guide.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/guide/guide.js b/src/components/guide/guide.js index e353d562ab..5e4ee8af00 100644 --- a/src/components/guide/guide.js +++ b/src/components/guide/guide.js @@ -345,7 +345,9 @@ function Guide(options) { } apiClient.getLiveTvPrograms(programQuery).then(function (programsResult) { - renderGuide(context, date, channelsResult.Items, programsResult.Items, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender); + const guideOptions = {focusProgramOnRender: focusProgramOnRender, scrollToTimeMs: scrollToTimeMs, focusToTimeMs: focusToTimeMs, startTimeOfDayMs: startTimeOfDayMs}; + + renderGuide(context, date, channelsResult.Items, programsResult.Items, renderOptions, guideOptions, apiClient); hideLoading(); }); @@ -667,7 +669,7 @@ function Guide(options) { return (channelIndex * 10000000) + (start.getTime() / 60000); } - function renderGuide(context, date, channels, programs, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) { + function renderGuide(context, date, channels, programs, renderOptions, guideOptions, apiClient) { programs.sort(function (a, b) { return getProgramSortOrder(a, channels) - getProgramSortOrder(b, channels); }); @@ -689,11 +691,11 @@ function Guide(options) { items = {}; renderPrograms(context, date, channels, programs, renderOptions); - if (focusProgramOnRender) { - focusProgram(context, itemId, channelRowId, focusToTimeMs, startTimeOfDayMs); + if (guideOptions.focusProgramOnRender) { + focusProgram(context, itemId, channelRowId, guideOptions.focusToTimeMs, guideOptions.startTimeOfDayMs); } - scrollProgramGridToTimeMs(context, scrollToTimeMs, startTimeOfDayMs); + scrollProgramGridToTimeMs(context, guideOptions.scrollToTimeMs, guideOptions.startTimeOfDayMs); } function scrollProgramGridToTimeMs(context, scrollToTimeMs, startTimeOfDayMs) { From e9369e40bdcd41a4f6f1c8c9c86dd424f162d63b Mon Sep 17 00:00:00 2001 From: Pier-Luc Ducharme Date: Fri, 30 Dec 2022 13:34:50 -0500 Subject: [PATCH 22/65] Refactor imageeditor to follow max-params rule --- src/components/imageeditor/imageeditor.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/components/imageeditor/imageeditor.js b/src/components/imageeditor/imageeditor.js index 039770a217..85916e5cf8 100644 --- a/src/components/imageeditor/imageeditor.js +++ b/src/components/imageeditor/imageeditor.js @@ -96,7 +96,7 @@ import template from './imageeditor.template.html'; return apiClient.getScaledImageUrl(item.Id || item.ItemId, options); } - function getCardHtml(image, index, numImages, apiClient, imageProviders, imageSize, tagName, enableFooterButtons) { + function getCardHtml(image, apiClient, options) { // TODO move card creation code to Card component let html = ''; @@ -106,7 +106,7 @@ import template from './imageeditor.template.html'; cssClass += ' backdropCard backdropCard-scalable'; - if (tagName === 'button') { + if (options.tagName === 'button') { cssClass += ' btnImageCard'; if (layoutManager.tv) { @@ -122,7 +122,7 @@ import template from './imageeditor.template.html'; html += '
'; @@ -151,23 +151,23 @@ import template from './imageeditor.template.html'; } html += '
'; - if (enableFooterButtons) { + if (options.enableFooterButtons) { html += '
'; if (image.ImageType === 'Backdrop') { - if (index > 0) { + if (options.index > 0) { html += ''; } else { html += ''; } - if (index < numImages - 1) { + if (options.index < options.numImages - 1) { html += ''; } else { html += ''; } } else { - if (imageProviders.length) { + if (options.imageProviders.length) { html += ''; } } @@ -178,7 +178,7 @@ import template from './imageeditor.template.html'; html += '
'; html += '
'; - html += ''; + html += ''; return html; } @@ -226,7 +226,8 @@ import template from './imageeditor.template.html'; for (let i = 0, length = images.length; i < length; i++) { const image = images[i]; - html += getCardHtml(image, i, length, apiClient, imageProviders, imageSize, tagName, enableFooterButtons); + const options = {index: i, numImages: length, imageProviders: imageProviders, imageSize: imageSize, tagName: tagName, enableFooterButtons: enableFooterButtons}; + html += getCardHtml(image, apiClient, options); } elem.innerHTML = html; From 6544b7c698c204cc06d0810a5dcdd2e4f86b78a9 Mon Sep 17 00:00:00 2001 From: Pier-Luc Ducharme Date: Fri, 30 Dec 2022 21:04:16 -0500 Subject: [PATCH 23/65] Refactor playbackmanager to follow max-params rule --- src/components/playback/playbackmanager.js | 166 +++++++++++++-------- 1 file changed, 102 insertions(+), 64 deletions(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index ffcd0e4d91..7591c22917 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -299,20 +299,20 @@ function getAudioMaxValues(deviceProfile) { } let startingPlaySession = new Date().getTime(); -function getAudioStreamUrl(item, transcodingProfile, directPlayContainers, maxBitrate, apiClient, maxAudioSampleRate, maxAudioBitDepth, maxAudioBitrate, startPosition) { +function getAudioStreamUrl(item, transcodingProfile, directPlayContainers, apiClient, startPosition, maxValues) { const url = 'Audio/' + item.Id + '/universal'; startingPlaySession++; return apiClient.getUrl(url, { UserId: apiClient.getCurrentUserId(), DeviceId: apiClient.deviceId(), - MaxStreamingBitrate: maxAudioBitrate || maxBitrate, + MaxStreamingBitrate: maxValues.maxAudioBitrate || maxValues.maxBitrate, Container: directPlayContainers, TranscodingContainer: transcodingProfile.Container || null, TranscodingProtocol: transcodingProfile.Protocol || null, AudioCodec: transcodingProfile.AudioCodec, - MaxAudioSampleRate: maxAudioSampleRate, - MaxAudioBitDepth: maxAudioBitDepth, + MaxAudioSampleRate: maxValues.maxAudioSampleRate, + MaxAudioBitDepth: maxValues.maxAudioBitDepth, api_key: apiClient.accessToken(), PlaySessionId: startingPlaySession, StartTimeTicks: startPosition || 0, @@ -344,7 +344,7 @@ function getAudioStreamUrlFromDeviceProfile(item, deviceProfile, maxBitrate, api const maxValues = getAudioMaxValues(deviceProfile); - return getAudioStreamUrl(item, transcodingProfile, directPlayContainers, maxBitrate, apiClient, maxValues.maxAudioSampleRate, maxValues.maxAudioBitDepth, maxValues.maxAudioBitrate, startPosition); + return getAudioStreamUrl(item, transcodingProfile, directPlayContainers, apiClient, startPosition, { maxBitrate: maxBitrate, ...maxValues }); } function getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPosition) { @@ -377,7 +377,7 @@ function getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPositio let streamUrl; if (item.MediaType === 'Audio' && !itemHelper.isLocalItem(item)) { - streamUrl = getAudioStreamUrl(item, audioTranscodingProfile, audioDirectPlayContainers, maxBitrate, apiClient, maxValues.maxAudioSampleRate, maxValues.maxAudioBitDepth, maxValues.maxAudioBitrate, startPosition); + streamUrl = getAudioStreamUrl(item, audioTranscodingProfile, audioDirectPlayContainers, apiClient, startPosition, { maxBitrate: maxBitrate, ...maxValues }); } streamUrls.push(streamUrl || ''); @@ -408,27 +408,12 @@ function setStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPositio }); } -function getPlaybackInfo(player, - apiClient, - item, - deviceProfile, - maxBitrate, - startPosition, - isPlayback, - mediaSourceId, - audioStreamIndex, - subtitleStreamIndex, - liveStreamId, - enableDirectPlay, - enableDirectStream, - allowVideoStreamCopy, - allowAudioStreamCopy, - secondarySubtitleStreamIndex) { +function getPlaybackInfo(player, apiClient, item, deviceProfile, mediaSourceId, liveStreamId, options) { if (!itemHelper.isLocalItem(item) && item.MediaType === 'Audio' && !player.useServerPlaybackInfoForAudio) { return Promise.resolve({ MediaSources: [ { - StreamUrl: getAudioStreamUrlFromDeviceProfile(item, deviceProfile, maxBitrate, apiClient, startPosition), + StreamUrl: getAudioStreamUrlFromDeviceProfile(item, deviceProfile, options.maxBitrate, apiClient, options.startPosition), Id: item.Id, MediaStreams: [], RunTimeTicks: item.RunTimeTicks @@ -446,10 +431,10 @@ function getPlaybackInfo(player, const query = { UserId: apiClient.getCurrentUserId(), - StartTimeTicks: startPosition || 0 + StartTimeTicks: options.startPosition || 0 }; - if (isPlayback) { + if (options.isPlayback) { query.IsPlayback = true; query.AutoOpenLiveStream = true; } else { @@ -457,27 +442,26 @@ function getPlaybackInfo(player, query.AutoOpenLiveStream = false; } - if (audioStreamIndex != null) { - query.AudioStreamIndex = audioStreamIndex; + if (options.audioStreamIndex != null) { + query.AudioStreamIndex = options.audioStreamIndex; } - if (subtitleStreamIndex != null) { - query.SubtitleStreamIndex = subtitleStreamIndex; + if (options.subtitleStreamIndex != null) { + query.SubtitleStreamIndex = options.subtitleStreamIndex; } - if (secondarySubtitleStreamIndex != null) { - query.SecondarySubtitleStreamIndex = secondarySubtitleStreamIndex; + if (options.secondarySubtitleStreamIndex != null) { + query.SecondarySubtitleStreamIndex = options.secondarySubtitleStreamIndex; } - if (enableDirectPlay != null) { - query.EnableDirectPlay = enableDirectPlay; + if (options.enableDirectPlay != null) { + query.EnableDirectPlay = options.enableDirectPlay; } - - if (enableDirectStream != null) { - query.EnableDirectStream = enableDirectStream; + if (options.enableDirectStream != null) { + query.EnableDirectStream = options.enableDirectStream; } - if (allowVideoStreamCopy != null) { - query.AllowVideoStreamCopy = allowVideoStreamCopy; + if (options.allowVideoStreamCopy != null) { + query.AllowVideoStreamCopy = options.allowVideoStreamCopy; } - if (allowAudioStreamCopy != null) { - query.AllowAudioStreamCopy = allowAudioStreamCopy; + if (options.allowAudioStreamCopy != null) { + query.AllowAudioStreamCopy = options.allowAudioStreamCopy; } if (mediaSourceId) { query.MediaSourceId = mediaSourceId; @@ -485,8 +469,8 @@ function getPlaybackInfo(player, if (liveStreamId) { query.LiveStreamId = liveStreamId; } - if (maxBitrate) { - query.MaxStreamingBitrate = maxBitrate; + if (options.maxBitrate) { + query.MaxStreamingBitrate = options.maxBitrate; } if (player.enableMediaProbe && !player.enableMediaProbe(item)) { query.EnableMediaProbe = false; @@ -537,7 +521,7 @@ function getOptimalMediaSource(apiClient, item, versions) { }); } -function getLiveStream(player, apiClient, item, playSessionId, deviceProfile, maxBitrate, startPosition, mediaSource, audioStreamIndex, subtitleStreamIndex) { +function getLiveStream(player, apiClient, item, playSessionId, deviceProfile, mediaSource, options) { const postData = { DeviceProfile: deviceProfile, OpenToken: mediaSource.OpenToken @@ -545,19 +529,19 @@ function getLiveStream(player, apiClient, item, playSessionId, deviceProfile, ma const query = { UserId: apiClient.getCurrentUserId(), - StartTimeTicks: startPosition || 0, + StartTimeTicks: options.startPosition || 0, ItemId: item.Id, PlaySessionId: playSessionId }; - if (maxBitrate) { - query.MaxStreamingBitrate = maxBitrate; + if (options.maxBitrate) { + query.MaxStreamingBitrate = options.maxBitrate; } - if (audioStreamIndex != null) { - query.AudioStreamIndex = audioStreamIndex; + if (options.audioStreamIndex != null) { + query.AudioStreamIndex = options.audioStreamIndex; } - if (subtitleStreamIndex != null) { - query.SubtitleStreamIndex = subtitleStreamIndex; + if (options.subtitleStreamIndex != null) { + query.SubtitleStreamIndex = options.subtitleStreamIndex; } // lastly, enforce player overrides for special situations @@ -1737,7 +1721,19 @@ class PlaybackManager { const currentPlayOptions = currentItem.playOptions || getDefaultPlayOptions(); - getPlaybackInfo(player, apiClient, currentItem, deviceProfile, maxBitrate, ticks, true, currentMediaSource.Id, audioStreamIndex, subtitleStreamIndex, liveStreamId, params.EnableDirectPlay, params.EnableDirectStream, params.AllowVideoStreamCopy, params.AllowAudioStreamCopy).then(function (result) { + const options = { + maxBitrate: maxBitrate, + startPosition: ticks, + isPlayback: true, + audioStreamIndex: audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex, + enableDirectPlay: params.EnableDirectPlay, + enableDirectStream: params.EnableDirectStream, + allowVideoStreamCopy: params.AllowVideoStreamCopy, + allowAudioStreamCopy: params.AllowAudioStreamCopy + }; + + getPlaybackInfo(player, apiClient, currentItem, deviceProfile, currentMediaSource.Id, liveStreamId, options).then(function (result) { if (validatePlaybackInfoResult(self, result)) { currentMediaSource = result.MediaSources[0]; @@ -2303,17 +2299,17 @@ class PlaybackManager { }, reject); } - function sendPlaybackListToPlayer(player, items, deviceProfile, maxBitrate, apiClient, startPositionTicks, mediaSourceId, audioStreamIndex, subtitleStreamIndex, startIndex) { - return setStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPositionTicks).then(function () { + function sendPlaybackListToPlayer(player, items, deviceProfile, apiClient, mediaSourceId, options) { + return setStreamUrls(items, deviceProfile, options.maxBitrate, apiClient, options.startPosition).then(function () { loading.hide(); return player.play({ items: items, - startPositionTicks: startPositionTicks || 0, + startPositionTicks: options.startPosition || 0, mediaSourceId: mediaSourceId, - audioStreamIndex: audioStreamIndex, - subtitleStreamIndex: subtitleStreamIndex, - startIndex: startIndex + audioStreamIndex: options.audioStreamIndex, + subtitleStreamIndex: options.subtitleStreamIndex, + startIndex: options.startIndex }); }); } @@ -2474,15 +2470,27 @@ class PlaybackManager { const mediaSourceId = playOptions.mediaSourceId; const audioStreamIndex = playOptions.audioStreamIndex; const subtitleStreamIndex = playOptions.subtitleStreamIndex; + const options = { + maxBitrate: maxBitrate, + startPosition: startPosition, + isPlayback: null, + audioStreamIndex: audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex, + startIndex: playOptions.startIndex, + enableDirectPlay: null, + enableDirectStream: null, + allowVideoStreamCopy: null, + allowAudioStreamCopy: null + }; if (player && !enableLocalPlaylistManagement(player)) { - return sendPlaybackListToPlayer(player, playOptions.items, deviceProfile, maxBitrate, apiClient, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex, playOptions.startIndex); + return sendPlaybackListToPlayer(player, playOptions.items, deviceProfile, apiClient, mediaSourceId, options); } // this reference was only needed by sendPlaybackListToPlayer playOptions.items = null; - return getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex).then(async (mediaSource) => { + return getPlaybackMediaSource(player, apiClient, deviceProfile, item, mediaSourceId, options).then(async (mediaSource) => { const user = await apiClient.getCurrentUser(); autoSetNextTracks(prevSource, mediaSource, user.Configuration.RememberAudioSelections, user.Configuration.RememberSubtitleSelections); @@ -2540,7 +2548,20 @@ class PlaybackManager { const maxBitrate = getSavedMaxStreamingBitrate(ServerConnections.getApiClient(item.ServerId), mediaType); return player.getDeviceProfile(item).then(function (deviceProfile) { - return getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, options.mediaSourceId, options.audioStreamIndex, options.subtitleStreamIndex).then(function (mediaSource) { + const mediaOptions = { + maxBitrate: maxBitrate, + startPosition: startPosition, + isPlayback: null, + audioStreamIndex: options.audioStreamIndex, + subtitleStreamIndex: options.subtitleStreamIndex, + startIndex: null, + enableDirectPlay: null, + enableDirectStream: null, + allowVideoStreamCopy: null, + allowAudioStreamCopy: null + }; + + return getPlaybackMediaSource(player, apiClient, deviceProfile, item, options.mediaSourceId, mediaOptions).then(function (mediaSource) { return createStreamInfo(apiClient, item.MediaType, item, mediaSource, startPosition, player); }); }); @@ -2560,7 +2581,19 @@ class PlaybackManager { const maxBitrate = getSavedMaxStreamingBitrate(ServerConnections.getApiClient(item.ServerId), mediaType); return player.getDeviceProfile(item).then(function (deviceProfile) { - return getPlaybackInfo(player, apiClient, item, deviceProfile, maxBitrate, startPosition, false, null, null, null, null).then(function (playbackInfoResult) { + const mediaOptions = { + maxBitrate: maxBitrate, + startPosition: startPosition, + isPlayback: true, + audioStreamIndex: null, + subtitleStreamIndex: null, + enableDirectPlay: null, + enableDirectStream: null, + allowVideoStreamCopy: null, + allowAudioStreamCopy: null + }; + + return getPlaybackInfo(player, apiClient, item, deviceProfile, null, null, mediaOptions).then(function (playbackInfoResult) { return playbackInfoResult.MediaSources; }); }); @@ -2701,13 +2734,18 @@ class PlaybackManager { return tracks; } - function getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex) { - return getPlaybackInfo(player, apiClient, item, deviceProfile, maxBitrate, startPosition, true, mediaSourceId, audioStreamIndex, subtitleStreamIndex, null).then(function (playbackInfoResult) { + function getPlaybackMediaSource(player, apiClient, deviceProfile, item, mediaSourceId, options) { + options.isPlayback = true; + + return getPlaybackInfo(player, apiClient, item, deviceProfile, mediaSourceId, null, options).then(function (playbackInfoResult) { if (validatePlaybackInfoResult(self, playbackInfoResult)) { return getOptimalMediaSource(apiClient, item, playbackInfoResult.MediaSources).then(function (mediaSource) { if (mediaSource) { if (mediaSource.RequiresOpening && !mediaSource.LiveStreamId) { - return getLiveStream(player, apiClient, item, playbackInfoResult.PlaySessionId, deviceProfile, maxBitrate, startPosition, mediaSource, null, null).then(function (openLiveStreamResult) { + options.audioStreamIndex = null; + options.subtitleStreamIndex = null; + + return getLiveStream(player, apiClient, item, playbackInfoResult.PlaySessionId, deviceProfile, mediaSource, options).then(function (openLiveStreamResult) { return supportsDirectPlay(apiClient, item, openLiveStreamResult.MediaSource).then(function (result) { openLiveStreamResult.MediaSource.enableDirectPlay = result; return openLiveStreamResult.MediaSource; From 29f16d5a04089d8ff87b40405bce296537c19084 Mon Sep 17 00:00:00 2001 From: Pier-Luc Ducharme Date: Mon, 16 Jan 2023 21:27:49 -0500 Subject: [PATCH 24/65] Refactor userdatabuttons to follow max-params rule --- .../userdatabuttons/userdatabuttons.js | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/components/userdatabuttons/userdatabuttons.js b/src/components/userdatabuttons/userdatabuttons.js index c170a7cc0f..c5cb746f9c 100644 --- a/src/components/userdatabuttons/userdatabuttons.js +++ b/src/components/userdatabuttons/userdatabuttons.js @@ -12,7 +12,10 @@ const userDataMethods = { markFavorite: markFavorite }; -function getUserDataButtonHtml(method, itemId, serverId, buttonCssClass, iconCssClass, icon, tooltip, style) { +function getUserDataButtonHtml(method, itemId, serverId, icon, tooltip, style, classes) { + let buttonCssClass = classes.buttonCssClass; + let iconCssClass = classes.iconCssClass; + if (style === 'fab-mini') { style = 'fab'; buttonCssClass = buttonCssClass ? (buttonCssClass + ' mini') : 'mini'; @@ -97,6 +100,11 @@ function getIconsHtml(options) { const iconCssClass = options.iconCssClass; + const classes = { + buttonCssClass: btnCssClass, + iconCssClass: iconCssClass + }; + const serverId = item.ServerId; if (includePlayed !== false) { @@ -104,18 +112,21 @@ function getIconsHtml(options) { if (itemHelper.canMarkPlayed(item)) { if (userData.Played) { - html += getUserDataButtonHtml('markPlayed', itemId, serverId, btnCssClass + ' btnUserDataOn', iconCssClass, 'check', tooltipPlayed, style); + const buttonCssClass = classes.buttonCssClass + ' btnUserDataOn'; + html += getUserDataButtonHtml('markPlayed', itemId, serverId, 'check', tooltipPlayed, style, {buttonCssClass: buttonCssClass, ...classes}); } else { - html += getUserDataButtonHtml('markPlayed', itemId, serverId, btnCssClass, iconCssClass, 'check', tooltipPlayed, style); + html += getUserDataButtonHtml('markPlayed', itemId, serverId, 'check', tooltipPlayed, style, classes); } } } const tooltipFavorite = globalize.translate('Favorite'); if (userData.IsFavorite) { - html += getUserDataButtonHtml('markFavorite', itemId, serverId, btnCssClass + ' btnUserData btnUserDataOn', iconCssClass, 'favorite', tooltipFavorite, style); + const buttonCssClass = classes.buttonCssClass + ' btnUserData btnUserDataOn'; + html += getUserDataButtonHtml('markFavorite', itemId, serverId, 'favorite', tooltipFavorite, style, {buttonCssClass: buttonCssClass, ...classes}); } else { - html += getUserDataButtonHtml('markFavorite', itemId, serverId, btnCssClass + ' btnUserData', iconCssClass, 'favorite', tooltipFavorite, style); + classes.buttonCssClass += ' btnUserData'; + html += getUserDataButtonHtml('markFavorite', itemId, serverId, 'favorite', tooltipFavorite, style, classes); } return html; From a3c330b4e1c67b75e8a3e3d05e5f1d8a102b184c Mon Sep 17 00:00:00 2001 From: Pier-Luc Ducharme Date: Mon, 30 Jan 2023 22:52:49 -0500 Subject: [PATCH 25/65] Add contributor to project --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index c867d81580..f3dbfec6da 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -59,6 +59,7 @@ - [Vankerkom](https://github.com/vankerkom) - [edvwib](https://github.com/edvwib) - [Rob Farraher](https://github.com/farraherbg) + - [Pier-Luc Ducharme](https://github.com/pl-ducharme) # Emby Contributors From cf5d65d86ec4c44c72e8c73deee998d931543102 Mon Sep 17 00:00:00 2001 From: Pier-Luc Ducharme Date: Thu, 9 Feb 2023 21:35:59 -0500 Subject: [PATCH 26/65] Simplify code with object shorthand syntax --- src/components/cardbuilder/cardBuilder.js | 4 +-- src/components/guide/guide.js | 2 +- src/components/imageeditor/imageeditor.js | 4 +-- src/components/playback/playbackmanager.js | 30 +++++++++---------- .../userdatabuttons/userdatabuttons.js | 11 ++----- 5 files changed, 23 insertions(+), 28 deletions(-) diff --git a/src/components/cardbuilder/cardBuilder.js b/src/components/cardbuilder/cardBuilder.js index 657a4102d9..a0c4aaf09b 100644 --- a/src/components/cardbuilder/cardBuilder.js +++ b/src/components/cardbuilder/cardBuilder.js @@ -1261,7 +1261,7 @@ import { appRouter } from '../appRouter'; logoUrl = null; footerCssClass = progressHtml ? 'innerCardFooter fullInnerCardFooter' : 'innerCardFooter'; - innerCardFooter += getCardFooterText(item, apiClient, options, footerCssClass, progressHtml, {forceName: forceName, overlayText: overlayText, isOuterFooter: false}, {imgUrl: imgUrl, logoUrl: logoUrl}); + innerCardFooter += getCardFooterText(item, apiClient, options, footerCssClass, progressHtml, { forceName, overlayText, isOuterFooter: false }, { imgUrl, logoUrl }); footerOverlayed = true; } else if (progressHtml) { innerCardFooter += '
'; @@ -1288,7 +1288,7 @@ import { appRouter } from '../appRouter'; logoUrl = null; } - outerCardFooter = getCardFooterText(item, apiClient, options, footerCssClass, progressHtml, {forceName: forceName, overlayText: overlayText, isOuterFooter: true}, {imgUrl: imgUrl, logoUrl: logoUrl}); + outerCardFooter = getCardFooterText(item, apiClient, options, footerCssClass, progressHtml, { forceName, overlayText, isOuterFooter: true }, { imgUrl, logoUrl }); } if (outerCardFooter && !options.cardLayout) { diff --git a/src/components/guide/guide.js b/src/components/guide/guide.js index 5e4ee8af00..63a682ee65 100644 --- a/src/components/guide/guide.js +++ b/src/components/guide/guide.js @@ -345,7 +345,7 @@ function Guide(options) { } apiClient.getLiveTvPrograms(programQuery).then(function (programsResult) { - const guideOptions = {focusProgramOnRender: focusProgramOnRender, scrollToTimeMs: scrollToTimeMs, focusToTimeMs: focusToTimeMs, startTimeOfDayMs: startTimeOfDayMs}; + const guideOptions = { focusProgramOnRender, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs }; renderGuide(context, date, channelsResult.Items, programsResult.Items, renderOptions, guideOptions, apiClient); diff --git a/src/components/imageeditor/imageeditor.js b/src/components/imageeditor/imageeditor.js index 85916e5cf8..9130bd311c 100644 --- a/src/components/imageeditor/imageeditor.js +++ b/src/components/imageeditor/imageeditor.js @@ -132,7 +132,7 @@ import template from './imageeditor.template.html'; html += '
'; - const imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, {maxWidth: options.imageSize}); + const imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: options.imageSize }); html += '
'; @@ -226,7 +226,7 @@ import template from './imageeditor.template.html'; for (let i = 0, length = images.length; i < length; i++) { const image = images[i]; - const options = {index: i, numImages: length, imageProviders: imageProviders, imageSize: imageSize, tagName: tagName, enableFooterButtons: enableFooterButtons}; + const options = { index: i, numImages: length, imageProviders, imageSize, tagName, enableFooterButtons }; html += getCardHtml(image, apiClient, options); } diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 7591c22917..947f46eec8 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -344,7 +344,7 @@ function getAudioStreamUrlFromDeviceProfile(item, deviceProfile, maxBitrate, api const maxValues = getAudioMaxValues(deviceProfile); - return getAudioStreamUrl(item, transcodingProfile, directPlayContainers, apiClient, startPosition, { maxBitrate: maxBitrate, ...maxValues }); + return getAudioStreamUrl(item, transcodingProfile, directPlayContainers, apiClient, startPosition, { maxBitrate, ...maxValues }); } function getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPosition) { @@ -377,7 +377,7 @@ function getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPositio let streamUrl; if (item.MediaType === 'Audio' && !itemHelper.isLocalItem(item)) { - streamUrl = getAudioStreamUrl(item, audioTranscodingProfile, audioDirectPlayContainers, apiClient, startPosition, { maxBitrate: maxBitrate, ...maxValues }); + streamUrl = getAudioStreamUrl(item, audioTranscodingProfile, audioDirectPlayContainers, apiClient, startPosition, { maxBitrate, ...maxValues }); } streamUrls.push(streamUrl || ''); @@ -1722,11 +1722,11 @@ class PlaybackManager { const currentPlayOptions = currentItem.playOptions || getDefaultPlayOptions(); const options = { - maxBitrate: maxBitrate, + maxBitrate, startPosition: ticks, isPlayback: true, - audioStreamIndex: audioStreamIndex, - subtitleStreamIndex: subtitleStreamIndex, + audioStreamIndex, + subtitleStreamIndex, enableDirectPlay: params.EnableDirectPlay, enableDirectStream: params.EnableDirectStream, allowVideoStreamCopy: params.AllowVideoStreamCopy, @@ -2304,9 +2304,9 @@ class PlaybackManager { loading.hide(); return player.play({ - items: items, + items, startPositionTicks: options.startPosition || 0, - mediaSourceId: mediaSourceId, + mediaSourceId, audioStreamIndex: options.audioStreamIndex, subtitleStreamIndex: options.subtitleStreamIndex, startIndex: options.startIndex @@ -2471,11 +2471,11 @@ class PlaybackManager { const audioStreamIndex = playOptions.audioStreamIndex; const subtitleStreamIndex = playOptions.subtitleStreamIndex; const options = { - maxBitrate: maxBitrate, - startPosition: startPosition, + maxBitrate, + startPosition, isPlayback: null, - audioStreamIndex: audioStreamIndex, - subtitleStreamIndex: subtitleStreamIndex, + audioStreamIndex, + subtitleStreamIndex, startIndex: playOptions.startIndex, enableDirectPlay: null, enableDirectStream: null, @@ -2549,8 +2549,8 @@ class PlaybackManager { return player.getDeviceProfile(item).then(function (deviceProfile) { const mediaOptions = { - maxBitrate: maxBitrate, - startPosition: startPosition, + maxBitrate, + startPosition, isPlayback: null, audioStreamIndex: options.audioStreamIndex, subtitleStreamIndex: options.subtitleStreamIndex, @@ -2582,8 +2582,8 @@ class PlaybackManager { return player.getDeviceProfile(item).then(function (deviceProfile) { const mediaOptions = { - maxBitrate: maxBitrate, - startPosition: startPosition, + maxBitrate, + startPosition, isPlayback: true, audioStreamIndex: null, subtitleStreamIndex: null, diff --git a/src/components/userdatabuttons/userdatabuttons.js b/src/components/userdatabuttons/userdatabuttons.js index c5cb746f9c..f75bbce81e 100644 --- a/src/components/userdatabuttons/userdatabuttons.js +++ b/src/components/userdatabuttons/userdatabuttons.js @@ -99,12 +99,7 @@ function getIconsHtml(options) { } const iconCssClass = options.iconCssClass; - - const classes = { - buttonCssClass: btnCssClass, - iconCssClass: iconCssClass - }; - + const classes = { buttonCssClass: btnCssClass, iconCssClass: iconCssClass }; const serverId = item.ServerId; if (includePlayed !== false) { @@ -113,7 +108,7 @@ function getIconsHtml(options) { if (itemHelper.canMarkPlayed(item)) { if (userData.Played) { const buttonCssClass = classes.buttonCssClass + ' btnUserDataOn'; - html += getUserDataButtonHtml('markPlayed', itemId, serverId, 'check', tooltipPlayed, style, {buttonCssClass: buttonCssClass, ...classes}); + html += getUserDataButtonHtml('markPlayed', itemId, serverId, 'check', tooltipPlayed, style, { buttonCssClass, ...classes }); } else { html += getUserDataButtonHtml('markPlayed', itemId, serverId, 'check', tooltipPlayed, style, classes); } @@ -123,7 +118,7 @@ function getIconsHtml(options) { const tooltipFavorite = globalize.translate('Favorite'); if (userData.IsFavorite) { const buttonCssClass = classes.buttonCssClass + ' btnUserData btnUserDataOn'; - html += getUserDataButtonHtml('markFavorite', itemId, serverId, 'favorite', tooltipFavorite, style, {buttonCssClass: buttonCssClass, ...classes}); + html += getUserDataButtonHtml('markFavorite', itemId, serverId, 'favorite', tooltipFavorite, style, { buttonCssClass, ...classes }); } else { classes.buttonCssClass += ' btnUserData'; html += getUserDataButtonHtml('markFavorite', itemId, serverId, 'favorite', tooltipFavorite, style, classes); From ecb84ff351eddca7f069431edca3c795cfea5a00 Mon Sep 17 00:00:00 2001 From: WontTell Date: Wed, 8 Mar 2023 02:55:32 +0000 Subject: [PATCH 27/65] Translated using Weblate (Spanish (Latin America)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/es_419/ --- src/strings/es_419.json | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/strings/es_419.json b/src/strings/es_419.json index db7ec1884c..a09b64a0b9 100644 --- a/src/strings/es_419.json +++ b/src/strings/es_419.json @@ -571,7 +571,7 @@ "LabelSelectVersionToInstall": "Seleccionar versión a instalar:", "LabelSelectUsers": "Seleccionar usuarios:", "LabelSelectFolderGroupsHelp": "Las carpetas sin marcar serán mostradas individualmente en su propia vista.", - "LabelSelectFolderGroups": "Agrupar automáticamente el contenido de las siguientes carpetas a vistas como Películas, Música y TV:", + "LabelSelectFolderGroups": "Agrupar automáticamente el contenido de las siguientes carpetas a vistas como «Películas», «Música» y «TV»:", "LabelSeasonNumber": "Temporada número:", "LabelScreensaver": "Protector de pantalla:", "LabelScheduledTaskLastRan": "Última ejecución {0}, tomando {1}.", @@ -1006,7 +1006,7 @@ "LabelMaxResumePercentageHelp": "Los medios se consideran totalmente reproducidos si se detienen después de este tiempo.", "LabelMaxResumePercentage": "Porcentaje máximo para la reanudación:", "LabelMaxParentalRating": "Máxima clasificación parental permitida:", - "LabelMaxChromecastBitrate": "Calidad de transmisión de Chromecast:", + "LabelMaxChromecastBitrate": "Calidad de transmisión de Google Cast:", "LabelMaxBackdropsPerItem": "Número máximo de imágenes de fondo por elemento:", "LabelMatchType": "Tipo de coincidencia:", "LabelManufacturerUrl": "URL del fabricante:", @@ -1354,7 +1354,7 @@ "MessagePluginInstallError": "Ocurrió un error instalando el complemento.", "PlaybackRate": "Tasa de reproducción", "Data": "Datos", - "ButtonUseQuickConnect": "Usar conexión rápida", + "ButtonUseQuickConnect": "Usar «Conexión rápida»", "ButtonActivate": "Activar", "Authorize": "Autorizar", "LabelCurrentStatus": "Estado actual:", @@ -1366,7 +1366,7 @@ "TonemappingAlgorithmHelp": "El mapeo de tonos puede ser modificado. Si no estas familiarizado con estas opciones, solo manten el predeterminado. El valor recomendado es Hable.", "LabelTonemappingThresholdHelp": "El algoritmo de mapeo de tonos puede ser finamente ajustado para cada escena. Y el umbral es usado para detectar si la escena ha cambiado. Si los valores entre el promedio de brillo del fotograma actual y el promedio actual excede el valor de umbral, se vuelve a calcular el brillo promedio y máximo. Los valores recomendados y por defecto son entre 0.2 y 0.8.", "ThumbCard": "Miniatura", - "LabelMaxMuxingQueueSizeHelp": "Numero máximo de paquetes que pueden estar en búfer mientras se espera a que se inicialicen todas las trasmisiones. Intenta incrementarlos si encuentras el error \"Too many packets buffered for output stream\" en los registros de ffmpeg. El valor recomendado es 2048.", + "LabelMaxMuxingQueueSizeHelp": "Numero máximo de paquetes que pueden estar en búfer mientras se espera a que se inicialicen todas las trasmisiones. Intenta incrementarlos si encuentras el error «Too many packets buffered for output stream» en los registros de ffmpeg. El valor recomendado es 2048.", "LabelMaxMuxingQueueSize": "Tamaño máximo cola de mezclado:", "LabelTonemappingParamHelp": "Modifica el algoritmo de mapeo de tonos. Los valores recomendados y por defecto son NaN. Se puede dejar en blanco.", "LabelTonemappingParam": "Parámetro Mapeo de tonos:", @@ -1380,7 +1380,7 @@ "LabelTonemappingAlgorithm": "Seleccione el algoritmo de mapeo de tonos:", "AllowTonemappingHelp": "El mapeo de tonos puede transformar el rango dinámico de un video de HDR a SDR manteniendo la calidad de imagen y los colores, que son datos muy importantes para mostrar la imagen original. Actualmente solo funciona con videos HDR10 o HLG. Esto requiere los tiempos de ejecución OpenCL o CUDA correspondientes.", "EnableTonemapping": "Habilitar mapeo de tonos", - "LabelOpenclDeviceHelp": "Este es el dispositivo OpenCL que se utiliza para el mapeo de tonos. El lado izquierdo del punto es el número de plataforma y el lado derecho es el número de dispositivo en la plataforma. El valor predeterminado es 0.0. Se requiere la aplicación ffmpeg que contiene el método de aceleración de hardware OpenCL.", + "LabelOpenclDeviceHelp": "Este es el dispositivo OpenCL que se utiliza para el mapeo de tonos. El lado izquierdo del punto es el número de plataforma y el lado derecho es el número de dispositivo en la plataforma. El valor predeterminado es 0.0. Se requiere la aplicación FFmpeg que contiene el método de aceleración de hardware OpenCL.", "LabelOpenclDevice": "Dispositivo OpenCL:", "LabelColorPrimaries": "Colores primarios:", "LabelColorTransfer": "Transferencia de Color:", @@ -1400,22 +1400,22 @@ "SelectServer": "Seleccionar Servidor", "Restart": "Reiniciar", "ResetPassword": "Resetear contraseña", - "QuickConnectNotActive": "Conexión Rápida no esta habilitado en el servidor", - "QuickConnectNotAvailable": "Pregunte al administrador del servidor para habilitar Conexión Rápida", - "QuickConnectInvalidCode": "Código Conexión Rápida inválido", - "QuickConnectDescription": "Para ingresar con Conexión Rápida, seleccione el botón Conexión Rápida en el dispositivo del cual estas ingresando e ingrese el siguiente código.", - "QuickConnectDeactivated": "Conexión Rápida se desactivó antes de que se pudiera aprobar la solicitud de inicio de sesión", - "QuickConnectAuthorizeFail": "Código Conexión Rápida desconocido", - "QuickConnectAuthorizeSuccess": "Requiere autorización", + "QuickConnectNotActive": "«Conexión rápida» no está habilitado en este servidor", + "QuickConnectNotAvailable": "Pide al administrador del servidor que habilite la «Conexión rápida»", + "QuickConnectInvalidCode": "Código de «Conexión rápida» inválido", + "QuickConnectDescription": "Para ingresar con «Conexión rápida», seleccione el botón «Conexión rápida» en el dispositivo del cual estas ingresando e ingrese el código mostrado a continuación.", + "QuickConnectDeactivated": "La «Conexión rápida» se desactivó antes de que se pudiera aprobar la solicitud de inicio de sesión", + "QuickConnectAuthorizeFail": "Código de «Conexión rápida» desconocido", + "QuickConnectAuthorizeSuccess": "Solicitud autorizada", "QuickConnectAuthorizeCode": "Ingrese el código {0} para acceder", - "QuickConnectActivationSuccessful": "Activación Exitosa", - "QuickConnect": "Conexión Rápida", + "QuickConnectActivationSuccessful": "Activado exitosamente", + "QuickConnect": "Conexión rápida", "Profile": "Perfil", "PosterCard": "Imagen del Cartel", "Poster": "Cartel", "Photo": "Foto", "MusicVideos": "Videos musicales", - "LabelQuickConnectCode": "Código conexión rápida:", + "LabelQuickConnectCode": "Código de «Conexión rápida»:", "LabelKnownProxies": "Proxies conocidos:", "LabelIconMaxResHelp": "Resolución maxima de los iconos por medio de la función 'upnp:icon'.", "EnableAutoCast": "Establecer como Predeterminado", @@ -1519,7 +1519,7 @@ "LabelSlowResponseEnabled": "Log de alarma si la respuesta del servidor fue lenta", "UseEpisodeImagesInNextUpHelp": "Las secciones Siguiente y Continuar viendo utilizaran imagenes del episodio como miniaturas en lugar de miniaturas del show.", "UseEpisodeImagesInNextUp": "Usar imágenes de los episodios en \"Siguiente\" y \"Continuar Viendo\"", - "LabelLocalCustomCss": "El CSS personalizado aplica solo a este cliente. Puede quieras deshabilitar el CSS del servidor.", + "LabelLocalCustomCss": "Código CSS personalizado para estilo que aplica solo a este cliente. Puede que quiera deshabilitar el código CSS personalizado del servidor.", "LabelDisableCustomCss": "Desactivar el código CSS personalizado para la tematización/marca proporcionada desde el servidor.", "DisableCustomCss": "Deshabilitar CSS proveniente del servidor", "LabelAutomaticallyAddToCollectionHelp": "Cuando al menos 2 películas tengan el mismo nombre de colección, se añadirán automáticamente a dicha colección.", @@ -1574,5 +1574,6 @@ "LabelDummyChapterDurationHelp": "El intervalo de la extracción de las imágenes de los capítulos, en segundos.", "LabelDummyChapterCount": "Límite:", "LabelChapterImageResolution": "Resolución:", - "LabelChapterImageResolutionHelp": "La resolución de las imágenes de capítulos extraídas." + "LabelChapterImageResolutionHelp": "La resolución de las imágenes de capítulos extraídas.", + "LabelMaxDaysForNextUp": "Días máximos en «A continuación»:" } From b4f48571765f734c38da9e02de89cab620637a3b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Mar 2023 12:26:33 +0000 Subject: [PATCH 28/65] Update dependency dompurify to v3 --- 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 97116e92d6..7187af5881 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "classnames": "2.3.2", "core-js": "3.29.0", "date-fns": "2.29.3", - "dompurify": "2.4.4", + "dompurify": "3.0.1", "epubjs": "0.4.2", "escape-html": "1.0.3", "fast-text-encoding": "1.0.6", @@ -5965,9 +5965,9 @@ "integrity": "sha512-l32Xp/TLgWb8ReqbVJAFIvXmY7go4nTxxlWiAFyhoQw9RKEOHBZNnyGvJWqDVSPmq3Y9HlM4npqF/T6VMOXhww==" }, "node_modules/dompurify": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.4.tgz", - "integrity": "sha512-1e2SpqHiRx4DPvmRuXU5J0di3iQACwJM+mFGE2HAkkK7Tbnfk9WcghcAmyWc9CRrjyRRUpmuhPUH6LphQQR3EQ==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.1.tgz", + "integrity": "sha512-60tsgvPKwItxZZdfLmamp0MTcecCta3avOhsLgPZ0qcWt96OasFfhkeIRbJ6br5i0fQawT1/RBGB5L58/Jpwuw==" }, "node_modules/domutils": { "version": "1.7.0", @@ -23488,9 +23488,9 @@ "integrity": "sha512-l32Xp/TLgWb8ReqbVJAFIvXmY7go4nTxxlWiAFyhoQw9RKEOHBZNnyGvJWqDVSPmq3Y9HlM4npqF/T6VMOXhww==" }, "dompurify": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.4.tgz", - "integrity": "sha512-1e2SpqHiRx4DPvmRuXU5J0di3iQACwJM+mFGE2HAkkK7Tbnfk9WcghcAmyWc9CRrjyRRUpmuhPUH6LphQQR3EQ==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.1.tgz", + "integrity": "sha512-60tsgvPKwItxZZdfLmamp0MTcecCta3avOhsLgPZ0qcWt96OasFfhkeIRbJ6br5i0fQawT1/RBGB5L58/Jpwuw==" }, "domutils": { "version": "1.7.0", diff --git a/package.json b/package.json index 3d25ed4276..2d01fb941a 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "classnames": "2.3.2", "core-js": "3.29.0", "date-fns": "2.29.3", - "dompurify": "2.4.4", + "dompurify": "3.0.1", "epubjs": "0.4.2", "escape-html": "1.0.3", "fast-text-encoding": "1.0.6", From 64ecc3eae7f1c9b35b0f8154cb5fa43d3690ac95 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 8 Mar 2023 11:03:48 -0500 Subject: [PATCH 29/65] Add plugin types --- src/components/displaySettings/displaySettings.js | 3 ++- src/components/playback/playbackmanager.js | 7 ++++--- src/plugins/backdropScreensaver/plugin.js | 3 ++- src/plugins/bookPlayer/plugin.js | 3 ++- src/plugins/chromecastPlayer/plugin.js | 3 ++- src/plugins/comicsPlayer/plugin.js | 3 ++- src/plugins/experimentalWarnings/plugin.js | 3 ++- src/plugins/htmlAudioPlayer/plugin.js | 3 ++- src/plugins/htmlVideoPlayer/plugin.js | 3 ++- src/plugins/logoScreensaver/plugin.js | 4 +++- src/plugins/pdfPlayer/plugin.js | 3 ++- src/plugins/photoPlayer/plugin.js | 3 ++- src/plugins/playAccessValidation/plugin.js | 3 ++- src/plugins/sessionPlayer/plugin.js | 3 ++- src/plugins/syncPlay/plugin.ts | 5 +++-- src/plugins/youtubePlayer/plugin.js | 3 ++- src/scripts/screensavermanager.js | 3 ++- src/types/plugin.ts | 13 +++++++++++++ 18 files changed, 51 insertions(+), 20 deletions(-) create mode 100644 src/types/plugin.ts diff --git a/src/components/displaySettings/displaySettings.js b/src/components/displaySettings/displaySettings.js index f351368a9a..195c919e9b 100644 --- a/src/components/displaySettings/displaySettings.js +++ b/src/components/displaySettings/displaySettings.js @@ -8,6 +8,7 @@ import datetime from '../../scripts/datetime'; import globalize from '../../scripts/globalize'; import loading from '../loading/loading'; import skinManager from '../../scripts/themeManager'; +import { PluginType } from '../../types/plugin.ts'; import Events from '../../utils/events.ts'; import '../../elements/emby-select/emby-select'; import '../../elements/emby-checkbox/emby-checkbox'; @@ -35,7 +36,7 @@ import template from './displaySettings.template.html'; function loadScreensavers(context, userSettings) { const selectScreensaver = context.querySelector('.selectScreensaver'); - const options = pluginManager.ofType('screensaver').map(plugin => { + const options = pluginManager.ofType(PluginType.Screensaver).map(plugin => { return { name: plugin.name, value: plugin.id diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index ffcd0e4d91..5d52321100 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -11,6 +11,7 @@ import { appHost } from '../apphost'; import Screenfull from 'screenfull'; import ServerConnections from '../ServerConnections'; import alert from '../alert'; +import { PluginType } from '../../types/plugin.ts'; import { includesAny } from '../../utils/container.ts'; const UNLIMITED_ITEMS = -1; @@ -2268,7 +2269,7 @@ class PlaybackManager { function runInterceptors(item, playOptions) { return new Promise(function (resolve, reject) { - const interceptors = pluginManager.ofType('preplayintercept'); + const interceptors = pluginManager.ofType(PluginType.PreplayIntercept); interceptors.sort(function (a, b) { return (a.order || 0) - (b.order || 0); @@ -3387,12 +3388,12 @@ class PlaybackManager { } Events.on(pluginManager, 'registered', function (e, plugin) { - if (plugin.type === 'mediaplayer') { + if (plugin.type === PluginType.MediaPlayer) { initMediaPlayer(plugin); } }); - pluginManager.ofType('mediaplayer').forEach(initMediaPlayer); + pluginManager.ofType(PluginType.MediaPlayer).forEach(initMediaPlayer); function sendProgressUpdate(player, progressEventName, reportPlaylist) { if (!player) { diff --git a/src/plugins/backdropScreensaver/plugin.js b/src/plugins/backdropScreensaver/plugin.js index 7db319a34e..823ab7d7e0 100644 --- a/src/plugins/backdropScreensaver/plugin.js +++ b/src/plugins/backdropScreensaver/plugin.js @@ -1,10 +1,11 @@ /* eslint-disable indent */ import ServerConnections from '../../components/ServerConnections'; +import { PluginType } from '../../types/plugin.ts'; class BackdropScreensaver { constructor() { this.name = 'Backdrop ScreenSaver'; - this.type = 'screensaver'; + this.type = PluginType.Screensaver; this.id = 'backdropscreensaver'; this.supportsAnonymous = false; } diff --git a/src/plugins/bookPlayer/plugin.js b/src/plugins/bookPlayer/plugin.js index e95c8657b1..df5e213b72 100644 --- a/src/plugins/bookPlayer/plugin.js +++ b/src/plugins/bookPlayer/plugin.js @@ -9,6 +9,7 @@ import TableOfContents from './tableOfContents'; import dom from '../../scripts/dom'; import { translateHtml } from '../../scripts/globalize'; import * as userSettings from '../../scripts/settings/userSettings'; +import { PluginType } from '../../types/plugin.ts'; import Events from '../../utils/events.ts'; import '../../elements/emby-button/paper-icon-button-light'; @@ -19,7 +20,7 @@ import './style.scss'; export class BookPlayer { constructor() { this.name = 'Book Player'; - this.type = 'mediaplayer'; + this.type = PluginType.MediaPlayer; this.id = 'bookplayer'; this.priority = 1; diff --git a/src/plugins/chromecastPlayer/plugin.js b/src/plugins/chromecastPlayer/plugin.js index 9044cd3e30..81cfeab86a 100644 --- a/src/plugins/chromecastPlayer/plugin.js +++ b/src/plugins/chromecastPlayer/plugin.js @@ -5,6 +5,7 @@ import globalize from '../../scripts/globalize'; import castSenderApiLoader from './castSenderApi'; import ServerConnections from '../../components/ServerConnections'; import alert from '../../components/alert'; +import { PluginType } from '../../types/plugin.ts'; import Events from '../../utils/events.ts'; // Based on https://github.com/googlecast/CastVideos-chrome/blob/master/CastVideos.js @@ -569,7 +570,7 @@ class ChromecastPlayer { constructor() { // playbackManager needs this this.name = PlayerName; - this.type = 'mediaplayer'; + this.type = PluginType.MediaPlayer; this.id = 'chromecast'; this.isLocalPlayer = false; this.lastPlayerData = {}; diff --git a/src/plugins/comicsPlayer/plugin.js b/src/plugins/comicsPlayer/plugin.js index d209069ad3..eb6d3cb11f 100644 --- a/src/plugins/comicsPlayer/plugin.js +++ b/src/plugins/comicsPlayer/plugin.js @@ -6,13 +6,14 @@ import keyboardnavigation from '../../scripts/keyboardNavigation'; import { appRouter } from '../../components/appRouter'; import ServerConnections from '../../components/ServerConnections'; import * as userSettings from '../../scripts/settings/userSettings'; +import { PluginType } from '../../types/plugin.ts'; import './style.scss'; export class ComicsPlayer { constructor() { this.name = 'Comics Player'; - this.type = 'mediaplayer'; + this.type = PluginType.MediaPlayer; this.id = 'comicsplayer'; this.priority = 1; this.imageMap = new Map(); diff --git a/src/plugins/experimentalWarnings/plugin.js b/src/plugins/experimentalWarnings/plugin.js index 563e6264f2..395f906890 100644 --- a/src/plugins/experimentalWarnings/plugin.js +++ b/src/plugins/experimentalWarnings/plugin.js @@ -2,6 +2,7 @@ import globalize from '../../scripts/globalize'; import * as userSettings from '../../scripts/settings/userSettings'; import { appHost } from '../../components/apphost'; import alert from '../../components/alert'; +import { PluginType } from '../../types/plugin.ts'; // TODO: Replace with date-fns // https://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php @@ -46,7 +47,7 @@ function showIsoMessage() { class ExpirementalPlaybackWarnings { constructor() { this.name = 'Experimental playback warnings'; - this.type = 'preplayintercept'; + this.type = PluginType.PreplayIntercept; this.id = 'expirementalplaybackwarnings'; } diff --git a/src/plugins/htmlAudioPlayer/plugin.js b/src/plugins/htmlAudioPlayer/plugin.js index b5d3c8bd02..4157246714 100644 --- a/src/plugins/htmlAudioPlayer/plugin.js +++ b/src/plugins/htmlAudioPlayer/plugin.js @@ -3,6 +3,7 @@ import { appHost } from '../../components/apphost'; import * as htmlMediaHelper from '../../components/htmlMediaHelper'; import profileBuilder from '../../scripts/browserDeviceProfile'; import { getIncludeCorsCredentials } from '../../scripts/settings/webSettings'; +import { PluginType } from '../../types/plugin.ts'; import Events from '../../utils/events.ts'; function getDefaultProfile() { @@ -85,7 +86,7 @@ class HtmlAudioPlayer { const self = this; self.name = 'Html Audio Player'; - self.type = 'mediaplayer'; + self.type = PluginType.MediaPlayer; self.id = 'htmlaudioplayer'; // Let any players created by plugins take priority diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index f2a2b8d30b..b8551defbc 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -30,6 +30,7 @@ import ServerConnections from '../../components/ServerConnections'; import profileBuilder, { canPlaySecondaryAudio } from '../../scripts/browserDeviceProfile'; import { getIncludeCorsCredentials } from '../../scripts/settings/webSettings'; import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../components/backdrop/backdrop'; +import { PluginType } from '../../types/plugin.ts'; import Events from '../../utils/events.ts'; import { includesAny } from '../../utils/container.ts'; @@ -166,7 +167,7 @@ function tryRemoveElement(elem) { /** * @type {string} */ - type = 'mediaplayer'; + type = PluginType.MediaPlayer; /** * @type {string} */ diff --git a/src/plugins/logoScreensaver/plugin.js b/src/plugins/logoScreensaver/plugin.js index 8d5f7031a5..b1168ab5bd 100644 --- a/src/plugins/logoScreensaver/plugin.js +++ b/src/plugins/logoScreensaver/plugin.js @@ -1,8 +1,10 @@ +import { PluginType } from '../../types/plugin.ts'; + export default function () { const self = this; self.name = 'Logo ScreenSaver'; - self.type = 'screensaver'; + self.type = PluginType.Screensaver; self.id = 'logoscreensaver'; self.supportsAnonymous = true; diff --git a/src/plugins/pdfPlayer/plugin.js b/src/plugins/pdfPlayer/plugin.js index 5f43d03fc9..b34404d7a9 100644 --- a/src/plugins/pdfPlayer/plugin.js +++ b/src/plugins/pdfPlayer/plugin.js @@ -4,6 +4,7 @@ import keyboardnavigation from '../../scripts/keyboardNavigation'; import dialogHelper from '../../components/dialogHelper/dialogHelper'; import dom from '../../scripts/dom'; import { appRouter } from '../../components/appRouter'; +import { PluginType } from '../../types/plugin.ts'; import Events from '../../utils/events.ts'; import './style.scss'; @@ -12,7 +13,7 @@ import '../../elements/emby-button/paper-icon-button-light'; export class PdfPlayer { constructor() { this.name = 'PDF Player'; - this.type = 'mediaplayer'; + this.type = PluginType.MediaPlayer; this.id = 'pdfplayer'; this.priority = 1; diff --git a/src/plugins/photoPlayer/plugin.js b/src/plugins/photoPlayer/plugin.js index aa3ba5f364..7c41c53188 100644 --- a/src/plugins/photoPlayer/plugin.js +++ b/src/plugins/photoPlayer/plugin.js @@ -1,9 +1,10 @@ import ServerConnections from '../../components/ServerConnections'; +import { PluginType } from '../../types/plugin.ts'; export default class PhotoPlayer { constructor() { this.name = 'Photo Player'; - this.type = 'mediaplayer'; + this.type = PluginType.MediaPlayer; this.id = 'photoplayer'; this.priority = 1; } diff --git a/src/plugins/playAccessValidation/plugin.js b/src/plugins/playAccessValidation/plugin.js index c353ea9096..3081f8cf49 100644 --- a/src/plugins/playAccessValidation/plugin.js +++ b/src/plugins/playAccessValidation/plugin.js @@ -1,6 +1,7 @@ import globalize from '../../scripts/globalize'; import ServerConnections from '../../components/ServerConnections'; import alert from '../../components/alert'; +import { PluginType } from '../../types/plugin.ts'; function showErrorMessage() { return alert(globalize.translate('MessagePlayAccessRestricted')); @@ -9,7 +10,7 @@ function showErrorMessage() { class PlayAccessValidation { constructor() { this.name = 'Playback validation'; - this.type = 'preplayintercept'; + this.type = PluginType.PreplayIntercept; this.id = 'playaccessvalidation'; this.order = -2; } diff --git a/src/plugins/sessionPlayer/plugin.js b/src/plugins/sessionPlayer/plugin.js index a8ad32f791..98e0e843ab 100644 --- a/src/plugins/sessionPlayer/plugin.js +++ b/src/plugins/sessionPlayer/plugin.js @@ -1,6 +1,7 @@ import { playbackManager } from '../../components/playback/playbackmanager'; import serverNotifications from '../../scripts/serverNotifications'; import ServerConnections from '../../components/ServerConnections'; +import { PluginType } from '../../types/plugin.ts'; import Events from '../../utils/events.ts'; function getActivePlayerId() { @@ -181,7 +182,7 @@ class SessionPlayer { const self = this; this.name = 'Remote Control'; - this.type = 'mediaplayer'; + this.type = PluginType.MediaPlayer; this.isLocalPlayer = false; this.id = 'remoteplayer'; diff --git a/src/plugins/syncPlay/plugin.ts b/src/plugins/syncPlay/plugin.ts index e4ef965a0d..59c066aaf7 100644 --- a/src/plugins/syncPlay/plugin.ts +++ b/src/plugins/syncPlay/plugin.ts @@ -5,8 +5,9 @@ import SyncPlay from './core'; import SyncPlayNoActivePlayer from './ui/players/NoActivePlayer'; import SyncPlayHtmlVideoPlayer from './ui/players/HtmlVideoPlayer'; import SyncPlayHtmlAudioPlayer from './ui/players/HtmlAudioPlayer'; +import { Plugin, PluginType } from '../../types/plugin'; -class SyncPlayPlugin { +class SyncPlayPlugin implements Plugin { name: string; id: string; type: string; @@ -17,7 +18,7 @@ class SyncPlayPlugin { this.id = 'syncplay'; // NOTE: This should probably be a "mediaplayer" so the playback manager can handle playback logic, but // SyncPlay needs refactored so it does not have an independent playback manager. - this.type = 'syncplay'; + this.type = PluginType.SyncPlay; this.priority = 1; this.init(); diff --git a/src/plugins/youtubePlayer/plugin.js b/src/plugins/youtubePlayer/plugin.js index a9dd8e9beb..2a10f8fcdc 100644 --- a/src/plugins/youtubePlayer/plugin.js +++ b/src/plugins/youtubePlayer/plugin.js @@ -2,6 +2,7 @@ import browser from '../../scripts/browser'; import { appRouter } from '../../components/appRouter'; import loading from '../../components/loading/loading'; import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../components/backdrop/backdrop'; +import { PluginType } from '../../types/plugin.ts'; import Events from '../../utils/events.ts'; /* globals YT */ @@ -197,7 +198,7 @@ function setCurrentSrc(instance, elem, options) { class YoutubePlayer { constructor() { this.name = 'Youtube Player'; - this.type = 'mediaplayer'; + this.type = PluginType.MediaPlayer; this.id = 'youtubeplayer'; // Let any players created by plugins take priority diff --git a/src/scripts/screensavermanager.js b/src/scripts/screensavermanager.js index 4b0eedaa51..c63d530685 100644 --- a/src/scripts/screensavermanager.js +++ b/src/scripts/screensavermanager.js @@ -3,6 +3,7 @@ import { pluginManager } from '../components/pluginManager'; import inputManager from './inputManager'; import * as userSettings from './settings/userSettings'; import ServerConnections from '../components/ServerConnections'; +import { PluginType } from '../types/plugin.ts'; import Events from '../utils/events.ts'; import './screensavermanager.scss'; @@ -34,7 +35,7 @@ function getScreensaverPlugin(isLoggedIn) { option = isLoggedIn ? 'backdropscreensaver' : 'logoscreensaver'; } - const plugins = pluginManager.ofType('screensaver'); + const plugins = pluginManager.ofType(PluginType.Screensaver); for (const plugin of plugins) { if (plugin.id === option) { diff --git a/src/types/plugin.ts b/src/types/plugin.ts new file mode 100644 index 0000000000..4b4b946e90 --- /dev/null +++ b/src/types/plugin.ts @@ -0,0 +1,13 @@ +export enum PluginType { + MediaPlayer = 'mediaplayer', + PreplayIntercept = 'preplayintercept', + Screensaver = 'screensaver', + SyncPlay = 'syncplay' +} + +export interface Plugin { + name: string + id: string + type: PluginType | string + priority: number +} From 3d91c72a0f177935555fe69bc4690c6c5f8de804 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 8 Mar 2023 11:49:19 -0500 Subject: [PATCH 30/65] Update SyncPlay plugin check --- src/scripts/libraryMenu.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scripts/libraryMenu.js b/src/scripts/libraryMenu.js index 92405f8fe3..77b38ab46a 100644 --- a/src/scripts/libraryMenu.js +++ b/src/scripts/libraryMenu.js @@ -16,6 +16,7 @@ import imageHelper from './imagehelper'; import { getMenuLinks } from '../scripts/settings/webSettings'; import Dashboard, { pageClassOn } from '../utils/dashboard'; import ServerConnections from '../components/ServerConnections'; +import { PluginType } from '../types/plugin.ts'; import Events from '../utils/events.ts'; import { getParameterByName } from '../utils/url.ts'; @@ -159,7 +160,7 @@ import '../styles/flexstyles.scss'; // Button is present headerSyncButton // SyncPlay plugin is loaded - && pluginManager.plugins.filter(plugin => plugin.id === 'syncplay').length > 0 + && pluginManager.ofType(PluginType.SyncPlay).length > 0 // SyncPlay enabled for user && policy?.SyncPlayAccess !== 'None' ) { From 2d95a95eaea64ad76565351776bba3b5800c1ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3bert=20=C3=96rn=20Ketilsson?= Date: Wed, 8 Mar 2023 16:17:30 +0000 Subject: [PATCH 31/65] Translated using Weblate (Icelandic) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/is/ --- src/strings/is-is.json | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/strings/is-is.json b/src/strings/is-is.json index 585b335c18..1d8d08631c 100644 --- a/src/strings/is-is.json +++ b/src/strings/is-is.json @@ -455,5 +455,16 @@ "ButtonActivate": "Virkja", "ButtonClose": "Loka", "ButtonSpace": "Bil", - "Authorize": "Heimila" + "Authorize": "Heimila", + "ChangingMetadataImageSettingsNewContent": "Breytingar á niðurhali lýsigögnum eða myndum mun aðeins gilda um ný efni sem bætt hafa verið í safnið. Til að breyta núverandi titla þarftu að endurnýja lýsigögnin handvirkt.", + "ColorTransfer": "Litaflutningur", + "Data": "Gögn", + "ClearQueue": "Hreinsa biðröð", + "DailyAt": "Daglega um {0}", + "DashboardServerName": "Þjónn: {0}", + "DashboardVersionNumber": "Útgáfa: {0}", + "ColorSpace": "Litarými", + "Copied": "Aftritað", + "Copy": "Afrita", + "CopyFailed": "Gat ekki afritað" } From aab068565d50b3ed617ea415133cea1f401e98bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3bert=20=C3=96rn=20Ketilsson?= Date: Wed, 8 Mar 2023 19:16:06 +0000 Subject: [PATCH 32/65] Translated using Weblate (Icelandic) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/is/ --- src/strings/is-is.json | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/strings/is-is.json b/src/strings/is-is.json index 1d8d08631c..4d131ff8ad 100644 --- a/src/strings/is-is.json +++ b/src/strings/is-is.json @@ -466,5 +466,17 @@ "ColorSpace": "Litarými", "Copied": "Aftritað", "Copy": "Afrita", - "CopyFailed": "Gat ekki afritað" + "CopyFailed": "Gat ekki afritað", + "ButtonExitApp": "Fara úr forriti", + "EnableFasterAnimations": "Hraðari hreyfimyndir", + "EnablePlugin": "Virkja", + "Bwdif": "BWDIF", + "DisablePlugin": "Slökkva", + "EnableAutoCast": "Setja sem Sjálfgefið", + "EnableDetailsBanner": "Upplýsingar borði", + "DeleteAll": "Eyða Öllu", + "ButtonBackspace": "Backspace", + "ButtonUseQuickConnect": "Nota hraðtengingu", + "Digital": "Stafrænt", + "DownloadAll": "Sækja allt" } From 329cf77c814d3795699230140e805833ced32c15 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Thu, 9 Mar 2023 00:01:05 -0500 Subject: [PATCH 33/65] Add eslint radix rule for parseInt --- .eslintrc.js | 1 + .../accessSchedule/accessSchedule.js | 2 +- src/components/activitylog.js | 4 ++-- src/components/cardbuilder/cardBuilder.js | 2 +- src/components/groupedcards.js | 2 +- src/components/guide/guide.js | 8 ++++---- src/components/imageeditor/imageeditor.js | 8 ++++---- src/components/itemMediaInfo/itemMediaInfo.js | 2 +- .../itemidentifier/itemidentifier.js | 4 ++-- .../libraryoptionseditor.js | 2 +- .../mediaLibraryCreator/mediaLibraryCreator.js | 2 +- .../mediaLibraryEditor/mediaLibraryEditor.js | 2 +- .../metadataEditor/metadataEditor.js | 4 ++-- src/components/playback/mediasession.js | 6 +++--- src/components/playback/playbackmanager.js | 12 ++++++------ src/components/playback/playersettingsmenu.js | 2 +- src/components/remotecontrol/remotecontrol.js | 6 ++---- src/components/shortcuts.js | 4 ++-- src/controllers/dashboard/dlna/profile.js | 18 +++++++++--------- src/controllers/dashboard/encodingsettings.js | 4 ++-- src/controllers/dashboard/library.js | 4 ++-- .../dashboard/scheduledtasks/scheduledtask.js | 2 +- src/controllers/dashboard/streaming.js | 2 +- src/controllers/livetv/livetvsuggested.js | 8 ++++---- src/controllers/music/musicrecommended.js | 6 +++--- src/controllers/playback/video/index.js | 8 ++++---- src/controllers/shows/tvrecommended.js | 6 +++--- .../emby-itemscontainer/emby-itemscontainer.js | 2 +- .../emby-progressbar/emby-progressbar.js | 4 ++-- .../emby-scrollbuttons/emby-scrollbuttons.js | 2 +- src/elements/emby-scroller/Scroller.tsx | 2 +- src/elements/emby-tabs/emby-tabs.js | 6 +++--- src/elements/emby-textarea/emby-textarea.js | 2 +- src/plugins/chromecastPlayer/plugin.js | 2 +- src/plugins/pdfPlayer/plugin.js | 2 +- src/plugins/syncPlay/core/Manager.js | 2 +- src/routes/movies/index.tsx | 4 ++-- src/routes/user/useredit.tsx | 4 ++-- src/scripts/browser.js | 4 ++-- src/scripts/serverNotifications.js | 4 ++-- src/scripts/settings/appSettings.js | 6 +++--- src/scripts/settings/userSettings.js | 4 ++-- 42 files changed, 90 insertions(+), 91 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index e2811f35a9..91a4cf29c3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -68,6 +68,7 @@ module.exports = { 'padded-blocks': ['error', 'never'], 'prefer-const': ['error', { 'destructuring': 'all' }], 'quotes': ['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': false }], + 'radix': ['error'], '@babel/semi': ['error'], 'space-before-blocks': ['error'], 'space-infix-ops': 'error', diff --git a/src/components/accessSchedule/accessSchedule.js b/src/components/accessSchedule/accessSchedule.js index 4db600ecef..33df97532e 100644 --- a/src/components/accessSchedule/accessSchedule.js +++ b/src/components/accessSchedule/accessSchedule.js @@ -19,7 +19,7 @@ import template from './accessSchedule.template.html'; const pct = hours % 1; if (pct) { - minutes = parseInt(60 * pct); + minutes = parseInt(60 * pct, 10); } return datetime.getDisplayTime(new Date(2000, 1, 1, hours, minutes, 0, 0)); diff --git a/src/components/activitylog.js b/src/components/activitylog.js index 82f58e1879..54de02b97c 100644 --- a/src/components/activitylog.js +++ b/src/components/activitylog.js @@ -64,10 +64,10 @@ import { toBoolean } from '../utils/string.ts'; function reloadData(instance, elem, apiClient, startIndex, limit) { if (startIndex == null) { - startIndex = parseInt(elem.getAttribute('data-activitystartindex') || '0'); + startIndex = parseInt(elem.getAttribute('data-activitystartindex') || '0', 10); } - limit = limit || parseInt(elem.getAttribute('data-activitylimit') || '7'); + limit = limit || parseInt(elem.getAttribute('data-activitylimit') || '7', 10); const minDate = new Date(); const hasUserId = toBoolean(elem.getAttribute('data-useractivity'), true); diff --git a/src/components/cardbuilder/cardBuilder.js b/src/components/cardbuilder/cardBuilder.js index a0c4aaf09b..b09247f613 100644 --- a/src/components/cardbuilder/cardBuilder.js +++ b/src/components/cardbuilder/cardBuilder.js @@ -663,7 +663,7 @@ import { appRouter } from '../appRouter'; const character = String(str.slice(charIndex, charIndex + 1).charCodeAt()); let sum = 0; for (let i = 0; i < character.length; i++) { - sum += parseInt(character.charAt(i)); + sum += parseInt(character.charAt(i), 10); } const index = String(sum).slice(-1); diff --git a/src/components/groupedcards.js b/src/components/groupedcards.js index a90423a6b0..295c3170cc 100644 --- a/src/components/groupedcards.js +++ b/src/components/groupedcards.js @@ -13,7 +13,7 @@ import ServerConnections from './ServerConnections'; const playedIndicator = card.querySelector('.playedIndicator'); const playedIndicatorHtml = playedIndicator ? playedIndicator.innerHTML : null; const options = { - Limit: parseInt(playedIndicatorHtml || '10'), + Limit: parseInt(playedIndicatorHtml || '10', 10), Fields: 'PrimaryImageAspectRatio,DateCreated', ParentId: itemId, GroupItems: false diff --git a/src/components/guide/guide.js b/src/components/guide/guide.js index 63a682ee65..36137af21d 100644 --- a/src/components/guide/guide.js +++ b/src/components/guide/guide.js @@ -1149,12 +1149,12 @@ function Guide(options) { guideContext.querySelector('.guideDateTabs').addEventListener('tabchange', function (e) { const allTabButtons = e.target.querySelectorAll('.guide-date-tab-button'); - const tabButton = allTabButtons[parseInt(e.detail.selectedTabIndex)]; + const tabButton = allTabButtons[parseInt(e.detail.selectedTabIndex, 10)]; if (tabButton) { - const previousButton = e.detail.previousIndex == null ? null : allTabButtons[parseInt(e.detail.previousIndex)]; + const previousButton = e.detail.previousIndex == null ? null : allTabButtons[parseInt(e.detail.previousIndex, 10)]; const date = new Date(); - date.setTime(parseInt(tabButton.getAttribute('data-date'))); + date.setTime(parseInt(tabButton.getAttribute('data-date'), 10)); const scrollWidth = programGrid.scrollWidth; let scrollToTimeMs; @@ -1166,7 +1166,7 @@ function Guide(options) { if (previousButton) { const previousDate = new Date(); - previousDate.setTime(parseInt(previousButton.getAttribute('data-date'))); + previousDate.setTime(parseInt(previousButton.getAttribute('data-date'), 10)); scrollToTimeMs += (previousDate.getHours() * 60 * 60 * 1000); scrollToTimeMs += (previousDate.getMinutes() * 60 * 1000); diff --git a/src/components/imageeditor/imageeditor.js b/src/components/imageeditor/imageeditor.js index 9130bd311c..1711169dbc 100644 --- a/src/components/imageeditor/imageeditor.js +++ b/src/components/imageeditor/imageeditor.js @@ -278,9 +278,9 @@ import template from './imageeditor.template.html'; const apiClient = ServerConnections.getApiClient(serverId); const type = imageCard.getAttribute('data-imagetype'); - const index = parseInt(imageCard.getAttribute('data-index')); - const providerCount = parseInt(imageCard.getAttribute('data-providers')); - const numImages = parseInt(imageCard.getAttribute('data-numimages')); + const index = parseInt(imageCard.getAttribute('data-index'), 10); + const providerCount = parseInt(imageCard.getAttribute('data-providers'), 10); + const numImages = parseInt(imageCard.getAttribute('data-numimages'), 10); import('../actionSheet/actionSheet').then(({default: actionSheet}) => { const commands = []; @@ -385,7 +385,7 @@ import template from './imageeditor.template.html'; addListeners(context, 'btnDeleteImage', 'click', function () { const type = this.getAttribute('data-imagetype'); let index = this.getAttribute('data-index'); - index = index === 'null' ? null : parseInt(index); + index = index === 'null' ? null : parseInt(index, 10); const apiClient = ServerConnections.getApiClient(currentItem.ServerId); deleteImage(context, currentItem.Id, type, index, apiClient, true); }); diff --git a/src/components/itemMediaInfo/itemMediaInfo.js b/src/components/itemMediaInfo/itemMediaInfo.js index 1a05d40849..ac04df4815 100644 --- a/src/components/itemMediaInfo/itemMediaInfo.js +++ b/src/components/itemMediaInfo/itemMediaInfo.js @@ -138,7 +138,7 @@ const attributeDelimiterHtml = layoutManager.tv ? '' : ': { diff --git a/src/components/mediaLibraryEditor/mediaLibraryEditor.js b/src/components/mediaLibraryEditor/mediaLibraryEditor.js index ed54675016..c90acc0078 100644 --- a/src/components/mediaLibraryEditor/mediaLibraryEditor.js +++ b/src/components/mediaLibraryEditor/mediaLibraryEditor.js @@ -93,7 +93,7 @@ import template from './mediaLibraryEditor.template.html'; const listItem = dom.parentWithClass(e.target, 'listItem'); if (listItem) { - const index = parseInt(listItem.getAttribute('data-index')); + const index = parseInt(listItem.getAttribute('data-index'), 10); const pathInfos = (currentOptions.library.LibraryOptions || {}).PathInfos || []; const pathInfo = index == null ? {} : pathInfos[index] || {}; const originalPath = pathInfo.Path || (index == null ? null : currentOptions.library.Locations[index]); diff --git a/src/components/metadataEditor/metadataEditor.js b/src/components/metadataEditor/metadataEditor.js index 6456c5721d..fb69d20aa2 100644 --- a/src/components/metadataEditor/metadataEditor.js +++ b/src/components/metadataEditor/metadataEditor.js @@ -357,14 +357,14 @@ import template from './metadataEditor.template.html'; let index; const btnDeletePerson = dom.parentWithClass(e.target, 'btnDeletePerson'); if (btnDeletePerson) { - index = parseInt(btnDeletePerson.getAttribute('data-index')); + index = parseInt(btnDeletePerson.getAttribute('data-index'), 10); currentItem.People.splice(index, 1); populatePeople(context, currentItem.People); } const btnEditPerson = dom.parentWithClass(e.target, 'btnEditPerson'); if (btnEditPerson) { - index = parseInt(btnEditPerson.getAttribute('data-index')); + index = parseInt(btnEditPerson.getAttribute('data-index'), 10); editPerson(context, currentItem.People[index], index); } }); diff --git a/src/components/playback/mediasession.js b/src/components/playback/mediasession.js index 089820fb47..d16fe7756f 100644 --- a/src/components/playback/mediasession.js +++ b/src/components/playback/mediasession.js @@ -114,8 +114,8 @@ import shell from '../../scripts/shell'; const itemId = item.Id; // Convert to ms - const duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0); - const currentTime = parseInt(playState.PositionTicks ? (playState.PositionTicks / 10000) : 0); + const duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0, 10); + const currentTime = parseInt(playState.PositionTicks ? (playState.PositionTicks / 10000) : 0, 10); const isPaused = playState.IsPaused || false; const canSeek = playState.CanSeek || false; @@ -247,7 +247,7 @@ import shell from '../../scripts/shell'; navigator.mediaSession.setActionHandler('seekto', function (object) { const item = playbackManager.getPlayerState(currentPlayer).NowPlayingItem; // Convert to ms - const duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0); + const duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0, 10); const wantedTime = object.seekTime * 1000; playbackManager.seekPercent(wantedTime / duration * 100, currentPlayer); }); diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 947f46eec8..d868d24cda 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1690,7 +1690,7 @@ class PlaybackManager { function changeStream(player, ticks, params) { if (canPlayerSeek(player) && params == null) { - player.currentTime(parseInt(ticks / 10000)); + player.currentTime(parseInt(ticks / 10000, 10)); return; } @@ -1714,7 +1714,7 @@ class PlaybackManager { const apiClient = ServerConnections.getApiClient(currentItem.ServerId); if (ticks) { - ticks = parseInt(ticks); + ticks = parseInt(ticks, 10); } const maxBitrate = params.MaxStreamingBitrate || self.getMaxStreamingBitrate(player); @@ -3645,7 +3645,7 @@ class PlaybackManager { percent /= 100; ticks *= percent; - this.seek(parseInt(ticks), player); + this.seek(parseInt(ticks, 10), player); } seekMs(ms, player = this._currentPlayer) { @@ -4032,13 +4032,13 @@ class PlaybackManager { this.setBrightness(cmd.Arguments.Brightness, player); break; case 'SetAudioStreamIndex': - this.setAudioStreamIndex(parseInt(cmd.Arguments.Index), player); + this.setAudioStreamIndex(parseInt(cmd.Arguments.Index, 10), player); break; case 'SetSubtitleStreamIndex': - this.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index), player); + this.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index, 10), player); break; case 'SetMaxStreamingBitrate': - this.setMaxStreamingBitrate(parseInt(cmd.Arguments.Bitrate), player); + this.setMaxStreamingBitrate(parseInt(cmd.Arguments.Bitrate, 10), player); break; case 'ToggleFullscreen': this.toggleFullscreen(player); diff --git a/src/components/playback/playersettingsmenu.js b/src/components/playback/playersettingsmenu.js index c7f8f5a6da..da3be20970 100644 --- a/src/components/playback/playersettingsmenu.js +++ b/src/components/playback/playersettingsmenu.js @@ -43,7 +43,7 @@ function showQualityMenu(player, btn) { items: menuItems, positionTo: btn }).then(function (id) { - const bitrate = parseInt(id); + const bitrate = parseInt(id, 10); if (bitrate !== selectedBitrate) { playbackManager.setMaxStreamingBitrate({ enableAutomaticBitrateDetection: bitrate ? false : true, diff --git a/src/components/remotecontrol/remotecontrol.js b/src/components/remotecontrol/remotecontrol.js index cce2cf7b43..26b7220bce 100644 --- a/src/components/remotecontrol/remotecontrol.js +++ b/src/components/remotecontrol/remotecontrol.js @@ -20,8 +20,6 @@ import ServerConnections from '../ServerConnections'; import toast from '../toast/toast'; import { appRouter } from '../appRouter'; -/*eslint prefer-const: "error"*/ - let showMuteButton = true; let showVolumeSlider = true; @@ -46,7 +44,7 @@ function showAudioMenu(context, player, button) { items: menuItems, positionTo: button, callback: function (id) { - playbackManager.setAudioStreamIndex(parseInt(id), player); + playbackManager.setAudioStreamIndex(parseInt(id, 10), player); } }); }); @@ -78,7 +76,7 @@ function showSubtitleMenu(context, player, button) { items: menuItems, positionTo: button, callback: function (id) { - playbackManager.setSubtitleStreamIndex(parseInt(id), player); + playbackManager.setSubtitleStreamIndex(parseInt(id, 10), player); } }); }); diff --git a/src/components/shortcuts.js b/src/components/shortcuts.js index bf8d1b74fe..60e51c784c 100644 --- a/src/components/shortcuts.js +++ b/src/components/shortcuts.js @@ -150,7 +150,7 @@ import toast from './toast/toast'; StartDate: card.getAttribute('data-startdate'), EndDate: card.getAttribute('data-enddate'), UserData: { - PlaybackPositionTicks: parseInt(card.getAttribute('data-positionticks') || '0') + PlaybackPositionTicks: parseInt(card.getAttribute('data-positionticks') || '0', 10) } }; } @@ -201,7 +201,7 @@ import toast from './toast/toast'; ServerId: serverId }); } else if (action === 'play' || action === 'resume') { - const startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0'); + const startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0', 10); if (playbackManager.canPlay(item)) { playbackManager.play({ diff --git a/src/controllers/dashboard/dlna/profile.js b/src/controllers/dashboard/dlna/profile.js index 3f5d6c365e..4d942f7cdc 100644 --- a/src/controllers/dashboard/dlna/profile.js +++ b/src/controllers/dashboard/dlna/profile.js @@ -100,7 +100,7 @@ import { getParameterByName } from '../../../utils/url.ts'; }).join('') + '
'; const elem = $('.httpHeaderIdentificationList', page).html(html).trigger('create'); $('.btnDeleteIdentificationHeader', elem).on('click', function () { - const itemIndex = parseInt(this.getAttribute('data-index')); + const itemIndex = parseInt(this.getAttribute('data-index'), 10); currentProfile.Identification.Headers.splice(itemIndex, 1); renderIdentificationHeaders(page, currentProfile.Identification.Headers); }); @@ -154,7 +154,7 @@ import { getParameterByName } from '../../../utils/url.ts'; }).join('') + '
'; const elem = $('.xmlDocumentAttributeList', page).html(html).trigger('create'); $('.btnDeleteXmlAttribute', elem).on('click', function () { - const itemIndex = parseInt(this.getAttribute('data-index')); + const itemIndex = parseInt(this.getAttribute('data-index'), 10); currentProfile.XmlRootAttributes.splice(itemIndex, 1); renderXmlDocumentAttributes(page, currentProfile.XmlRootAttributes); }); @@ -198,12 +198,12 @@ import { getParameterByName } from '../../../utils/url.ts'; }).join('') + '
'; const elem = $('.subtitleProfileList', page).html(html).trigger('create'); $('.btnDeleteProfile', elem).on('click', function () { - const itemIndex = parseInt(this.getAttribute('data-index')); + const itemIndex = parseInt(this.getAttribute('data-index'), 10); currentProfile.SubtitleProfiles.splice(itemIndex, 1); renderSubtitleProfiles(page, currentProfile.SubtitleProfiles); }); $('.lnkEditSubProfile', elem).on('click', function () { - const itemIndex = parseInt(this.getAttribute('data-index')); + const itemIndex = parseInt(this.getAttribute('data-index'), 10); editSubtitleProfile(page, currentProfile.SubtitleProfiles[itemIndex]); }); } @@ -292,7 +292,7 @@ import { getParameterByName } from '../../../utils/url.ts'; deleteDirectPlayProfile(page, index); }); $('.lnkEditSubProfile', elem).on('click', function () { - const index = parseInt(this.getAttribute('data-profileindex')); + const index = parseInt(this.getAttribute('data-profileindex'), 10); editDirectPlayProfile(page, currentProfile.DirectPlayProfiles[index]); }); } @@ -353,7 +353,7 @@ import { getParameterByName } from '../../../utils/url.ts'; deleteTranscodingProfile(page, index); }); $('.lnkEditSubProfile', elem).on('click', function () { - const index = parseInt(this.getAttribute('data-profileindex')); + const index = parseInt(this.getAttribute('data-profileindex'), 10); editTranscodingProfile(page, currentProfile.TranscodingProfiles[index]); }); } @@ -437,7 +437,7 @@ import { getParameterByName } from '../../../utils/url.ts'; deleteContainerProfile(page, index); }); $('.lnkEditSubProfile', elem).on('click', function () { - const index = parseInt(this.getAttribute('data-profileindex')); + const index = parseInt(this.getAttribute('data-profileindex'), 10); editContainerProfile(page, currentProfile.ContainerProfiles[index]); }); } @@ -509,7 +509,7 @@ import { getParameterByName } from '../../../utils/url.ts'; deleteCodecProfile(page, index); }); $('.lnkEditSubProfile', elem).on('click', function () { - const index = parseInt(this.getAttribute('data-profileindex')); + const index = parseInt(this.getAttribute('data-profileindex'), 10); editCodecProfile(page, currentProfile.CodecProfiles[index]); }); } @@ -589,7 +589,7 @@ import { getParameterByName } from '../../../utils/url.ts'; deleteResponseProfile(page, index); }); $('.lnkEditSubProfile', elem).on('click', function () { - const index = parseInt(this.getAttribute('data-profileindex')); + const index = parseInt(this.getAttribute('data-profileindex'), 10); editResponseProfile(page, currentProfile.ResponseProfiles[index]); }); } diff --git a/src/controllers/dashboard/encodingsettings.js b/src/controllers/dashboard/encodingsettings.js index 67001ccb82..b8c89726cd 100644 --- a/src/controllers/dashboard/encodingsettings.js +++ b/src/controllers/dashboard/encodingsettings.js @@ -98,8 +98,8 @@ import alert from '../../components/alert'; config.VppTonemappingBrightness = form.querySelector('#txtVppTonemappingBrightness').value; config.VppTonemappingContrast = form.querySelector('#txtVppTonemappingContrast').value; config.EncoderPreset = form.querySelector('#selectEncoderPreset').value; - config.H264Crf = parseInt(form.querySelector('#txtH264Crf').value || '0'); - config.H265Crf = parseInt(form.querySelector('#txtH265Crf').value || '0'); + config.H264Crf = parseInt(form.querySelector('#txtH264Crf').value || '0', 10); + config.H265Crf = parseInt(form.querySelector('#txtH265Crf').value || '0', 10); config.DeinterlaceMethod = form.querySelector('#selectDeinterlaceMethod').value; config.DeinterlaceDoubleRate = form.querySelector('#chkDoubleRateDeinterlacing').checked; config.EnableSubtitleExtraction = form.querySelector('#chkEnableSubtitleExtraction').checked; diff --git a/src/controllers/dashboard/library.js b/src/controllers/dashboard/library.js index 24e7a477d1..49ff203902 100644 --- a/src/controllers/dashboard/library.js +++ b/src/controllers/dashboard/library.js @@ -92,7 +92,7 @@ import cardBuilder from '../../components/cardbuilder/cardBuilder'; function showCardMenu(page, elem, virtualFolders) { const card = dom.parentWithClass(elem, 'card'); - const index = parseInt(card.getAttribute('data-index')); + const index = parseInt(card.getAttribute('data-index'), 10); const virtualFolder = virtualFolders[index]; const menuItems = []; menuItems.push({ @@ -192,7 +192,7 @@ import cardBuilder from '../../components/cardbuilder/cardBuilder'; }); $('.editLibrary', divVirtualFolders).on('click', function () { const card = $(this).parents('.card')[0]; - const index = parseInt(card.getAttribute('data-index')); + const index = parseInt(card.getAttribute('data-index'), 10); const virtualFolder = virtualFolders[index]; if (virtualFolder.ItemId) { diff --git a/src/controllers/dashboard/scheduledtasks/scheduledtask.js b/src/controllers/dashboard/scheduledtasks/scheduledtask.js index c326a689fc..64db2e4292 100644 --- a/src/controllers/dashboard/scheduledtasks/scheduledtask.js +++ b/src/controllers/dashboard/scheduledtasks/scheduledtask.js @@ -235,7 +235,7 @@ import { getParameterByName } from '../../../utils/url.ts'; const btnDeleteTrigger = dom.parentWithClass(e.target, 'btnDeleteTrigger'); if (btnDeleteTrigger) { - ScheduledTaskPage.confirmDeleteTrigger(view, parseInt(btnDeleteTrigger.getAttribute('data-index'))); + ScheduledTaskPage.confirmDeleteTrigger(view, parseInt(btnDeleteTrigger.getAttribute('data-index'), 10)); } }); view.addEventListener('viewshow', function () { diff --git a/src/controllers/dashboard/streaming.js b/src/controllers/dashboard/streaming.js index bc640a1f68..8832e4bff4 100644 --- a/src/controllers/dashboard/streaming.js +++ b/src/controllers/dashboard/streaming.js @@ -15,7 +15,7 @@ import Dashboard from '../../utils/dashboard'; loading.show(); const form = this; ApiClient.getServerConfiguration().then(function (config) { - config.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($('#txtRemoteClientBitrateLimit', form).val() || '0')); + config.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($('#txtRemoteClientBitrateLimit', form).val() || '0'), 10); ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult); }); diff --git a/src/controllers/livetv/livetvsuggested.js b/src/controllers/livetv/livetvsuggested.js index 4deb2b713a..8b97984d0a 100644 --- a/src/controllers/livetv/livetvsuggested.js +++ b/src/controllers/livetv/livetvsuggested.js @@ -222,17 +222,17 @@ export default function (view, params) { } function onBeforeTabChange(evt) { - preLoadTab(view, parseInt(evt.detail.selectedTabIndex)); + preLoadTab(view, parseInt(evt.detail.selectedTabIndex, 10)); } function onTabChange(evt) { - const previousTabController = tabControllers[parseInt(evt.detail.previousIndex)]; + const previousTabController = tabControllers[parseInt(evt.detail.previousIndex, 10)]; if (previousTabController && previousTabController.onHide) { previousTabController.onHide(); } - loadTab(view, parseInt(evt.detail.selectedTabIndex)); + loadTab(view, parseInt(evt.detail.selectedTabIndex, 10)); } function getTabContainers() { @@ -339,7 +339,7 @@ export default function (view, params) { let isViewRestored; const self = this; - let currentTabIndex = parseInt(params.tab || getDefaultTabIndex('livetv')); + let currentTabIndex = parseInt(params.tab || getDefaultTabIndex('livetv'), 10); let initialTabIndex = currentTabIndex; let lastFullRender = 0; [].forEach.call(view.querySelectorAll('.sectionTitleTextButton-programs'), function (link) { diff --git a/src/controllers/music/musicrecommended.js b/src/controllers/music/musicrecommended.js index 3ea00a9a8c..bbb154a4e1 100644 --- a/src/controllers/music/musicrecommended.js +++ b/src/controllers/music/musicrecommended.js @@ -245,11 +245,11 @@ import Dashboard from '../../utils/dashboard'; } function onBeforeTabChange(e) { - preLoadTab(view, parseInt(e.detail.selectedTabIndex)); + preLoadTab(view, parseInt(e.detail.selectedTabIndex, 10)); } function onTabChange(e) { - loadTab(view, parseInt(e.detail.selectedTabIndex)); + loadTab(view, parseInt(e.detail.selectedTabIndex, 10)); } function getTabContainers() { @@ -350,7 +350,7 @@ import Dashboard from '../../utils/dashboard'; } } - let currentTabIndex = parseInt(params.tab || getDefaultTabIndex(params.topParentId)); + let currentTabIndex = parseInt(params.tab || getDefaultTabIndex(params.topParentId), 10); const suggestionsTabIndex = 1; this.initTab = function () { diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js index cacea1a304..d7bbab581d 100644 --- a/src/controllers/playback/video/index.js +++ b/src/controllers/playback/video/index.js @@ -975,7 +975,7 @@ import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../../components title: globalize.translate('Audio'), positionTo: positionTo }).then(function (id) { - const index = parseInt(id); + const index = parseInt(id, 10); if (index !== currentIndex) { playbackManager.setAudioStreamIndex(index, player); @@ -1022,7 +1022,7 @@ import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../../components positionTo }).then(function (id) { if (id) { - const index = parseInt(id); + const index = parseInt(id, 10); if (index !== currentIndex) { playbackManager.setSecondarySubtitleStreamIndex(index, player); } @@ -1099,7 +1099,7 @@ import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../../components console.error(e); } } else { - const index = parseInt(id); + const index = parseInt(id, 10); if (index !== currentIndex) { playbackManager.setSubtitleStreamIndex(index, player); @@ -1633,7 +1633,7 @@ import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../../components ms /= 100; ms *= value; ms += programStartDateMs; - return '

' + getDisplayTimeWithoutAmPm(new Date(parseInt(ms)), true) + '

'; + return '

' + getDisplayTimeWithoutAmPm(new Date(parseInt(ms, 10)), true) + '

'; } return '--:--'; diff --git a/src/controllers/shows/tvrecommended.js b/src/controllers/shows/tvrecommended.js index 5d9b3e2e0b..d1e53b38de 100644 --- a/src/controllers/shows/tvrecommended.js +++ b/src/controllers/shows/tvrecommended.js @@ -224,11 +224,11 @@ import autoFocuser from '../../components/autoFocuser'; export default function (view, params) { function onBeforeTabChange(e) { - preLoadTab(view, parseInt(e.detail.selectedTabIndex)); + preLoadTab(view, parseInt(e.detail.selectedTabIndex, 10)); } function onTabChange(e) { - const newIndex = parseInt(e.detail.selectedTabIndex); + const newIndex = parseInt(e.detail.selectedTabIndex, 10); loadTab(view, newIndex); } @@ -340,7 +340,7 @@ import autoFocuser from '../../components/autoFocuser'; } const self = this; - let currentTabIndex = parseInt(params.tab || getDefaultTabIndex(params.topParentId)); + let currentTabIndex = parseInt(params.tab || getDefaultTabIndex(params.topParentId), 10); const suggestionsTabIndex = 1; self.initTab = function () { diff --git a/src/elements/emby-itemscontainer/emby-itemscontainer.js b/src/elements/emby-itemscontainer/emby-itemscontainer.js index 00e2e94d3a..ae0f0fef54 100644 --- a/src/elements/emby-itemscontainer/emby-itemscontainer.js +++ b/src/elements/emby-itemscontainer/emby-itemscontainer.js @@ -414,7 +414,7 @@ import Sortable from 'sortablejs'; clearRefreshInterval(itemsContainer); if (!intervalMs) { - intervalMs = parseInt(itemsContainer.getAttribute('data-refreshinterval') || '0'); + intervalMs = parseInt(itemsContainer.getAttribute('data-refreshinterval') || '0', 10); } if (intervalMs) { diff --git a/src/elements/emby-progressbar/emby-progressbar.js b/src/elements/emby-progressbar/emby-progressbar.js index e232bbcde0..cad2f4bbfa 100644 --- a/src/elements/emby-progressbar/emby-progressbar.js +++ b/src/elements/emby-progressbar/emby-progressbar.js @@ -3,8 +3,8 @@ const ProgressBarPrototype = Object.create(HTMLDivElement.prototype); function onAutoTimeProgress() { - const start = parseInt(this.getAttribute('data-starttime')); - const end = parseInt(this.getAttribute('data-endtime')); + const start = parseInt(this.getAttribute('data-starttime'), 10); + const end = parseInt(this.getAttribute('data-endtime'), 10); const now = new Date().getTime(); const total = end - start; diff --git a/src/elements/emby-scrollbuttons/emby-scrollbuttons.js b/src/elements/emby-scrollbuttons/emby-scrollbuttons.js index e7fa1df29f..3d98918d7a 100644 --- a/src/elements/emby-scrollbuttons/emby-scrollbuttons.js +++ b/src/elements/emby-scrollbuttons/emby-scrollbuttons.js @@ -91,7 +91,7 @@ const EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype); return 0; } - value = parseInt(value); + value = parseInt(value, 10); if (isNaN(value)) { return 0; } diff --git a/src/elements/emby-scroller/Scroller.tsx b/src/elements/emby-scroller/Scroller.tsx index 6cd83fc784..14313318a6 100644 --- a/src/elements/emby-scroller/Scroller.tsx +++ b/src/elements/emby-scroller/Scroller.tsx @@ -75,7 +75,7 @@ const Scroller: FC = ({ return 0; } - if (isNaN(parseInt(value))) { + if (isNaN(parseInt(value, 10))) { return 0; } diff --git a/src/elements/emby-tabs/emby-tabs.js b/src/elements/emby-tabs/emby-tabs.js index 9455b5e1db..7c07796f74 100644 --- a/src/elements/emby-tabs/emby-tabs.js +++ b/src/elements/emby-tabs/emby-tabs.js @@ -75,11 +75,11 @@ import '../../styles/scrollstyles.scss'; current.classList.remove(activeButtonClass); } - const previousIndex = current ? parseInt(current.getAttribute('data-index')) : null; + const previousIndex = current ? parseInt(current.getAttribute('data-index'), 10) : null; setActiveTabButton(tabButton); - const index = parseInt(tabButton.getAttribute('data-index')); + const index = parseInt(tabButton.getAttribute('data-index'), 10); triggerBeforeTabChange(tabs, index, previousIndex); @@ -194,7 +194,7 @@ import '../../styles/scrollstyles.scss'; initScroller(this); const current = this.querySelector('.' + activeButtonClass); - const currentIndex = current ? parseInt(current.getAttribute('data-index')) : parseInt(this.getAttribute('data-index') || '0'); + const currentIndex = current ? parseInt(current.getAttribute('data-index'), 10) : parseInt(this.getAttribute('data-index') || '0', 10); if (currentIndex !== -1) { this.selectedTabIndex = currentIndex; diff --git a/src/elements/emby-textarea/emby-textarea.js b/src/elements/emby-textarea/emby-textarea.js index 649578ce16..ed48f415ff 100644 --- a/src/elements/emby-textarea/emby-textarea.js +++ b/src/elements/emby-textarea/emby-textarea.js @@ -14,7 +14,7 @@ function calculateOffset(textarea) { let offset = 0; for (let i = 0; i < props.length; i++) { - offset += parseInt(style[props[i]]); + offset += parseInt(style[props[i]], 10); } return offset; } diff --git a/src/plugins/chromecastPlayer/plugin.js b/src/plugins/chromecastPlayer/plugin.js index 9044cd3e30..5f74477149 100644 --- a/src/plugins/chromecastPlayer/plugin.js +++ b/src/plugins/chromecastPlayer/plugin.js @@ -683,7 +683,7 @@ class ChromecastPlayer { } seek(position) { - position = parseInt(position); + position = parseInt(position, 10); position = position / 10000000; diff --git a/src/plugins/pdfPlayer/plugin.js b/src/plugins/pdfPlayer/plugin.js index 5f43d03fc9..575080af2a 100644 --- a/src/plugins/pdfPlayer/plugin.js +++ b/src/plugins/pdfPlayer/plugin.js @@ -261,7 +261,7 @@ export class PdfPlayer { for (const page of pages) { if (!this.pages[page]) { this.pages[page] = document.createElement('canvas'); - this.renderPage(this.pages[page], parseInt(page.slice(4))); + this.renderPage(this.pages[page], parseInt(page.slice(4), 10)); } } diff --git a/src/plugins/syncPlay/core/Manager.js b/src/plugins/syncPlay/core/Manager.js index 740e0709d9..ee1e3e3ae7 100644 --- a/src/plugins/syncPlay/core/Manager.js +++ b/src/plugins/syncPlay/core/Manager.js @@ -254,7 +254,7 @@ class Manager { if (typeof cmd.When === 'string') { cmd.When = new Date(cmd.When); cmd.EmittedAt = new Date(cmd.EmittedAt); - cmd.PositionTicks = cmd.PositionTicks ? parseInt(cmd.PositionTicks) : null; + cmd.PositionTicks = cmd.PositionTicks ? parseInt(cmd.PositionTicks, 10) : null; } if (!this.isSyncPlayEnabled()) { diff --git a/src/routes/movies/index.tsx b/src/routes/movies/index.tsx index 3b74b464d5..9b1405c9e5 100644 --- a/src/routes/movies/index.tsx +++ b/src/routes/movies/index.tsx @@ -55,7 +55,7 @@ const getTabs = () => { const Movies: FC = () => { const [ searchParams ] = useSearchParams(); - const currentTabIndex = parseInt(searchParams.get('tab') || getDefaultTabIndex(searchParams.get('topParentId')).toString()); + const currentTabIndex = parseInt(searchParams.get('tab') || getDefaultTabIndex(searchParams.get('topParentId')).toString(), 10); const [ selectedIndex, setSelectedIndex ] = useState(currentTabIndex); const element = useRef(null); @@ -95,7 +95,7 @@ const Movies: FC = () => { }; const onTabChange = useCallback((e: { detail: { selectedTabIndex: string; }; }) => { - const newIndex = parseInt(e.detail.selectedTabIndex); + const newIndex = parseInt(e.detail.selectedTabIndex, 10); setSelectedIndex(newIndex); }, []); diff --git a/src/routes/user/useredit.tsx b/src/routes/user/useredit.tsx index 5afa0c4fd8..1da3d8919c 100644 --- a/src/routes/user/useredit.tsx +++ b/src/routes/user/useredit.tsx @@ -228,8 +228,8 @@ const UserEdit: FunctionComponent = () => { user.Policy.EnableContentDownloading = (page.querySelector('.chkEnableDownloading') as HTMLInputElement).checked; user.Policy.EnableRemoteAccess = (page.querySelector('.chkRemoteAccess') as HTMLInputElement).checked; user.Policy.RemoteClientBitrateLimit = Math.floor(1e6 * parseFloat((page.querySelector('#txtRemoteClientBitrateLimit') as HTMLInputElement).value || '0')); - user.Policy.LoginAttemptsBeforeLockout = parseInt((page.querySelector('#txtLoginAttemptsBeforeLockout') as HTMLInputElement).value || '0'); - user.Policy.MaxActiveSessions = parseInt((page.querySelector('#txtMaxActiveSessions') as HTMLInputElement).value || '0'); + user.Policy.LoginAttemptsBeforeLockout = parseInt((page.querySelector('#txtLoginAttemptsBeforeLockout') as HTMLInputElement).value || '0', 10); + user.Policy.MaxActiveSessions = parseInt((page.querySelector('#txtMaxActiveSessions') as HTMLInputElement).value || '0', 10); user.Policy.AuthenticationProviderId = (page.querySelector('#selectLoginProvider') as HTMLSelectElement).value; user.Policy.PasswordResetProviderId = (page.querySelector('#selectPasswordResetProvider') as HTMLSelectElement).value; user.Policy.EnableContentDeletion = (page.querySelector('.chkEnableDeleteAllFolders') as HTMLInputElement).checked; diff --git a/src/scripts/browser.js b/src/scripts/browser.js index 2a28130150..a6042189dc 100644 --- a/src/scripts/browser.js +++ b/src/scripts/browser.js @@ -224,7 +224,7 @@ const uaMatch = function (ua) { version = version || match[2] || '0'; - let versionMajor = parseInt(version.split('.')[0]); + let versionMajor = parseInt(version.split('.')[0], 10); if (isNaN(versionMajor)) { versionMajor = 0; @@ -295,7 +295,7 @@ if (browser.web0s) { delete browser.safari; const v = (navigator.appVersion).match(/Tizen (\d+).(\d+)/); - browser.tizenVersion = parseInt(v[1]); + browser.tizenVersion = parseInt(v[1], 10); } else { browser.orsay = userAgent.toLowerCase().indexOf('smarthub') !== -1; } diff --git a/src/scripts/serverNotifications.js b/src/scripts/serverNotifications.js index df902bb286..de8c0c483c 100644 --- a/src/scripts/serverNotifications.js +++ b/src/scripts/serverNotifications.js @@ -98,11 +98,11 @@ function processGeneralCommand(cmd, apiClient) { break; case 'SetAudioStreamIndex': notifyApp(); - playbackManager.setAudioStreamIndex(parseInt(cmd.Arguments.Index)); + playbackManager.setAudioStreamIndex(parseInt(cmd.Arguments.Index, 10)); break; case 'SetSubtitleStreamIndex': notifyApp(); - playbackManager.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index)); + playbackManager.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index, 10)); break; case 'ToggleFullscreen': inputManager.handleCommand('togglefullscreen'); diff --git a/src/scripts/settings/appSettings.js b/src/scripts/settings/appSettings.js index 7a48943954..df18b0ddff 100644 --- a/src/scripts/settings/appSettings.js +++ b/src/scripts/settings/appSettings.js @@ -70,7 +70,7 @@ class AppSettings { // return a huge number so that it always direct plays return 150000000; } else { - return parseInt(this.get(key) || '0') || 1500000; + return parseInt(this.get(key) || '0', 10) || 1500000; } } @@ -80,7 +80,7 @@ class AppSettings { } const defaultValue = 320000; - return parseInt(this.get('maxStaticMusicBitrate') || defaultValue.toString()) || defaultValue; + return parseInt(this.get('maxStaticMusicBitrate') || defaultValue.toString(), 10) || defaultValue; } maxChromecastBitrate(val) { @@ -89,7 +89,7 @@ class AppSettings { } val = this.get('chromecastBitrate1'); - return val ? parseInt(val) : null; + return val ? parseInt(val, 10) : null; } /** diff --git a/src/scripts/settings/userSettings.js b/src/scripts/settings/userSettings.js index 658236414f..916e159394 100644 --- a/src/scripts/settings/userSettings.js +++ b/src/scripts/settings/userSettings.js @@ -348,7 +348,7 @@ export class UserSettings { return this.set('skipBackLength', val.toString()); } - return parseInt(this.get('skipBackLength') || '10000'); + return parseInt(this.get('skipBackLength') || '10000', 10); } /** @@ -361,7 +361,7 @@ export class UserSettings { return this.set('skipForwardLength', val.toString()); } - return parseInt(this.get('skipForwardLength') || '30000'); + return parseInt(this.get('skipForwardLength') || '30000', 10); } /** From 082a8319fdbbef1b5e36e5c9b1250a5077fa2d78 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Thu, 9 Mar 2023 00:20:43 -0500 Subject: [PATCH 34/65] Remove redundant inline eslint rules --- src/components/playback/playqueuemanager.js | 2 -- src/components/recordingcreator/recordingfields.js | 2 -- src/components/recordingcreator/recordinghelper.js | 2 -- src/components/recordingcreator/seriesrecordingeditor.js | 2 -- src/components/refreshdialog/refreshdialog.js | 2 -- 5 files changed, 10 deletions(-) diff --git a/src/components/playback/playqueuemanager.js b/src/components/playback/playqueuemanager.js index a1ed503372..cc27b9beec 100644 --- a/src/components/playback/playqueuemanager.js +++ b/src/components/playback/playqueuemanager.js @@ -1,5 +1,3 @@ -/*eslint prefer-const: "error"*/ - let currentId = 0; function addUniquePlaylistItemId(item) { if (!item.PlaylistItemId) { diff --git a/src/components/recordingcreator/recordingfields.js b/src/components/recordingcreator/recordingfields.js index a666a49562..742a77df4b 100644 --- a/src/components/recordingcreator/recordingfields.js +++ b/src/components/recordingcreator/recordingfields.js @@ -12,8 +12,6 @@ import ServerConnections from '../ServerConnections'; import toast from '../toast/toast'; import template from './recordingfields.template.html'; -/*eslint prefer-const: "error"*/ - function loadData(parent, program) { if (program.IsSeries) { parent.querySelector('.recordSeriesContainer').classList.remove('hide'); diff --git a/src/components/recordingcreator/recordinghelper.js b/src/components/recordingcreator/recordinghelper.js index 1780668afd..a65ae006dc 100644 --- a/src/components/recordingcreator/recordinghelper.js +++ b/src/components/recordingcreator/recordinghelper.js @@ -5,8 +5,6 @@ import toast from '../toast/toast'; import confirm from '../confirm/confirm'; import dialog from '../dialog/dialog'; -/*eslint prefer-const: "error"*/ - function changeRecordingToSeries(apiClient, timerId, programId, confirmTimerCancellation) { loading.show(); diff --git a/src/components/recordingcreator/seriesrecordingeditor.js b/src/components/recordingcreator/seriesrecordingeditor.js index 590c600e74..79d35b9fe1 100644 --- a/src/components/recordingcreator/seriesrecordingeditor.js +++ b/src/components/recordingcreator/seriesrecordingeditor.js @@ -17,8 +17,6 @@ import '../../styles/flexstyles.scss'; import ServerConnections from '../ServerConnections'; import template from './seriesrecordingeditor.template.html'; -/*eslint prefer-const: "error"*/ - let currentDialog; let recordingUpdated = false; let recordingDeleted = false; diff --git a/src/components/refreshdialog/refreshdialog.js b/src/components/refreshdialog/refreshdialog.js index 27ce6b97cf..eac336389f 100644 --- a/src/components/refreshdialog/refreshdialog.js +++ b/src/components/refreshdialog/refreshdialog.js @@ -13,8 +13,6 @@ import '../formdialog.scss'; import ServerConnections from '../ServerConnections'; import toast from '../toast/toast'; -/*eslint prefer-const: "error"*/ - function getEditorHtml() { let html = ''; From 16c47fc74f473e91f4c56b3bcc9fcf3438f2cca8 Mon Sep 17 00:00:00 2001 From: fdolbec123 Date: Thu, 9 Mar 2023 16:51:22 +0000 Subject: [PATCH 35/65] Translated using Weblate (French (Canada)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fr_CA/ --- src/strings/fr-ca.json | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/strings/fr-ca.json b/src/strings/fr-ca.json index 26e2fe3a71..15f1fe017b 100644 --- a/src/strings/fr-ca.json +++ b/src/strings/fr-ca.json @@ -334,7 +334,7 @@ "DownloadsValue": "{0} téléchargements", "DisplayModeHelp": "Sélectionner l'agencement que vous désirez pour l'interface.", "DisplayMissingEpisodesWithinSeasons": "Afficher les épisodes manquants dans les saisons", - "DisplayInOtherHomeScreenSections": "Afficher dans les sections de l’écran d’accueil comme « Ajouts récents » et reprendre le visionnement", + "DisplayInOtherHomeScreenSections": "Afficher dans les sections de l’écran d’accueil comme « Ajouts récents » et «Reprendre le visionnement»", "Directors": "Réalisateurs", "Director": "Réalisateur", "DetectingDevices": "Détection des appareils", @@ -349,7 +349,7 @@ "HeaderCodecProfile": "Profil de codec", "HeaderChapterImages": "Images des chapitres", "HeaderChannelAccess": "Accès aux chaînes", - "LatestFromLibrary": "{0}, ajouts récents", + "LatestFromLibrary": "{0} ajouts récents", "HideWatchedContentFromLatestMedia": "Masquer le contenu déjà vu dans les 'Derniers Médias'", "HeaderLatestRecordings": "Derniers enregistrements", "HeaderLatestMusic": "Dernière musique", @@ -1020,5 +1020,25 @@ "LabelMaxParentalRating": "Classification parentale maximale :", "SpecialFeatures": "Bonus", "Sort": "Trier", - "SortByValue": "Trier par" + "SortByValue": "Trier par", + "LabelMovieCategories": "Catégories de films:", + "LabelNewPassword": "Nouveau mot de passe:", + "LabelOriginalName": "Nom original:", + "LabelPasswordRecoveryPinCode": "Code NIP:", + "LabelOriginalTitle": "Titre original:", + "LabelMaxStreamingBitrate": "Qualité maximale de streaming:", + "LabelNotificationEnabled": "Activer cette notification", + "LabelNewName": "Nouveau nom:", + "LabelNewPasswordConfirm": "Confirmer le nouveau mot de passe:", + "LabelPersonRole": "Rôle:", + "LabelPasswordConfirm": "Confirmer le mot de passe:", + "LabelPersonRoleHelp": "Exemple: Conducteur de camion à crème glacée", + "LabelPleaseRestart": "Les changements prendront effets après avoir rechargé manuellement le client web.", + "LabelMinAudiobookResumeHelp": "Les titres sont considérés comme non joué s'ils sont arrêtés avant cette durée.", + "LabelPassword": "Mot de passe:", + "LabelPath": "Chemin:", + "LabelMetadataPath": "Chemin des métadonnées:", + "LabelDummyChapterDuration": "Intervalle:", + "LabelDummyChapterCount": "Limite:", + "LabelChapterImageResolution": "Résolution:" } From 339311008e1c06c81ff21507a2cd8fa4d3c79f94 Mon Sep 17 00:00:00 2001 From: stanol Date: Thu, 9 Mar 2023 18:59:01 +0000 Subject: [PATCH 36/65] Translated using Weblate (Ukrainian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/uk/ --- src/strings/uk.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/uk.json b/src/strings/uk.json index 3a6d695e64..7a7527dc02 100644 --- a/src/strings/uk.json +++ b/src/strings/uk.json @@ -1439,7 +1439,7 @@ "SubtitleDownloadersHelp": "Увімкніть та оцініть бажані завантажувачі субтитрів у порядку пріоритету.", "SubtitleAppearanceSettingsDisclaimer": "Наведені нижче налаштування не застосовуються до графічних субтитрів, згаданих вище, або субтитрів ASS/SSA, які вбудовують власні стилі.", "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Ці налаштування також застосовуються до будь-якого відтворення Google Cast, запущеного цим пристроєм.", - "Subtitle": "Підзаголовок", + "Subtitle": "Субтитри", "Studios": "Студії", "StopRecording": "Зупинити запис", "StopPlayback": "Зупинити відтворення", From 85fcf9821acfdfd7e63b6cde4e7c5a8137cba478 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sun, 8 Jan 2023 19:38:01 +0100 Subject: [PATCH 37/65] Add setting for collection management --- src/components/itemContextMenu.js | 2 +- src/routes/user/useredit.tsx | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/itemContextMenu.js b/src/components/itemContextMenu.js index e1c1545b69..e191a9afb7 100644 --- a/src/components/itemContextMenu.js +++ b/src/components/itemContextMenu.js @@ -99,7 +99,7 @@ import toast from './toast/toast'; }); } - if (!restrictOptions) { + if (options.EnableCollectionManagement && !restrictOptions) { if (itemHelper.supportsAddingToCollection(item)) { commands.push({ name: globalize.translate('AddToCollection'), diff --git a/src/routes/user/useredit.tsx b/src/routes/user/useredit.tsx index 5afa0c4fd8..345b31c638 100644 --- a/src/routes/user/useredit.tsx +++ b/src/routes/user/useredit.tsx @@ -159,6 +159,7 @@ const UserEdit: FunctionComponent = () => { (page.querySelector('.chkIsAdmin') as HTMLInputElement).checked = user.Policy.IsAdministrator; (page.querySelector('.chkDisabled') as HTMLInputElement).checked = user.Policy.IsDisabled; (page.querySelector('.chkIsHidden') as HTMLInputElement).checked = user.Policy.IsHidden; + (page.querySelector('.chkEnableCollectionManagement') as HTMLInputElement).checked = user.Policy.EnableCollectionManagement; (page.querySelector('.chkRemoteControlSharedDevices') as HTMLInputElement).checked = user.Policy.EnableSharedDeviceControl; (page.querySelector('.chkEnableRemoteControlOtherUsers') as HTMLInputElement).checked = user.Policy.EnableRemoteControlOfOtherUsers; (page.querySelector('.chkEnableDownloading') as HTMLInputElement).checked = user.Policy.EnableContentDownloading; @@ -224,6 +225,7 @@ const UserEdit: FunctionComponent = () => { user.Policy.EnableAudioPlaybackTranscoding = (page.querySelector('.chkEnableAudioPlaybackTranscoding') as HTMLInputElement).checked; user.Policy.EnableVideoPlaybackTranscoding = (page.querySelector('.chkEnableVideoPlaybackTranscoding') as HTMLInputElement).checked; user.Policy.EnablePlaybackRemuxing = (page.querySelector('.chkEnableVideoPlaybackRemuxing') as HTMLInputElement).checked; + user.Policy.EnableCollectionManagement = (page.querySelector('.chkEnableCollectionManagement') as HTMLInputElement).checked; user.Policy.ForceRemoteSourceTranscoding = (page.querySelector('.chkForceRemoteSourceTranscoding') as HTMLInputElement).checked; user.Policy.EnableContentDownloading = (page.querySelector('.chkEnableDownloading') as HTMLInputElement).checked; user.Policy.EnableRemoteAccess = (page.querySelector('.chkRemoteAccess') as HTMLInputElement).checked; @@ -375,6 +377,11 @@ const UserEdit: FunctionComponent = () => { className='chkIsAdmin' title='OptionAllowUserToManageServer' /> +

{globalize.translate('HeaderFeatureAccess')} From 8dbf40fa0a5077c34a2bf14a5ecb911d49e358d4 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Thu, 9 Mar 2023 19:43:06 -0500 Subject: [PATCH 38/65] Backport pull request #4330 from jellyfin/release-10.8.z Fix navigation for some types of INPUT Original-merge: 7e99e3ec515d9a461358b5053da0c78a9f452e8d Merged-by: Bill Thornton Backported-by: crobibero --- src/scripts/keyboardNavigation.js | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/scripts/keyboardNavigation.js b/src/scripts/keyboardNavigation.js index feef180630..39c187479d 100644 --- a/src/scripts/keyboardNavigation.js +++ b/src/scripts/keyboardNavigation.js @@ -50,6 +50,11 @@ const NavigationKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']; */ const InteractiveElements = ['INPUT', 'TEXTAREA']; +/** + * Types of INPUT element for which navigation shouldn't be constrained. + */ +const NonInteractiveInputElements = ['button', 'checkbox', 'color', 'file', 'hidden', 'image', 'radio', 'reset', 'submit']; + let hasFieldKey = false; try { hasFieldKey = 'key' in new KeyboardEvent('keydown'); @@ -84,6 +89,24 @@ export function isNavigationKey(key) { return NavigationKeys.indexOf(key) != -1; } +/** + * Returns _true_ if the element is interactive. + * + * @param {Element} element - Element. + * @return {boolean} _true_ if the element is interactive. + */ +export function isInteractiveElement(element) { + if (element && InteractiveElements.includes(element.tagName)) { + if (element.tagName === 'INPUT') { + return !NonInteractiveInputElements.includes(element.type); + } + + return true; + } + + return false; +} + export function enable() { window.addEventListener('keydown', function (e) { const key = getKeyName(e); @@ -97,7 +120,7 @@ export function enable() { switch (key) { case 'ArrowLeft': - if (!InteractiveElements.includes(document.activeElement?.tagName)) { + if (!isInteractiveElement(document.activeElement)) { inputManager.handleCommand('left'); } else { capture = false; @@ -107,7 +130,7 @@ export function enable() { inputManager.handleCommand('up'); break; case 'ArrowRight': - if (!InteractiveElements.includes(document.activeElement?.tagName)) { + if (!isInteractiveElement(document.activeElement)) { inputManager.handleCommand('right'); } else { capture = false; From 2c4d065e0ebaca280bc71a2e5c126d22203168be Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Thu, 9 Mar 2023 19:43:07 -0500 Subject: [PATCH 39/65] Backport pull request #4362 from jellyfin/release-10.8.z Fix subtitle offset reset when seeking progressive stream Original-merge: af27e084d5fd6d7f0372b8f10a5eff339c73866c Merged-by: Bill Thornton Backported-by: crobibero --- src/components/playback/playbackmanager.js | 1 + src/plugins/htmlVideoPlayer/plugin.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 947f46eec8..e6cba06d2e 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1740,6 +1740,7 @@ class PlaybackManager { const streamInfo = createStreamInfo(apiClient, currentItem.MediaType, currentItem, currentMediaSource, ticks, player); streamInfo.fullscreen = currentPlayOptions.fullscreen; streamInfo.lastMediaInfoQuery = lastMediaInfoQuery; + streamInfo.resetSubtitleOffset = false; if (!streamInfo.url) { showPlaybackInfoErrorMessage(self, 'PlaybackErrorNoCompatibleStream'); diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index 2582785f8e..a4f512768f 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -382,7 +382,7 @@ function tryRemoveElement(elem) { this.#currentTime = null; - this.resetSubtitleOffset(); + if (options.resetSubtitleOffset !== false) this.resetSubtitleOffset(); return this.createMediaElement(options).then(elem => { return this.updateVideoUrl(options).then(() => { From c9b72d87fe6299e79c025db60901a306325deab7 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Thu, 9 Mar 2023 19:43:08 -0500 Subject: [PATCH 40/65] Backport pull request #4395 from jellyfin/release-10.8.z Fix installed plugin version html Original-merge: 22d1f40587a79a0774fe0fe6f8c07a258d077f24 Merged-by: Bill Thornton Backported-by: crobibero --- src/controllers/dashboard/plugins/add/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/dashboard/plugins/add/index.js b/src/controllers/dashboard/plugins/add/index.js index 5e0a2d3f14..150fe3e1fd 100644 --- a/src/controllers/dashboard/plugins/add/index.js +++ b/src/controllers/dashboard/plugins/add/index.js @@ -68,7 +68,7 @@ function renderPackage(pkg, installedPlugins, page) { if (installedPlugin) { const currentVersionText = globalize.translate('MessageYouHaveVersionInstalled', '' + installedPlugin.Version + ''); - $('#pCurrentVersion', page).show().text(currentVersionText); + $('#pCurrentVersion', page).show().html(currentVersionText); } else { $('#pCurrentVersion', page).hide().text(''); } From ce06fc3c286effdc24fef547e0293dea68d5fe18 Mon Sep 17 00:00:00 2001 From: Niels van Velzen Date: Mon, 15 Aug 2022 08:25:38 +0200 Subject: [PATCH 41/65] Remove NPM prepare script --- package.json | 1 - scripts/prepare.js | 12 ------------ 2 files changed, 13 deletions(-) delete mode 100755 scripts/prepare.js diff --git a/package.json b/package.json index bc19c04a9e..4148aad18c 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,6 @@ "scripts": { "start": "npm run serve", "serve": "webpack serve --config webpack.dev.js", - "prepare": "node ./scripts/prepare.js", "build:development": "webpack --config webpack.dev.js", "build:production": "cross-env NODE_ENV=\"production\" webpack --config webpack.prod.js", "build:check": "tsc --noEmit", diff --git a/scripts/prepare.js b/scripts/prepare.js deleted file mode 100755 index 898b105e2f..0000000000 --- a/scripts/prepare.js +++ /dev/null @@ -1,12 +0,0 @@ -const { execSync } = require('child_process'); - -/** - * The npm `prepare` script needs to run a build to support installing - * a package from git repositories (this is dumb but a limitation of how - * npm behaves). We don't want to run these in CI though because - * building is slow so this script will skip the build when the - * `SKIP_PREPARE` environment variable has been set. - */ -if (!process.env.SKIP_PREPARE) { - execSync('webpack --config webpack.prod.js', { stdio: 'inherit' }); -} From c50bc44c3b0f289a6b958f992669141b2e519576 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Fri, 10 Mar 2023 12:24:43 -0500 Subject: [PATCH 42/65] Run web build script manually --- debian/rules | 1 + deployment/Dockerfile.docker | 4 +++- deployment/build.portable | 1 + fedora/jellyfin-web.spec | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/debian/rules b/debian/rules index d9ba35ed30..091af0db11 100755 --- a/debian/rules +++ b/debian/rules @@ -12,6 +12,7 @@ override_dh_clistrip: override_dh_auto_build: npm ci --no-audit --unsafe-perm + npm run build:production mv $(CURDIR)/dist $(CURDIR)/web override_dh_auto_clean: diff --git a/deployment/Dockerfile.docker b/deployment/Dockerfile.docker index 33cf501665..5605e1150f 100644 --- a/deployment/Dockerfile.docker +++ b/deployment/Dockerfile.docker @@ -8,4 +8,6 @@ RUN apk add autoconf g++ make libpng-dev gifsicle alpine-sdk automake libtool ma WORKDIR ${SOURCE_DIR} COPY . . -RUN npm ci --no-audit --unsafe-perm && mv dist ${ARTIFACT_DIR} +RUN npm ci --no-audit --unsafe-perm \ + && npm run build:production \ + && mv dist ${ARTIFACT_DIR} diff --git a/deployment/build.portable b/deployment/build.portable index 18f7a8d1e6..8bf8a0d2af 100755 --- a/deployment/build.portable +++ b/deployment/build.portable @@ -15,6 +15,7 @@ fi # build archives npm ci --no-audit --unsafe-perm +npm run build:production mv dist jellyfin-web_${version} tar -czf jellyfin-web_${version}_portable.tar.gz jellyfin-web_${version} rm -rf dist diff --git a/fedora/jellyfin-web.spec b/fedora/jellyfin-web.spec index 28407b8bcd..595ef33f2c 100644 --- a/fedora/jellyfin-web.spec +++ b/fedora/jellyfin-web.spec @@ -35,6 +35,7 @@ chown root:root -R . %build npm ci --no-audit --unsafe-perm +npm run build:production %install From 8277fa0d3294e3b3c456f16c4a666b074a60b532 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Fri, 10 Mar 2023 12:31:36 -0500 Subject: [PATCH 43/65] Remove SKIP_PREPARE env variable usages --- .ci/azure-pipelines-build.yml | 2 -- .github/workflows/lint.yml | 6 ------ 2 files changed, 8 deletions(-) diff --git a/.ci/azure-pipelines-build.yml b/.ci/azure-pipelines-build.yml index 021b6471cd..9c3a51c9fc 100644 --- a/.ci/azure-pipelines-build.yml +++ b/.ci/azure-pipelines-build.yml @@ -26,8 +26,6 @@ jobs: - script: 'npm ci --no-audit' displayName: 'Install Dependencies' - env: - SKIP_PREPARE: 'true' - script: 'npm run build:development' displayName: 'Build Development' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 15526f009a..498d800fee 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -50,8 +50,6 @@ jobs: - name: Install Node.js dependencies run: npm ci --no-audit - env: - SKIP_PREPARE: true - name: Run eslint run: npm run lint @@ -76,8 +74,6 @@ jobs: - name: Install Node.js dependencies run: npm ci --no-audit - env: - SKIP_PREPARE: true - name: Run stylelint run: npm run stylelint:css @@ -102,8 +98,6 @@ jobs: - name: Install Node.js dependencies run: npm ci --no-audit - env: - SKIP_PREPARE: true - name: Run stylelint run: npm run stylelint:scss From 51fee9d55ab8c9cc81a6b02077f95baaa44f2939 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Fri, 10 Mar 2023 12:33:12 -0500 Subject: [PATCH 44/65] Remove SKIP_PREPARE env variable usages --- .github/workflows/lint.yml | 2 -- .github/workflows/tsc.yml | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 498d800fee..4d8519501c 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -24,8 +24,6 @@ jobs: - name: Install Node.js dependencies run: npm ci --no-audit - env: - SKIP_PREPARE: true - name: Run a production build run: npm run build:production diff --git a/.github/workflows/tsc.yml b/.github/workflows/tsc.yml index be0f2596aa..2b1b3bf594 100644 --- a/.github/workflows/tsc.yml +++ b/.github/workflows/tsc.yml @@ -24,8 +24,6 @@ jobs: - name: Install Node.js dependencies run: npm ci --no-audit - env: - SKIP_PREPARE: true - name: Run tsc - run: npm run build:check \ No newline at end of file + run: npm run build:check From cb8f3cbe034b4eced7254dc32719c00d97cd2653 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 Mar 2023 20:20:34 +0000 Subject: [PATCH 45/65] Update github/codeql-action action to v2.2.6 --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d0d11b4c5f..9d4ab5b257 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -21,11 +21,11 @@ jobs: - name: Checkout repository uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 - name: Initialize CodeQL - uses: github/codeql-action/init@32dc499307d133bb5085bae78498c0ac2cf762d5 # v2.2.5 + uses: github/codeql-action/init@16964e90ba004cdf0cd845b866b5df21038b7723 # v2.2.6 with: languages: ${{ matrix.language }} queries: +security-extended - name: Autobuild - uses: github/codeql-action/autobuild@32dc499307d133bb5085bae78498c0ac2cf762d5 # v2.2.5 + uses: github/codeql-action/autobuild@16964e90ba004cdf0cd845b866b5df21038b7723 # v2.2.6 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@32dc499307d133bb5085bae78498c0ac2cf762d5 # v2.2.5 + uses: github/codeql-action/analyze@16964e90ba004cdf0cd845b866b5df21038b7723 # v2.2.6 From 95ae063f422cbf49c5aee9f59c230c4fda91cb85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Kucharczyk?= Date: Fri, 10 Mar 2023 18:14:49 +0000 Subject: [PATCH 46/65] Translated using Weblate (Czech) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/cs/ --- src/strings/cs.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/strings/cs.json b/src/strings/cs.json index 369b0c17ca..a8d7ae5656 100644 --- a/src/strings/cs.json +++ b/src/strings/cs.json @@ -1622,7 +1622,7 @@ "DeletedScene": "Vymazaná scéna", "BehindTheScenes": "Z natáčení", "Trailer": "Upoutávka", - "Clip": "Krátký film", + "Clip": "Filmový klip", "AllowEmbeddedSubtitlesHelp": "Zakázat titulky, které jsou vložené v kontejneru média. Vyžaduje kompletní přeskenování knihovny.", "AllowEmbeddedSubtitlesAllowTextOption": "Povolit textové titulky", "AllowEmbeddedSubtitlesAllowImageOption": "Povolit grafické titulky", @@ -1714,5 +1714,7 @@ "SubtitleMagenta": "Fialová", "SubtitleRed": "Červená", "SubtitleWhite": "Bílá", - "SubtitleYellow": "Žlutá" + "SubtitleYellow": "Žlutá", + "Featurette": "Středně dlouhý film", + "Short": "Krátký film" } From 8e73e31d7cc50722e2fb553bd55c882df8c5b546 Mon Sep 17 00:00:00 2001 From: blob03 Date: Fri, 10 Mar 2023 18:46:22 +0000 Subject: [PATCH 47/65] Translated using Weblate (French) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fr/ --- src/strings/fr.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/strings/fr.json b/src/strings/fr.json index e26cc1a0c0..4c01e2b798 100644 --- a/src/strings/fr.json +++ b/src/strings/fr.json @@ -1614,7 +1614,7 @@ "AudioIsExternal": "Le flux audio est externe", "SelectAll": "Tout sélectionner", "ButtonExitApp": "Quitter l'application", - "Clip": "Court-métrage", + "Clip": "Clip", "ThemeVideo": "Générique", "ThemeSong": "Thème musical", "Sample": "Échantillon", @@ -1714,5 +1714,7 @@ "SubtitleMagenta": "Magenta", "SubtitleRed": "Rouge", "SubtitleWhite": "Blanc", - "SubtitleYellow": "Jaune" + "SubtitleYellow": "Jaune", + "Featurette": "Featurette", + "Short": "Court-métrage" } From 65eb19c7b0daae51496d889dad6d00f16aeaa794 Mon Sep 17 00:00:00 2001 From: Oskari Lavinto Date: Sat, 11 Mar 2023 01:17:44 +0000 Subject: [PATCH 48/65] Translated using Weblate (Finnish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fi/ --- src/strings/fi.json | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/strings/fi.json b/src/strings/fi.json index e35b229682..9d5e968ff0 100644 --- a/src/strings/fi.json +++ b/src/strings/fi.json @@ -1634,7 +1634,7 @@ "ButtonSpace": "Välilyönti", "ThemeVideo": "Tunnusvideo", "ThemeSong": "Tunnusmusiikki", - "Clip": "Lyhytfilmi", + "Clip": "Klippi", "Scene": "Kohtaus", "Interview": "Haastattelu", "UnknownAudioStreamInfo": "Äänivirran tiedot ovat tuntemattomia", @@ -1677,7 +1677,7 @@ "MessageNoFavoritesAvailable": "Suosikkeja ei ole tällä hetkellä käytettävissä.", "EnableCardLayout": "Näytä visuaalinen KorttiLaatikko", "Unreleased": "Ei vielä julkaistu", - "MediaInfoDvVersionMajor": "", + "MediaInfoDvVersionMajor": "DV-pääversio", "DownloadAll": "Lataa kaikki", "Experimental": "Kokeellinen", "LabelStereoDownmixAlgorithm": "Stereoäänen alasmiksausalgoritmi:", @@ -1697,5 +1697,22 @@ "ResolutionMatchSource": "Vastaa lähdettä", "PreferEmbeddedExtrasTitlesOverFileNames": "Suosi lisämateriaaleille upotettuja otsikoita tiedostonimien sijaan", "PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Lisämateriaaleilla on usein sama otsikko kuin niiden isännällä. Valitse tämä käyttääksesi silti upotettuja otsikoita.", - "SecondarySubtitles": "Toissijaiset tekstitykset" + "SecondarySubtitles": "Toissijaiset tekstitykset", + "MediaInfoElPresentFlag": "DV EL havaittu", + "SubtitleBlack": "Musta", + "SubtitleCyan": "Syaani", + "SubtitleGray": "Harmaa", + "SubtitleGreen": "Vihreä", + "SubtitleLightGray": "Vaaleanharmaa", + "SubtitleMagenta": "Magenta", + "SubtitleRed": "Punainen", + "SubtitleWhite": "Valkoinen", + "SubtitleYellow": "Keltainen", + "MediaInfoDvBlSignalCompatibilityId": "DV BL -signaaliyhteensopivuuden ID", + "SubtitleBlue": "Sininen", + "Featurette": "Oheisfilmi", + "Short": "Lyhytfilmi", + "MediaInfoBlPresentFlag": "DV BL havaittu", + "MediaInfoRpuPresentFlag": "DV RPU havaittu", + "MediaInfoDvVersionMinor": "DV-väliversio" } From 935fa8a1e7e4e4e2a5114746b2e129a17a19b928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=80=A0xu=5Fzh?= Date: Sat, 11 Mar 2023 02:44:37 +0000 Subject: [PATCH 49/65] Translated using Weblate (Chinese (Simplified)) 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, 4 insertions(+), 2 deletions(-) diff --git a/src/strings/zh-cn.json b/src/strings/zh-cn.json index d6e77b18ef..f05bb4d988 100644 --- a/src/strings/zh-cn.json +++ b/src/strings/zh-cn.json @@ -1621,7 +1621,7 @@ "DeletedScene": "删减场景", "BehindTheScenes": "幕后花絮", "Trailer": "预告片", - "Clip": "花絮", + "Clip": "片段", "ButtonExitApp": "退出应用", "ShowParentImages": "显示系列图片", "AllowEmbeddedSubtitlesAllowTextOption": "允许文本", @@ -1714,5 +1714,7 @@ "SubtitleGreen": "绿色", "SubtitleMagenta": "品红色", "SubtitleRed": "红色", - "SubtitleYellow": "黄色" + "SubtitleYellow": "黄色", + "Featurette": "花絮", + "Short": "短片" } From 52461bc7ceb7b8a6792c205b5655930139954788 Mon Sep 17 00:00:00 2001 From: Andi Chandler Date: Sat, 11 Mar 2023 18:35:14 +0000 Subject: [PATCH 50/65] 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, 4 insertions(+), 2 deletions(-) diff --git a/src/strings/en-gb.json b/src/strings/en-gb.json index 3dfb6b8d0d..c52fb52d48 100644 --- a/src/strings/en-gb.json +++ b/src/strings/en-gb.json @@ -1629,7 +1629,7 @@ "DeletedScene": "Deleted Scene", "BehindTheScenes": "Behind the Scenes", "Trailer": "Trailer", - "Clip": "Featurette", + "Clip": "Clip", "ShowParentImages": "Show programme images", "NextUpRewatching": "Rewatching", "MixedMoviesShows": "Mixed Films and Programmes", @@ -1714,5 +1714,7 @@ "SubtitleMagenta": "Magenta", "SubtitleRed": "Red", "SubtitleWhite": "White", - "SubtitleYellow": "Yellow" + "SubtitleYellow": "Yellow", + "Featurette": "Featurette", + "Short": "Short" } From 95822fd2cf5b2dd94bf61817c56a57ab0753e70b Mon Sep 17 00:00:00 2001 From: Andrei Date: Sat, 11 Mar 2023 20:44:04 +0000 Subject: [PATCH 51/65] Translated using Weblate (Belarusian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/be/ --- src/strings/be-by.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/strings/be-by.json b/src/strings/be-by.json index fab979dd48..3e64e8e09b 100644 --- a/src/strings/be-by.json +++ b/src/strings/be-by.json @@ -1380,7 +1380,7 @@ "UnknownAudioStreamInfo": "Інфармацыя аб аўдыяплыні невядомая", "DirectPlayError": "Узнікла памылка пры запуску прамога прайгравання", "SelectAll": "Абраць усё", - "Clip": "Художнік", + "Clip": "Кліп", "Sample": "Прыклад", "LabelVppTonemappingBrightness": "Узмацненне яркасці танальнага адлюстравання VPP:", "LabelVppTonemappingBrightnessHelp": "Прымяніць узмацненне яркасці ў танальным адлюстраванні VPP. І рэкамендаванае, і стандартнае значэнне роўна 0.", @@ -1700,5 +1700,7 @@ "SubtitleMagenta": "Пурпурны", "SubtitleRed": "Чырвоны", "SubtitleWhite": "Белы", - "SubtitleYellow": "Жоўты" + "SubtitleYellow": "Жоўты", + "Featurette": "Кароткаметражка", + "Short": "Кароткаметражка" } From 43addea602d6cfbe8bc931edbf6be563e93ec0da Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Thu, 9 Mar 2023 21:42:57 +0100 Subject: [PATCH 52/65] Only disable collection management for TV --- src/components/itemContextMenu.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/itemContextMenu.js b/src/components/itemContextMenu.js index e191a9afb7..e0bcb1562b 100644 --- a/src/components/itemContextMenu.js +++ b/src/components/itemContextMenu.js @@ -15,7 +15,6 @@ import toast from './toast/toast'; const user = options.user; const canPlay = playbackManager.canPlay(item); - const restrictOptions = (browser.operaTv || browser.web0s) && !user.Policy.IsAdministrator; const commands = []; @@ -99,8 +98,8 @@ import toast from './toast/toast'; }); } - if (options.EnableCollectionManagement && !restrictOptions) { - if (itemHelper.supportsAddingToCollection(item)) { + if (!browser.tv) { + if (itemHelper.supportsAddingToCollection(item) && options.EnableCollectionManagement) { commands.push({ name: globalize.translate('AddToCollection'), id: 'addtocollection', @@ -272,7 +271,7 @@ import toast from './toast/toast'; }); } - if (!restrictOptions && options.share === true && itemHelper.canShare(item, user)) { + if (!browser.tv && options.share === true && itemHelper.canShare(item, user)) { commands.push({ name: globalize.translate('Share'), id: 'share', From 83c4200257f51bbe6a33a758b14710b79f00bf9b Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Thu, 9 Mar 2023 22:02:56 +0100 Subject: [PATCH 53/65] Update @jellyfin/sdk to unstable.202303130502 --- package-lock.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index dcc6fb05f6..8f608b63c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2611,11 +2611,11 @@ "integrity": "sha512-xQVJw+lZUg4U1TmLS80reBECfPtpCgRF8hhUSvUUQM9g68OvINyUU3K2yqRH+8tomGpghiRaIcr/bUJ83e0veA==" }, "node_modules/@jellyfin/sdk": { - "version": "0.0.0-unstable.202302070552", - "resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202302070552.tgz", - "integrity": "sha512-hwrHLLFPTCEcrMywpLWwgGKEDKBjgu3o+ruMV3qCG7uAmKAQq48kuaZ818rJD+LjWBjBIUixnLJq1qUlHsgc+A==", + "version": "0.0.0-unstable.202303130502", + "resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202303130502.tgz", + "integrity": "sha512-j3ntDjTnZlU511J0CpuPVSSSYrx9so4Y3q6qYOVsB6/evH4/2BNkWYRbKgCnUtCULIV90T6KGc2EcS4GGxojCg==", "dependencies": { - "axios": "1.2.6", + "axios": "1.3.4", "compare-versions": "5.0.3" } }, @@ -4111,9 +4111,9 @@ } }, "node_modules/axios": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.6.tgz", - "integrity": "sha512-rC/7F08XxZwjMV4iuWv+JpD3E0Ksqg9nac4IIg6RwNuF0JTeWoCo/mBNG54+tNhhI11G3/VDRbdDQTs9hGp4pQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz", + "integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -20912,11 +20912,11 @@ "integrity": "sha512-xQVJw+lZUg4U1TmLS80reBECfPtpCgRF8hhUSvUUQM9g68OvINyUU3K2yqRH+8tomGpghiRaIcr/bUJ83e0veA==" }, "@jellyfin/sdk": { - "version": "0.0.0-unstable.202302070552", - "resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202302070552.tgz", - "integrity": "sha512-hwrHLLFPTCEcrMywpLWwgGKEDKBjgu3o+ruMV3qCG7uAmKAQq48kuaZ818rJD+LjWBjBIUixnLJq1qUlHsgc+A==", + "version": "0.0.0-unstable.202303130502", + "resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202303130502.tgz", + "integrity": "sha512-j3ntDjTnZlU511J0CpuPVSSSYrx9so4Y3q6qYOVsB6/evH4/2BNkWYRbKgCnUtCULIV90T6KGc2EcS4GGxojCg==", "requires": { - "axios": "1.2.6", + "axios": "1.3.4", "compare-versions": "5.0.3" } }, @@ -22088,9 +22088,9 @@ "dev": true }, "axios": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.6.tgz", - "integrity": "sha512-rC/7F08XxZwjMV4iuWv+JpD3E0Ksqg9nac4IIg6RwNuF0JTeWoCo/mBNG54+tNhhI11G3/VDRbdDQTs9hGp4pQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz", + "integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==", "requires": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", From f732018c7542905c6c4ff6dda86983da870ff468 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Mar 2023 21:52:25 +0000 Subject: [PATCH 54/65] Update Linters to v5.54.1 --- package-lock.json | 164 +++++++++++++++++++++++----------------------- package.json | 4 +- 2 files changed, 84 insertions(+), 84 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8f608b63c0..e65ff720de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,8 +68,8 @@ "@types/lodash-es": "4.17.6", "@types/react": "17.0.53", "@types/react-dom": "17.0.19", - "@typescript-eslint/eslint-plugin": "5.54.0", - "@typescript-eslint/parser": "5.54.0", + "@typescript-eslint/eslint-plugin": "5.54.1", + "@typescript-eslint/parser": "5.54.1", "@uupaa/dynamic-import-polyfill": "1.0.2", "autoprefixer": "10.4.13", "babel-loader": "9.1.2", @@ -3200,14 +3200,14 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.0.tgz", - "integrity": "sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.1.tgz", + "integrity": "sha512-a2RQAkosH3d3ZIV08s3DcL/mcGc2M/UC528VkPULFxR9VnVPT8pBu0IyBAJJmVsCmhVfwQX1v6q+QGnmSe1bew==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.54.0", - "@typescript-eslint/type-utils": "5.54.0", - "@typescript-eslint/utils": "5.54.0", + "@typescript-eslint/scope-manager": "5.54.1", + "@typescript-eslint/type-utils": "5.54.1", + "@typescript-eslint/utils": "5.54.1", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", @@ -3249,14 +3249,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.0.tgz", - "integrity": "sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.1.tgz", + "integrity": "sha512-8zaIXJp/nG9Ff9vQNh7TI+C3nA6q6iIsGJ4B4L6MhZ7mHnTMR4YP5vp2xydmFXIy8rpyIVbNAG44871LMt6ujg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.54.0", - "@typescript-eslint/types": "5.54.0", - "@typescript-eslint/typescript-estree": "5.54.0", + "@typescript-eslint/scope-manager": "5.54.1", + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/typescript-estree": "5.54.1", "debug": "^4.3.4" }, "engines": { @@ -3276,13 +3276,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.54.0.tgz", - "integrity": "sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.54.1.tgz", + "integrity": "sha512-zWKuGliXxvuxyM71UA/EcPxaviw39dB2504LqAmFDjmkpO8qNLHcmzlh6pbHs1h/7YQ9bnsO8CCcYCSA8sykUg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.54.0", - "@typescript-eslint/visitor-keys": "5.54.0" + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/visitor-keys": "5.54.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3293,13 +3293,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.54.0.tgz", - "integrity": "sha512-WI+WMJ8+oS+LyflqsD4nlXMsVdzTMYTxl16myXPaCXnSgc7LWwMsjxQFZCK/rVmTZ3FN71Ct78ehO9bRC7erYQ==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.54.1.tgz", + "integrity": "sha512-WREHsTz0GqVYLIbzIZYbmUUr95DKEKIXZNH57W3s+4bVnuF1TKe2jH8ZNH8rO1CeMY3U4j4UQeqPNkHMiGem3g==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.54.0", - "@typescript-eslint/utils": "5.54.0", + "@typescript-eslint/typescript-estree": "5.54.1", + "@typescript-eslint/utils": "5.54.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -3320,9 +3320,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.54.0.tgz", - "integrity": "sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.54.1.tgz", + "integrity": "sha512-G9+1vVazrfAfbtmCapJX8jRo2E4MDXxgm/IMOF4oGh3kq7XuK3JRkOg6y2Qu1VsTRmWETyTkWt1wxy7X7/yLkw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3333,13 +3333,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.0.tgz", - "integrity": "sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.1.tgz", + "integrity": "sha512-bjK5t+S6ffHnVwA0qRPTZrxKSaFYocwFIkZx5k7pvWfsB1I57pO/0M0Skatzzw1sCkjJ83AfGTL0oFIFiDX3bg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.54.0", - "@typescript-eslint/visitor-keys": "5.54.0", + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/visitor-keys": "5.54.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3404,16 +3404,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.54.0.tgz", - "integrity": "sha512-cuwm8D/Z/7AuyAeJ+T0r4WZmlnlxQ8wt7C7fLpFlKMR+dY6QO79Cq1WpJhvZbMA4ZeZGHiRWnht7ZJ8qkdAunw==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.54.1.tgz", + "integrity": "sha512-IY5dyQM8XD1zfDe5X8jegX6r2EVU5o/WJnLu/znLPWCBF7KNGC+adacXnt5jEYS9JixDcoccI6CvE4RCjHMzCQ==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.54.0", - "@typescript-eslint/types": "5.54.0", - "@typescript-eslint/typescript-estree": "5.54.0", + "@typescript-eslint/scope-manager": "5.54.1", + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/typescript-estree": "5.54.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -3445,12 +3445,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.0.tgz", - "integrity": "sha512-xu4wT7aRCakGINTLGeyGqDn+78BwFlggwBjnHa1ar/KaGagnmwLYmlrXIrgAaQ3AE1Vd6nLfKASm7LrFHNbKGA==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.1.tgz", + "integrity": "sha512-q8iSoHTgwCfgcRJ2l2x+xCbu8nBlRAlsQ33k24Adj8eoVBE0f8dUeI+bAa8F84Mv05UGbAx57g2zrRsYIooqQg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.54.0", + "@typescript-eslint/types": "5.54.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -21437,14 +21437,14 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.0.tgz", - "integrity": "sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.1.tgz", + "integrity": "sha512-a2RQAkosH3d3ZIV08s3DcL/mcGc2M/UC528VkPULFxR9VnVPT8pBu0IyBAJJmVsCmhVfwQX1v6q+QGnmSe1bew==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.54.0", - "@typescript-eslint/type-utils": "5.54.0", - "@typescript-eslint/utils": "5.54.0", + "@typescript-eslint/scope-manager": "5.54.1", + "@typescript-eslint/type-utils": "5.54.1", + "@typescript-eslint/utils": "5.54.1", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", @@ -21466,53 +21466,53 @@ } }, "@typescript-eslint/parser": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.0.tgz", - "integrity": "sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.1.tgz", + "integrity": "sha512-8zaIXJp/nG9Ff9vQNh7TI+C3nA6q6iIsGJ4B4L6MhZ7mHnTMR4YP5vp2xydmFXIy8rpyIVbNAG44871LMt6ujg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.54.0", - "@typescript-eslint/types": "5.54.0", - "@typescript-eslint/typescript-estree": "5.54.0", + "@typescript-eslint/scope-manager": "5.54.1", + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/typescript-estree": "5.54.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.54.0.tgz", - "integrity": "sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.54.1.tgz", + "integrity": "sha512-zWKuGliXxvuxyM71UA/EcPxaviw39dB2504LqAmFDjmkpO8qNLHcmzlh6pbHs1h/7YQ9bnsO8CCcYCSA8sykUg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.54.0", - "@typescript-eslint/visitor-keys": "5.54.0" + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/visitor-keys": "5.54.1" } }, "@typescript-eslint/type-utils": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.54.0.tgz", - "integrity": "sha512-WI+WMJ8+oS+LyflqsD4nlXMsVdzTMYTxl16myXPaCXnSgc7LWwMsjxQFZCK/rVmTZ3FN71Ct78ehO9bRC7erYQ==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.54.1.tgz", + "integrity": "sha512-WREHsTz0GqVYLIbzIZYbmUUr95DKEKIXZNH57W3s+4bVnuF1TKe2jH8ZNH8rO1CeMY3U4j4UQeqPNkHMiGem3g==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.54.0", - "@typescript-eslint/utils": "5.54.0", + "@typescript-eslint/typescript-estree": "5.54.1", + "@typescript-eslint/utils": "5.54.1", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.54.0.tgz", - "integrity": "sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.54.1.tgz", + "integrity": "sha512-G9+1vVazrfAfbtmCapJX8jRo2E4MDXxgm/IMOF4oGh3kq7XuK3JRkOg6y2Qu1VsTRmWETyTkWt1wxy7X7/yLkw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.0.tgz", - "integrity": "sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.1.tgz", + "integrity": "sha512-bjK5t+S6ffHnVwA0qRPTZrxKSaFYocwFIkZx5k7pvWfsB1I57pO/0M0Skatzzw1sCkjJ83AfGTL0oFIFiDX3bg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.54.0", - "@typescript-eslint/visitor-keys": "5.54.0", + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/visitor-keys": "5.54.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -21552,16 +21552,16 @@ } }, "@typescript-eslint/utils": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.54.0.tgz", - "integrity": "sha512-cuwm8D/Z/7AuyAeJ+T0r4WZmlnlxQ8wt7C7fLpFlKMR+dY6QO79Cq1WpJhvZbMA4ZeZGHiRWnht7ZJ8qkdAunw==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.54.1.tgz", + "integrity": "sha512-IY5dyQM8XD1zfDe5X8jegX6r2EVU5o/WJnLu/znLPWCBF7KNGC+adacXnt5jEYS9JixDcoccI6CvE4RCjHMzCQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.54.0", - "@typescript-eslint/types": "5.54.0", - "@typescript-eslint/typescript-estree": "5.54.0", + "@typescript-eslint/scope-manager": "5.54.1", + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/typescript-estree": "5.54.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -21579,12 +21579,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.0.tgz", - "integrity": "sha512-xu4wT7aRCakGINTLGeyGqDn+78BwFlggwBjnHa1ar/KaGagnmwLYmlrXIrgAaQ3AE1Vd6nLfKASm7LrFHNbKGA==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.1.tgz", + "integrity": "sha512-q8iSoHTgwCfgcRJ2l2x+xCbu8nBlRAlsQ33k24Adj8eoVBE0f8dUeI+bAa8F84Mv05UGbAx57g2zrRsYIooqQg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.54.0", + "@typescript-eslint/types": "5.54.1", "eslint-visitor-keys": "^3.3.0" }, "dependencies": { diff --git a/package.json b/package.json index 4148aad18c..3a9f925bcd 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "@types/lodash-es": "4.17.6", "@types/react": "17.0.53", "@types/react-dom": "17.0.19", - "@typescript-eslint/eslint-plugin": "5.54.0", - "@typescript-eslint/parser": "5.54.0", + "@typescript-eslint/eslint-plugin": "5.54.1", + "@typescript-eslint/parser": "5.54.1", "@uupaa/dynamic-import-polyfill": "1.0.2", "autoprefixer": "10.4.13", "babel-loader": "9.1.2", From 4937f2d60c297e0842a77cff0b0e385bac577de7 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Tue, 14 Mar 2023 01:32:36 -0400 Subject: [PATCH 55/65] Add random int utility function --- src/components/cardbuilder/cardBuilder.js | 13 ++----------- src/components/playback/playqueuemanager.js | 4 +++- src/plugins/logoScreensaver/plugin.js | 7 ++----- src/utils/number.ts | 10 ++++++++++ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/components/cardbuilder/cardBuilder.js b/src/components/cardbuilder/cardBuilder.js index b09247f613..dfbc0a6768 100644 --- a/src/components/cardbuilder/cardBuilder.js +++ b/src/components/cardbuilder/cardBuilder.js @@ -18,6 +18,7 @@ import browser from '../../scripts/browser'; import { playbackManager } from '../playback/playbackmanager'; import itemShortcuts from '../shortcuts'; import imageHelper from '../../scripts/imagehelper'; +import { randomInt } from '../../utils/number.ts'; import './card.scss'; import '../../elements/emby-button/paper-icon-button-light'; import '../guide/programs.scss'; @@ -640,16 +641,6 @@ import { appRouter } from '../appRouter'; }; } - /** - * Generates a random integer in a given range. - * @param {number} min - Minimum of the range. - * @param {number} max - Maximum of the range. - * @returns {number} Randomly generated number. - */ - function getRandomInt(min, max) { - return Math.floor(Math.random() * (max - min + 1)) + min; - } - /** * Generates an index used to select the default color of a card based on a string. * @param {?string} [str] - String to use for generating the index. @@ -669,7 +660,7 @@ import { appRouter } from '../appRouter'; return (index % numRandomColors) + 1; } else { - return getRandomInt(1, numRandomColors); + return randomInt(1, numRandomColors); } } diff --git a/src/components/playback/playqueuemanager.js b/src/components/playback/playqueuemanager.js index cc27b9beec..65f20a71a2 100644 --- a/src/components/playback/playqueuemanager.js +++ b/src/components/playback/playqueuemanager.js @@ -1,3 +1,5 @@ +import { randomInt } from '../../utils/number.ts'; + let currentId = 0; function addUniquePlaylistItemId(item) { if (!item.PlaylistItemId) { @@ -56,7 +58,7 @@ class PlayQueueManager { const currentPlaylistItem = this._playlist.splice(this.getCurrentPlaylistIndex(), 1)[0]; for (let i = this._playlist.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * i); + const j = randomInt(0, i - 1); const temp = this._playlist[i]; this._playlist[i] = this._playlist[j]; this._playlist[j] = temp; diff --git a/src/plugins/logoScreensaver/plugin.js b/src/plugins/logoScreensaver/plugin.js index b1168ab5bd..fc999ccccf 100644 --- a/src/plugins/logoScreensaver/plugin.js +++ b/src/plugins/logoScreensaver/plugin.js @@ -1,4 +1,5 @@ import { PluginType } from '../../types/plugin.ts'; +import { randomInt } from '../../utils/number.ts'; export default function () { const self = this; @@ -25,16 +26,12 @@ export default function () { const elem = document.querySelector('.logoScreenSaverImage'); if (elem && elem.animate) { - const random = getRandomInt(0, animations.length - 1); + const random = randomInt(0, animations.length - 1); animations[random](elem, 1); } } - function getRandomInt(min, max) { - return Math.floor(Math.random() * (max - min + 1)) + min; - } - function bounceInLeft(elem, iterations) { const keyframes = [ { transform: 'translate3d(-3000px, 0, 0)', opacity: '0', offset: 0 }, diff --git a/src/utils/number.ts b/src/utils/number.ts index 71d1129883..16797d7d51 100644 --- a/src/utils/number.ts +++ b/src/utils/number.ts @@ -2,6 +2,16 @@ function toLocaleStringSupportsOptions() { return !!(typeof Intl === 'object' && Intl && typeof Intl.NumberFormat === 'function'); } +/** + * Generates a random integer in a given range. + * @param {number} min - Minimum of the range. + * @param {number} max - Maximum of the range. + * @returns {number} Randomly generated number. + */ +export function randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + /** * Gets the value of a number formatted as a perentage. * @param {number} value The value as a number. From 7903313c0671716ebac68d7118d56c42f90832af Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Mar 2023 10:47:52 +0000 Subject: [PATCH 56/65] Update dependency stylelint-order to v6.0.3 --- package-lock.json | 30 +++++++++++++++--------------- package.json | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index e65ff720de..898b0337f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -105,7 +105,7 @@ "stylelint": "15.2.0", "stylelint-config-rational-order": "0.1.2", "stylelint-no-browser-hacks": "1.2.1", - "stylelint-order": "6.0.2", + "stylelint-order": "6.0.3", "stylelint-scss": "4.4.0", "ts-loader": "9.4.2", "typescript": "4.9.5", @@ -17063,22 +17063,22 @@ } }, "node_modules/stylelint-order": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-6.0.2.tgz", - "integrity": "sha512-yuac0BE6toHd27wUPvYVVQicAJthKFIv1HPQFH3Q0dExiO3Z6Uam7geoO0tUd5Z9ddsATYK++1qWNDX4RxMH5Q==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-6.0.3.tgz", + "integrity": "sha512-1j1lOb4EU/6w49qZeT2SQVJXm0Ht+Qnq9GMfUa3pMwoyojIWfuA+JUDmoR97Bht1RLn4ei0xtLGy87M7d29B1w==", "dev": true, "dependencies": { "postcss": "^8.4.21", - "postcss-sorting": "^8.0.1" + "postcss-sorting": "^8.0.2" }, "peerDependencies": { "stylelint": "^14.0.0 || ^15.0.0" } }, "node_modules/stylelint-order/node_modules/postcss-sorting": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-8.0.1.tgz", - "integrity": "sha512-go9Zoxx7KQH+uLrJ9xa5wRErFeXu01ydA6O8m7koPXkmAN7Ts//eRcIqjo0stBR4+Nir2gMYDOWAOx7O5EPUZA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-8.0.2.tgz", + "integrity": "sha512-M9dkSrmU00t/jK7rF6BZSZauA5MAaBW4i5EnJXspMwt4iqTh/L9j6fgMnbElEOfyRyfLfVbIHj/R52zHzAPe1Q==", "dev": true, "peerDependencies": { "postcss": "^8.4.20" @@ -31951,19 +31951,19 @@ } }, "stylelint-order": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-6.0.2.tgz", - "integrity": "sha512-yuac0BE6toHd27wUPvYVVQicAJthKFIv1HPQFH3Q0dExiO3Z6Uam7geoO0tUd5Z9ddsATYK++1qWNDX4RxMH5Q==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-6.0.3.tgz", + "integrity": "sha512-1j1lOb4EU/6w49qZeT2SQVJXm0Ht+Qnq9GMfUa3pMwoyojIWfuA+JUDmoR97Bht1RLn4ei0xtLGy87M7d29B1w==", "dev": true, "requires": { "postcss": "^8.4.21", - "postcss-sorting": "^8.0.1" + "postcss-sorting": "^8.0.2" }, "dependencies": { "postcss-sorting": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-8.0.1.tgz", - "integrity": "sha512-go9Zoxx7KQH+uLrJ9xa5wRErFeXu01ydA6O8m7koPXkmAN7Ts//eRcIqjo0stBR4+Nir2gMYDOWAOx7O5EPUZA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-8.0.2.tgz", + "integrity": "sha512-M9dkSrmU00t/jK7rF6BZSZauA5MAaBW4i5EnJXspMwt4iqTh/L9j6fgMnbElEOfyRyfLfVbIHj/R52zHzAPe1Q==", "dev": true, "requires": {} } diff --git a/package.json b/package.json index 3a9f925bcd..44f8484f80 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "stylelint": "15.2.0", "stylelint-config-rational-order": "0.1.2", "stylelint-no-browser-hacks": "1.2.1", - "stylelint-order": "6.0.2", + "stylelint-order": "6.0.3", "stylelint-scss": "4.4.0", "ts-loader": "9.4.2", "typescript": "4.9.5", From 10419311bc6f088f447acac78b9efe57c63fda00 Mon Sep 17 00:00:00 2001 From: HanaO00 Date: Tue, 14 Mar 2023 14:24:24 +0000 Subject: [PATCH 57/65] Translated using Weblate (French) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fr/ --- src/strings/fr.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strings/fr.json b/src/strings/fr.json index 4c01e2b798..b53c9fcbc4 100644 --- a/src/strings/fr.json +++ b/src/strings/fr.json @@ -234,7 +234,7 @@ "HeaderApiKeys": "Clés API", "HeaderApiKeysHelp": "Les applications externes ont besoin d'une clé d'API pour communiquer avec le serveur. Les clés sont distribuées lors d'une connexion avec un compte normal ou en accordant manuellement une clé à une application.", "HeaderApp": "Application", - "HeaderAppearsOn": "Apparait dans", + "HeaderAppearsOn": "Apparaît dans", "HeaderAudioBooks": "Livres audio", "HeaderAudioSettings": "Réglages audio", "HeaderBlockItemsWithNoRating": "Bloquer les éléments avec des informations de classification inconnues ou n'en disposant pas :", @@ -979,7 +979,7 @@ "Rate": "Débit", "RecentlyWatched": "Vu récemment", "RecommendationBecauseYouLike": "Parce que vous aimez {0}", - "RecommendationBecauseYouWatched": "Parce que vous avez regardé {0}", + "RecommendationBecauseYouWatched": "Parce-que vous avez regardé {0}", "RecommendationDirectedBy": "Réalisé par {0}", "RecommendationStarring": "Avec {0}", "Record": "Enregistrer", From 4963a4b22c017a9031326af5bb358f19783db48e Mon Sep 17 00:00:00 2001 From: Bas Date: Tue, 14 Mar 2023 17:58:48 +0000 Subject: [PATCH 58/65] Translated using Weblate (Dutch) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/nl/ --- src/strings/nl.json | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/strings/nl.json b/src/strings/nl.json index 7d493b7a6f..540dbf752b 100644 --- a/src/strings/nl.json +++ b/src/strings/nl.json @@ -787,7 +787,7 @@ "NewEpisodesOnly": "Alleen nieuwe afleveringen", "News": "Nieuws", "Next": "Volgende", - "NextUp": "Hierna", + "NextUp": "Volgende", "No": "Nee", "NoNewDevicesFound": "Er zijn geen nieuwe apparaten gevonden. Sluit deze melding en voer handmatig de apparaat gegevens in om een nieuwe tuner toe te voegen.", "MessageNoNextUpItems": "Niets gevonden. Start met kijken!", @@ -1544,7 +1544,7 @@ "LabelSyncPlaySettingsSkipToSyncHelp": "Synchronisatie correctiemethode die bestaat uit het zoeken naar de geschatte positie. Synchronisatie Correctie moet ingeschakeld zijn.", "MessageSent": "Bericht verzonden.", "Mixer": "Mixer", - "UseEpisodeImagesInNextUpHelp": "'Hierna'- en 'Verderkijken'-secties zullen afleveringsafbeeldingen gebruiken als thumbnails in plaats van de primaire thumbnail van de serie.", + "UseEpisodeImagesInNextUpHelp": "Secties 'Volgende' en 'Verderkijken' zullen afleveringsafbeeldingen gebruiken als miniaturen in plaats van de primaire miniatuur van de serie.", "SetUsingLastTracks": "Ondertitel/Audio-sporen instellen met vorig item", "SetUsingLastTracksHelp": "Probeer de ondertiteling/het audiospoor in te stellen op de video die het meest overeenkomt met de laatste video.", "TextSent": "Tekst verzonden.", @@ -1556,11 +1556,11 @@ "VideoProfileNotSupported": "Het profiel van de videocodec wordt niet ondersteund", "Lyricist": "Tekstschrijver", "NextChapter": "Volgend hoofdstuk", - "LabelMaxDaysForNextUp": "Maximaal dagen in 'Hierna':", - "LabelMaxDaysForNextUpHelp": "Zet het maximaal aantal dagen dat een serie in de 'Hierna'-lijst staat zonder het te kijken.", + "LabelMaxDaysForNextUp": "Maximaal dagen in 'Volgende':", + "LabelMaxDaysForNextUpHelp": "Stel het maximaal aantal dagen in dat een serie in de 'Volgende'-lijst staat zonder het te kijken.", "PreviousChapter": "Vorig hoofdstuk", "Remixer": "Remixer", - "UseEpisodeImagesInNextUp": "Gebruik afleveringscovers in de secties 'Hierna' en 'Verderkijken'", + "UseEpisodeImagesInNextUp": "Gebruik afleveringscovers in de secties 'Volgende' en 'Verderkijken'", "EnableGamepadHelp": "Luister naar input van alle aangesloten controllers. (Vereist weergavemodus 'Tv')", "VideoCodecNotSupported": "De videocodec wordt niet ondersteund", "AudioBitrateNotSupported": "De bitrate van de audio wordt niet ondersteund", @@ -1625,11 +1625,11 @@ "ButtonBackspace": "Backspace", "StoryArc": "Verhaallijn", "ItemDetails": "Itemdetails", - "EnableRewatchingNextUp": "Opnieuw kijken inschakelen in Hierna", + "EnableRewatchingNextUp": "Opnieuw kijken inschakelen in Volgende", "Bold": "Vetgedrukt", "LabelTextWeight": "Tekstdikte:", "HomeVideosPhotos": "Homevideo's en foto's", - "EnableRewatchingNextUpHelp": "Laat reeds gekeken afleveringen zien in 'Hierna'-secties.", + "EnableRewatchingNextUpHelp": "Laat reeds gekeken afleveringen zien in sectie 'Volgende'.", "ContainerBitrateExceedsLimit": "De bitrate van de video overschrijdt de limiet", "LabelMaxVideoResolution": "Maximaal toegestane resolutie voor transcoderingen", "UnknownAudioStreamInfo": "De audio stream info is onbekend", @@ -1674,7 +1674,7 @@ "DeletedScene": "Verwijderde scene", "BehindTheScenes": "Achter de scenes", "Trailer": "Trailer", - "Clip": "Korte film", + "Clip": "Clip", "SelectAll": "Selecteer alles", "DirectPlayError": "Er is een fout opgetreden tijdens het starten van direct afspelen", "OptionDateShowAdded": "Datum Serie Toegevoegd", @@ -1713,5 +1713,7 @@ "SubtitleMagenta": "Magenta", "SubtitleRed": "Rood", "SubtitleWhite": "Wit", - "SubtitleYellow": "Geel" + "SubtitleYellow": "Geel", + "Featurette": "Featurette", + "Short": "Korte film" } From 579d8710734562594e307373f2a100a34909efca Mon Sep 17 00:00:00 2001 From: blob03 Date: Tue, 14 Mar 2023 19:52:07 +0000 Subject: [PATCH 59/65] Translated using Weblate (French) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fr/ --- src/strings/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/fr.json b/src/strings/fr.json index b53c9fcbc4..95e7431d34 100644 --- a/src/strings/fr.json +++ b/src/strings/fr.json @@ -979,7 +979,7 @@ "Rate": "Débit", "RecentlyWatched": "Vu récemment", "RecommendationBecauseYouLike": "Parce que vous aimez {0}", - "RecommendationBecauseYouWatched": "Parce-que vous avez regardé {0}", + "RecommendationBecauseYouWatched": "Parce que vous avez regardé {0}", "RecommendationDirectedBy": "Réalisé par {0}", "RecommendationStarring": "Avec {0}", "Record": "Enregistrer", From ed7d9e2189242222cd9bf8cf4577827ea4e7a24d Mon Sep 17 00:00:00 2001 From: Bas Date: Tue, 14 Mar 2023 21:19:35 +0000 Subject: [PATCH 60/65] Translated using Weblate (Dutch) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/nl/ --- src/strings/nl.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strings/nl.json b/src/strings/nl.json index 540dbf752b..2caf6c21a3 100644 --- a/src/strings/nl.json +++ b/src/strings/nl.json @@ -109,7 +109,7 @@ "Connect": "Verbind", "ContinueWatching": "Verderkijken", "Continuing": "Wordt vervolgd", - "CriticRating": "Critici-beoordeling", + "CriticRating": "Beoordeling critici", "CustomDlnaProfilesHelp": "Maak een aangepast profiel om een nieuw apparaat aan te maken of overschrijf een systeemprofiel.", "DateAdded": "Datum toegevoegd", "DatePlayed": "Datum afgespeeld", @@ -822,7 +822,7 @@ "OptionAutomaticallyGroupSeriesHelp": "Series die verspreid zijn over meerdere mappen binnen deze bibliotheek worden automatisch samengevoegd tot één serie.", "OptionBluray": "BD", "OptionCommunityRating": "Beoordeling gemeenschap", - "OptionCriticRating": "Beoordeling door critici", + "OptionCriticRating": "Beoordeling critici", "OptionCustomUsers": "Aangepast", "OptionDaily": "Dagelijks", "OptionDateAdded": "Datum toegevoegd", From c4f6e11f6c27cc1a87cac97bb9bb56ede82e53f7 Mon Sep 17 00:00:00 2001 From: Hannes Braun Date: Fri, 6 Jan 2023 17:39:55 +0100 Subject: [PATCH 61/65] Add setting for ParallelImageEncodingLimit --- src/controllers/dashboard/general.html | 7 +++++++ src/controllers/dashboard/general.js | 2 ++ src/strings/en-us.json | 3 +++ 3 files changed, 12 insertions(+) diff --git a/src/controllers/dashboard/general.html b/src/controllers/dashboard/general.html index f099a81c5b..62f92d097c 100644 --- a/src/controllers/dashboard/general.html +++ b/src/controllers/dashboard/general.html @@ -80,6 +80,13 @@

+
+

${HeaderPerformance}

+
+ +
${LabelParallelImageEncodingLimitHelp}
+
+