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 4fa437b46..f2e0cd0bf 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 da3537327..9248c209d 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 f2a2b8d30..8902b9cf2 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 8902b9cf2..695829ca2 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 695829ca2..aaf22f759 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 aaf22f759..793606714 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 793606714..cef47fe11 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 cef47fe11..4e120e5f7 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 4e120e5f7..8b5afd90d 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 c06043e47..05bfb8ee5 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 08c4904bb..fd2ae8d05 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 707713eee..db7ec1884 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 97116e92d..dcc6fb05f 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 3d25ed427..bc19c04a9 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 b5d3c8bd0..a1cad660f 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 f2a2b8d30..388cb4caa 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 eebd423d9..1b5d41fc4 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 89856057b..dedc1dfdc 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 2b8bd2128..ffcd0e4d9 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 3c3a03974..537e842d9 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 c06043e47..478b6be23 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 0f909a969..bd0707b57 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 f8c9f4502..5bc2a3b78 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 0f909a969..a00e6750f 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 f8c9f4502..ad691b532 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 b4b01a1fd..585b335c1 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 53dd01ff2..e2811f35a 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 658837df8..657a4102d 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 e353d562a..5e4ee8af0 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 039770a21..85916e5cf 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 ffcd0e4d9..7591c2291 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 c170a7cc0..c5cb746f9 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 c867d8158..f3dbfec6d 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 657a4102d..a0c4aaf09 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 5e4ee8af0..63a682ee6 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 85916e5cf..9130bd311 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 7591c2291..947f46eec 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 c5cb746f9..f75bbce81 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 db7ec1884..a09b64a0b 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 97116e92d..7187af588 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 3d25ed427..2d01fb941 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 f351368a9..195c919e9 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 ffcd0e4d9..5d5232110 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 7db319a34..823ab7d7e 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 e95c8657b..df5e213b7 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 9044cd3e3..81cfeab86 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 d209069ad..eb6d3cb11 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 563e6264f..395f90689 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 b5d3c8bd0..415724671 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 f2a2b8d30..b8551defb 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 8d5f7031a..b1168ab5b 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 5f43d03fc..b34404d7a 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 aa3ba5f36..7c41c5318 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 c353ea909..3081f8cf4 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 a8ad32f79..98e0e843a 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 e4ef965a0..59c066aaf 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 a9dd8e9be..2a10f8fcd 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 4b0eedaa5..c63d53068 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 000000000..4b4b946e9 --- /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 92405f8fe..77b38ab46 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 585b335c1..1d8d08631 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 1d8d08631..4d131ff8a 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 e2811f35a..91a4cf29c 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 4db600ece..33df97532 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 82f58e187..54de02b97 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 a0c4aaf09..b09247f61 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 a90423a6b..295c3170c 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 63a682ee6..36137af21 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 9130bd311..1711169db 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 1a05d4084..ac04df481 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 ed5467501..c90acc007 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 6456c5721..fb69d20aa 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 089820fb4..d16fe7756 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 947f46eec..d868d24cd 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 c7f8f5a6d..da3be2097 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 cce2cf7b4..26b7220bc 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 bf8d1b74f..60e51c784 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 3f5d6c365..4d942f7cd 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 67001ccb8..b8c89726c 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 24e7a477d..49ff20390 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 c326a689f..64db2e429 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 bc640a1f6..8832e4bff 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 4deb2b713..8b97984d0 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 3ea00a9a8..bbb154a4e 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 cacea1a30..d7bbab581 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 5d9b3e2e0..d1e53b38d 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 00e2e94d3..ae0f0fef5 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 e232bbcde..cad2f4bbf 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 e7fa1df29..3d98918d7 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 6cd83fc78..14313318a 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 9455b5e1d..7c07796f7 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 649578ce1..ed48f415f 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 9044cd3e3..5f7447714 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 5f43d03fc..575080af2 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 740e0709d..ee1e3e3ae 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 3b74b464d..9b1405c9e 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 5afa0c4fd..1da3d8919 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 2a2813015..a6042189d 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 df902bb28..de8c0c483 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 7a4894395..df18b0ddf 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 658236414..916e15939 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 a1ed50337..cc27b9bee 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 a666a4956..742a77df4 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 1780668af..a65ae006d 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 590c600e7..79d35b9fe 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 27ce6b97c..eac336389 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 26e2fe3a7..15f1fe017 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 3a6d695e6..7a7527dc0 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 e1c1545b6..e191a9afb 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 5afa0c4fd..345b31c63 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 feef18063..39c187479 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 947f46eec..e6cba06d2 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 2582785f8..a4f512768 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 5e0a2d3f1..150fe3e1f 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 bc19c04a9..4148aad18 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 898b105e2..000000000 --- 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 d9ba35ed3..091af0db1 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 33cf50166..5605e1150 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 18f7a8d1e..8bf8a0d2a 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 28407b8bc..595ef33f2 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 021b6471c..9c3a51c9f 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 15526f009..498d800fe 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 498d800fe..4d8519501 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 be0f2596a..2b1b3bf59 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 d0d11b4c5..9d4ab5b25 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 369b0c17c..a8d7ae565 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 e26cc1a0c..4c01e2b79 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 e35b22968..9d5e968ff 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 d6e77b18e..f05bb4d98 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 3dfb6b8d0..c52fb52d4 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 fab979dd4..3e64e8e09 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 e191a9afb..e0bcb1562 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 dcc6fb05f..8f608b63c 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 8f608b63c..e65ff720d 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 4148aad18..3a9f925bc 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 b09247f61..dfbc0a676 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 cc27b9bee..65f20a71a 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 b1168ab5b..fc999cccc 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 71d112988..16797d7d5 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 e65ff720d..898b0337f 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 3a9f925bc..44f8484f8 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 4c01e2b79..b53c9fcbc 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 7d493b7a6..540dbf752 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 b53c9fcbc..95e7431d3 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 540dbf752..2caf6c21a 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 f099a81c5..62f92d097 100644 --- a/src/controllers/dashboard/general.html +++ b/src/controllers/dashboard/general.html @@ -80,6 +80,13 @@

+
+

${HeaderPerformance}

+
+ +
${LabelParallelImageEncodingLimitHelp}
+
+