From b43adb740625f76304423a6c4e563a290981c07a Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Sat, 11 Apr 2020 16:24:40 -0500 Subject: [PATCH 001/281] Add quick connect --- src/controllers/auth/login.js | 48 ++++++++++++++++++++++++ src/libraries/apiclient/apiclientcore.js | 23 +++++++++++- src/login.html | 4 ++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/controllers/auth/login.js b/src/controllers/auth/login.js index 4296b8bfb3..746384a64c 100644 --- a/src/controllers/auth/login.js +++ b/src/controllers/auth/login.js @@ -150,6 +150,53 @@ define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layout }); } + function loginQuickConnect() { + var apiClient = getApiClient(); + var identifier = "" + var interval = 0; + var friendlyName = "test"; + $.get('/QuickConnect/Initiate?FriendlyName=' + friendlyName).then(json => { + if (!json.Secret || !json.Code) { + Dashboard.alert({ + message: json.Error, + title: "Error" + }); + return; + } + + Dashboard.alert({ + message: "Authorize request " + json.Code + " to continue", + title: "Quick Connect Code" + }); + + loading.show(); + + identifier = json.Secret; + interval = setInterval(() => { + $.get('/QuickConnect/Connect?Secret=' + identifier).then(x => { + if(x.Authenticated) { + apiClient.quickConnect(x.Authentication).then((result) => { + var user = result.User; + var serverId = getParameterByName("serverid"); + var newUrl; + + if (user.Policy.IsAdministrator && !serverId) { + newUrl = "dashboard.html"; + } else { + newUrl = "home.html"; + } + + loading.hide(); + Dashboard.onServerChanged(user.Id, result.AccessToken, apiClient); + Dashboard.navigate(newUrl); + clearInterval(interval); + }); + } + }); + }, 5000); + }); + } + view.querySelector("#divUsers").addEventListener("click", function (e) { var card = dom.parentWithClass(e.target, "card"); var cardContent = card ? card.querySelector(".cardContent") : null; @@ -183,6 +230,7 @@ define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layout Dashboard.navigate("forgotpassword.html"); }); view.querySelector(".btnCancel").addEventListener("click", showVisualForm); + view.querySelector(".btnQuick").addEventListener("click", loginQuickConnect); view.querySelector(".btnManual").addEventListener("click", function () { view.querySelector("#txtManualName").value = ""; showManualForm(view, true); diff --git a/src/libraries/apiclient/apiclientcore.js b/src/libraries/apiclient/apiclientcore.js index 557a4e1033..80be946a60 100644 --- a/src/libraries/apiclient/apiclientcore.js +++ b/src/libraries/apiclient/apiclientcore.js @@ -356,7 +356,28 @@ define(["events", "appStorage"], function(events, appStorage) { instance.onAuthenticated ? instance.onAuthenticated(instance, result).then(afterOnAuthenticated) : afterOnAuthenticated() }, reject) }) - }, ApiClient.prototype.ensureWebSocket = function() { + }, ApiClient.prototype.quickConnect = function (token) { + if (!token) return Promise.reject(); + var url = this.getUrl("Users/AuthenticateWithQuickConnect"), + instance = this; + return new Promise(function(resolve, reject) { + var postData = { + Token: token + }; + instance.ajax({ + type: "POST", + url: url, + data: JSON.stringify(postData), + dataType: "json", + contentType: "application/json" + }).then(function(result) { + var afterOnAuthenticated = function() { + redetectBitrate(instance), resolve(result) + }; + instance.onAuthenticated ? instance.onAuthenticated(instance, result).then(afterOnAuthenticated) : afterOnAuthenticated() + }, reject) + }) + }, ApiClient.prototype.ensureWebSocket = function() { if (!this.isWebSocketOpenOrConnecting() && this.isWebSocketSupported()) try { this.openWebSocket() } catch (err) { diff --git a/src/login.html b/src/login.html index 8e48901c11..343b85906e 100644 --- a/src/login.html +++ b/src/login.html @@ -42,6 +42,10 @@ + + + + Incoming login requests: +
+ +
+ diff --git a/src/quickconnect.html b/src/quickconnect.html new file mode 100644 index 0000000000..770796a10e --- /dev/null +++ b/src/quickconnect.html @@ -0,0 +1,29 @@ +
+
+
+
+
+

Quick Connect

+
+
+ + Quick connect is: Failed to load status + +
+ + +
If unchecked, users will have to click the Activate button in their profile before initiating a quick connect login.
+
+ + +
+
+
\ No newline at end of file diff --git a/src/scripts/librarymenu.js b/src/scripts/librarymenu.js index 11c89b01da..930df8be49 100644 --- a/src/scripts/librarymenu.js +++ b/src/scripts/librarymenu.js @@ -349,6 +349,12 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " href: "devices.html", pageIds: ["devicesPage", "devicePage"], icon: "devices" + }); + links.push({ + name: "Quick Connect", + href: "quickconnect.html", + pageIds: ["quickConnectPage", "quickConnectPage"], + icon: "devices" }); links.push({ name: globalize.translate("HeaderActivity"), diff --git a/src/scripts/routes.js b/src/scripts/routes.js index 9c3db58a7f..1520e96632 100644 --- a/src/scripts/routes.js +++ b/src/scripts/routes.js @@ -72,6 +72,12 @@ define([ transition: "fade", controller: "user/subtitles" }); + defineRoute({ + path: "/mypreferencesquickconnect.html", + autoFocus: false, + transition: "fade", + controller: "user/quickconnect" + }); defineRoute({ path: "/dashboard.html", @@ -103,6 +109,12 @@ define([ roles: "admin", controller: "device" }); + defineRoute({ + path: "/quickconnect.html", + autoFocus: false, + roles: "admin", + controller: "quickconnect" + }); defineRoute({ path: "/dlnaprofile.html", autoFocus: false, diff --git a/src/scripts/site.js b/src/scripts/site.js index 3b992eaf2b..311478c019 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -829,6 +829,7 @@ var AppInfo = {}; define("displaySettings", [componentsPath + "/displaysettings/displaysettings"], returnFirstDependency); define("playbackSettings", [componentsPath + "/playbacksettings/playbacksettings"], returnFirstDependency); define("homescreenSettings", [componentsPath + "/homescreensettings/homescreensettings"], returnFirstDependency); + define("quickConnectSettings", [componentsPath + "/quickconnectsettings/quickconnectsettings"], returnFirstDependency); define("playbackManager", [componentsPath + "/playback/playbackmanager"], getPlaybackManager); define("layoutManager", [componentsPath + "/layoutManager", "apphost"], getLayoutManager); define("homeSections", [componentsPath + "/homesections/homesections"], returnFirstDependency); From fdfdcd60fe3d7a66cfc334f0692978fc3bb8e27c Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Mon, 13 Apr 2020 16:23:16 -0500 Subject: [PATCH 003/281] Switch off of jQuery --- CONTRIBUTORS.md | 1 + .../quickconnectsettings/quickconnectsettings.js | 8 +++++--- src/controllers/auth/login.js | 12 ++++++------ src/controllers/quickconnect.js | 16 +++++++++------- src/controllers/user/menu.js | 2 +- src/controllers/user/quickconnect.js | 9 +++++++++ src/mypreferencesquickconnect.html | 6 +++--- src/quickconnect.html | 2 +- 8 files changed, 35 insertions(+), 21 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index aa3ec707e3..ffbf054829 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -34,6 +34,7 @@ - [Ryan Hartzell](https://github.com/ryan-hartzell) - [Thibault Nocchi](https://github.com/ThibaultNocchi) - [MrTimscampi](https://github.com/MrTimscampi) + - [ConfusedPolarBear](https://github.com/ConfusedPolarBear) # Emby Contributors diff --git a/src/components/quickconnectsettings/quickconnectsettings.js b/src/components/quickconnectsettings/quickconnectsettings.js index a30db441e6..ed7985dcfa 100644 --- a/src/components/quickconnectsettings/quickconnectsettings.js +++ b/src/components/quickconnectsettings/quickconnectsettings.js @@ -15,12 +15,14 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa } function list(apiClient) { - var elem = $("#quickConnectIncoming"); - elem.html(""); + console.debug("getting json"); apiClient.getJSON("/QuickConnect/List").then(json => { - console.debug("raw json", json); + var elem = $("#quickConnectIncoming"); + elem.html(""); + console.debug("raw json", json, "length is", json.length); for(var i = 0; i < json.length; i++) { var current = json[i]; + console.debug("current is", current); var html = "
  • " + current.Code + " - " + current.FriendlyName + " - "; if(!current.Authenticated) { diff --git a/src/controllers/auth/login.js b/src/controllers/auth/login.js index f5dc9b487b..845ae9a38f 100644 --- a/src/controllers/auth/login.js +++ b/src/controllers/auth/login.js @@ -153,10 +153,10 @@ define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layout function loginQuickConnect() { var apiClient = getApiClient(); var friendlyName = "test"; - - var url = apiClient.getUrl("/QuickConnect/Initiate?FriendlyName=" + friendlyName); - apiClient.getJSON(url) - .then(json => { + + var url = apiClient.getUrl("/QuickConnect/Initiate?FriendlyName=" + friendlyName); + apiClient.getJSON(url) + .then(json => { if (!json.Secret || !json.Code) { Dashboard.alert({ message: json.Error, @@ -173,9 +173,9 @@ define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layout loading.show(); var interval = setInterval(() => { - var url = apiClient.getUrl('/QuickConnect/Connect?Secret=' + json.Secret); + var url = apiClient.getUrl('/QuickConnect/Connect?Secret=' + json.Secret); apiClient.getJSON(url) - .then(data => { + .then(data => { if(data.Authenticated) { apiClient.quickConnect(data.Authentication).then((result) => { var user = result.User; diff --git a/src/controllers/quickconnect.js b/src/controllers/quickconnect.js index e3d1f76054..5c3c8f9a18 100644 --- a/src/controllers/quickconnect.js +++ b/src/controllers/quickconnect.js @@ -2,13 +2,15 @@ define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, "use strict"; function loadPage(page, status) { + console.debug("status is \"" + status + "\""); + var active = (status == "Active"); var available = (status == "Available") || active; - - $("#quickConnectStatus").text(status.toLocaleLowerCase()); - $("#chkQuickConnectAvailable").checked(available); - $("#chkQuickConnectActive").checked(active); - + + page.querySelector("#quickConnectStatus").textContent = status.toLocaleLowerCase(); + page.querySelector("#chkQuickConnectAvailable").checked = available; + page.querySelector("#chkQuickConnectActive").checked = active; + loading.hide(); } @@ -44,8 +46,8 @@ define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, } $(document).on("pageinit", "#quickConnectPage", function () { - $("#quickConnectPage").off("submit", onSubmit).on("submit", onSubmit); - $("#btnQuickConnectSubmit").click(onSubmit); + document.querySelector("#quickConnectPage").onsubmit = onSubmit; + document.querySelector("#btnQuickConnectSubmit").onclick = onSubmit; }).on("pageshow", "#quickConnectPage", function () { loading.show(); var page = this; diff --git a/src/controllers/user/menu.js b/src/controllers/user/menu.js index ff8db72681..f5d05c5be3 100644 --- a/src/controllers/user/menu.js +++ b/src/controllers/user/menu.js @@ -24,7 +24,7 @@ define(["apphost", "connectionManager", "layoutManager", "listViewStyle", "emby- page.querySelector(".lnkHomePreferences").setAttribute("href", "mypreferenceshome.html?userId=" + userId); page.querySelector(".lnkPlaybackPreferences").setAttribute("href", "mypreferencesplayback.html?userId=" + userId); page.querySelector(".lnkSubtitlePreferences").setAttribute("href", "mypreferencessubtitles.html?userId=" + userId); - page.querySelector(".lnkQuickConnectPreferences").setAttribute("href", "mypreferencesquickconnect.html?userId=" + userId); + page.querySelector(".lnkQuickConnectPreferences").setAttribute("href", "mypreferencesquickconnect.html?userId=" + userId); if (window.NativeShell && window.NativeShell.AppHost.supports("clientsettings")) { page.querySelector(".clientSettings").classList.remove("hide"); diff --git a/src/controllers/user/quickconnect.js b/src/controllers/user/quickconnect.js index d6f2ae25c1..6e63bcdc08 100644 --- a/src/controllers/user/quickconnect.js +++ b/src/controllers/user/quickconnect.js @@ -2,6 +2,13 @@ define(["quickConnectSettings", "dom", "globalize", "loading", "userSettings", " "use strict"; return function (view, params) { + function notImplemented() { + Dashboard.alert({ + message: "This button is not implemented yet, you must check the checkbox labeled \"Always accept quick connect login requests\" in the dashboard", + title: "Not implemented" + }); + } + var quickConnectSettingsInstance = null; var hasChanges; var userId = params.userId || ApiClient.getCurrentUserId(); @@ -9,6 +16,8 @@ define(["quickConnectSettings", "dom", "globalize", "loading", "userSettings", " view.addEventListener("viewshow", function () { console.debug("defining instance"); + $("#btnQuickConnectActivate").click(notImplemented); + quickConnectSettingsInstance = new QuickConnectSettings({ serverId: ApiClient.serverId(), userId: userId, diff --git a/src/mypreferencesquickconnect.html b/src/mypreferencesquickconnect.html index 326ce51b48..b9ffdfaccd 100644 --- a/src/mypreferencesquickconnect.html +++ b/src/mypreferencesquickconnect.html @@ -1,12 +1,12 @@
    - Incoming login requests:
      -
    • Failed to load incoming requests
    • -
    +
  • Failed to load incoming requests
  • + diff --git a/src/quickconnect.html b/src/quickconnect.html index 770796a10e..875716285c 100644 --- a/src/quickconnect.html +++ b/src/quickconnect.html @@ -16,7 +16,7 @@
    If unchecked, users will have to click the Activate button in their profile before initiating a quick connect login.
    From c37e8f2f1bcb827893fe32a3fcf77107964a853e Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Sat, 18 Apr 2020 19:20:15 -0500 Subject: [PATCH 004/281] Implement auto refresh and activate button --- .../quickconnectsettings.js | 85 +++++++++++++------ src/controllers/auth/login.js | 75 ++++++++-------- src/controllers/quickconnect.js | 54 +++++++----- src/controllers/user/quickconnect.js | 63 +++++++------- src/mypreferencesmenu.html | 4 +- src/mypreferencesquickconnect.html | 2 +- src/quickconnect.html | 6 +- src/scripts/librarymenu.js | 2 +- src/scripts/site.js | 2 +- 9 files changed, 170 insertions(+), 123 deletions(-) diff --git a/src/components/quickconnectsettings/quickconnectsettings.js b/src/components/quickconnectsettings/quickconnectsettings.js index ed7985dcfa..fc167802d8 100644 --- a/src/components/quickconnectsettings/quickconnectsettings.js +++ b/src/components/quickconnectsettings/quickconnectsettings.js @@ -1,11 +1,10 @@ -define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loading', 'connectionManager', 'homeSections', 'dom', 'events', 'listViewStyle', 'emby-select', 'emby-checkbox'], function (require, appHost, layoutManager, focusManager, globalize, loading, connectionManager, homeSections, dom, events) { +define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loading', 'connectionManager', 'listViewStyle', 'emby-select', 'emby-checkbox'], function (require, appHost, layoutManager, focusManager, globalize, loading, connectionManager) { "use strict"; function authorizeRequest(event) { var lookup = event.data.lookup; - var apiClient = event.data.apiClient; var url = ApiClient.getUrl("/QuickConnect/Authorize"); - apiClient.ajax({ + ApiClient.ajax({ type: "POST", url: url, data: { @@ -13,46 +12,72 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa } }, true); } - - function list(apiClient) { - console.debug("getting json"); - apiClient.getJSON("/QuickConnect/List").then(json => { - var elem = $("#quickConnectIncoming"); + + QuickConnectSettings.prototype.list = function(argPage) { + ApiClient.getJSON("/QuickConnect/List").then(json => { + var elem = $(argPage.querySelector("#quickConnectIncoming")); elem.html(""); - console.debug("raw json", json, "length is", json.length); - for(var i = 0; i < json.length; i++) { + for (var i = 0; i < json.length; i++) { var current = json[i]; - console.debug("current is", current); var html = "
  • " + current.Code + " - " + current.FriendlyName + " - "; - - if(!current.Authenticated) { + + if (!current.Authenticated) { html += "authorize"; - } - else { + } else { html += " (already authorized)"; } - + html += "
  • "; elem.append(html); - $("#qc" + current.Lookup).click({ lookup: current.Lookup, apiClient: apiClient}, authorizeRequest); + $("#qc" + current.Lookup).click({ lookup: current.Lookup }, authorizeRequest); } + + return true; + }).catch((e) => { + console.error("Unable to get quick connect login requests. error:", e); }); - } + }; + + QuickConnectSettings.prototype.activate = function() { + var url = ApiClient.getUrl("/QuickConnect/Activate"); + ApiClient.ajax({ + type: "POST", + url: url, + contentType: "application/json", + dataType: "json" + }).then((json) => { + let message = json.Error; + + console.log("message is \"" + message + "\""); + if (message && message !== "") { + console.error("Error activating quick connect. Error: ", json.Error); + + Dashboard.alert({ + title: "Unable to activate quick connect", + message: message + }); + + return false; + } + + Dashboard.alert({ + message: "Already active" + }); + + return true; + }).catch((e) => { + console.error("Error activating quick connect. Error:", e); + throw e; + }); + }; function QuickConnectSettings(options) { this.options = options; } QuickConnectSettings.prototype.loadData = function () { - loading.show(); - - var apiClient = connectionManager.getApiClient(this.options.serverId); - - list(apiClient); - - console.debug("request list finished"); - - loading.hide(); + this.options.interval = setInterval(this.list, 5000, this.options.page); + this.list(this.options.page); }; QuickConnectSettings.prototype.submit = function () { @@ -60,8 +85,14 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa }; QuickConnectSettings.prototype.destroy = function () { + console.debug("clearing refresh interval", this.options.interval); + clearInterval(this.options.interval); this.options = null; }; + QuickConnectSettings.prototype.interval = function (interval) { + this.options.interval = interval; + }; + return QuickConnectSettings; }); diff --git a/src/controllers/auth/login.js b/src/controllers/auth/login.js index 845ae9a38f..94fa15d412 100644 --- a/src/controllers/auth/login.js +++ b/src/controllers/auth/login.js @@ -152,51 +152,54 @@ define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layout function loginQuickConnect() { var apiClient = getApiClient(); - var friendlyName = "test"; - + var friendlyName = navigator.userAgent; // TODO: what should this be changed to? + var url = apiClient.getUrl("/QuickConnect/Initiate?FriendlyName=" + friendlyName); apiClient.getJSON(url) - .then(json => { - if (!json.Secret || !json.Code) { + .then(json => { + if (!json.Secret || !json.Code) { + Dashboard.alert({ + message: json.Error, + title: "Error" + }); + + return false; + } + Dashboard.alert({ - message: json.Error, - title: "Error" + message: "Authorize request " + json.Code + " to continue", + title: "Quick Connect Code" }); - return; - } - Dashboard.alert({ - message: "Authorize request " + json.Code + " to continue", - title: "Quick Connect Code" - }); + loading.show(); - loading.show(); + var interval = setInterval(async function() { + let connectUrl = apiClient.getUrl('/QuickConnect/Connect?Secret=' + json.Secret); + let data = await apiClient.getJSON(connectUrl); + if (data.Authenticated) { + let result = await apiClient.quickConnect(data.Authentication); + var user = result.User; + var serverId = getParameterByName("serverid"); + var newUrl = "home.html"; - var interval = setInterval(() => { - var url = apiClient.getUrl('/QuickConnect/Connect?Secret=' + json.Secret); - apiClient.getJSON(url) - .then(data => { - if(data.Authenticated) { - apiClient.quickConnect(data.Authentication).then((result) => { - var user = result.User; - var serverId = getParameterByName("serverid"); - var newUrl; + if (user.Policy.IsAdministrator && !serverId) { + newUrl = "dashboard.html"; + } - if (user.Policy.IsAdministrator && !serverId) { - newUrl = "dashboard.html"; - } else { - newUrl = "home.html"; - } + loading.hide(); + Dashboard.onServerChanged(user.Id, result.AccessToken, apiClient); + Dashboard.navigate(newUrl); + clearInterval(interval); - loading.hide(); - Dashboard.onServerChanged(user.Id, result.AccessToken, apiClient); - Dashboard.navigate(newUrl); - clearInterval(interval); - }); + return true; } - }); - }, 5000); - }); + return false; + }, 5000); + + return true; + }).catch((e) => { + console.error("Unable to initiate quick connect login request. Error:", e); + }); } view.querySelector("#divUsers").addEventListener("click", function (e) { @@ -240,7 +243,7 @@ define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layout view.querySelector(".btnSelectServer").addEventListener("click", function () { Dashboard.selectServer(); }); - view.addEventListener("viewshow", function (e) { + view.addEventListener("viewshow", function () { loading.show(); if (!appHost.supports('multiserver')) { diff --git a/src/controllers/quickconnect.js b/src/controllers/quickconnect.js index 5c3c8f9a18..a6ebc381ce 100644 --- a/src/controllers/quickconnect.js +++ b/src/controllers/quickconnect.js @@ -1,9 +1,8 @@ -define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, libraryMenu) { +define(["jQuery", "loading", "fnchecked"], function ($, loading) { "use strict"; + var page; function loadPage(page, status) { - console.debug("status is \"" + status + "\""); - var active = (status == "Active"); var available = (status == "Available") || active; @@ -16,44 +15,53 @@ define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, function onSubmit() { loading.show(); - - var available = $("#chkQuickConnectAvailable").is(":checked") ? "Available" : "Unavailable"; + + var newStatus = page.querySelector("#chkQuickConnectAvailable").checked ? "Available" : "Unavailable"; + if (newStatus && page.querySelector("#chkQuickConnectActive").checked) { + newStatus = "Active"; + } + var url = ApiClient.getUrl("/QuickConnect/Available"); - + ApiClient.ajax({ type: "POST", data: { - "Status": available + "Status": newStatus }, url: url }, true).then(() => { - if($("#chkQuickConnectActive").is(":checked")) { - url = ApiClient.getUrl("/QuickConnect/Activate"); - ApiClient.ajax({ - type: "POST", - url: url - }, true); - } - Dashboard.alert({ message: "Settings saved", title: "Saved" }); + + setTimeout(updatePage, 500); + + return true; + }).catch((e) => { + console.error("Unable to set quick connect status. error:", e); }); - + loading.hide(); return false; } - $(document).on("pageinit", "#quickConnectPage", function () { - document.querySelector("#quickConnectPage").onsubmit = onSubmit; - document.querySelector("#btnQuickConnectSubmit").onclick = onSubmit; - }).on("pageshow", "#quickConnectPage", function () { - loading.show(); - var page = this; + function updatePage() { var promise1 = ApiClient.getQuickConnect("Status"); - Promise.all([promise1]).then(function (responses) { + Promise.all([promise1]).then((responses) => { loadPage(page, responses[0]); + return true; + }).catch((e) => { + console.error("Unable to get quick connect status. error:", e); }); + } + + $(document).on("pageshow", "#quickConnectPage", function () { + loading.show(); + page = this; + + page.querySelector("#btnQuickConnectSubmit").onclick = onSubmit; + + updatePage(); }); }); diff --git a/src/controllers/user/quickconnect.js b/src/controllers/user/quickconnect.js index 6e63bcdc08..fae5d49865 100644 --- a/src/controllers/user/quickconnect.js +++ b/src/controllers/user/quickconnect.js @@ -1,50 +1,55 @@ define(["quickConnectSettings", "dom", "globalize", "loading", "userSettings", "autoFocuser", "listViewStyle"], function (QuickConnectSettings, dom, globalize, loading, userSettings, autoFocuser) { "use strict"; - return function (view, params) { - function notImplemented() { - Dashboard.alert({ - message: "This button is not implemented yet, you must check the checkbox labeled \"Always accept quick connect login requests\" in the dashboard", - title: "Not implemented" - }); - } - + return function (view) { var quickConnectSettingsInstance = null; - var hasChanges; - var userId = params.userId || ApiClient.getCurrentUserId(); - var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); + view.addEventListener("viewshow", function () { - console.debug("defining instance"); - - $("#btnQuickConnectActivate").click(notImplemented); - quickConnectSettingsInstance = new QuickConnectSettings({ - serverId: ApiClient.serverId(), - userId: userId, - element: view.querySelector(".quickConnectSettingsContainer"), - userSettings: currentSettings, - enableSaveButton: false, - enableSaveConfirmation: false, - autoFocus: autoFocuser.isEnabled() + page: view, + interval: 0 }); - + + view.querySelector("#btnQuickConnectActivate").addEventListener("click", () => { + quickConnectSettingsInstance.activate(quickConnectSettingsInstance); + }); + quickConnectSettingsInstance.loadData(); - }); - view.addEventListener("change", function () { - hasChanges = true; + + ApiClient.getQuickConnect("Status").then((status) => { + let btn = view.querySelector("#btnQuickConnectActivate"); + + if (status === "Unavailable") { + btn.textContent = "Quick connect is not available on this server"; + btn.disabled = true; + return false; + } + + else if (status === "Available") { + return false; + } + + btn.style.display = "none"; + return true; + }).catch((e) => { + throw e; + }); }); view.addEventListener("viewbeforehide", function () { - hasChanges = false; - if (quickConnectSettingsInstance) { quickConnectSettingsInstance.submit(); } + onDestroy(); }); view.addEventListener("viewdestroy", function () { + onDestroy(); + }); + + function onDestroy() { if (quickConnectSettingsInstance) { quickConnectSettingsInstance.destroy(); quickConnectSettingsInstance = null; } - }); + } }; }); diff --git a/src/mypreferencesmenu.html b/src/mypreferencesmenu.html index c8db1d17f3..bfc5e793ef 100644 --- a/src/mypreferencesmenu.html +++ b/src/mypreferencesmenu.html @@ -51,13 +51,13 @@
    - +
    Quick Connect
    - +
    diff --git a/src/mypreferencesquickconnect.html b/src/mypreferencesquickconnect.html index b9ffdfaccd..d92e49a427 100644 --- a/src/mypreferencesquickconnect.html +++ b/src/mypreferencesquickconnect.html @@ -2,7 +2,7 @@ - + Incoming login requests:
      diff --git a/src/quickconnect.html b/src/quickconnect.html index 875716285c..9a7dfdfb3e 100644 --- a/src/quickconnect.html +++ b/src/quickconnect.html @@ -6,9 +6,9 @@

      Quick Connect

    - + Quick connect is: Failed to load status - +
    If unchecked, users will have to click the Activate button in their profile before initiating a quick connect login.
    - + diff --git a/src/scripts/librarymenu.js b/src/scripts/librarymenu.js index 930df8be49..2accf4948d 100644 --- a/src/scripts/librarymenu.js +++ b/src/scripts/librarymenu.js @@ -350,7 +350,7 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " pageIds: ["devicesPage", "devicePage"], icon: "devices" }); - links.push({ + links.push({ name: "Quick Connect", href: "quickconnect.html", pageIds: ["quickConnectPage", "quickConnectPage"], diff --git a/src/scripts/site.js b/src/scripts/site.js index 311478c019..3b8abf2bfe 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -829,7 +829,7 @@ var AppInfo = {}; define("displaySettings", [componentsPath + "/displaysettings/displaysettings"], returnFirstDependency); define("playbackSettings", [componentsPath + "/playbacksettings/playbacksettings"], returnFirstDependency); define("homescreenSettings", [componentsPath + "/homescreensettings/homescreensettings"], returnFirstDependency); - define("quickConnectSettings", [componentsPath + "/quickconnectsettings/quickconnectsettings"], returnFirstDependency); + define("quickConnectSettings", [componentsPath + "/quickconnectsettings/quickconnectsettings"], returnFirstDependency); define("playbackManager", [componentsPath + "/playback/playbackmanager"], getPlaybackManager); define("layoutManager", [componentsPath + "/layoutManager", "apphost"], getLayoutManager); define("homeSections", [componentsPath + "/homesections/homesections"], returnFirstDependency); From 43d01146a23b9ee9c4044a5d0b545ee6fe6ce692 Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Sun, 19 Apr 2020 01:39:05 -0500 Subject: [PATCH 005/281] Fix linting --- .../quickconnectsettings/quickconnectsettings.js | 2 +- src/controllers/quickconnect.js | 4 ++-- src/controllers/user/quickconnect.js | 4 +--- src/libraries/apiclient/apiclientcore.js | 7 ++++--- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/components/quickconnectsettings/quickconnectsettings.js b/src/components/quickconnectsettings/quickconnectsettings.js index fc167802d8..c65782cafe 100644 --- a/src/components/quickconnectsettings/quickconnectsettings.js +++ b/src/components/quickconnectsettings/quickconnectsettings.js @@ -61,7 +61,7 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa } Dashboard.alert({ - message: "Already active" + message: "Successfully activated" }); return true; diff --git a/src/controllers/quickconnect.js b/src/controllers/quickconnect.js index a6ebc381ce..35e5516f45 100644 --- a/src/controllers/quickconnect.js +++ b/src/controllers/quickconnect.js @@ -2,7 +2,7 @@ define(["jQuery", "loading", "fnchecked"], function ($, loading) { "use strict"; var page; - function loadPage(page, status) { + function loadPage(status) { var active = (status == "Active"); var available = (status == "Available") || active; @@ -49,7 +49,7 @@ define(["jQuery", "loading", "fnchecked"], function ($, loading) { function updatePage() { var promise1 = ApiClient.getQuickConnect("Status"); Promise.all([promise1]).then((responses) => { - loadPage(page, responses[0]); + loadPage(responses[0]); return true; }).catch((e) => { console.error("Unable to get quick connect status. error:", e); diff --git a/src/controllers/user/quickconnect.js b/src/controllers/user/quickconnect.js index fae5d49865..2b03dec415 100644 --- a/src/controllers/user/quickconnect.js +++ b/src/controllers/user/quickconnect.js @@ -23,9 +23,7 @@ define(["quickConnectSettings", "dom", "globalize", "loading", "userSettings", " btn.textContent = "Quick connect is not available on this server"; btn.disabled = true; return false; - } - - else if (status === "Available") { + } else if (status === "Available") { return false; } diff --git a/src/libraries/apiclient/apiclientcore.js b/src/libraries/apiclient/apiclientcore.js index 04421b8372..e1892505fc 100644 --- a/src/libraries/apiclient/apiclientcore.js +++ b/src/libraries/apiclient/apiclientcore.js @@ -358,8 +358,8 @@ define(["events", "appStorage"], function(events, appStorage) { }) }, ApiClient.prototype.quickConnect = function (token) { if (!token) return Promise.reject(); - var url = this.getUrl("Users/AuthenticateWithQuickConnect"), - instance = this; + var url = this.getUrl("Users/AuthenticateWithQuickConnect"); + var instance = this; return new Promise(function(resolve, reject) { var postData = { Token: token @@ -372,7 +372,8 @@ define(["events", "appStorage"], function(events, appStorage) { contentType: "application/json" }).then(function(result) { var afterOnAuthenticated = function() { - redetectBitrate(instance), resolve(result) + redetectBitrate(instance); + return resolve(result); }; instance.onAuthenticated ? instance.onAuthenticated(instance, result).then(afterOnAuthenticated) : afterOnAuthenticated() }, reject) From bf03a7ba57af89f1a38c41457dbe7c70f501a04d Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Sat, 25 Apr 2020 15:46:22 -0500 Subject: [PATCH 006/281] Improve UI --- .../quickconnectsettings.js | 42 ++++++++++++++----- src/controllers/auth/login.js | 42 ++++++++++++------- src/controllers/quickconnect.js | 12 ++---- src/mypreferencesmenu.html | 2 +- src/mypreferencesquickconnect.html | 5 +-- src/quickconnect.html | 5 --- src/scripts/librarymenu.js | 2 +- 7 files changed, 65 insertions(+), 45 deletions(-) diff --git a/src/components/quickconnectsettings/quickconnectsettings.js b/src/components/quickconnectsettings/quickconnectsettings.js index c65782cafe..59250df76a 100644 --- a/src/components/quickconnectsettings/quickconnectsettings.js +++ b/src/components/quickconnectsettings/quickconnectsettings.js @@ -11,25 +11,45 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa "Lookup": lookup } }, true); + + require(["toast"], function (toast) { + toast("Request authorized"); + }); + + // prevent bubbling + return false; } QuickConnectSettings.prototype.list = function(argPage) { ApiClient.getJSON("/QuickConnect/List").then(json => { + let found = false; var elem = $(argPage.querySelector("#quickConnectIncoming")); - elem.html(""); - for (var i = 0; i < json.length; i++) { - var current = json[i]; - var html = "
  • " + current.Code + " - " + current.FriendlyName + " - "; + elem.text("No pending login requests"); - if (!current.Authenticated) { - html += "authorize"; - } else { - html += " (already authorized)"; + for (var i = 0; i < json.length; i++) { + if (!found) { + elem.html(""); + found = true; } - html += "
  • "; + var current = json[i]; + + let html = '
    '; + html += '
    ' + current.Code + '
    '; + html += '
    ' + current.FriendlyName + '
    '; + html += '
    '; + + if (!current.Authenticated) { + html += 'authorize'; + } else { + html += " (authorized)"; + } + + html += '
    '; elem.append(html); + $("#qc" + current.Lookup).click({ lookup: current.Lookup }, authorizeRequest); + $("#div" + current.Lookup).click({ lookup: current.Lookup }, authorizeRequest); } return true; @@ -60,8 +80,8 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa return false; } - Dashboard.alert({ - message: "Successfully activated" + require(["toast"], function (toast) { + toast("Successfully activated"); }); return true; diff --git a/src/controllers/auth/login.js b/src/controllers/auth/login.js index 94fa15d412..ff36939fb2 100644 --- a/src/controllers/auth/login.js +++ b/src/controllers/auth/login.js @@ -152,7 +152,7 @@ define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layout function loginQuickConnect() { var apiClient = getApiClient(); - var friendlyName = navigator.userAgent; // TODO: what should this be changed to? + var friendlyName = navigator.userAgent; var url = apiClient.getUrl("/QuickConnect/Initiate?FriendlyName=" + friendlyName); apiClient.getJSON(url) @@ -174,25 +174,37 @@ define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layout loading.show(); var interval = setInterval(async function() { - let connectUrl = apiClient.getUrl('/QuickConnect/Connect?Secret=' + json.Secret); - let data = await apiClient.getJSON(connectUrl); - if (data.Authenticated) { - let result = await apiClient.quickConnect(data.Authentication); - var user = result.User; - var serverId = getParameterByName("serverid"); - var newUrl = "home.html"; + try { + let connectUrl = apiClient.getUrl('/QuickConnect/Connect?Secret=' + json.Secret); + let data = await apiClient.getJSON(connectUrl); + if (data.Authenticated) { + let result = await apiClient.quickConnect(data.Authentication); + var user = result.User; + var serverId = getParameterByName("serverid"); + var newUrl = "home.html"; - if (user.Policy.IsAdministrator && !serverId) { - newUrl = "dashboard.html"; + if (user.Policy.IsAdministrator && !serverId) { + newUrl = "dashboard.html"; + } + + loading.hide(); + Dashboard.onServerChanged(user.Id, result.AccessToken, apiClient); + Dashboard.navigate(newUrl); + clearInterval(interval); + + return true; } + } catch (e) { + Dashboard.alert({ + message: "Quick connect was deactivated before the login request could be approved", + title: "Unexpected error" + }); - loading.hide(); - Dashboard.onServerChanged(user.Id, result.AccessToken, apiClient); - Dashboard.navigate(newUrl); + console.error("Unable to login with quick connect", e); clearInterval(interval); - - return true; + loading.hide(); } + return false; }, 5000); diff --git a/src/controllers/quickconnect.js b/src/controllers/quickconnect.js index 35e5516f45..3432e79231 100644 --- a/src/controllers/quickconnect.js +++ b/src/controllers/quickconnect.js @@ -3,12 +3,10 @@ define(["jQuery", "loading", "fnchecked"], function ($, loading) { var page; function loadPage(status) { - var active = (status == "Active"); - var available = (status == "Available") || active; + var available = status === "Available" || status === "Active"; page.querySelector("#quickConnectStatus").textContent = status.toLocaleLowerCase(); page.querySelector("#chkQuickConnectAvailable").checked = available; - page.querySelector("#chkQuickConnectActive").checked = active; loading.hide(); } @@ -17,9 +15,6 @@ define(["jQuery", "loading", "fnchecked"], function ($, loading) { loading.show(); var newStatus = page.querySelector("#chkQuickConnectAvailable").checked ? "Available" : "Unavailable"; - if (newStatus && page.querySelector("#chkQuickConnectActive").checked) { - newStatus = "Active"; - } var url = ApiClient.getUrl("/QuickConnect/Available"); @@ -30,9 +25,8 @@ define(["jQuery", "loading", "fnchecked"], function ($, loading) { }, url: url }, true).then(() => { - Dashboard.alert({ - message: "Settings saved", - title: "Saved" + require(["toast"], function (toast) { + toast("Settings saved"); }); setTimeout(updatePage, 500); diff --git a/src/mypreferencesmenu.html b/src/mypreferencesmenu.html index bfc5e793ef..6f753e5554 100644 --- a/src/mypreferencesmenu.html +++ b/src/mypreferencesmenu.html @@ -51,7 +51,7 @@
    - + tap_and_play
    Quick Connect
    diff --git a/src/mypreferencesquickconnect.html b/src/mypreferencesquickconnect.html index d92e49a427..b58ca8074f 100644 --- a/src/mypreferencesquickconnect.html +++ b/src/mypreferencesquickconnect.html @@ -3,10 +3,9 @@ Activate - Incoming login requests:
    -
      -
    • Failed to load incoming requests
    • +
      +
      Failed to load incoming requests
    diff --git a/src/quickconnect.html b/src/quickconnect.html index 9a7dfdfb3e..7d7ec879a6 100644 --- a/src/quickconnect.html +++ b/src/quickconnect.html @@ -14,11 +14,6 @@ Enable quick connect on this server - -
    If unchecked, users will have to click the Activate button in their profile before initiating a quick connect login.
    -
    Failed to load incoming requests
    +
    ${MessagePleaseWait}
    diff --git a/src/quickconnect.html b/src/quickconnect.html index 7d7ec879a6..dff74eb836 100644 --- a/src/quickconnect.html +++ b/src/quickconnect.html @@ -3,16 +3,16 @@
    -

    Quick Connect

    +

    ${QuickConnect}

    - Quick connect is: Failed to load status + ${LabelCurrentStatus}
    diff --git a/src/scripts/librarymenu.js b/src/scripts/librarymenu.js index 131dcf7472..e3ef65f22f 100644 --- a/src/scripts/librarymenu.js +++ b/src/scripts/librarymenu.js @@ -351,7 +351,7 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " icon: "devices" }); links.push({ - name: "Quick Connect", + name: globalize.translate("QuickConnect"), href: "quickconnect.html", pageIds: ["quickConnectPage", "quickConnectPage"], icon: "tap_and_play" diff --git a/src/strings/en-us.json b/src/strings/en-us.json index d5fc40ef01..ad390a0fe2 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -48,6 +48,7 @@ "AuthProviderHelp": "Select an Authentication Provider to be used to authenticate this user's password.", "Auto": "Auto", "AutoBasedOnLanguageSetting": "Auto (based on language setting)", + "Authorize": "authorize", "Backdrop": "Backdrop", "Backdrops": "Backdrops", "Banner": "Banner", @@ -63,6 +64,7 @@ "Browse": "Browse", "BrowsePluginCatalogMessage": "Browse our plugin catalog to view available plugins.", "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when transcoding videos. Avoiding this will greatly improve performance. Select Auto to burn image based formats (VOBSUB, PGS, SUB, IDX) and certain ASS or SSA subtitles.", + "ButtonActivate": "Activate", "ButtonAdd": "Add", "ButtonAddImage": "Add Image", "ButtonAddMediaLibrary": "Add Media Library", @@ -140,6 +142,7 @@ "ButtonTrailer": "Trailer", "ButtonUninstall": "Uninstall", "ButtonUp": "Up", + "ButtonUseQuickConnect": "Use Quick Connect", "ButtonViewWebsite": "View website", "ButtonWebsite": "Website", "CancelRecording": "Cancel recording", @@ -231,6 +234,7 @@ "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", "EnablePhotos": "Display photos", "EnablePhotosHelp": "Images will be detected and displayed alongside other media files.", + "EnableQuickConnect": "Enable quick connect on this server", "EnableStreamLooping": "Auto-loop live streams", "EnableStreamLoopingHelp": "Enable this if live streams only contain a few seconds of data and need to be continuously requested. Enabling this when not needed may cause problems.", "EnableThemeSongs": "Theme songs", @@ -587,6 +591,7 @@ "LabelCountry": "Country:", "LabelCriticRating": "Critic rating:", "LabelCurrentPassword": "Current password:", + "LabelCurrentStatus": "Current status:", "LabelCustomCertificatePath": "Custom SSL certificate path:", "LabelCustomCertificatePathHelp": "Path to a PKCS #12 file containing a certificate and private key to enable TLS support on a custom domain.", "LabelCustomCss": "Custom CSS:", @@ -1260,6 +1265,11 @@ "Programs": "Programs", "Quality": "Quality", "QueueAllFromHere": "Queue all from here", + "QuickConnect": "Quick Connect", + "QuickConnectActivationSuccessful": "Successfully activated", + "QuickConnectAuthorizeCode": "Authorize request {0} to continue", + "QuickConnectNoPending": "No pending login requests", + "QuickConnectNotAvailable": "Quick connect is not available on this server", "Raised": "Raised", "Rate": "Rate", "RecentlyWatched": "Recently watched", From a6d37e763319c1e65f1a7358a1b8ac0895b6492c Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Sun, 26 Apr 2020 17:47:31 -0500 Subject: [PATCH 008/281] Change missed var declarations into let --- .../quickconnectsettings/quickconnectsettings.js | 8 ++++---- src/controllers/auth/login.js | 14 +++++++------- src/controllers/quickconnect.js | 10 +++++----- src/controllers/user/quickconnect.js | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/components/quickconnectsettings/quickconnectsettings.js b/src/components/quickconnectsettings/quickconnectsettings.js index 6010fab5c3..45bfe815cc 100644 --- a/src/components/quickconnectsettings/quickconnectsettings.js +++ b/src/components/quickconnectsettings/quickconnectsettings.js @@ -23,16 +23,16 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa QuickConnectSettings.prototype.list = function(argPage) { ApiClient.getJSON("/QuickConnect/List").then(json => { let found = false; - var elem = argPage.querySelector('#quickConnectIncoming'); + let elem = argPage.querySelector('#quickConnectIncoming'); elem.innerText = globalize.translate('QuickConnectNoPending'); - for (var i = 0; i < json.length; i++) { + for (let i = 0; i < json.length; i++) { if (!found) { elem.innerHTML = ""; found = true; } - var current = json[i]; + let current = json[i]; let html = '
    '; html += '
    ' + current.Code + '
    '; @@ -57,7 +57,7 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa }; QuickConnectSettings.prototype.activate = function() { - var url = ApiClient.getUrl("/QuickConnect/Activate"); + let url = ApiClient.getUrl("/QuickConnect/Activate"); ApiClient.ajax({ type: "POST", url: url, diff --git a/src/controllers/auth/login.js b/src/controllers/auth/login.js index 86e8874e7e..8b0bcdd28d 100644 --- a/src/controllers/auth/login.js +++ b/src/controllers/auth/login.js @@ -151,10 +151,10 @@ define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layout } function loginQuickConnect() { - var apiClient = getApiClient(); - var friendlyName = navigator.userAgent; + let apiClient = getApiClient(); + let friendlyName = navigator.userAgent; - var url = apiClient.getUrl("/QuickConnect/Initiate?FriendlyName=" + friendlyName); + let url = apiClient.getUrl("/QuickConnect/Initiate?FriendlyName=" + friendlyName); apiClient.getJSON(url) .then(json => { if (!json.Secret || !json.Code) { @@ -173,15 +173,15 @@ define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layout loading.show(); - var interval = setInterval(async function() { + let interval = setInterval(async function() { try { let connectUrl = apiClient.getUrl('/QuickConnect/Connect?Secret=' + json.Secret); let data = await apiClient.getJSON(connectUrl); if (data.Authenticated) { let result = await apiClient.quickConnect(data.Authentication); - var user = result.User; - var serverId = getParameterByName("serverid"); - var newUrl = "home.html"; + let user = result.User; + let serverId = getParameterByName("serverid"); + let newUrl = "home.html"; if (user.Policy.IsAdministrator && !serverId) { newUrl = "dashboard.html"; diff --git a/src/controllers/quickconnect.js b/src/controllers/quickconnect.js index 3432e79231..93b74a1b52 100644 --- a/src/controllers/quickconnect.js +++ b/src/controllers/quickconnect.js @@ -1,9 +1,9 @@ define(["jQuery", "loading", "fnchecked"], function ($, loading) { "use strict"; - var page; + let page; function loadPage(status) { - var available = status === "Available" || status === "Active"; + let available = status === "Available" || status === "Active"; page.querySelector("#quickConnectStatus").textContent = status.toLocaleLowerCase(); page.querySelector("#chkQuickConnectAvailable").checked = available; @@ -14,9 +14,9 @@ define(["jQuery", "loading", "fnchecked"], function ($, loading) { function onSubmit() { loading.show(); - var newStatus = page.querySelector("#chkQuickConnectAvailable").checked ? "Available" : "Unavailable"; + let newStatus = page.querySelector("#chkQuickConnectAvailable").checked ? "Available" : "Unavailable"; - var url = ApiClient.getUrl("/QuickConnect/Available"); + let url = ApiClient.getUrl("/QuickConnect/Available"); ApiClient.ajax({ type: "POST", @@ -41,7 +41,7 @@ define(["jQuery", "loading", "fnchecked"], function ($, loading) { } function updatePage() { - var promise1 = ApiClient.getQuickConnect("Status"); + let promise1 = ApiClient.getQuickConnect("Status"); Promise.all([promise1]).then((responses) => { loadPage(responses[0]); return true; diff --git a/src/controllers/user/quickconnect.js b/src/controllers/user/quickconnect.js index 035aef8f2f..bee0c1b817 100644 --- a/src/controllers/user/quickconnect.js +++ b/src/controllers/user/quickconnect.js @@ -2,7 +2,7 @@ define(["quickConnectSettings", "dom", "globalize", "loading", "userSettings", " "use strict"; return function (view) { - var quickConnectSettingsInstance = null; + let quickConnectSettingsInstance = null; view.addEventListener("viewshow", function () { quickConnectSettingsInstance = new QuickConnectSettings({ From 8655de4469c3aade0e1f949169c8f536a43e210b Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Fri, 1 May 2020 13:49:06 -0500 Subject: [PATCH 009/281] Rename to camel case --- .../quickConnectSettings.js} | 0 src/controllers/{quickconnect.js => quickConnect.js} | 0 src/controllers/user/{quickconnect.js => quickConnect.js} | 0 ...referencesquickconnect.html => myPreferencesQuickConnect.html} | 0 src/{quickconnect.html => quickConnect.html} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/components/{quickconnectsettings/quickconnectsettings.js => quickConnectSettings/quickConnectSettings.js} (100%) rename src/controllers/{quickconnect.js => quickConnect.js} (100%) rename src/controllers/user/{quickconnect.js => quickConnect.js} (100%) rename src/{mypreferencesquickconnect.html => myPreferencesQuickConnect.html} (100%) rename src/{quickconnect.html => quickConnect.html} (100%) diff --git a/src/components/quickconnectsettings/quickconnectsettings.js b/src/components/quickConnectSettings/quickConnectSettings.js similarity index 100% rename from src/components/quickconnectsettings/quickconnectsettings.js rename to src/components/quickConnectSettings/quickConnectSettings.js diff --git a/src/controllers/quickconnect.js b/src/controllers/quickConnect.js similarity index 100% rename from src/controllers/quickconnect.js rename to src/controllers/quickConnect.js diff --git a/src/controllers/user/quickconnect.js b/src/controllers/user/quickConnect.js similarity index 100% rename from src/controllers/user/quickconnect.js rename to src/controllers/user/quickConnect.js diff --git a/src/mypreferencesquickconnect.html b/src/myPreferencesQuickConnect.html similarity index 100% rename from src/mypreferencesquickconnect.html rename to src/myPreferencesQuickConnect.html diff --git a/src/quickconnect.html b/src/quickConnect.html similarity index 100% rename from src/quickconnect.html rename to src/quickConnect.html From d8cfe064e60379033fdf61a963efbc27296130af Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Fri, 1 May 2020 14:18:04 -0500 Subject: [PATCH 010/281] Changed code to camel case --- src/controllers/user/menu.js | 2 +- src/scripts/librarymenu.js | 2 +- src/scripts/routes.js | 8 ++++---- src/scripts/site.js | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/controllers/user/menu.js b/src/controllers/user/menu.js index f5d05c5be3..9482b26cb5 100644 --- a/src/controllers/user/menu.js +++ b/src/controllers/user/menu.js @@ -24,7 +24,7 @@ define(["apphost", "connectionManager", "layoutManager", "listViewStyle", "emby- page.querySelector(".lnkHomePreferences").setAttribute("href", "mypreferenceshome.html?userId=" + userId); page.querySelector(".lnkPlaybackPreferences").setAttribute("href", "mypreferencesplayback.html?userId=" + userId); page.querySelector(".lnkSubtitlePreferences").setAttribute("href", "mypreferencessubtitles.html?userId=" + userId); - page.querySelector(".lnkQuickConnectPreferences").setAttribute("href", "mypreferencesquickconnect.html?userId=" + userId); + page.querySelector(".lnkQuickConnectPreferences").setAttribute("href", "myPreferencesQuickConnect.html?userId=" + userId); if (window.NativeShell && window.NativeShell.AppHost.supports("clientsettings")) { page.querySelector(".clientSettings").classList.remove("hide"); diff --git a/src/scripts/librarymenu.js b/src/scripts/librarymenu.js index e3ef65f22f..d123395ca0 100644 --- a/src/scripts/librarymenu.js +++ b/src/scripts/librarymenu.js @@ -352,7 +352,7 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " }); links.push({ name: globalize.translate("QuickConnect"), - href: "quickconnect.html", + href: "quickConnect.html", pageIds: ["quickConnectPage", "quickConnectPage"], icon: "tap_and_play" }); diff --git a/src/scripts/routes.js b/src/scripts/routes.js index 1520e96632..f0806f56e0 100644 --- a/src/scripts/routes.js +++ b/src/scripts/routes.js @@ -73,10 +73,10 @@ define([ controller: "user/subtitles" }); defineRoute({ - path: "/mypreferencesquickconnect.html", + path: "/myPreferencesQuickConnect.html", autoFocus: false, transition: "fade", - controller: "user/quickconnect" + controller: "user/quickConnect" }); defineRoute({ @@ -110,10 +110,10 @@ define([ controller: "device" }); defineRoute({ - path: "/quickconnect.html", + path: "/quickConnect.html", autoFocus: false, roles: "admin", - controller: "quickconnect" + controller: "quickConnect" }); defineRoute({ path: "/dlnaprofile.html", diff --git a/src/scripts/site.js b/src/scripts/site.js index 3b8abf2bfe..ca8a828b0b 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -829,7 +829,7 @@ var AppInfo = {}; define("displaySettings", [componentsPath + "/displaysettings/displaysettings"], returnFirstDependency); define("playbackSettings", [componentsPath + "/playbacksettings/playbacksettings"], returnFirstDependency); define("homescreenSettings", [componentsPath + "/homescreensettings/homescreensettings"], returnFirstDependency); - define("quickConnectSettings", [componentsPath + "/quickconnectsettings/quickconnectsettings"], returnFirstDependency); + define("quickConnectSettings", [componentsPath + "/quickConnectSettings/quickConnectSettings"], returnFirstDependency); define("playbackManager", [componentsPath + "/playback/playbackmanager"], getPlaybackManager); define("layoutManager", [componentsPath + "/layoutManager", "apphost"], getLayoutManager); define("homeSections", [componentsPath + "/homesections/homesections"], returnFirstDependency); From 2655b4dca3da200f9dc720f37b4d6e7f32b4d839 Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Mon, 4 May 2020 17:23:57 -0500 Subject: [PATCH 011/281] Migrate API changes to apiclient repo --- src/libraries/apiclient/apiclientcore.js | 25 ------------------------ 1 file changed, 25 deletions(-) diff --git a/src/libraries/apiclient/apiclientcore.js b/src/libraries/apiclient/apiclientcore.js index e1892505fc..557a4e1033 100644 --- a/src/libraries/apiclient/apiclientcore.js +++ b/src/libraries/apiclient/apiclientcore.js @@ -356,31 +356,6 @@ define(["events", "appStorage"], function(events, appStorage) { instance.onAuthenticated ? instance.onAuthenticated(instance, result).then(afterOnAuthenticated) : afterOnAuthenticated() }, reject) }) - }, ApiClient.prototype.quickConnect = function (token) { - if (!token) return Promise.reject(); - var url = this.getUrl("Users/AuthenticateWithQuickConnect"); - var instance = this; - return new Promise(function(resolve, reject) { - var postData = { - Token: token - }; - instance.ajax({ - type: "POST", - url: url, - data: JSON.stringify(postData), - dataType: "json", - contentType: "application/json" - }).then(function(result) { - var afterOnAuthenticated = function() { - redetectBitrate(instance); - return resolve(result); - }; - instance.onAuthenticated ? instance.onAuthenticated(instance, result).then(afterOnAuthenticated) : afterOnAuthenticated() - }, reject) - }) - }, ApiClient.prototype.getQuickConnect = function(verb) { - var url = this.getUrl("/QuickConnect/" + verb); - return this.getJSON(url); }, ApiClient.prototype.ensureWebSocket = function() { if (!this.isWebSocketOpenOrConnecting() && this.isWebSocketSupported()) try { this.openWebSocket() From 429c47f414851bf95f24736ce2e08e370c397eac Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Thu, 25 Jun 2020 16:53:45 +0800 Subject: [PATCH 012/281] add tonemapping settings --- src/components/itemMediaInfo/itemMediaInfo.js | 12 +++++ src/components/playerstats/playerstats.js | 28 ++++++++++ src/controllers/dashboard/encodingsettings.js | 26 +++++++++ src/encodingsettings.html | 53 +++++++++++++++++++ src/strings/en-us.json | 26 ++++++++- src/strings/zh-cn.json | 26 ++++++++- 6 files changed, 169 insertions(+), 2 deletions(-) diff --git a/src/components/itemMediaInfo/itemMediaInfo.js b/src/components/itemMediaInfo/itemMediaInfo.js index 81c84b6a23..ad5f261ec6 100644 --- a/src/components/itemMediaInfo/itemMediaInfo.js +++ b/src/components/itemMediaInfo/itemMediaInfo.js @@ -90,6 +90,18 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', if (stream.BitDepth) { attributes.push(createAttribute(globalize.translate('MediaInfoBitDepth'), stream.BitDepth + ' bit')); } + if (stream.VideoRange) { + attributes.push(createAttribute(globalize.translate('MediaInfoVideoRange'), stream.VideoRange)); + } + if (stream.ColorSpace) { + attributes.push(createAttribute(globalize.translate('MediaInfoColorSpace'), stream.ColorSpace)); + } + if (stream.ColorTransfer) { + attributes.push(createAttribute(globalize.translate('MediaInfoColorTransfer'), stream.ColorTransfer)); + } + if (stream.ColorPrimaries) { + attributes.push(createAttribute(globalize.translate('MediaInfoColorPrimaries'), stream.ColorPrimaries)); + } if (stream.PixelFormat) { attributes.push(createAttribute(globalize.translate('MediaInfoPixelFormat'), stream.PixelFormat)); } diff --git a/src/components/playerstats/playerstats.js b/src/components/playerstats/playerstats.js index a65baf3553..e3fe6452f8 100644 --- a/src/components/playerstats/playerstats.js +++ b/src/components/playerstats/playerstats.js @@ -279,6 +279,34 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'syncPlay }); } + if (videoStream.VideoRange) { + sessionStats.push({ + label: globalize.translate('LabelVideoRange'), + value: videoStream.VideoRange + }); + } + + if (videoStream.ColorSpace) { + sessionStats.push({ + label: globalize.translate('LabelColorSpace'), + value: videoStream.ColorSpace + }); + } + + if (videoStream.ColorTransfer) { + sessionStats.push({ + label: globalize.translate('LabelColorTransfer'), + value: videoStream.ColorTransfer + }); + } + + if (videoStream.ColorPrimaries) { + sessionStats.push({ + label: globalize.translate('LabelColorPrimaries'), + value: videoStream.ColorPrimaries + }); + } + var audioInfos = []; if (audioCodec) { diff --git a/src/controllers/dashboard/encodingsettings.js b/src/controllers/dashboard/encodingsettings.js index 0f54f9d70f..d728321284 100644 --- a/src/controllers/dashboard/encodingsettings.js +++ b/src/controllers/dashboard/encodingsettings.js @@ -8,12 +8,20 @@ define(['jQuery', 'loading', 'globalize', 'dom', 'libraryMenu'], function ($, lo page.querySelector('#chkDecodingColorDepth10Hevc').checked = config.EnableDecodingColorDepth10Hevc; page.querySelector('#chkDecodingColorDepth10Vp9').checked = config.EnableDecodingColorDepth10Vp9; page.querySelector('#chkHardwareEncoding').checked = config.EnableHardwareEncoding; + page.querySelector('#chkTonemapping').checked = config.EnableTonemapping; $('#selectVideoDecoder', page).val(config.HardwareAccelerationType); $('#selectThreadCount', page).val(config.EncodingThreadCount); $('#txtDownMixAudioBoost', page).val(config.DownMixAudioBoost); page.querySelector('.txtEncoderPath').value = config.EncoderAppPathDisplay || ''; $('#txtTranscodingTempPath', page).val(systemInfo.TranscodingTempPath || ''); $('#txtVaapiDevice', page).val(config.VaapiDevice || ''); + $('#txtOpenclDevice', page).val(config.OpenclDevice || ''); + $('#selectTonemappingAlgorithm', page).val(config.TonemappingAlgorithm); + $('#selectTonemappingRange', page).val(config.TonemappingRange); + $('#txtTonemappingDesat', page).val(config.TonemappingDesat); + $('#txtTonemappingThreshold', page).val(config.TonemappingThreshold); + $('#txtTonemappingPeak', page).val(config.TonemappingPeak); + $('#txtTonemappingParam', page).val(config.TonemappingParam || ''); page.querySelector('#selectEncoderPreset').value = config.EncoderPreset || ''; page.querySelector('#txtH264Crf').value = config.H264Crf || ''; page.querySelector('#selectDeinterlaceMethod').value = config.DeinterlaceMethod || ''; @@ -59,6 +67,14 @@ define(['jQuery', 'loading', 'globalize', 'dom', 'libraryMenu'], function ($, lo config.EncodingThreadCount = $('#selectThreadCount', form).val(); config.HardwareAccelerationType = $('#selectVideoDecoder', form).val(); config.VaapiDevice = $('#txtVaapiDevice', form).val(); + config.OpenclDevice = $('#txtOpenclDevice', form).val(); + config.EnableTonemapping = form.querySelector('#chkTonemapping').checked; + config.TonemappingAlgorithm = form.querySelector('#selectTonemappingAlgorithm').value; + config.TonemappingRange = form.querySelector('#selectTonemappingRange').value; + config.TonemappingDesat = $('#txtTonemappingDesat', form).val(); + config.TonemappingThreshold = $('#txtTonemappingThreshold', form).val(); + config.TonemappingPeak = $('#txtTonemappingPeak', form).val(); + config.TonemappingParam = $('#txtTonemappingParam', form).val(); config.EncoderPreset = form.querySelector('#selectEncoderPreset').value; config.H264Crf = parseInt(form.querySelector('#txtH264Crf').value || '0'); config.DeinterlaceMethod = form.querySelector('#selectDeinterlaceMethod').value; @@ -141,6 +157,16 @@ define(['jQuery', 'loading', 'globalize', 'dom', 'libraryMenu'], function ($, lo page.querySelector('#txtVaapiDevice').removeAttribute('required'); } + if ('nvenc' == this.value) { + page.querySelector('.fldOpenclDevice').classList.remove('hide'); + page.querySelector('#txtOpenclDevice').setAttribute('required', 'required'); + page.querySelector('.tonemappingOptions').classList.remove('hide'); + } else { + page.querySelector('.fldOpenclDevice').classList.add('hide'); + page.querySelector('#txtOpenclDevice').removeAttribute('required'); + page.querySelector('.tonemappingOptions').classList.add('hide'); + } + if (this.value) { page.querySelector('.hardwareAccelerationOptions').classList.remove('hide'); } else { diff --git a/src/encodingsettings.html b/src/encodingsettings.html index 858375b145..c020df9121 100644 --- a/src/encodingsettings.html +++ b/src/encodingsettings.html @@ -31,6 +31,11 @@
    ${LabelVaapiDeviceHelp}
    +
    + +
    ${LabelOpenclDeviceHelp}
    +
    +

    ${LabelEnableHardwareDecodingFor}

    @@ -89,6 +94,54 @@
    +
    +
    + +
    ${AllowTonemappingHelp}
    +
    +
    + + +
    +
    + +
    ${TonemappingRangeHelp}
    +
    +
    + +
    ${LabelTonemappingDesatHelp}
    +
    +
    + +
    ${LabelTonemappingThresholdHelp}
    +
    +
    + +
    ${LabelTonemappingPeakHelp}
    +
    +
    + +
    ${LabelTonemappingParamHelp}
    +
    +
    +
    +
    + + +
    diff --git a/src/controllers/user/quickConnect/index.js b/src/controllers/user/quickConnect/index.js new file mode 100644 index 0000000000..80543a0b58 --- /dev/null +++ b/src/controllers/user/quickConnect/index.js @@ -0,0 +1,78 @@ +import QuickConnectSettings from 'quickConnectSettings'; +import globalize from 'globalize'; +import toast from 'toast'; + +export default function (view) { + let quickConnectSettingsInstance = null; + + view.addEventListener('viewshow', function () { + let codeElement = view.querySelector('#txtQuickConnectCode'); + + quickConnectSettingsInstance = new QuickConnectSettings({ + page: view, + interval: 0 + }); + + view.querySelector('#btnQuickConnectActivate').addEventListener('click', () => { + quickConnectSettingsInstance.activate(quickConnectSettingsInstance).then(() => { + renderPage(); + }); + }); + + view.querySelector('#btnQuickConnectAuthorize').addEventListener('click', () => { + if (!codeElement.validity.valid) { + toast(globalize.translate('QuickConnectInvalidCode')); + + return; + } + + let code = codeElement.value; + quickConnectSettingsInstance.authorize(code); + }); + + renderPage(); + }); + view.addEventListener('viewbeforehide', function () { + if (quickConnectSettingsInstance) { + quickConnectSettingsInstance.submit(); + } + onDestroy(); + }); + view.addEventListener('viewdestroy', function () { + onDestroy(); + }); + + function onDestroy() { + if (quickConnectSettingsInstance) { + quickConnectSettingsInstance.destroy(); + quickConnectSettingsInstance = null; + } + } + + function renderPage(forceActive = false) { + ApiClient.getQuickConnect('Status').then((status) => { + let btn = view.querySelector('#btnQuickConnectActivate'); + let container = view.querySelector('.quickConnectSettingsContainer'); + + // The activation button should only be visible when quick connect is unavailable (with the text replaced with an error) or when it is available (so it can be activated) + // The authorization container is only usable when quick connect is active, so it should be hidden otherwise + container.style.display = 'none'; + + if (status === 'Unavailable') { + btn.textContent = globalize.translate('QuickConnectNotAvailable'); + btn.disabled = true; + btn.classList.remove('button-submit'); + btn.classList.add('button'); + } else if (status === 'Active' || forceActive) { + container.style.display = ''; + btn.style.display = 'none'; + } + + return true; + }).catch((e) => { + throw e; + }); + } + + renderPage(); +} diff --git a/src/myPreferencesQuickConnect.html b/src/myPreferencesQuickConnect.html deleted file mode 100644 index 4f1f9febab..0000000000 --- a/src/myPreferencesQuickConnect.html +++ /dev/null @@ -1,11 +0,0 @@ -
    - - -
    -
    -
    ${MessagePleaseWait}
    - -
    -
    diff --git a/src/quickConnect.html b/src/quickconnect.html similarity index 89% rename from src/quickConnect.html rename to src/quickconnect.html index dff74eb836..671bb88d77 100644 --- a/src/quickConnect.html +++ b/src/quickconnect.html @@ -1,6 +1,6 @@
    -
    -
    +
    +

    ${QuickConnect}

    @@ -19,6 +19,6 @@ -
    +
    -
    \ No newline at end of file +
    diff --git a/src/scripts/routes.js b/src/scripts/routes.js index 3472d66496..ec623a485c 100644 --- a/src/scripts/routes.js +++ b/src/scripts/routes.js @@ -94,10 +94,11 @@ define([ controller: 'user/home/index' }); defineRoute({ - path: '/myPreferencesQuickConnect.html', + alias: '/mypreferencesquickconnect.html', + path: '/controllers/user/quickConnect/index.html', autoFocus: false, transition: 'fade', - controller: 'user/quickConnect' + controller: 'user/quickConnect/index' }); defineRoute({ alias: '/mypreferencesplayback.html', @@ -145,10 +146,10 @@ define([ controller: 'dashboard/devices/device' }); defineRoute({ - path: '/quickConnect.html', + path: '/quickconnect.html', autoFocus: false, roles: 'admin', - controller: "quickConnect" + controller: 'dashboard/quickconnect' }); defineRoute({ path: '/dlnaprofile.html', diff --git a/src/strings/en-us.json b/src/strings/en-us.json index 57a025d8b7..17e4662d2a 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -48,7 +48,7 @@ "AuthProviderHelp": "Select an Authentication Provider to be used to authenticate this user's password.", "Auto": "Auto", "AutoBasedOnLanguageSetting": "Auto (based on language setting)", - "Authorize": "authorize", + "Authorize": "Authorize", "Backdrop": "Backdrop", "Backdrops": "Backdrops", "Banner": "Banner", @@ -816,6 +816,7 @@ "LabelPublicHttpPortHelp": "The public port number that should be mapped to the local HTTP port.", "LabelPublicHttpsPort": "Public HTTPS port number:", "LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local HTTPS port.", + "LabelQuickConnectCode": "Quick connect code:", "LabelReadHowYouCanContribute": "Learn how you can contribute.", "LabelReasonForTranscoding": "Reason for transcoding:", "LabelRecord": "Record:", @@ -1322,8 +1323,12 @@ "QuickConnect": "Quick Connect", "QuickConnectActivationSuccessful": "Successfully activated", "QuickConnectAuthorizeCode": "Authorize request {0} to continue", - "QuickConnectNoPending": "No pending login requests", - "QuickConnectNotAvailable": "Quick connect is not available on this server", + "QuickConnectAuthorizeSuccess": "Request authorized", + "QuickConnectAuthorizeFail": "Unknown quick connect code", + "QuickConnectDescription": "To sign in with quick connect, select the Quick Connect button on the device you are logging in from and enter the displayed code below.", + "QuickConnectInvalidCode": "Invalid quick connect code", + "QuickConnectNotAvailable": "Ask your server administrator to enable quick connect", + "QuickConnectNotActive": "Quick connect is not active on this server", "Raised": "Raised", "Rate": "Rate", "RecentlyWatched": "Recently watched", From 5b9533c927fb9981461c8cd5697583be202ebbb8 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Wed, 19 Aug 2020 18:00:13 +0800 Subject: [PATCH 015/281] minor changes --- src/controllers/dashboard/encodingsettings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/dashboard/encodingsettings.js b/src/controllers/dashboard/encodingsettings.js index d33e7fa7e8..05d5d9b31c 100644 --- a/src/controllers/dashboard/encodingsettings.js +++ b/src/controllers/dashboard/encodingsettings.js @@ -79,7 +79,7 @@ import libraryMenu from 'libraryMenu'; config.TonemappingDesat = form.querySelector('#txtTonemappingDesat').value; config.TonemappingThreshold = form.querySelector('#txtTonemappingThreshold').value; config.TonemappingPeak = form.querySelector('#txtTonemappingPeak').value; - config.TonemappingParam = form.querySelector('#txtTonemappingParam').value; + config.TonemappingParam = form.querySelector('#txtTonemappingParam').value || '0'; config.EncoderPreset = form.querySelector('#selectEncoderPreset').value; config.H264Crf = parseInt(form.querySelector('#txtH264Crf').value || '0'); config.DeinterlaceMethod = form.querySelector('#selectDeinterlaceMethod').value; @@ -162,7 +162,7 @@ import libraryMenu from 'libraryMenu'; page.querySelector('#txtVaapiDevice').removeAttribute('required'); } - if ('nvenc' == this.value) { + if (this.value == 'nvenc') { page.querySelector('.fldOpenclDevice').classList.remove('hide'); page.querySelector('#txtOpenclDevice').setAttribute('required', 'required'); page.querySelector('.tonemappingOptions').classList.remove('hide'); From 9f92c1d158b1c01b279eb9b46f70c06d93986f22 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Tue, 25 Aug 2020 01:57:21 +0800 Subject: [PATCH 016/281] expose max_muxing_queue_size to user --- src/controllers/dashboard/encodingsettings.html | 4 ++++ src/controllers/dashboard/encodingsettings.js | 2 ++ src/strings/.en-us.json.swp | Bin 0 -> 16384 bytes src/strings/en-us.json | 4 +++- src/strings/zh-cn.json | 4 +++- 5 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 src/strings/.en-us.json.swp diff --git a/src/controllers/dashboard/encodingsettings.html b/src/controllers/dashboard/encodingsettings.html index 402532e600..4032939a89 100644 --- a/src/controllers/dashboard/encodingsettings.html +++ b/src/controllers/dashboard/encodingsettings.html @@ -129,6 +129,10 @@
    ${LabelDownMixAudioScaleHelp}
    +
    + +
    ${LabelMaxMuxingQueueSizeHelp}
    +
    @@ -47,32 +45,18 @@ - - - - - - - -
    + +
    + + + +
    diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js index 420268ea75..5da8ec45d8 100644 --- a/src/controllers/playback/video/index.js +++ b/src/controllers/playback/video/index.js @@ -21,50 +21,6 @@ import 'css!assets/css/videoosd'; /* eslint-disable indent */ - function seriesImageUrl(item, options) { - if (item.Type !== 'Episode') { - return null; - } - - options = options || {}; - options.type = options.type || 'Primary'; - if (options.type === 'Primary' && item.SeriesPrimaryImageTag) { - options.tag = item.SeriesPrimaryImageTag; - return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); - } - - if (options.type === 'Thumb') { - if (item.SeriesThumbImageTag) { - options.tag = item.SeriesThumbImageTag; - return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); - } - - if (item.ParentThumbImageTag) { - options.tag = item.ParentThumbImageTag; - return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options); - } - } - - return null; - } - - function imageUrl(item, options) { - options = options || {}; - options.type = options.type || 'Primary'; - - if (item.ImageTags && item.ImageTags[options.type]) { - options.tag = item.ImageTags[options.type]; - return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options); - } - - if (options.type === 'Primary' && item.AlbumId && item.AlbumPrimaryImageTag) { - options.tag = item.AlbumPrimaryImageTag; - return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options); - } - - return null; - } - function getOpenedDialog() { return document.querySelector('.dialogContainer .dialog.opened'); } @@ -164,7 +120,6 @@ import 'css!assets/css/videoosd'; currentItem = item; const displayItem = itemInfo.displayItem || item; updateRecordingButton(displayItem); - setPoster(displayItem, item); let parentName = displayItem.SeriesName || displayItem.Album; if (displayItem.EpisodeTitle || displayItem.IsSeries) { @@ -172,42 +127,6 @@ import 'css!assets/css/videoosd'; } setTitle(displayItem, parentName); - const titleElement = view.querySelector('.osdTitle'); - let displayName = itemHelper.getDisplayName(displayItem, { - includeParentInfo: displayItem.Type !== 'Program', - includeIndexNumber: displayItem.Type !== 'Program' - }); - - if (!displayName) { - displayName = displayItem.Type; - } - - titleElement.innerHTML = displayName; - - if (displayName) { - titleElement.classList.remove('hide'); - } else { - titleElement.classList.add('hide'); - } - - const mediaInfoHtml = mediaInfo.getPrimaryMediaInfoHtml(displayItem, { - runtime: false, - subtitles: false, - tomatoes: false, - endsAt: false, - episodeTitle: false, - originalAirDate: displayItem.Type !== 'Program', - episodeTitleIndexNumber: displayItem.Type !== 'Program', - programIndicator: false - }); - const osdMediaInfo = view.querySelector('.osdMediaInfo'); - osdMediaInfo.innerHTML = mediaInfoHtml; - - if (mediaInfoHtml) { - osdMediaInfo.classList.remove('hide'); - } else { - osdMediaInfo.classList.add('hide'); - } const secondaryMediaInfo = view.querySelector('.osdSecondaryMediaInfo'); const secondaryMediaInfoHtml = mediaInfo.getSecondaryMediaInfoHtml(displayItem, { @@ -222,12 +141,6 @@ import 'css!assets/css/videoosd'; secondaryMediaInfo.classList.add('hide'); } - if (displayName) { - view.querySelector('.osdMainTextContainer').classList.remove('hide'); - } else { - view.querySelector('.osdMainTextContainer').classList.add('hide'); - } - if (enableProgressByTimeOfDay) { setDisplayTime(startTimeText, displayItem.StartDate); setDisplayTime(endTimeText, displayItem.EndDate); @@ -277,7 +190,6 @@ import 'css!assets/css/videoosd'; currentItem = item; if (!item) { - setPoster(null); updateRecordingButton(null); Emby.Page.setTitle(''); nowPlayingVolumeSlider.disabled = true; @@ -314,7 +226,20 @@ import 'css!assets/css/videoosd'; } function setTitle(item, parentName) { - Emby.Page.setTitle(parentName || ''); + let itemName = itemHelper.getDisplayName(item, { + includeParentInfo: item.Type !== 'Program', + includeIndexNumber: item.Type !== 'Program' + }); + + if (itemName && parentName) { + itemName = `${parentName} - ${itemName}`; + } + + if (!itemName) { + itemName = parentName || ''; + } + + Emby.Page.setTitle(itemName); const documentTitle = parentName || (item ? item.Name : null); @@ -323,38 +248,6 @@ import 'css!assets/css/videoosd'; } } - function setPoster(item, secondaryItem) { - const osdPoster = view.querySelector('.osdPoster'); - - if (item) { - let imgUrl = seriesImageUrl(item, { - maxWidth: osdPoster.clientWidth, - type: 'Primary' - }) || seriesImageUrl(item, { - maxWidth: osdPoster.clientWidth, - type: 'Thumb' - }) || imageUrl(item, { - maxWidth: osdPoster.clientWidth, - type: 'Primary' - }); - - if (!imgUrl && secondaryItem && (imgUrl = seriesImageUrl(secondaryItem, { - maxWidth: osdPoster.clientWidth, - type: 'Primary' - }) || seriesImageUrl(secondaryItem, { - maxWidth: osdPoster.clientWidth, - type: 'Thumb' - }) || imageUrl(secondaryItem, { - maxWidth: osdPoster.clientWidth, - type: 'Primary' - })), imgUrl) { - return void (osdPoster.innerHTML = ''); - } - } - - osdPoster.innerHTML = ''; - } - let mouseIsDown = false; function showOsd() { From 3f592881583d18025f8475b58e3f2366a56225e4 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Thu, 20 Aug 2020 20:39:33 +0200 Subject: [PATCH 018/281] Improve Up Next dialog --- src/assets/css/videoosd.css | 51 +++++--------------- src/components/mediainfo/mediainfo.js | 12 ++--- src/components/upnextdialog/upnextdialog.css | 23 +++++++-- src/components/upnextdialog/upnextdialog.js | 13 +++-- 4 files changed, 44 insertions(+), 55 deletions(-) diff --git a/src/assets/css/videoosd.css b/src/assets/css/videoosd.css index 7273121f53..9995a7ff84 100644 --- a/src/assets/css/videoosd.css +++ b/src/assets/css/videoosd.css @@ -6,18 +6,29 @@ -ms-user-select: none; } -.osdPoster img, .videoOsdBottom { bottom: 0; left: 0; right: 0; + position: fixed; + background: linear-gradient(0deg, rgba(16, 16, 16, 0.6) 0%, rgba(16, 16, 16, 0) 100%); + padding-top: 7.5em; + padding-bottom: 1.75em; + display: flex; + flex-direction: row; + justify-content: center; + will-change: opacity; + transition: opacity 0.3s ease-out; + color: #fff; + user-select: none; + -webkit-touch-callout: none; } .osdHeader { transition: opacity 0.3s ease-out; position: relative; z-index: 1; - background: linear-gradient(180deg, rgba(16, 16 16, 0.75) 0%, rgba(16, 16, 16, 0.15) 80%, rgba(16, 16, 16, 0) 100%); + background: linear-gradient(180deg, rgba(16, 16, 16, 0.6) 0%, rgba(16, 16, 16, 0) 100%); backdrop-filter: none; color: #eee; height: 7.5em; @@ -88,21 +99,6 @@ opacity: 0.6; } -.videoOsdBottom { - position: fixed; - background: linear-gradient(0deg, rgba(16, 16, 16, 0.75) 0%, rgba(16, 16, 16, 0.15) 80%, rgba(16, 16, 16, 0) 100%); - padding-top: 10em; - padding-bottom: 1.75em; - display: flex; - flex-direction: row; - justify-content: center; - will-change: opacity; - transition: opacity 0.3s ease-out; - color: #fff; - user-select: none; - -webkit-touch-callout: none; -} - .videoOsdBottom-hidden { opacity: 0; } @@ -157,27 +153,6 @@ user-select: none; } -.osdPoster { - width: 10%; - position: relative; - margin-right: 0.5em; -} - -.osdPoster img { - position: absolute; - height: auto; - width: 100%; - -webkit-box-shadow: 0 0 1.9vh #000; - box-shadow: 0 0 1.9vh #000; - border: 0.08em solid #222; - user-drag: none; - user-select: none; - -moz-user-select: none; - -webkit-user-drag: none; - -webkit-user-select: none; - -ms-user-select: none; -} - .osdTitle, .osdTitleSmall { margin: 0 1em 0 0; diff --git a/src/components/mediainfo/mediainfo.js b/src/components/mediainfo/mediainfo.js index 1d78d490a2..d5da29d3bc 100644 --- a/src/components/mediainfo/mediainfo.js +++ b/src/components/mediainfo/mediainfo.js @@ -100,11 +100,10 @@ import 'emby-button'; return html; } - export function getMediaInfoHtml(item, options) { + export function getMediaInfoHtml(item, options = {}) { let html = ''; const miscInfo = []; - options = options || {}; let text; let date; let minutes; @@ -289,7 +288,9 @@ import 'emby-button'; return getMediaInfoItem(m); }).join(''); - html += getStarIconsHtml(item); + if (options.starRating !== false) { + html += getStarIconsHtml(item); + } if (item.HasSubtitles && options.subtitles !== false) { html += '
    CC
    '; @@ -418,9 +419,8 @@ import 'emby-button'; return false; } - export function getPrimaryMediaInfoHtml(item, options) { - options = options || {}; - if (options.interactive == null) { + export function getPrimaryMediaInfoHtml(item, options = {}) { + if (options.interactive === undefined) { options.interactive = false; } diff --git a/src/components/upnextdialog/upnextdialog.css b/src/components/upnextdialog/upnextdialog.css index 067804919f..754fd418ca 100644 --- a/src/components/upnextdialog/upnextdialog.css +++ b/src/components/upnextdialog/upnextdialog.css @@ -1,9 +1,24 @@ -.upNextDialog { - width: 30vw; +.upNextContainer { + box-sizing: border-box; position: fixed; - left: auto; + top: 0; bottom: 0; - right: 0; + left: 50%; + transform: translateX(-50%); + padding: 1em; + display: flex; + flex-grow: 1; + width: calc(100vh * (16 / 9)); + height: 100vh; + justify-content: end; + align-items: flex-end; +} + +.upNextDialog-container { + border-radius: 5px; + width: 30em; + height: 11em; + left: auto; padding: 1%; display: flex; flex-direction: column; diff --git a/src/components/upnextdialog/upnextdialog.js b/src/components/upnextdialog/upnextdialog.js index c665d81173..8d3202cc1c 100644 --- a/src/components/upnextdialog/upnextdialog.js +++ b/src/components/upnextdialog/upnextdialog.js @@ -17,9 +17,7 @@ import 'flexStyles'; function getHtml() { let html = ''; - html += '
    '; - html += '
    '; - + html += '
    '; html += '
    '; html += '

     

    '; @@ -29,8 +27,6 @@ import 'flexStyles'; html += '
    '; html += '
    '; - html += '
    '; - html += '
    '; html += '
    '; + html += '
    '; return html; } @@ -73,9 +70,11 @@ import 'flexStyles'; const elem = instance.options.parent; - elem.querySelector('.upNextDialog-overview').innerHTML = item.Overview || ''; - elem.querySelector('.upNextDialog-mediainfo').innerHTML = mediaInfo.getPrimaryMediaInfoHtml(item, { + criticRating: false, + originalAirDate: false, + starRating: false, + subtitles: false }); let title = itemHelper.getDisplayName(item); From e38fa15e4d40d1ccc6e51e10bb6052502317adea Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sat, 22 Aug 2020 02:38:06 +0200 Subject: [PATCH 019/281] Constrain width only on desktop --- src/assets/css/videoosd.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/assets/css/videoosd.css b/src/assets/css/videoosd.css index 9995a7ff84..a23a4cf8ee 100644 --- a/src/assets/css/videoosd.css +++ b/src/assets/css/videoosd.css @@ -105,10 +105,13 @@ .osdControls { flex-grow: 1; - max-width: calc(100vh * 1.77); padding: 0 0.8em; } +.layout-desktop .osdControls { + max-width: calc(100vh * 1.77 - 2vh); +} + .videoOsdBottom .buttons { padding: 0.25em 0 0; display: -webkit-box; From 1812df57ad9a45c40b24378f5bc35953bceead40 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sat, 22 Aug 2020 14:07:54 +0200 Subject: [PATCH 020/281] Fix up next dialog on Chrome --- src/components/upnextdialog/upnextdialog.css | 67 ++++---------------- src/components/upnextdialog/upnextdialog.js | 2 - 2 files changed, 11 insertions(+), 58 deletions(-) diff --git a/src/components/upnextdialog/upnextdialog.css b/src/components/upnextdialog/upnextdialog.css index 754fd418ca..efb0366488 100644 --- a/src/components/upnextdialog/upnextdialog.css +++ b/src/components/upnextdialog/upnextdialog.css @@ -1,25 +1,10 @@ .upNextContainer { - box-sizing: border-box; position: fixed; - top: 0; + right: 0; bottom: 0; - left: 50%; - transform: translateX(-50%); - padding: 1em; - display: flex; - flex-grow: 1; - width: calc(100vh * (16 / 9)); - height: 100vh; - justify-content: end; - align-items: flex-end; -} - -.upNextDialog-container { - border-radius: 5px; width: 30em; - height: 11em; - left: auto; - padding: 1%; + padding: 1em; + margin: 0 2em 2em 0; display: flex; flex-direction: column; will-change: transform, opacity; @@ -38,18 +23,18 @@ font-weight: 500; } -.upNextDialog-poster { - display: none; - max-width: 40%; - max-height: 15%; - position: relative; - margin-right: 1em; - flex-shrink: 0; - margin-bottom: 0.5em; +.upNextDialog-nextVideoText, +.upNextDialog-title { + width: 25.5em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .upNextDialog-buttons { + width: 29.75em; justify-content: end; + align-content: flex-end; } .upNextDialog-button { @@ -61,34 +46,4 @@ .upNextDialog { flex-direction: row; } - - .upNextDialog-poster { - max-width: initial; - max-height: initial; - width: 30%; - margin-bottom: 0; - } -} - -@media all and (max-width: 50em) { - .upNextDialog-overview { - display: none !important; - } -} - -.upNextDialog-poster-img { - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: auto; - width: 100%; - box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37); - user-drag: none; - border: 0; - user-select: none; - -moz-user-select: none; - -webkit-user-drag: none; - -webkit-user-select: none; - -ms-user-select: none; } diff --git a/src/components/upnextdialog/upnextdialog.js b/src/components/upnextdialog/upnextdialog.js index 8d3202cc1c..1d55556710 100644 --- a/src/components/upnextdialog/upnextdialog.js +++ b/src/components/upnextdialog/upnextdialog.js @@ -17,7 +17,6 @@ import 'flexStyles'; function getHtml() { let html = ''; - html += '
    '; html += '
    '; html += '

     

    '; @@ -42,7 +41,6 @@ import 'flexStyles'; // main html += '
    '; - html += '
    '; return html; } From 02015aaa9c60e727242c34363a7130d2c069a831 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sat, 29 Aug 2020 18:32:42 +0200 Subject: [PATCH 021/281] Adjust OSD color for WCAG compliance --- src/assets/css/videoosd.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/assets/css/videoosd.css b/src/assets/css/videoosd.css index a23a4cf8ee..f0792c2c45 100644 --- a/src/assets/css/videoosd.css +++ b/src/assets/css/videoosd.css @@ -11,7 +11,7 @@ left: 0; right: 0; position: fixed; - background: linear-gradient(0deg, rgba(16, 16, 16, 0.6) 0%, rgba(16, 16, 16, 0) 100%); + background: linear-gradient(0deg, rgba(16, 16, 16, 0.75) 0%, rgba(16, 16, 16, 0) 100%); padding-top: 7.5em; padding-bottom: 1.75em; display: flex; @@ -28,7 +28,7 @@ transition: opacity 0.3s ease-out; position: relative; z-index: 1; - background: linear-gradient(180deg, rgba(16, 16, 16, 0.6) 0%, rgba(16, 16, 16, 0) 100%); + background: linear-gradient(180deg, rgba(16, 16, 16, 0.75) 0%, rgba(16, 16, 16, 0) 100%); backdrop-filter: none; color: #eee; height: 7.5em; From 0db000e5b51b1a66cb7b6150879314b8e3d2918e Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sun, 30 Aug 2020 13:47:37 +0200 Subject: [PATCH 022/281] Fix CSS selector for top OSD header --- src/assets/css/videoosd.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/css/videoosd.css b/src/assets/css/videoosd.css index f0792c2c45..b2446d5d48 100644 --- a/src/assets/css/videoosd.css +++ b/src/assets/css/videoosd.css @@ -24,7 +24,7 @@ -webkit-touch-callout: none; } -.osdHeader { +.skinHeader-withBackground.osdHeader { transition: opacity 0.3s ease-out; position: relative; z-index: 1; From 8900da42d8f08b1700e04e3296203c49f2dd7aac Mon Sep 17 00:00:00 2001 From: Cameron Date: Tue, 1 Sep 2020 10:07:06 +0100 Subject: [PATCH 023/281] Hide Alphapicker when not sorting alphabetically (movies --- src/controllers/movies/movies.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/controllers/movies/movies.js b/src/controllers/movies/movies.js index 91b428ec68..d48812cb94 100644 --- a/src/controllers/movies/movies.js +++ b/src/controllers/movies/movies.js @@ -26,6 +26,11 @@ import 'emby-itemscontainer'; const updateFilterControls = () => { if (this.alphaPicker) { this.alphaPicker.value(query.NameStartsWithOrGreater); + if (query.SortBy.indexOf('SortName') === 0) { + this.alphaPicker.visible(true); + } else { + this.alphaPicker.visible(false); + } } }; From 477ecfdc9fd8fe2185a8aab9e7c0b06152f8887e Mon Sep 17 00:00:00 2001 From: Cameron Date: Tue, 1 Sep 2020 10:09:22 +0100 Subject: [PATCH 024/281] Hide Alphapicker when not sorting alphabetically (TV) --- src/controllers/shows/tvshows.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/controllers/shows/tvshows.js b/src/controllers/shows/tvshows.js index 281c921e48..31ef72621d 100644 --- a/src/controllers/shows/tvshows.js +++ b/src/controllers/shows/tvshows.js @@ -198,7 +198,16 @@ import 'emby-itemscontainer'; function updateFilterControls(tabContent) { const query = getQuery(tabContent); - self.alphaPicker.value(query.NameStartsWithOrGreater); + + if (self.alphaPicker) { + self.alphaPicker.value(query.NameStartsWithOrGreater); + + if (query.SortBy.indexOf('SortName') === 0) { + self.alphaPicker.visible(true); + } else { + self.alphaPicker.visible(false); + } + } } const self = this; From d8cb6068940d56034a92314754d2b3fdb0d08cef Mon Sep 17 00:00:00 2001 From: Cameron Date: Tue, 1 Sep 2020 10:09:28 +0100 Subject: [PATCH 025/281] Hide Alphapicker when not sorting alphabetically (Music) --- src/controllers/music/musicalbums.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/controllers/music/musicalbums.js b/src/controllers/music/musicalbums.js index 7ea8fa254a..5bb8546e76 100644 --- a/src/controllers/music/musicalbums.js +++ b/src/controllers/music/musicalbums.js @@ -186,7 +186,16 @@ import 'emby-itemscontainer'; const updateFilterControls = (tabContent) => { const query = getQuery(); - this.alphaPicker.value(query.NameStartsWithOrGreater); + + if (this.alphaPicker) { + this.alphaPicker.value(query.NameStartsWithOrGreater); + + if (query.SortBy.indexOf('SortName') === 0) { + this.alphaPicker.visible(true); + } else { + this.alphaPicker.visible(false); + } + } }; let savedQueryKey; From ab7fafa891b5c26ec758424a91c594fed7e03efb Mon Sep 17 00:00:00 2001 From: Cameron Date: Tue, 1 Sep 2020 10:12:10 +0100 Subject: [PATCH 026/281] Remove ailiasing this --- src/controllers/shows/tvshows.js | 47 ++++++++++++++++---------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/controllers/shows/tvshows.js b/src/controllers/shows/tvshows.js index 31ef72621d..17407e4c5d 100644 --- a/src/controllers/shows/tvshows.js +++ b/src/controllers/shows/tvshows.js @@ -54,8 +54,8 @@ import 'emby-itemscontainer'; return context.savedQueryKey; } - function onViewStyleChange() { - const viewStyle = self.getCurrentViewStyle(); + const onViewStyleChange = () => { + const viewStyle = this.getCurrentViewStyle(); const itemsContainer = tabContent.querySelector('.itemsContainer'); if (viewStyle == 'List') { @@ -67,13 +67,13 @@ import 'emby-itemscontainer'; } itemsContainer.innerHTML = ''; - } + }; - function reloadItems(page) { + const reloadItems = (page) => { loading.show(); isLoading = true; const query = getQuery(page); - ApiClient.getItems(ApiClient.getCurrentUserId(), query).then(function (result) { + ApiClient.getItems(ApiClient.getCurrentUserId(), query).then((result) => { function onNextPageClick() { if (isLoading) { return; @@ -109,7 +109,7 @@ import 'emby-itemscontainer'; sortButton: false, filterButton: false }); - const viewStyle = self.getCurrentViewStyle(); + const viewStyle = this.getCurrentViewStyle(); if (viewStyle == 'Thumb') { html = cardBuilder.getCardsHtml({ items: result.Items, @@ -196,25 +196,24 @@ import 'emby-itemscontainer'; }); } - function updateFilterControls(tabContent) { + const updateFilterControls = (tabContent) => { const query = getQuery(tabContent); - if (self.alphaPicker) { - self.alphaPicker.value(query.NameStartsWithOrGreater); + if (this.alphaPicker) { + this.alphaPicker.value(query.NameStartsWithOrGreater); if (query.SortBy.indexOf('SortName') === 0) { - self.alphaPicker.visible(true); + this.alphaPicker.visible(true); } else { - self.alphaPicker.visible(false); + this.alphaPicker.visible(false); } } - } + }; - const self = this; const data = {}; let isLoading = false; - self.showFilterMenu = function () { + this.showFilterMenu = function () { import('components/filterdialog/filterdialog').then(({default: filterDialogFactory}) => { const filterDialog = new filterDialogFactory({ query: getQuery(tabContent), @@ -229,11 +228,11 @@ import 'emby-itemscontainer'; }); }; - self.getCurrentViewStyle = function () { + this.getCurrentViewStyle = function () { return getPageData(tabContent).view; }; - function initPage(tabContent) { + const initPage = (tabContent) => { const alphaPickerElement = tabContent.querySelector('.alphaPicker'); const itemsContainer = tabContent.querySelector('.itemsContainer'); @@ -244,7 +243,7 @@ import 'emby-itemscontainer'; query.StartIndex = 0; reloadItems(tabContent); }); - self.alphaPicker = new AlphaPicker({ + this.alphaPicker = new AlphaPicker({ element: alphaPickerElement, valueChangeEvent: 'click' }); @@ -253,8 +252,8 @@ import 'emby-itemscontainer'; alphaPickerElement.classList.add('alphaPicker-fixed-right'); itemsContainer.classList.add('padded-right-withalphapicker'); - tabContent.querySelector('.btnFilter').addEventListener('click', function () { - self.showFilterMenu(); + tabContent.querySelector('.btnFilter').addEventListener('click', () => { + this.showFilterMenu(); }); tabContent.querySelector('.btnSort').addEventListener('click', function (e) { libraryBrowser.showSortMenu({ @@ -286,8 +285,8 @@ import 'emby-itemscontainer'; }); }); const btnSelectView = tabContent.querySelector('.btnSelectView'); - btnSelectView.addEventListener('click', function (e) { - libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), 'Banner,List,Poster,PosterCard,Thumb,ThumbCard'.split(',')); + btnSelectView.addEventListener('click', (e) => { + libraryBrowser.showLayoutMenu(e.target, this.getCurrentViewStyle(), 'Banner,List,Poster,PosterCard,Thumb,ThumbCard'.split(',')); }); btnSelectView.addEventListener('layoutchange', function (e) { const viewStyle = e.detail.viewStyle; @@ -297,17 +296,17 @@ import 'emby-itemscontainer'; onViewStyleChange(); reloadItems(tabContent); }); - } + }; initPage(tabContent); onViewStyleChange(); - self.renderTab = function () { + this.renderTab = function () { reloadItems(tabContent); updateFilterControls(tabContent); }; - self.destroy = function () {}; + this.destroy = function () {}; } /* eslint-enable indent */ From 840ef01a1303582584b914a31c650822fe57c6b5 Mon Sep 17 00:00:00 2001 From: Cameron Date: Tue, 1 Sep 2020 10:13:15 +0100 Subject: [PATCH 027/281] Replace loops for for..of --- src/controllers/shows/tvshows.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/controllers/shows/tvshows.js b/src/controllers/shows/tvshows.js index 17407e4c5d..7d76c78faa 100644 --- a/src/controllers/shows/tvshows.js +++ b/src/controllers/shows/tvshows.js @@ -169,18 +169,18 @@ import 'emby-itemscontainer'; let elems = tabContent.querySelectorAll('.paging'); - for (let i = 0, length = elems.length; i < length; i++) { - elems[i].innerHTML = pagingHtml; + for (const elem of elems) { + elem.innerHTML = pagingHtml; } elems = tabContent.querySelectorAll('.btnNextPage'); - for (let i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener('click', onNextPageClick); + for (const elem of elems) { + elem.addEventListener('click', onNextPageClick); } elems = tabContent.querySelectorAll('.btnPreviousPage'); - for (let i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener('click', onPreviousPageClick); + for (const elem of elems) { + elem.addEventListener('click', onPreviousPageClick); } const itemsContainer = tabContent.querySelector('.itemsContainer'); @@ -194,7 +194,7 @@ import 'emby-itemscontainer'; autoFocuser.autoFocus(page); }); }); - } + }; const updateFilterControls = (tabContent) => { const query = getQuery(tabContent); From 4968f71858834e0ad29f9ad446698d0faa2e808d Mon Sep 17 00:00:00 2001 From: Cameron Date: Tue, 1 Sep 2020 10:14:14 +0100 Subject: [PATCH 028/281] Replace loops for for..of --- src/controllers/music/musicalbums.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/controllers/music/musicalbums.js b/src/controllers/music/musicalbums.js index 5bb8546e76..5ecb553024 100644 --- a/src/controllers/music/musicalbums.js +++ b/src/controllers/music/musicalbums.js @@ -155,20 +155,21 @@ import 'emby-itemscontainer'; overlayPlayButton: true }); } + let elems = tabContent.querySelectorAll('.paging'); - for (let i = 0, length = elems.length; i < length; i++) { - elems[i].innerHTML = pagingHtml; + for (const elem of elems) { + elem.innerHTML = pagingHtml; } elems = tabContent.querySelectorAll('.btnNextPage'); - for (let i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener('click', onNextPageClick); + for (const elem of elems) { + elem.addEventListener('click', onNextPageClick); } elems = tabContent.querySelectorAll('.btnPreviousPage'); - for (let i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener('click', onPreviousPageClick); + for (const elem of elems) { + elem.addEventListener('click', onPreviousPageClick); } const itemsContainer = tabContent.querySelector('.itemsContainer'); @@ -209,10 +210,12 @@ import 'emby-itemscontainer'; mode: 'albums', serverId: ApiClient.serverId() }); + events.on(filterDialog, 'filterchange', function () { getQuery().StartIndex = 0; reloadItems(tabContent); }); + filterDialog.show(); }); }; @@ -232,6 +235,7 @@ import 'emby-itemscontainer'; query.StartIndex = 0; reloadItems(tabContent); }); + this.alphaPicker = new AlphaPicker({ element: alphaPickerElement, valueChangeEvent: 'click' @@ -244,6 +248,7 @@ import 'emby-itemscontainer'; tabContent.querySelector('.btnFilter').addEventListener('click', () => { this.showFilterMenu(); }); + tabContent.querySelector('.btnSort').addEventListener('click', (e) => { libraryBrowser.showSortMenu({ items: [{ @@ -276,10 +281,12 @@ import 'emby-itemscontainer'; button: e.target }); }); + const btnSelectView = tabContent.querySelector('.btnSelectView'); btnSelectView.addEventListener('click', (e) => { libraryBrowser.showLayoutMenu(e.target, this.getCurrentViewStyle(), 'List,Poster,PosterCard'.split(',')); }); + btnSelectView.addEventListener('layoutchange', function (e) { const viewStyle = e.detail.viewStyle; getPageData().view = viewStyle; @@ -288,6 +295,7 @@ import 'emby-itemscontainer'; onViewStyleChange(); reloadItems(tabContent); }); + tabContent.querySelector('.btnPlayAll').addEventListener('click', playAll); tabContent.querySelector('.btnShuffle').addEventListener('click', shuffle); }; From f7d0b9491619262a8e420552872d16a6a5b9ca49 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Tue, 1 Sep 2020 13:32:12 +0300 Subject: [PATCH 029/281] Babel libarchive --- webpack.dev.js | 2 +- webpack.prod.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webpack.dev.js b/webpack.dev.js index 3d0c2a48a0..33e171daa8 100644 --- a/webpack.dev.js +++ b/webpack.dev.js @@ -15,7 +15,7 @@ module.exports = merge(common, { rules: [ { test: /\.js$/, - exclude: /node_modules[\\/](?!date-fns|epubjs|jellyfin-apiclient|query-string|split-on-first|strict-uri-encode|xmldom)/, + exclude: /node_modules[\\/](?!date-fns|epubjs|libarchive|jellyfin-apiclient|query-string|split-on-first|strict-uri-encode|xmldom)/, use: { loader: 'babel-loader', options: { diff --git a/webpack.prod.js b/webpack.prod.js index 52d6d0a865..408eb4bb59 100644 --- a/webpack.prod.js +++ b/webpack.prod.js @@ -8,7 +8,7 @@ module.exports = merge(common, { rules: [ { test: /\.js$/, - exclude: /node_modules[\\/](?!date-fns|epubjs|jellyfin-apiclient|query-string|split-on-first|strict-uri-encode|xmldom)/, + exclude: /node_modules[\\/](?!date-fns|epubjs|libarchive|jellyfin-apiclient|query-string|split-on-first|strict-uri-encode|xmldom)/, use: { loader: 'babel-loader', options: { From eccaad366e6150c7dfa2010275714ee8dba8aa07 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Tue, 1 Sep 2020 23:52:27 +0300 Subject: [PATCH 030/281] Add timeout for polyfilled CustomElements (webOS 1.2) --- src/components/viewContainer.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/viewContainer.js b/src/components/viewContainer.js index 9d64130cdb..6be8cfd19b 100644 --- a/src/components/viewContainer.js +++ b/src/components/viewContainer.js @@ -82,7 +82,8 @@ import 'css!components/viewManager/viewContainer'; } allPages[pageIndex] = view; - setControllerClass(view, options).then(() => { + // Timeout for polyfilled CustomElements (webOS 1.2) + setControllerClass(view, options).then(() => new Promise((resolve) => setTimeout(resolve, 0))).then(() => { if (onBeforeChange) { onBeforeChange(view, false, options); } From 748592fa9310732bff082466a3308a51f24740bb Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Wed, 2 Sep 2020 01:06:07 +0300 Subject: [PATCH 031/281] Remove nested Promise --- src/components/viewContainer.js | 75 +++++++++++++++++---------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/src/components/viewContainer.js b/src/components/viewContainer.js index 6be8cfd19b..bbec0c0e65 100644 --- a/src/components/viewContainer.js +++ b/src/components/viewContainer.js @@ -36,54 +36,56 @@ import 'css!components/viewManager/viewContainer'; const newViewInfo = normalizeNewView(options, isPluginpage); const newView = newViewInfo.elem; - return new Promise((resolve) => { - const currentPage = allPages[pageIndex]; + const currentPage = allPages[pageIndex]; - if (currentPage) { - triggerDestroy(currentPage); - } + if (currentPage) { + triggerDestroy(currentPage); + } - let view = newView; + let view = newView; - if (typeof view == 'string') { - view = document.createElement('div'); - view.innerHTML = newView; - } + if (typeof view == 'string') { + view = document.createElement('div'); + view.innerHTML = newView; + } - view.classList.add('mainAnimatedPage'); + view.classList.add('mainAnimatedPage'); - if (currentPage) { - if (newViewInfo.hasScript && window.$) { - mainAnimatedPages.removeChild(currentPage); - view = $(view).appendTo(mainAnimatedPages)[0]; - } else { - mainAnimatedPages.replaceChild(view, currentPage); - } + if (currentPage) { + if (newViewInfo.hasScript && window.$) { + mainAnimatedPages.removeChild(currentPage); + view = $(view).appendTo(mainAnimatedPages)[0]; } else { - if (newViewInfo.hasScript && window.$) { - view = $(view).appendTo(mainAnimatedPages)[0]; - } else { - mainAnimatedPages.appendChild(view); - } + mainAnimatedPages.replaceChild(view, currentPage); } - - if (options.type) { - view.setAttribute('data-type', options.type); + } else { + if (newViewInfo.hasScript && window.$) { + view = $(view).appendTo(mainAnimatedPages)[0]; + } else { + mainAnimatedPages.appendChild(view); } + } - const properties = []; + if (options.type) { + view.setAttribute('data-type', options.type); + } - if (options.fullscreen) { - properties.push('fullscreen'); - } + const properties = []; - if (properties.length) { - view.setAttribute('data-properties', properties.join(',')); - } + if (options.fullscreen) { + properties.push('fullscreen'); + } - allPages[pageIndex] = view; + if (properties.length) { + view.setAttribute('data-properties', properties.join(',')); + } + + allPages[pageIndex] = view; + + return setControllerClass(view, options) // Timeout for polyfilled CustomElements (webOS 1.2) - setControllerClass(view, options).then(() => new Promise((resolve) => setTimeout(resolve, 0))).then(() => { + .then(() => new Promise((resolve) => setTimeout(resolve, 0))) + .then(() => { if (onBeforeChange) { onBeforeChange(view, false, options); } @@ -101,9 +103,8 @@ import 'css!components/viewManager/viewContainer'; $.mobile.activePage = view; } - resolve(view); + return view; }); - }); } } From 6553cea696995f565cea607edfd03e465d70c8bc Mon Sep 17 00:00:00 2001 From: "Brian J. Murrell" Date: Thu, 3 Sep 2020 10:33:59 -0400 Subject: [PATCH 032/281] Add BR: git for all distros Seems the Fedora yarn package also doesn't Requires: git so add it as a BuildRequires:. Signed-off-by: Brian J. Murrell --- fedora/jellyfin-web.spec | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fedora/jellyfin-web.spec b/fedora/jellyfin-web.spec index 1d85e5ae6b..d4af00d36b 100644 --- a/fedora/jellyfin-web.spec +++ b/fedora/jellyfin-web.spec @@ -2,7 +2,7 @@ Name: jellyfin-web Version: 10.7.0 -Release: 1%{?dist} +Release: 2%{?dist} Summary: The Free Software Media System web client License: GPLv3 URL: https://jellyfin.org @@ -11,11 +11,12 @@ Source0: jellyfin-web-%{version}.tar.gz %if 0%{?centos} BuildRequires: yarn -# sadly the yarn RPM at https://dl.yarnpkg.com/rpm/ uses git but doesn't Requires: it -BuildRequires: git %else BuildRequires: nodejs-yarn %endif +# sadly the yarn RPM at https://dl.yarnpkg.com/rpm/ uses git but doesn't Requires: it +# ditto for Fedora's yarn RPM +BuildRequires: git BuildArch: noarch # Disable Automatic Dependency Processing From 28928ead7cfb101f7b8d55fd21361e0bcfb0fa44 Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Thu, 3 Sep 2020 16:19:35 -0500 Subject: [PATCH 033/281] Modified to work with latest server code --- .../quickConnectSettings.js | 39 ++------ src/controllers/dashboard/quickconnect.js | 5 +- src/controllers/session/login/index.js | 93 ++++++++----------- src/controllers/user/quickConnect/index.js | 2 - src/strings/en-us.json | 1 + 5 files changed, 51 insertions(+), 89 deletions(-) diff --git a/src/components/quickConnectSettings/quickConnectSettings.js b/src/components/quickConnectSettings/quickConnectSettings.js index 35f051a121..a62cfc2298 100644 --- a/src/components/quickConnectSettings/quickConnectSettings.js +++ b/src/components/quickConnectSettings/quickConnectSettings.js @@ -5,21 +5,14 @@ export class QuickConnectSettings { constructor() { } authorize(code) { - let url = ApiClient.getUrl('/QuickConnect/Authorize'); + let url = ApiClient.getUrl('/QuickConnect/Authorize?Code=' + code); ApiClient.ajax({ type: 'POST', - url: url, - data: { - 'Code': code - } + url: url }, true).then(() => { - require(['toast'], function (toast) { - toast(globalize.translate('QuickConnectAuthorizeSuccess')); - }); + toast(globalize.translate('QuickConnectAuthorizeSuccess')); }).catch(() => { - require(['toast'], function (toast) { - toast(globalize.translate('QuickConnectAuthorizeFail')); - }); + toast(globalize.translate('QuickConnectAuthorizeFail')); }); // prevent bubbling @@ -30,28 +23,16 @@ export class QuickConnectSettings { let url = ApiClient.getUrl('/QuickConnect/Activate'); return ApiClient.ajax({ type: 'POST', - url: url, - contentType: 'application/json', - dataType: 'json' - }).then((json) => { - let message = json.Error; - - if (message && message !== '') { - console.error('Error activating quick connect. Error: ', json.Error); - - Dashboard.alert({ - title: 'Unable to activate quick connect', - message: message - }); - - return false; - } - + url: url + }).then(() => { toast(globalize.translate('QuickConnectActivationSuccessful')); - return true; }).catch((e) => { console.error('Error activating quick connect. Error:', e); + Dashboard.alert({ + title: globalize.translate('HeaderError'), + message: globalize.translate('DefaultErrorMessage') + }); throw e; }); } diff --git a/src/controllers/dashboard/quickconnect.js b/src/controllers/dashboard/quickconnect.js index 22f4781b7d..9d08bb6b48 100644 --- a/src/controllers/dashboard/quickconnect.js +++ b/src/controllers/dashboard/quickconnect.js @@ -26,13 +26,10 @@ import loading from 'loading'; let newStatus = page.querySelector('#chkQuickConnectAvailable').checked ? 'Available' : 'Unavailable'; - let url = ApiClient.getUrl('/QuickConnect/Available'); + let url = ApiClient.getUrl('/QuickConnect/Available?Status=' + newStatus); ApiClient.ajax({ type: 'POST', - data: { - 'Status': newStatus - }, url: url }, true).then(() => { require(['toast'], function (toast) { diff --git a/src/controllers/session/login/index.js b/src/controllers/session/login/index.js index d0446de099..aa5c8cc2d2 100644 --- a/src/controllers/session/login/index.js +++ b/src/controllers/session/login/index.js @@ -154,71 +154,56 @@ import 'emby-checkbox'; }); } + // FIXME: Clicking ok on the code dialog redirects back to the homepage. function loginQuickConnect() { let apiClient = getApiClient(); - let friendlyName = navigator.userAgent; - let url = apiClient.getUrl('/QuickConnect/Initiate?FriendlyName=' + friendlyName); - apiClient.getJSON(url) - .then(json => { - if (!json.Secret || !json.Code) { - console.error('Malformed quick connect response', json); - return false; - } + let url = apiClient.getUrl('/QuickConnect/Initiate'); + apiClient.getJSON(url).then(function (json) { + if (!json.Secret || !json.Code) { + console.error('Malformed quick connect response', json); + return false; + } - Dashboard.alert({ - message: Globalize.translate('QuickConnectAuthorizeCode', json.Code), - title: Globalize.translate('QuickConnect') - }); + Dashboard.alert({ + message: globalize.translate('QuickConnectAuthorizeCode', json.Code), + title: globalize.translate('QuickConnect') + }); - loading.show(); - - let interval = setInterval(async function() { - try { - let connectUrl = apiClient.getUrl('/QuickConnect/Connect?Secret=' + json.Secret); - let data = await apiClient.getJSON(connectUrl); - if (data.Authenticated) { - let result = await apiClient.quickConnect(data.Authentication); - let user = result.User; - let serverId = getParameterByName('serverid'); - let newUrl = 'home.html'; - - if (user.Policy.IsAdministrator && !serverId) { - newUrl = 'dashboard.html'; - } - - loading.hide(); - Dashboard.onServerChanged(user.Id, result.AccessToken, apiClient); - Dashboard.navigate(newUrl); - clearInterval(interval); - - return true; - } - } catch (e) { - Dashboard.alert({ - message: 'Quick connect was deactivated before the login request could be approved', - title: 'Unexpected error' - }); - - console.error('Unable to login with quick connect', e); - clearInterval(interval); - loading.hide(); + let interval = setInterval(function() { + let connectUrl = apiClient.getUrl('/QuickConnect/Connect?Secret=' + json.Secret); + apiClient.getJSON(connectUrl).then(async function(data) { + if (!data.Authenticated) { + return; } - return false; - }, 5000); + clearInterval(interval); - return true; - }).catch((e) => { - Dashboard.alert({ - message: Globalize.translate('QuickConnectNotActive'), - title: 'Error' + let result = await apiClient.quickConnect(data.Authentication); + Dashboard.onServerChanged(result.User.Id, result.AccessToken, apiClient); + Dashboard.navigate('home.html'); + }, function (e) { + clearInterval(interval); + + Dashboard.alert({ + message: globalize.translate('QuickConnectDeactivated'), + title: globalize.translate('HeaderError') + }); + + console.error('Unable to login with quick connect', e); }); + }, 5000); - console.error('Quick connect error: ', e); - - return false; + return true; + }, function(e) { + Dashboard.alert({ + message: globalize.translate('QuickConnectNotActive'), + title: globalize.translate('HeaderError') }); + + console.error('Quick connect error: ', e); + return false; + }); } view.querySelector('#divUsers').addEventListener('click', function (e) { diff --git a/src/controllers/user/quickConnect/index.js b/src/controllers/user/quickConnect/index.js index 80543a0b58..2d6f4b15c8 100644 --- a/src/controllers/user/quickConnect/index.js +++ b/src/controllers/user/quickConnect/index.js @@ -73,6 +73,4 @@ export default function (view) { throw e; }); } - - renderPage(); } diff --git a/src/strings/en-us.json b/src/strings/en-us.json index b46020794e..b4442ee0f9 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -1156,6 +1156,7 @@ "QuickConnectAuthorizeCode": "Authorize request {0} to continue", "QuickConnectAuthorizeSuccess": "Request authorized", "QuickConnectAuthorizeFail": "Unknown quick connect code", + "QuickConnectDeactivated": "Quick connect was deactivated before the login request could be approved", "QuickConnectDescription": "To sign in with quick connect, select the Quick Connect button on the device you are logging in from and enter the displayed code below.", "QuickConnectInvalidCode": "Invalid quick connect code", "QuickConnectNotAvailable": "Ask your server administrator to enable quick connect", From 723472aca58a0cc4a4cfbbcbaea8267e83341c48 Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Thu, 3 Sep 2020 16:51:15 -0500 Subject: [PATCH 034/281] Complete modifications to work with latest server code --- src/controllers/dashboard/quickconnect.js | 7 +- src/controllers/session/login/index.js | 115 ++++++++++--------- src/controllers/user/quickConnect/index.html | 2 +- src/controllers/user/quickConnect/index.js | 20 +--- src/quickconnect.html | 2 +- src/strings/en-us.json | 2 +- 6 files changed, 71 insertions(+), 77 deletions(-) diff --git a/src/controllers/dashboard/quickconnect.js b/src/controllers/dashboard/quickconnect.js index 9d08bb6b48..012f7b7aa3 100644 --- a/src/controllers/dashboard/quickconnect.js +++ b/src/controllers/dashboard/quickconnect.js @@ -1,4 +1,6 @@ import loading from 'loading'; +import toast from 'toast'; +import globalize from 'globalize'; /* eslint-disable indent */ @@ -32,10 +34,7 @@ import loading from 'loading'; type: 'POST', url: url }, true).then(() => { - require(['toast'], function (toast) { - toast('Settings saved'); - }); - + toast(globalize.translate('SettingsSaved')); setTimeout(updatePage, 500); return true; diff --git a/src/controllers/session/login/index.js b/src/controllers/session/login/index.js index aa5c8cc2d2..c49ed0aee6 100644 --- a/src/controllers/session/login/index.js +++ b/src/controllers/session/login/index.js @@ -19,8 +19,7 @@ import 'emby-checkbox'; var user = result.User; loading.hide(); - Dashboard.onServerChanged(user.Id, result.AccessToken, apiClient); - Dashboard.navigate('home.html'); + onLoginSuccessful(user.Id, result.AccessToken, apiClient); }, function (response) { page.querySelector('#txtManualName').value = ''; page.querySelector('#txtManualPassword').value = ''; @@ -41,6 +40,60 @@ import 'emby-checkbox'; }); } + function authenticateQuickConnect(apiClient) { + let url = apiClient.getUrl('/QuickConnect/Initiate'); + apiClient.getJSON(url).then(function (json) { + if (!json.Secret || !json.Code) { + console.error('Malformed quick connect response', json); + return false; + } + + Dashboard.alert({ + message: globalize.translate('QuickConnectAuthorizeCode', json.Code), + title: globalize.translate('QuickConnect') + }); + + let connectUrl = apiClient.getUrl('/QuickConnect/Connect?Secret=' + json.Secret); + + let interval = setInterval(function() { + apiClient.getJSON(connectUrl).then(async function(data) { + if (!data.Authenticated) { + return; + } + + clearInterval(interval); + + let result = await apiClient.quickConnect(data.Authentication); + onLoginSuccessful(result.User.Id, result.AccessToken, apiClient); + }, function (e) { + clearInterval(interval); + + Dashboard.alert({ + message: globalize.translate('QuickConnectDeactivated'), + title: globalize.translate('HeaderError') + }); + + console.error('Unable to login with quick connect', e); + }); + }, 5000, connectUrl); + + return true; + }, function(e) { + Dashboard.alert({ + message: globalize.translate('QuickConnectNotActive'), + title: globalize.translate('HeaderError') + }); + + console.error('Quick connect error: ', e); + return false; + }); + } + + function onLoginSuccessful(id, accessToken, apiClient) { + Dashboard.onServerChanged(id, accessToken, apiClient); + Dashboard.navigate('home.html'); + } + function showManualForm(context, showCancel, focusPassword) { context.querySelector('.chkRememberLogin').checked = appSettings.enableAutoLogin(); context.querySelector('.manualLoginForm').classList.remove('hide'); @@ -154,58 +207,6 @@ import 'emby-checkbox'; }); } - // FIXME: Clicking ok on the code dialog redirects back to the homepage. - function loginQuickConnect() { - let apiClient = getApiClient(); - - let url = apiClient.getUrl('/QuickConnect/Initiate'); - apiClient.getJSON(url).then(function (json) { - if (!json.Secret || !json.Code) { - console.error('Malformed quick connect response', json); - return false; - } - - Dashboard.alert({ - message: globalize.translate('QuickConnectAuthorizeCode', json.Code), - title: globalize.translate('QuickConnect') - }); - - let interval = setInterval(function() { - let connectUrl = apiClient.getUrl('/QuickConnect/Connect?Secret=' + json.Secret); - apiClient.getJSON(connectUrl).then(async function(data) { - if (!data.Authenticated) { - return; - } - - clearInterval(interval); - - let result = await apiClient.quickConnect(data.Authentication); - Dashboard.onServerChanged(result.User.Id, result.AccessToken, apiClient); - Dashboard.navigate('home.html'); - }, function (e) { - clearInterval(interval); - - Dashboard.alert({ - message: globalize.translate('QuickConnectDeactivated'), - title: globalize.translate('HeaderError') - }); - - console.error('Unable to login with quick connect', e); - }); - }, 5000); - - return true; - }, function(e) { - Dashboard.alert({ - message: globalize.translate('QuickConnectNotActive'), - title: globalize.translate('HeaderError') - }); - - console.error('Quick connect error: ', e); - return false; - }); - } - view.querySelector('#divUsers').addEventListener('click', function (e) { const card = dom.parentWithClass(e.target, 'card'); const cardContent = card ? card.querySelector('.cardContent') : null; @@ -239,7 +240,11 @@ import 'emby-checkbox'; Dashboard.navigate('forgotpassword.html'); }); view.querySelector('.btnCancel').addEventListener('click', showVisualForm); - view.querySelector('.btnQuick').addEventListener('click', loginQuickConnect); + view.querySelector('.btnQuick').addEventListener('click', function () { + const apiClient = getApiClient(); + authenticateQuickConnect(apiClient); + return false; + }); view.querySelector('.btnManual').addEventListener('click', function () { view.querySelector('#txtManualName').value = ''; showManualForm(view, true); diff --git a/src/controllers/user/quickConnect/index.html b/src/controllers/user/quickConnect/index.html index 5f698a4a6b..15df59ff17 100644 --- a/src/controllers/user/quickConnect/index.html +++ b/src/controllers/user/quickConnect/index.html @@ -1,4 +1,4 @@ -
    +
    diff --git a/src/controllers/user/quickConnect/index.js b/src/controllers/user/quickConnect/index.js index 2d6f4b15c8..9e8d1a3b31 100644 --- a/src/controllers/user/quickConnect/index.js +++ b/src/controllers/user/quickConnect/index.js @@ -8,10 +8,7 @@ export default function (view) { view.addEventListener('viewshow', function () { let codeElement = view.querySelector('#txtQuickConnectCode'); - quickConnectSettingsInstance = new QuickConnectSettings({ - page: view, - interval: 0 - }); + quickConnectSettingsInstance = new QuickConnectSettings(); view.querySelector('#btnQuickConnectActivate').addEventListener('click', () => { quickConnectSettingsInstance.activate(quickConnectSettingsInstance).then(() => { @@ -30,24 +27,17 @@ export default function (view) { quickConnectSettingsInstance.authorize(code); }); + view.querySelector('.quickConnectSettingsContainer').addEventListener('submit', (e) => { + e.preventDefault(); + }); + renderPage(); }); view.addEventListener('viewbeforehide', function () { if (quickConnectSettingsInstance) { quickConnectSettingsInstance.submit(); } - onDestroy(); }); - view.addEventListener('viewdestroy', function () { - onDestroy(); - }); - - function onDestroy() { - if (quickConnectSettingsInstance) { - quickConnectSettingsInstance.destroy(); - quickConnectSettingsInstance = null; - } - } function renderPage(forceActive = false) { ApiClient.getQuickConnect('Status').then((status) => { diff --git a/src/quickconnect.html b/src/quickconnect.html index 671bb88d77..b5b6d48991 100644 --- a/src/quickconnect.html +++ b/src/quickconnect.html @@ -17,7 +17,7 @@
    diff --git a/src/strings/en-us.json b/src/strings/en-us.json index b4442ee0f9..df5b6a36c6 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -1153,7 +1153,7 @@ "Quality": "Quality", "QuickConnect": "Quick Connect", "QuickConnectActivationSuccessful": "Successfully activated", - "QuickConnectAuthorizeCode": "Authorize request {0} to continue", + "QuickConnectAuthorizeCode": "Enter code {0} to login", "QuickConnectAuthorizeSuccess": "Request authorized", "QuickConnectAuthorizeFail": "Unknown quick connect code", "QuickConnectDeactivated": "Quick connect was deactivated before the login request could be approved", From f10535fc8c616679a611dad2046e656030fb3cc1 Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Fri, 4 Sep 2020 21:45:12 +0800 Subject: [PATCH 035/281] update strings --- src/controllers/dashboard/encodingsettings.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/dashboard/encodingsettings.html b/src/controllers/dashboard/encodingsettings.html index 00fcaa53e4..388d2edbad 100644 --- a/src/controllers/dashboard/encodingsettings.html +++ b/src/controllers/dashboard/encodingsettings.html @@ -118,7 +118,7 @@
    From e9caf5e336bd2830d5ebc66853d6a55b057c8aea Mon Sep 17 00:00:00 2001 From: Ian Walton Date: Mon, 7 Sep 2020 12:54:12 -0400 Subject: [PATCH 036/281] Add auto-cast feature. --- package.json | 1 + src/components/autocast.js | 49 +++++++++++++++++++ .../playback/playerSelectionMenu.js | 21 ++++++++ src/scripts/libraryMenu.js | 8 +++ src/scripts/site.js | 1 + src/strings/en-us.json | 1 + 6 files changed, 81 insertions(+) create mode 100644 src/components/autocast.js diff --git a/package.json b/package.json index 5ca5c15151..1521a1d918 100644 --- a/package.json +++ b/package.json @@ -177,6 +177,7 @@ "src/components/remotecontrol/remotecontrol.js", "src/components/sanatizefilename.js", "src/components/scrollManager.js", + "src/components/autocast.js", "src/plugins/experimentalWarnings/plugin.js", "src/plugins/sessionPlayer/plugin.js", "src/plugins/htmlAudioPlayer/plugin.js", diff --git a/src/components/autocast.js b/src/components/autocast.js new file mode 100644 index 0000000000..3572f42bb2 --- /dev/null +++ b/src/components/autocast.js @@ -0,0 +1,49 @@ +import events from 'events'; +import playbackManager from 'playbackManager'; + +export function supported() { + return typeof(Storage) !== 'undefined'; +} + +export function enable(isEnabled) { + if (!supported()) return; + + if (isEnabled) { + const currentPlayerInfo = playbackManager.getPlayerInfo(); + + if (currentPlayerInfo && currentPlayerInfo.id && currentPlayerInfo.id) { + localStorage.setItem('autocastPlayerId', currentPlayerInfo.id); + } + } else { + localStorage.removeItem('autocastPlayerId'); + } +} + +export function isEnabled() { + if (!supported()) return false; + + const playerId = localStorage.getItem('autocastPlayerId'); + const currentPlayerInfo = playbackManager.getPlayerInfo(); + + return (currentPlayerInfo && playerId && currentPlayerInfo.id === playerId); +} + +function onOpen() { + if (!supported()) return; + + const playerId = localStorage.getItem('autocastPlayerId'); + + playbackManager.getTargets().then(function (targets) { + for (var i = 0; i < targets.length; i++) { + if (targets[i].id == playerId) { + playbackManager.trySetActivePlayer(targets[i].playerName, targets[i]); + break; + } + } + }); +} + +const apiClient = window.connectionManager.currentApiClient(); +if (apiClient) { + events.on(apiClient, 'websocketopen', onOpen); +} diff --git a/src/components/playback/playerSelectionMenu.js b/src/components/playback/playerSelectionMenu.js index 7799613400..3fe5be70d8 100644 --- a/src/components/playback/playerSelectionMenu.js +++ b/src/components/playback/playerSelectionMenu.js @@ -6,6 +6,7 @@ import playbackManager from 'playbackManager'; import appRouter from 'appRouter'; import globalize from 'globalize'; import appHost from 'apphost'; +import * as autocast from 'autocast'; function mirrorItem(info, player) { var item = info.item; @@ -219,6 +220,16 @@ function showActivePlayerMenuInternal(dialogHelper, playerInfo) { html += ''; } + html += '
    '; + + if (autocast.supported()) { + html += ''; + } + html += '
    '; html += '
    '; @@ -237,6 +248,12 @@ function showActivePlayerMenuInternal(dialogHelper, playerInfo) { chkMirror.addEventListener('change', onMirrorChange); } + var chkAutoCast = dlg.querySelector('.chkAutoCast'); + + if (chkAutoCast) { + chkAutoCast.addEventListener('change', onAutoCastChange); + } + var destination = ''; var btnRemoteControl = dlg.querySelector('.btnRemoteControl'); @@ -269,6 +286,10 @@ function onMirrorChange() { playbackManager.enableDisplayMirroring(this.checked); } +function onAutoCastChange() { + autocast.enable(this.checked); +} + document.addEventListener('viewshow', function (e) { var state = e.detail.state || {}; var item = state.item; diff --git a/src/scripts/libraryMenu.js b/src/scripts/libraryMenu.js index 04edecf198..7a332a853c 100644 --- a/src/scripts/libraryMenu.js +++ b/src/scripts/libraryMenu.js @@ -52,6 +52,7 @@ import 'flexStyles'; lazyLoadViewMenuBarImages(); bindMenuEvents(); + updateCastIcon(); } function getCurrentApiClient() { @@ -910,6 +911,12 @@ import 'flexStyles'; } } + function ensureHeader() { + return new Promise(function (resolve) { + window.connectionManager.user(getCurrentApiClient()).then(updateUserInHeader).then(resolve); + }); + } + let currentPageType; pageClassOn('pagebeforeshow', 'page', function (e) { if (!this.classList.contains('withTabs')) { @@ -996,6 +1003,7 @@ import 'flexStyles'; }; window.LibraryMenu = LibraryMenu; + renderHeader(); export default LibraryMenu; diff --git a/src/scripts/site.js b/src/scripts/site.js index f14670d82d..e8f00080f1 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -591,6 +591,7 @@ function initClient() { define('metadataEditor', [componentsPath + '/metadataEditor/metadataEditor'], returnFirstDependency); define('personEditor', [componentsPath + '/metadataEditor/personEditor'], returnFirstDependency); define('playerSelectionMenu', [componentsPath + '/playback/playerSelectionMenu'], returnFirstDependency); + define('autocast', [componentsPath + '/autocast'], returnFirstDependency); define('playerSettingsMenu', [componentsPath + '/playback/playersettingsmenu'], returnFirstDependency); define('playMethodHelper', [componentsPath + '/playback/playmethodhelper'], returnFirstDependency); define('brightnessOsd', [componentsPath + '/playback/brightnessosd'], returnFirstDependency); diff --git a/src/strings/en-us.json b/src/strings/en-us.json index e39199c56f..074d9c95f1 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -183,6 +183,7 @@ "EditImages": "Edit images", "EditMetadata": "Edit metadata", "EditSubtitles": "Edit subtitles", + "EnableAutoCast": "Set as Default", "EnableBackdropsHelp": "Display backdrops in the background of some pages while browsing the library.", "EnableCinemaMode": "Cinema mode", "EnableColorCodedBackgrounds": "Color coded backgrounds", From c8c8be39cda9258bebb0adf18a72062cee70d003 Mon Sep 17 00:00:00 2001 From: Ian Walton Date: Mon, 7 Sep 2020 13:10:38 -0400 Subject: [PATCH 037/281] Appease SonarCloud. --- src/components/autocast.js | 4 ++-- src/components/playback/playerSelectionMenu.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/autocast.js b/src/components/autocast.js index 3572f42bb2..4d191a62da 100644 --- a/src/components/autocast.js +++ b/src/components/autocast.js @@ -5,10 +5,10 @@ export function supported() { return typeof(Storage) !== 'undefined'; } -export function enable(isEnabled) { +export function enable(enabled) { if (!supported()) return; - if (isEnabled) { + if (enabled) { const currentPlayerInfo = playbackManager.getPlayerInfo(); if (currentPlayerInfo && currentPlayerInfo.id && currentPlayerInfo.id) { diff --git a/src/components/playback/playerSelectionMenu.js b/src/components/playback/playerSelectionMenu.js index 3fe5be70d8..dcf36dd9b4 100644 --- a/src/components/playback/playerSelectionMenu.js +++ b/src/components/playback/playerSelectionMenu.js @@ -224,8 +224,8 @@ function showActivePlayerMenuInternal(dialogHelper, playerInfo) { if (autocast.supported()) { html += ''; } From afa1403769e1b5ccc0bf27e585d763a3fd888a82 Mon Sep 17 00:00:00 2001 From: Larvitar Date: Tue, 8 Sep 2020 08:40:45 +0000 Subject: [PATCH 038/281] Translated using Weblate (Polish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/pl/ --- src/strings/pl.json | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/strings/pl.json b/src/strings/pl.json index 0893252ce3..860d369d32 100644 --- a/src/strings/pl.json +++ b/src/strings/pl.json @@ -1253,7 +1253,7 @@ "LabelLibraryPageSize": "Rozmiar strony biblioteki:", "LabelDeinterlaceMethod": "Metoda usuwania przeplotu:", "Episode": "Odcinek", - "DeinterlaceMethodHelp": "Wybierz metodę usuwania przeplotu używaną podczas transkodowania.", + "DeinterlaceMethodHelp": "Wybierz metodę usuwania przeplotu używaną podczas transkodowania. Gdy przyśpieszenie sprzętowe wspierające usuwanie przeplotu jest włączone sprzętowe usuwanie przeplotu zostanie użyte zamiast tego ustawienia.", "ClientSettings": "Ustawienia klienta", "ButtonTogglePlaylist": "Playlista", "ButtonSyncPlay": "SyncPlay", @@ -1365,5 +1365,12 @@ "Profile": "Profil", "PosterCard": "Widokówka", "Poster": "Plakat", - "MusicVideos": "Teledyski" + "MusicVideos": "Teledyski", + "VideoAudio": "Dźwięk Wideo", + "Bwdif": "BWDIF", + "UseDoubleRateDeinterlacing": "Podwój częstotliwość wyświetlania klatek podczas usuwania przeplotu", + "Photo": "Zdjęcie", + "LabelIconMaxResHelp": "Maksymalna rozdzielczość ikon udostępnianych przez upnp:icon.", + "LabelAlbumArtMaxResHelp": "Maksymalna rozdzielczość okładki albumu udostępnianej przez upnp:albumArtURI.", + "Other": "Inne" } From 64e6a114aee2754925d40724051509e52fcaa339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Miguel=20Moreno?= Date: Tue, 8 Sep 2020 18:10:46 +0000 Subject: [PATCH 039/281] Translated using Weblate (Spanish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/es/ --- src/strings/es.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/es.json b/src/strings/es.json index ebd6ed698c..2ebe9fba2f 100644 --- a/src/strings/es.json +++ b/src/strings/es.json @@ -1077,7 +1077,7 @@ "DirectStreamHelp2": "La transmisión directa del archivo usa muy poco procesamiento sin mínima pérdida de calidad en el vídeo.", "Director": "Dirección de", "Directors": "Directores", - "Display": "Mostrar", + "Display": "Visualización", "DisplayInMyMedia": "Mostrar en la pantalla de inicio", "DisplayInOtherHomeScreenSections": "Mostrar en las secciones de la pantalla de inicio al igual que \"últimos\" y \"continuar viendo\"", "DisplayMissingEpisodesWithinSeasons": "Mostrar episodios ausentes en las temporadas", From a2854de17f5e0f2b15148638a120bda358a27354 Mon Sep 17 00:00:00 2001 From: Dengomanolo Date: Tue, 8 Sep 2020 18:09:58 +0000 Subject: [PATCH 040/281] Translated using Weblate (Portuguese) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/pt/ --- src/strings/pt.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strings/pt.json b/src/strings/pt.json index dd3dc6e960..d08244d010 100644 --- a/src/strings/pt.json +++ b/src/strings/pt.json @@ -915,19 +915,19 @@ "Banner": "Insígnia", "Backdrops": "Imagens de Fundo", "Backdrop": "Imagem de Fundo", - "AuthProviderHelp": "Seleccione um mecanismo de autenticação a ser utilizado para validar as credenciais deste utilizador.", + "AuthProviderHelp": "Selecione um mecanismo de autenticação a ser utilizado para validar as credenciais do usuário.", "Audio": "Áudio", "AspectRatio": "Proporção da tela", "Ascending": "Crescente", "Art": "Capa", - "AroundTime": "Por volta das {0}", + "AroundTime": "Por volta das", "Anytime": "Qualquer altura", "AnyLanguage": "Qualquer idioma", "Artists": "Artistas", "AsManyAsPossible": "Tantos quanto possível", "AllowedRemoteAddressesHelp": "Lista separada por vírgula de endereços IP ou entradas de máscara de IP/rede para redes que terão permissão para se conectar remotamente. Se deixado em branco, todos os endereços remotos serão permitidos.", "AllowRemoteAccessHelp": "Se desmarcada, todas as conexões remotas serão bloqueadas.", - "AllowRemoteAccess": "Permitir ligações remotas a este Servidor Jellyfin.", + "AllowRemoteAccess": "Permitir conexões remotas a este servidor.", "AllowOnTheFlySubtitleExtractionHelp": "Legendas integradas podem ser extraídas do vídeo e enviadas como texto simples para os clientes de forma a evitar transcodificação. Em certos dispositivos, esta operação pode demorar algum tempo e causar paragens de reprodução durante o processo de extração. Desative esta opção para que as legendas sejam integradas no vídeo durante a conversão para um formato suportado pelo dispositivo de destino.", "AllowOnTheFlySubtitleExtraction": "Permitir a extração de legendas em tempo real", "AllowHWTranscodingHelp": "Permita que o sintonizador transcodifique os fluxos em tempo real. Isso pode ajudar a reduzir a transcodificação exigida pelo servidor.", From 9dc2c44c98b2c76c0d10c7b0a5b3e7ace0548e7d Mon Sep 17 00:00:00 2001 From: DeruytterA Date: Tue, 8 Sep 2020 19:39:00 +0000 Subject: [PATCH 041/281] Translated using Weblate (Dutch) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/nl/ --- src/strings/nl.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/strings/nl.json b/src/strings/nl.json index dcdfa80e78..05c0bdd05c 100644 --- a/src/strings/nl.json +++ b/src/strings/nl.json @@ -1231,7 +1231,7 @@ "TabStreaming": "Streamen", "AlbumArtist": "Album Artiest", "Album": "Album", - "DeinterlaceMethodHelp": "Selecteer de deinterlacingmethode die u wilt gebruiken bij het transcoderen van geïnterlinieerde inhoud.", + "DeinterlaceMethodHelp": "Selecteer de deinterlacingmethode die u wilt gebruiken bij het software transcoderen van geïnterlinieerde inhoud. Wanneer hardware versnelling ondersteuning voor hardware deinterlacing is ingeschakeld de hardware deinterlacer gaat worden gebruikt in plaats van deze instelling.", "ClientSettings": "Client instellingen", "ButtonSplit": "Splitsen", "BoxSet": "Box Set", @@ -1347,5 +1347,9 @@ "MessageGetInstalledPluginsError": "Er is een fout opgetreden bij het ophalen van de lijst met geïnstalleerde plugins.", "MessagePluginInstallError": "Er is een fout opgetreden tijdens het installeren van de plugin.", "LabelUnstable": "Niet stabiel", - "NextTrack": "Ga naar volgende" + "NextTrack": "Ga naar volgende", + "LabelAlbumArtMaxResHelp": "Maximum resolutie van het album art is blootgesteld via de eigenschap upnp:albumArtURI.", + "Image": "Afbeelding", + "Other": "Andere", + "Data": "Gegevens" } From 5f61bf8ff2d8b4710297af2f460b0bf4ed6ca066 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Tue, 8 Sep 2020 22:13:02 +0000 Subject: [PATCH 042/281] Translated using Weblate (Russian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/ru/ --- src/strings/ru.json | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/strings/ru.json b/src/strings/ru.json index 144a2d4ecb..20df7a795a 100644 --- a/src/strings/ru.json +++ b/src/strings/ru.json @@ -1274,7 +1274,7 @@ "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Используется информация об эпизоде из встроенных метаданных, если они доступны.", "LabelLibraryPageSizeHelp": "Устанавливается количество элементов для отображения на странице медиатеки. Установите 0 для отключения нумерации страниц.", "LabelDeinterlaceMethod": "Метод устранения гребёнки:", - "DeinterlaceMethodHelp": "Выберите метод устранения гребёнки, который будет использоваться при перекодировании чересстрочного содержания.", + "DeinterlaceMethodHelp": "Выберите метод устранения гребёнки, который будет использоваться при программном перекодировании чересстрочного содержания. Когда аппаратное ускорение поддерживающее аппаратное устранение гребёнки включено, аппаратное устранение гребёнки будет использоваться вместо этого параметра.", "UnsupportedPlayback": "Jellyfin не может расшифровать содержимое, защищенное DRM, но в любом случае будет предпринята попытка расшифровки всего содержимого, включая защищенные заголовки. Некоторые файлы могут выглядеть полностью черными из-за шифрования или других неподдерживаемых функций, таких как интерактивные заголовки.", "LabelRequireHttpsHelp": "Если этот флажок установлен, сервер будет автоматически перенаправлять все запросы через HTTP на HTTPS. Это не имеет никакого эффекта, если сервер не слушает HTTPS.", "LabelEnableHttpsHelp": "Прослушивается указанный HTTPS-порт. Чтобы это вступило в силу, также необходимо предоставить действительный сертификат.", @@ -1352,5 +1352,26 @@ "Preview": "Предварительный просмотр", "MessageGetInstalledPluginsError": "Произошла ошибка при получении списка установленных плагинов.", "MessagePluginInstallError": "Во время установки плагина произошла ошибка.", - "PlaybackRate": "Рейтинг" + "PlaybackRate": "Рейтинг", + "Bwdif": "Фильтр BWDIF", + "VideoAudio": "Видео Аудио", + "Video": "Видео", + "UseDoubleRateDeinterlacingHelp": "Этот параметр использует частоту полей при устранении гребёнки, часто называемом \"bob\", который удваивает частоту кадров видео, чтобы обеспечить полное движение, подобное просмотру чересстрочного видео на телевизоре.", + "UseDoubleRateDeinterlacing": "Удваивать частоту кадров при устранении гребёнки", + "ThumbCard": "Бегунок-карта", + "Subtitle": "Субтитры", + "SpecialFeatures": "Особенности", + "SelectServer": "Выбрать сервер", + "Restart": "Перезапустить", + "ResetPassword": "Сбросить пароль", + "Profile": "Профиль", + "PosterCard": "Постер-карта", + "Poster": "Постер", + "Photo": "Фото", + "MusicVideos": "Музыкальные видео", + "LabelIconMaxResHelp": "Максимальное разрешение значков, являемое через свойство upnp:icon.", + "LabelAlbumArtMaxResHelp": "Максимальное разрешение обложки альбома, являемое через свойство upnp:albumArtURI.", + "Image": "Рисунок", + "Other": "Другое", + "Data": "Данные" } From c947d848a0f2d6e2cb895a5c538fa34434dbdff7 Mon Sep 17 00:00:00 2001 From: Juan Date: Tue, 8 Sep 2020 23:44:15 +0000 Subject: [PATCH 043/281] Translated using Weblate (Spanish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/es/ --- src/strings/es.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strings/es.json b/src/strings/es.json index 2ebe9fba2f..76ac4a9249 100644 --- a/src/strings/es.json +++ b/src/strings/es.json @@ -1369,5 +1369,6 @@ "MusicVideos": "Vídeos Musicales", "LabelIconMaxResHelp": "Máxima resolución de los iconos expuesta a través de la propiedad upnp:icon.", "LabelAlbumArtMaxResHelp": "Máxima resolución del material artístico del álbum expuesta a través de la propiedad upnp:albumArtURI.", - "Other": "Otro" + "Other": "Otro", + "VideoAudio": "Vídeo Audio" } From 0c012f193881263f026e379fa157ee66d4d5835e Mon Sep 17 00:00:00 2001 From: Nyanmisaka <799610810@qq.com> Date: Wed, 9 Sep 2020 01:55:18 +0000 Subject: [PATCH 044/281] 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 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/strings/zh-cn.json b/src/strings/zh-cn.json index 1a4f73d9d4..a43c5efa4b 100644 --- a/src/strings/zh-cn.json +++ b/src/strings/zh-cn.json @@ -1371,5 +1371,7 @@ "Image": "图片", "Other": "其他", "Data": "数据", - "UseDoubleRateDeinterlacing": "反交错时使帧率翻倍" + "UseDoubleRateDeinterlacing": "反交错时使帧率翻倍", + "UseDoubleRateDeinterlacingHelp": "此设置使用去隔行时的场频,通常称为 Bob 去隔行,它将视频的帧频加倍,以提供完整的运动效果,就像在电视上观看隔行视频时看到的那样。", + "Bwdif": "BWDIF" } From 0ee827bca8b43952f5c6b11fb73281437a43815b Mon Sep 17 00:00:00 2001 From: GiJaLo Date: Wed, 9 Sep 2020 10:26:21 +0000 Subject: [PATCH 045/281] Translated using Weblate (Dutch) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/nl/ --- src/strings/nl.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strings/nl.json b/src/strings/nl.json index 05c0bdd05c..0138f0879c 100644 --- a/src/strings/nl.json +++ b/src/strings/nl.json @@ -1351,5 +1351,6 @@ "LabelAlbumArtMaxResHelp": "Maximum resolutie van het album art is blootgesteld via de eigenschap upnp:albumArtURI.", "Image": "Afbeelding", "Other": "Andere", - "Data": "Gegevens" + "Data": "Gegevens", + "LabelIconMaxResHelp": "Maximale resolutie van pictogrammen die worden weergegeven via de eigenschap upnp:icon." } From 42ba1e80ed01a5ebde7898466a939537702dc2cc Mon Sep 17 00:00:00 2001 From: GiJaLo Date: Wed, 9 Sep 2020 10:26:36 +0000 Subject: [PATCH 046/281] Translated using Weblate (Dutch) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/nl/ --- src/strings/nl.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strings/nl.json b/src/strings/nl.json index 0138f0879c..14d47f7407 100644 --- a/src/strings/nl.json +++ b/src/strings/nl.json @@ -1352,5 +1352,6 @@ "Image": "Afbeelding", "Other": "Andere", "Data": "Gegevens", - "LabelIconMaxResHelp": "Maximale resolutie van pictogrammen die worden weergegeven via de eigenschap upnp:icon." + "LabelIconMaxResHelp": "Maximale resolutie van pictogrammen die worden weergegeven via de eigenschap upnp:icon.", + "MusicVideos": "Muziek Videos" } From 77efca12f62333ac96d96725825ee7654eb57bd1 Mon Sep 17 00:00:00 2001 From: GiJaLo Date: Wed, 9 Sep 2020 10:27:51 +0000 Subject: [PATCH 047/281] Translated using Weblate (Dutch) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/nl/ --- src/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/nl.json b/src/strings/nl.json index 14d47f7407..6df9ebd5bc 100644 --- a/src/strings/nl.json +++ b/src/strings/nl.json @@ -856,7 +856,7 @@ "OptionHideUserFromLoginHelp": "Handig voor pivé of verborgen beheer accounts. De gebruiker zal handmatig moeten inloggen met een gebruikersnaam en wachtwoord.", "OptionHlsSegmentedSubtitles": "HLS gesegmenteerde ondertiteling", "OptionIgnoreTranscodeByteRangeRequests": "Transcodeer byte range-aanvragen negeren", - "OptionIgnoreTranscodeByteRangeRequestsHelp": "Indien ingeschakeld, zullen deze verzoeken worden gehonoreerd, maar zal de byte bereik header worden genegeerd.", + "OptionIgnoreTranscodeByteRangeRequestsHelp": "Deze verzoeken worden gehonoreerd, maar zal de byte bereik header worden genegeerd.", "OptionImdbRating": "IMDb Waardering", "OptionLikes": "Leuk", "OptionMissingEpisode": "Ontbrekende Afleveringen", From 1c2d22309a4bca96a933f83e172e8abd23fa1012 Mon Sep 17 00:00:00 2001 From: GiJaLo Date: Wed, 9 Sep 2020 10:28:15 +0000 Subject: [PATCH 048/281] Translated using Weblate (Dutch) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/nl/ --- src/strings/nl.json | 46 ++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/strings/nl.json b/src/strings/nl.json index 6df9ebd5bc..02cc20c13a 100644 --- a/src/strings/nl.json +++ b/src/strings/nl.json @@ -864,9 +864,9 @@ "OptionOnInterval": "Op interval", "OptionParentalRating": "Kijkwijzer classificatie", "OptionPlainStorageFolders": "Alle mappen weergeven als gewone opslagmappen", - "OptionPlainStorageFoldersHelp": "Indien ingeschakeld worden alle mappen in DIDL weergegeven als 'object.container.storageFolder' in plaats van een meer specifiek type, zoals 'object.container.person.musicArtist'.", + "OptionPlainStorageFoldersHelp": "Alle mappen in DIDL worden weergegeven als 'object.container.storageFolder' in plaats van een meer specifiek type, zoals 'object.container.person.musicArtist'.", "OptionPlainVideoItems": "Alle video's weergeven als gewone video items", - "OptionPlainVideoItemsHelp": "Indien ingeschakeld worden alle video's in DIDL weergegeven als 'object.item.videoItem' in plaats van een meer specifiek type, zoals 'object.item.videoItem.movie'.", + "OptionPlainVideoItemsHelp": "Alle video's in DIDL worden weergegeven als 'object.item.videoItem' in plaats van een meer specifiek type, zoals 'object.item.videoItem.movie'.", "OptionPlayCount": "Afspeel telling", "OptionPremiereDate": "Première Datum", "OptionReleaseDate": "Uitgave datum", @@ -876,7 +876,7 @@ "OptionRequirePerfectSubtitleMatchHelp": "Een perfecte match vereisen zal de ondertitels filteren om alleen ondertitels te downloaden die getest en geverifieerd zijn met je exacte videobestand. Dit uitvinken zal de kans om ondertitels te vinden vergroten, maar ook de kans op een niet gesynchroniseerd of foute ondertitel vergroten.", "OptionResumable": "Hervatbaar", "OptionSaveMetadataAsHidden": "Metagegevens en afbeeldingen opslaan als verborgen bestanden", - "OptionSaveMetadataAsHiddenHelp": "Het veranderen van dit zal gelden voor nieuwe metadata die wordt opgeslagen. Bestaande metadata bestanden zullen de volgende keer dat ze worden opgeslagen door Jellyfin Server worden bijgewerkt.", + "OptionSaveMetadataAsHiddenHelp": "Als u dit wijzigt, is dit van toepassing op nieuwe metagegevens die in de toekomst worden opgeslagen. Bestaande metadatabestanden worden bijgewerkt de volgende keer dat ze door de server worden opgeslagen.", "OptionSubstring": "Subtekenreeks", "OptionTrackName": "Naam van Nummer", "OptionTvdbRating": "TVDB Waardering", @@ -913,9 +913,9 @@ "PleaseAddAtLeastOneFolder": "Voeg tenminste 1 map aan deze bibliotheek toe door op de Toevoegen knop te klikken.", "PleaseConfirmPluginInstallation": "Klik op OK om te bevestigen dat u bovenstaande heeft gelezen en door wenst te gaan met het installeren van de plugin.", "PleaseEnterNameOrId": "Voer een naam of een externe ID in.", - "PleaseRestartServerName": "Herstart Jellyfin Server - {0} aub.", + "PleaseRestartServerName": "Start Jellyfin opnieuw op {0}.", "PleaseSelectTwoItems": "Selecteer ten minste twee items.", - "MessagePluginInstalled": "Het installeren van de plugin is gelukt. Jellyfin Server zal heropgestart moeten worden om de wijzigingen door te voeren.", + "MessagePluginInstalled": "De plug-in is succesvol geïnstalleerd. De server moet opnieuw worden opgestart om de wijzigingen door te voeren.", "PreferEmbeddedTitlesOverFileNames": "Prefereer ingesloten titels boven bestandsnamen", "PreferEmbeddedTitlesOverFileNamesHelp": "Dit bepaalt de standaard weergavetitel wanneer er geen internet metagegevens of lokale metadata beschikbaar is.", "Premieres": "Premières", @@ -939,7 +939,7 @@ "RecordingScheduled": "Opname schema.", "Recordings": "Opnames", "Refresh": "Vernieuwen", - "RefreshDialogHelp": "Metadata wordt vernieuwd op basis van de instellingen en internet diensten die zijn ingeschakeld in het dashboard van de Jellyfin Server.", + "RefreshDialogHelp": "Metagegevens worden vernieuwd op basis van instellingen en internetservices die zijn ingeschakeld in het dashboard.", "RefreshMetadata": "Metadata vernieuwen", "RefreshQueued": "Verversen wachtrij.", "ReleaseDate": "Uitgave datum", @@ -975,10 +975,10 @@ "SeriesRecordingScheduled": "Serieopname gepland.", "SeriesSettings": "Series instellingen", "SeriesYearToPresent": "{0} - Heden", - "ServerNameIsRestarting": "Jellyfin Server - {0} is opnieuw aan het opstarten.", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} is aan het afsluiten.", - "ServerRestartNeededAfterPluginInstall": "Jellyfin server zal heropgestart moeten worden na het installeren van een plugin.", - "ServerUpdateNeeded": "Deze Jellyfin Server moet worden bijgewerkt. Om de laatste versie te downloaden, gaat u naar {0}", + "ServerNameIsRestarting": "De server op {0} wordt opnieuw opgestart.", + "ServerNameIsShuttingDown": "De server op {0} wordt afgesloten.", + "ServerRestartNeededAfterPluginInstall": "Jellyfin moet opnieuw worden opgestart na het installeren van een plug-in.", + "ServerUpdateNeeded": "Deze server moet worden bijgewerkt. Ga naar {0} om de nieuwste versie te downloaden", "Settings": "Instellingen", "SettingsSaved": "Instellingen opgeslagen.", "SettingsWarning": "Het veranderen van deze waarden kunnen instabiliteit of connectiviteit storingen veroorzaken. Als u problemen ondervindt, raden wij aan de veranderingen terug te zetten naar standaard.", @@ -1174,7 +1174,7 @@ "LabelAudioBitDepth": "Audio bit diepte:", "OptionRandom": "Willekeurig", "PlaybackData": "Afspeel Data", - "PasswordResetProviderHelp": "Kies een wachtwoord reset provider om te gebruiken wanneer deze gebruiker een wachtwoord reset aanvraagt", + "PasswordResetProviderHelp": "Kies een provider voor wachtwoordherstel die moet worden gebruikt wanneer deze gebruiker een wachtwoordherstel aanvraagt.", "Screenshots": "Schermafdruk", "Series": "Series", "Trailers": "Trailers", @@ -1269,7 +1269,7 @@ "LastSeen": "Laatst bekeken {0}", "PersonRole": "als {0}", "ListPaging": "{0}-{1} van de {2}", - "WriteAccessRequired": "De Jellyfin Server vereist schrijftoegang tot deze map. Zorg evoor dat Jellyfin schrijftoegang tot de map heeft en probeer opnieuw.", + "WriteAccessRequired": "Jellyfin vereist schrijftoegang tot deze map. Zorg voor schrijftoegang en probeer het opnieuw.", "PathNotFound": "Het pad kan niet gevonden worden. Zorg ervoor dat het pad correct is en probeer opnieuw.", "Yadif": "YADIF", "SelectAdminUsername": "Selecteer een gebruikersnaam voor het beheerder account.", @@ -1353,5 +1353,25 @@ "Other": "Andere", "Data": "Gegevens", "LabelIconMaxResHelp": "Maximale resolutie van pictogrammen die worden weergegeven via de eigenschap upnp:icon.", - "MusicVideos": "Muziek Videos" + "MusicVideos": "Muziek Videos", + "Preview": "Preview", + "SubtitleVerticalPositionHelp": "Regelnummer waar tekst verschijnt. Positieve cijfers geven top-down aan. Negatieve getallen geven bottom-up aan.", + "ButtonCast": "Cast", + "Bwdif": "BWDIF", + "VideoAudio": "Video Geluid", + "Video": "Video", + "UseDoubleRateDeinterlacingHelp": "Deze instelling gebruikt de veldsnelheid bij de-interlacing, ook wel bob-de-interliniëring genoemd, waarmee de framesnelheid van de video wordt verdubbeld om volledige beweging te bieden, zoals je zou zien bij het bekijken van geïnterlinieerde video op een tv.", + "UseDoubleRateDeinterlacing": "Verdubbel de framesnelheid bij de-interliniëring", + "ThumbCard": "Thumb Card", + "Subtitle": "Ondertiteling", + "SpecialFeatures": "Speciale Features", + "SelectServer": "Selecteer Server", + "Restart": "Herstarten", + "ResetPassword": "Wachtwoord opnieuw instellen", + "Profile": "Profiel", + "PreviousTrack": "Ga naar vorige", + "PosterCard": "Poster kaart", + "Poster": "Poster", + "PlaybackRate": "Afspeelsnelheid", + "Photo": "Foto" } From fba96da9548ee7cba28a912339c910fcd90ffed2 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 9 Sep 2020 17:34:08 -0400 Subject: [PATCH 049/281] Alpha picker only returns items starting with selected letter --- src/controllers/list.js | 2 +- src/controllers/movies/movies.js | 4 ++-- src/controllers/movies/movietrailers.js | 4 ++-- src/controllers/music/musicalbums.js | 4 ++-- src/controllers/music/musicartists.js | 4 ++-- src/controllers/shows/tvshows.js | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/controllers/list.js b/src/controllers/list.js index fe04fc18e8..07e07eeb05 100644 --- a/src/controllers/list.js +++ b/src/controllers/list.js @@ -163,7 +163,7 @@ import 'emby-scroller'; instance.setFilterStatus(hasFilters); if (instance.alphaPicker) { - query.NameStartsWithOrGreater = instance.alphaPicker.value(); + query.NameStartsWith = instance.alphaPicker.value(); } return query; diff --git a/src/controllers/movies/movies.js b/src/controllers/movies/movies.js index ab5aff9ecd..e05b1fa96a 100644 --- a/src/controllers/movies/movies.js +++ b/src/controllers/movies/movies.js @@ -25,7 +25,7 @@ import 'emby-itemscontainer'; const updateFilterControls = () => { if (this.alphaPicker) { - this.alphaPicker.value(query.NameStartsWithOrGreater); + this.alphaPicker.value(query.NameStartsWith); } }; @@ -168,7 +168,7 @@ import 'emby-itemscontainer'; if (alphaPickerElement) { alphaPickerElement.addEventListener('alphavaluechanged', function (e) { let newValue = e.detail.value; - query.NameStartsWithOrGreater = newValue; + query.NameStartsWith = newValue; query.StartIndex = 0; itemsContainer.refreshItems(); }); diff --git a/src/controllers/movies/movietrailers.js b/src/controllers/movies/movietrailers.js index f2c7feada7..def55d919a 100644 --- a/src/controllers/movies/movietrailers.js +++ b/src/controllers/movies/movietrailers.js @@ -185,7 +185,7 @@ import 'emby-itemscontainer'; const updateFilterControls = (tabContent) => { const query = getQuery(tabContent); - this.alphaPicker.value(query.NameStartsWithOrGreater); + this.alphaPicker.value(query.NameStartsWith); }; const data = {}; @@ -216,7 +216,7 @@ import 'emby-itemscontainer'; alphaPickerElement.addEventListener('alphavaluechanged', function (e) { const newValue = e.detail.value; const query = getQuery(tabContent); - query.NameStartsWithOrGreater = newValue; + query.NameStartsWith = newValue; query.StartIndex = 0; reloadItems(); }); diff --git a/src/controllers/music/musicalbums.js b/src/controllers/music/musicalbums.js index 7947aa1376..42490fd2f4 100644 --- a/src/controllers/music/musicalbums.js +++ b/src/controllers/music/musicalbums.js @@ -186,7 +186,7 @@ import 'emby-itemscontainer'; const updateFilterControls = (tabContent) => { const query = getQuery(); - this.alphaPicker.value(query.NameStartsWithOrGreater); + this.alphaPicker.value(query.NameStartsWith); }; let savedQueryKey; @@ -219,7 +219,7 @@ import 'emby-itemscontainer'; alphaPickerElement.addEventListener('alphavaluechanged', function (e) { const newValue = e.detail.value; const query = getQuery(); - query.NameStartsWithOrGreater = newValue; + query.NameStartsWith = newValue; query.StartIndex = 0; reloadItems(tabContent); }); diff --git a/src/controllers/music/musicartists.js b/src/controllers/music/musicartists.js index 32e0a22a07..3517437622 100644 --- a/src/controllers/music/musicartists.js +++ b/src/controllers/music/musicartists.js @@ -169,7 +169,7 @@ import 'emby-itemscontainer'; const updateFilterControls = (tabContent) => { const query = getQuery(tabContent); - this.alphaPicker.value(query.NameStartsWithOrGreater); + this.alphaPicker.value(query.NameStartsWith); }; const data = {}; @@ -201,7 +201,7 @@ import 'emby-itemscontainer'; alphaPickerElement.addEventListener('alphavaluechanged', function (e) { const newValue = e.detail.value; const query = getQuery(tabContent); - query.NameStartsWithOrGreater = newValue; + query.NameStartsWith = newValue; query.StartIndex = 0; reloadItems(tabContent); }); diff --git a/src/controllers/shows/tvshows.js b/src/controllers/shows/tvshows.js index ef45eba0f7..fee4fd24a5 100644 --- a/src/controllers/shows/tvshows.js +++ b/src/controllers/shows/tvshows.js @@ -198,7 +198,7 @@ import 'emby-itemscontainer'; function updateFilterControls(tabContent) { const query = getQuery(tabContent); - self.alphaPicker.value(query.NameStartsWithOrGreater); + self.alphaPicker.value(query.NameStartsWith); } const self = this; @@ -231,7 +231,7 @@ import 'emby-itemscontainer'; alphaPickerElement.addEventListener('alphavaluechanged', function (e) { const newValue = e.detail.value; const query = getQuery(tabContent); - query.NameStartsWithOrGreater = newValue; + query.NameStartsWith = newValue; query.StartIndex = 0; reloadItems(tabContent); }); From e06b9ec4d05824a675f95297063243fde08c16c7 Mon Sep 17 00:00:00 2001 From: Lars Kerick Date: Thu, 10 Sep 2020 06:53:38 +0000 Subject: [PATCH 050/281] Translated using Weblate (German) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/de/ --- src/strings/de.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/de.json b/src/strings/de.json index cd4428c124..4979faf1da 100644 --- a/src/strings/de.json +++ b/src/strings/de.json @@ -1270,7 +1270,7 @@ "Yadif": "YADIF", "LabelLibraryPageSizeHelp": "Setzt die Anzahl der auf einer Seite angezeigten Objekte. Setze auf 0, um alle Elemente auf einer Seite anzuzeigen.", "LabelLibraryPageSize": "Bibliothek Seiten Größe:", - "DeinterlaceMethodHelp": "Wähle die Deinterlacing-Methode zum Transkodieren von Inhalten im Zeilensprungverfahren (Interlace).", + "DeinterlaceMethodHelp": "Wähle die Deinterlacing-Methode zum Transkodieren von Inhalten im Zeilensprungverfahren (Interlace). Sofern bei unterstützten Geräten Deinterlacing durch Hardwarebeschleunigung aktiviert ist, wird der Hardware-Deinterlacer anstelle dieser Einstellung verwendet.", "LabelDeinterlaceMethod": "Deinterlacing-Methode:", "UnsupportedPlayback": "Jellyfin kann keine DRM-geschützten Inhalte entschlüsseln, aber es wird versucht, alle Inhalte unabhängig davon zu entschlüsseln, einschließlich geschützter Titel. Einige Dateien können aufgrund der Verschlüsselung oder anderer nicht unterstützter Funktionen, wie z.B. interaktive Titel, komplett schwarz erscheinen.", "Filter": "Filter", From fa7d8bf4daf4fb2aba5a706219b77d68f3b5b83a Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Thu, 10 Sep 2020 15:04:06 -0500 Subject: [PATCH 051/281] Apply suggestions from code review --- .../quickConnectSettings.js | 4 - src/controllers/dashboard/quickconnect.js | 90 +++++++++---------- src/controllers/user/quickConnect/index.js | 5 -- 3 files changed, 45 insertions(+), 54 deletions(-) diff --git a/src/components/quickConnectSettings/quickConnectSettings.js b/src/components/quickConnectSettings/quickConnectSettings.js index a62cfc2298..e802f92ba1 100644 --- a/src/components/quickConnectSettings/quickConnectSettings.js +++ b/src/components/quickConnectSettings/quickConnectSettings.js @@ -36,10 +36,6 @@ export class QuickConnectSettings { throw e; }); } - - submit() { - return false; - } } export default QuickConnectSettings; diff --git a/src/controllers/dashboard/quickconnect.js b/src/controllers/dashboard/quickconnect.js index 012f7b7aa3..87c88d8a41 100644 --- a/src/controllers/dashboard/quickconnect.js +++ b/src/controllers/dashboard/quickconnect.js @@ -2,57 +2,57 @@ import loading from 'loading'; import toast from 'toast'; import globalize from 'globalize'; -/* eslint-disable indent */ +const unavailable = 'Unavailable'; +const available = 'Available'; +const active = 'Active'; +let page; - let page; - export default function(view) { - view.addEventListener('viewshow', function () { - page = this; - loading.show(); - page.querySelector('#btnQuickConnectSubmit').onclick = onSubmit; - updatePage(); - }); - } - - function loadPage(status) { - let available = status === 'Available' || status === 'Active'; - - page.querySelector('#quickConnectStatus').textContent = status.toLocaleLowerCase(); - page.querySelector('#chkQuickConnectAvailable').checked = available; - - loading.hide(); - } - - function onSubmit() { +export default function(view) { + view.addEventListener('viewshow', function () { + page = this; loading.show(); + page.querySelector('#btnQuickConnectSubmit').onclick = onSubmit; + updatePage(); + }); +} - let newStatus = page.querySelector('#chkQuickConnectAvailable').checked ? 'Available' : 'Unavailable'; +function loadPage(status) { + let check = status === available || status === active; - let url = ApiClient.getUrl('/QuickConnect/Available?Status=' + newStatus); + page.querySelector('#quickConnectStatus').textContent = status.toLocaleLowerCase(); + page.querySelector('#chkQuickConnectAvailable').checked = check; - ApiClient.ajax({ - type: 'POST', - url: url - }, true).then(() => { - toast(globalize.translate('SettingsSaved')); - setTimeout(updatePage, 500); + loading.hide(); +} - return true; - }).catch((e) => { - console.error('Unable to set quick connect status. error:', e); - }); +function onSubmit() { + loading.show(); - loading.hide(); - return false; - } + let newStatus = page.querySelector('#chkQuickConnectAvailable').checked ? available : unavailable; - function updatePage() { - ApiClient.getQuickConnect('Status').then((response) => { - loadPage(response); - return true; - }).catch((e) => { - console.error('Unable to get quick connect status. error:', e); - }); - } + let url = ApiClient.getUrl('/QuickConnect/Available?Status=' + newStatus); -/* eslint-enable indent */ + ApiClient.ajax({ + type: 'POST', + url: url + }, true).then(() => { + toast(globalize.translate('SettingsSaved')); + setTimeout(updatePage, 500); + + return true; + }).catch((e) => { + console.error('Unable to set quick connect status. error:', e); + }); + + loading.hide(); + return false; +} + +function updatePage() { + ApiClient.getQuickConnect('Status').then((response) => { + loadPage(response); + return true; + }).catch((e) => { + console.error('Unable to get quick connect status. error:', e); + }); +} diff --git a/src/controllers/user/quickConnect/index.js b/src/controllers/user/quickConnect/index.js index 9e8d1a3b31..00fc5488b9 100644 --- a/src/controllers/user/quickConnect/index.js +++ b/src/controllers/user/quickConnect/index.js @@ -33,11 +33,6 @@ export default function (view) { renderPage(); }); - view.addEventListener('viewbeforehide', function () { - if (quickConnectSettingsInstance) { - quickConnectSettingsInstance.submit(); - } - }); function renderPage(forceActive = false) { ApiClient.getQuickConnect('Status').then((status) => { From c8b6b44b7bf79c5a14055c6262b85b5af9cd7554 Mon Sep 17 00:00:00 2001 From: Deniz Date: Thu, 10 Sep 2020 17:05:39 +0000 Subject: [PATCH 052/281] Translated using Weblate (Turkish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/tr/ --- src/strings/tr.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strings/tr.json b/src/strings/tr.json index f480257f69..9730857ea8 100644 --- a/src/strings/tr.json +++ b/src/strings/tr.json @@ -614,5 +614,6 @@ "LabelSize": "Boyut:", "LabelSimultaneousConnectionLimit": "Eşzamanlı yayın limiti:", "LabelServerName": "Sunucu adı:", - "ButtonSyncPlay": "SyncPlay" + "ButtonSyncPlay": "SyncPlay", + "Settings": "Ayarlar" } From eb67f3fb8893a858bcf17cd31e1f0646eeb4d899 Mon Sep 17 00:00:00 2001 From: Moritz Date: Thu, 10 Sep 2020 16:29:02 +0000 Subject: [PATCH 053/281] Translated using Weblate (German) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/de/ --- src/strings/de.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/strings/de.json b/src/strings/de.json index 4979faf1da..4e3a002b86 100644 --- a/src/strings/de.json +++ b/src/strings/de.json @@ -1365,5 +1365,10 @@ "SpecialFeatures": "Besonderheiten", "Poster": "Poster", "Photo": "Foto", - "Other": "Sonstiges" + "Other": "Sonstiges", + "Bwdif": "BWDIF", + "UseDoubleRateDeinterlacingHelp": "Diese Einstellung verwendet die Halbbildrate beim Deinterlacing, oft auch als Bob-Deinterlacing bezeichnet, die die Bildrate des Videos verdoppelt, um eine vollständige Bewegung wie beim Betrachten von Interlaced-Video auf einem Fernseher zu erzielen.", + "UseDoubleRateDeinterlacing": "Verdoppelung der Bildfrequenz beim Deinterlacing", + "LabelIconMaxResHelp": "Maximale Auflösung der Icons, die über die Eigenschaft upnp:icon bereitgestellt wird.", + "LabelAlbumArtMaxResHelp": "Maximale Auflösung des Albumcovers, die über die Eigenschaft upnp:albumArtURI bereitgestellt wird." } From 8c0e35487484cb9145a5a74abe6eb0002a6c9eb2 Mon Sep 17 00:00:00 2001 From: Hilman Maulana Date: Fri, 11 Sep 2020 05:08:27 +0000 Subject: [PATCH 054/281] Translated using Weblate (Indonesian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/id/ --- src/strings/id.json | 296 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 286 insertions(+), 10 deletions(-) diff --git a/src/strings/id.json b/src/strings/id.json index 1d5ef06332..c7a83a9efa 100644 --- a/src/strings/id.json +++ b/src/strings/id.json @@ -3,8 +3,8 @@ "ButtonSignOut": "Sign out", "HeaderEasyPinCode": "Kode Pin Mudah", "HeaderSetupLibrary": "Atur pustaka media Anda", - "LabelContentType": "Tipe konten:", - "LabelCountry": "Negara:", + "LabelContentType": "Tipe konten :", + "LabelCountry": "Negara :", "LabelFinish": "Selesai", "LabelLanguage": "Bahasa:", "LabelSaveLocalMetadata": "Simpan artwork dan metadata ke dalam folder media", @@ -31,7 +31,7 @@ "Favorites": "Favorit", "Genres": "Aliran", "HeaderAlbumArtists": "Album Artis", - "HeaderContinueWatching": "Lanjutkan Menonton", + "HeaderContinueWatching": "Lanjut Menonton", "Artists": "Artis", "AllowMediaConversion": "Izinkan konversi media", "AllEpisodes": "Semua episode", @@ -203,7 +203,7 @@ "DeleteImageConfirmation": "Anda yakin ingin menghapus gambar ini?", "DeleteImage": "Hapus Gambar", "DeleteDeviceConfirmation": "Anda yakin ingin menghapus perangkat ini? Ini akan muncul kembali saat pengguna login lagi.", - "DeinterlaceMethodHelp": "Pilih metode deinterlacing yang akan digunakan saat melakukan transcoding konten interlace.", + "DeinterlaceMethodHelp": "Pilih metode deinterlacing yang akan digunakan saat software mentranskode konten yang saling terkait. Ketika akselerasi perangkat keras yang mendukung penghilangan interlacing perangkat keras diaktifkan, penghilang antar-kabel perangkat keras akan digunakan alih-alih pengaturan ini.", "DefaultSubtitlesHelp": "Subtitel dimuat berdasarkan bendera default dan paksa dalam metadata yang disematkan. Preferensi bahasa dipertimbangkan ketika beberapa opsi tersedia.", "CustomDlnaProfilesHelp": "Buat profil khusus untuk menargetkan perangkat baru atau mengganti profil sistem.", "ColorTransfer": "Transfer warna", @@ -253,7 +253,7 @@ "LanNetworksHelp": "Daftar alamat IP atau entri IP / netmask yang dipisahkan koma untuk jaringan yang akan dipertimbangkan di jaringan lokal saat memberlakukan pembatasan bandwidth. Jika disetel, semua alamat IP lainnya akan dianggap berada di jaringan eksternal dan tunduk pada pembatasan bandwidth eksternal. Jika dibiarkan kosong, hanya subnet server yang dianggap berada di jaringan lokal.", "DashboardServerName": "Server : {0}", "LabelUserRemoteClientBitrateLimitHelp": "Ganti nilai global default yang ditetapkan di pengaturan pemutaran server.", - "LabelTranscodingTempPathHelp": "Tentukan jalur kustom untuk file transcode yang disajikan ke klien. Biarkan kosong untuk menggunakan default server.", + "LabelTranscodingTempPathHelp": "Tentukan lokasi kustom untuk file transcode yang disajikan ke klien. Biarkan kosong untuk menggunakan default server.", "LabelSyncPlayTimeOffset": "Pengimbangan waktu dengan server :", "LabelServerName": "Nama Server :", "LabelServerHostHelp": "192.168.1.100:8096 atau https://myserver.com", @@ -264,7 +264,7 @@ "LabelMoviePrefixHelp": "Jika prefiks diterapkan pada judul film, masukkan di sini agar server dapat menanganinya dengan benar.", "LabelLocalHttpServerPortNumberHelp": "Nomor port TCP untuk server HTTP.", "LabelLocalHttpServerPortNumber": "Nomor port HTTP lokal :", - "LabelKodiMetadataEnablePathSubstitutionHelp": "Mengaktifkan substitusi jalur dari jalur gambar menggunakan pengaturan substitusi jalur server.", + "LabelKodiMetadataEnablePathSubstitutionHelp": "Mengaktifkan substitusi lokasi dari lokasi gambar menggunakan pengaturan substitusi lokasi server.", "LabelHttpsPortHelp": "Nomor port TCP untuk server HTTPS.", "LabelServerNameHelp": "Nama ini akan digunakan untuk mengidentifikasi server dan akan menggunakan nama host server secara default.", "LabelBaseUrlHelp": "Tambahkan subdirektori khusus ke URL server. Misalnya: http://example.com/<baseurl> ", @@ -277,7 +277,7 @@ "LabelAbortedByServerShutdown": "(Dibatalkan oleh penghentian server)", "HeaderServerSettings": "Pengaturan Server", "HeaderServerAddressSettings": "Pengaturan Alamat Server", - "HeaderSelectServerCachePathHelp": "Jelajahi atau masukkan jalur yang akan digunakan untuk file cache server. Folder harus dapat akses.", + "HeaderSelectServerCachePathHelp": "Jelajahi atau masukkan lokasi yang akan digunakan untuk file cache server. Folder harus dapat akses.", "HeaderSelectServerCachePath": "Pilih lokasi Cache Server", "HeaderProfileServerSettingsHelp": "Nilai-nilai ini mengontrol bagaimana server akan menampilkan dirinya kepada klien.", "HeaderConnectToServer": "Sambungkan ke server", @@ -348,7 +348,7 @@ "Features": "Fitur", "Favorite": "Favorit", "FastForward": "Maju cepat", - "FFmpegSavePathNotFound": "Kami tidak dapat menemukan FFmpeg menggunakan jalur yang Anda masukkan. FFprobe juga diperlukan dan harus ada di folder yang sama. Komponen ini biasanya digabungkan dalam unduhan yang sama. Harap periksa jalurnya dan coba lagi.", + "FFmpegSavePathNotFound": "Kami tidak dapat menemukan FFmpeg menggunakan lokasi yang Anda masukkan. FFprobe juga diperlukan dan harus ada di folder yang sama. Komponen ini biasanya digabungkan dalam unduhan yang sama. Harap periksa lokasi dan coba lagi.", "Extras": "Ekstra", "ExtractChapterImagesHelp": "Mengekstrak gambar bab akan memungkinkan klien untuk menampilkan menu pemilihan adegan grafis. Prosesnya bisa lambat, membutuhkan banyak sumber daya, dan mungkin memerlukan beberapa gigabyte ruang. Ini berjalan saat video ditemukan, dan juga sebagai tugas yang dijadwalkan setiap malam. Jadwal dapat dikonfigurasi di area tugas terjadwal. Tidak disarankan untuk menjalankan tugas ini selama jam penggunaan puncak.", "ExtraLarge": "Ekstra besar", @@ -360,7 +360,7 @@ "ErrorGettingTvLineups": "Terjadi kesalahan saat mengunduh daftar TV. Harap pastikan informasi Anda benar dan coba lagi.", "ErrorAddingXmlTvFile": "Ada kesalahan saat mengakses file XMLTV. Harap pastikan file tersebut ada dan coba lagi.", "ErrorAddingTunerDevice": "Terjadi kesalahan saat menambahkan perangkat tuner. Harap pastikan itu dapat diakses dan coba lagi.", - "ErrorAddingMediaPathToVirtualFolder": "Terjadi kesalahan saat menambahkan jalur media. Harap pastikan jalurnya valid dan Jellyfin memiliki akses ke lokasi itu.", + "ErrorAddingMediaPathToVirtualFolder": "Terjadi kesalahan saat menambahkan lokasi media. Harap pastikan lokasi valid dan Jellyfin memiliki akses ke lokasi itu.", "ErrorAddingListingsToSchedulesDirect": "Terjadi kesalahan saat menambahkan daftar ke akun Jadwal Langsung Anda. Jadwal Langsung hanya mengizinkan jumlah daftar terbatas per akun. Anda mungkin perlu masuk ke situs web Jadwal Langsung dan menghapus daftar orang lain dari akun Anda sebelum melanjutkan.", "Episodes": "Episodes", "Episode": "Episode", @@ -371,5 +371,281 @@ "EnableThemeVideosHelp": "Putar video tema di latar belakang saat menjelajahi pustaka.", "EnableThemeSongsHelp": "Putar lagu tema di latar belakang saat menjelajahi pustaka.", "EnableStreamLoopingHelp": "Aktifkan ini jika live streaming hanya berisi beberapa detik data dan perlu terus diminta. Mengaktifkan ini saat tidak diperlukan dapat menyebabkan masalah.", - "EnableStreamLooping": "Putar otomatis live streaming" + "EnableStreamLooping": "Putar otomatis live streaming", + "LabelEnableAutomaticPortMap": "Aktifkan pemetaan port otomatis", + "LabelEmbedAlbumArtDidlHelp": "Beberapa perangkat lebih memilih metode ini untuk mendapatkan seni album. Orang lain mungkin gagal bermain dengan opsi ini diaktifkan.", + "LabelEmbedAlbumArtDidl": "Sematkan seni album di Didl", + "LabelEasyPinCode": "Kode pin mudah :", + "LabelDynamicExternalId": "{0} Id:", + "LabelDropShadow": "Bayangan jatuh :", + "LabelDroppedFrames": "Frame jatuh :", + "LabelDropImageHere": "Lepaskan gambar di sini, atau klik untuk menelusuri.", + "LabelDownloadLanguages": "Unduh bahasa :", + "LabelDownMixAudioScaleHelp": "Tingkatkan audio saat downmixing. Nilai satu akan mempertahankan volume aslinya.", + "LabelDownMixAudioScale": "Peningkatan audio saat downmixing :", + "LabelDisplaySpecialsWithinSeasons": "Tampilkan spesial dalam musim mereka ditayangkan", + "LabelDisplayOrder": "Urutan tampilan :", + "LabelDisplayName": "Nama tampilan :", + "LabelDisplayMode": "Mode tampilan :", + "LabelDisplayLanguageHelp": "Menerjemahkan Jellyfin adalah proyek yang sedang berlangsung.", + "LabelDisplayLanguage": "Bahasa tampilan :", + "LabelDiscNumber": "Nomor disk :", + "LabelDidlMode": "Mode DIDL :", + "LabelDeviceDescription": "Deskripsi perangkat", + "LabelDeinterlaceMethod": "Metode deinterlacing :", + "LabelDefaultUserHelp": "Menentukan pustaka pengguna mana yang harus ditampilkan pada perangkat yang terhubung. Ini dapat diganti untuk setiap perangkat menggunakan profil.", + "LabelDefaultUser": "Pengguna awal :", + "LabelDefaultScreen": "Layar awal :", + "LabelDeathDate": "Tanggal kematian :", + "LabelDay": "Hari :", + "LabelDateTimeLocale": "Tanggal waktu lokal :", + "LabelDateAddedBehaviorHelp": "Jika ada nilai metadata, nilai itu akan selalu digunakan sebelum salah satu opsi ini.", + "LabelDateAddedBehavior": "Tanggal ditambahkan perilaku untuk konten baru :", + "LabelDateAdded": "Tanggal Ditambahkan :", + "LabelCustomRating": "Peringkat khusus :", + "LabelCustomDeviceDisplayNameHelp": "Berikan nama tampilan khusus atau biarkan kosong untuk menggunakan nama yang dilaporkan oleh perangkat.", + "LabelCustomCssHelp": "Terapkan gaya kustom Anda sendiri di antarmuka web.", + "LabelCustomCss": "CSS Kustom :", + "LabelCurrentPassword": "Kata sandi saat ini :", + "LabelCriticRating": "Peringkat kritik :", + "LabelCorruptedFrames": "Bingkai rusak :", + "LabelCommunityRating": "Peringkat komunitas :", + "LabelCollection": "Koleksi :", + "LabelChannels": "Saluran :", + "LabelCertificatePasswordHelp": "Jika sertifikat Anda memerlukan kata sandi, harap masukkan di sini.", + "LabelCertificatePassword": "Kata sandi sertifikat :", + "LabelCancelled": "Dibatalkan", + "LabelCache": "Cache :", + "LabelBurnSubtitles": "Membakar subtitle :", + "LabelBlockContentWithTags": "Blokir item dengan tag :", + "LabelBlastMessageIntervalHelp": "Menentukan durasi dalam detik antara pesan ledakan hidup.", + "LabelBlastMessageInterval": "Interval pesan hidup", + "LabelBitrate": "Bitrate :", + "LabelBirthYear": "Tahun lahir :", + "LabelBirthDate": "Tanggal lahir :", + "LabelBindToLocalNetworkAddress": "Ikat ke alamat jaringan lokal :", + "LabelAutomaticallyRefreshInternetMetadataEvery": "Segarkan metadata secara otomatis dari internet :", + "LabelAuthProvider": "Penyedia Otentikasi :", + "LabelAudioSampleRate": "Tingkat sampel audio :", + "LabelAudioLanguagePreference": "Bahasa audio yang disukai :", + "LabelAudioCodec": "Codec audio :", + "LabelAudioChannels": "Saluran audio :", + "LabelAudioBitrate": "Kecepatan bit audio :", + "LabelAudioBitDepth": "Kedalaman bit audio :", + "LabelArtistsHelp": "Pisahkan beberapa artis dengan titik koma.", + "LabelArtists": "Artis :", + "LabelAppNameExample": "Contoh : Sickbeard, Sonarr", + "LabelAppName": "Nama aplikasi", + "LabelAllowedRemoteAddressesMode": "Mode filter alamat IP jarak jauh :", + "LabelAllowedRemoteAddresses": "Filter alamat IP jarak jauh :", + "LabelAllowHWTranscoding": "Izinkan transcoding perangkat keras", + "LabelAlbumArtists": "Artis album :", + "LabelAlbumArtPN": "Seni album PN :", + "LabelAlbumArtMaxWidth": "Lebar maksimal seni album :", + "LabelAlbumArtMaxHeight": "Tinggi maksimal seni album :", + "LabelAlbumArtHelp": "PN digunakan untuk seni album, dalam atribut dlna : profileID di upnp : albumArtURI. Beberapa perangkat memerlukan nilai tertentu, terlepas dari ukuran gambarnya.", + "LabelAlbumArtMaxResHelp": "Resolusi maksimum seni album yang diekspos melalui properti upnp : albumArtURI.", + "LabelAlbum": "Album :", + "LabelAirsBeforeSeason": "Tayang sebelum musim :", + "LabelAirsBeforeEpisode": "Tayang setelah musim :", + "LabelAirsAfterSeason": "Tayang setelah musim :", + "LabelAirTime": "Jam tayang :", + "LabelAirDays": "Hari tayang :", + "LabelAccessStart": "Waktu mulai :", + "LabelAccessEnd": "Akhir waktu :", + "LabelAccessDay": "Hari dalam seminggu :", + "Label3DFormat": "Format 3D :", + "Kids": "Anak-anak", + "Items": "Item", + "ItemCount": "{0} item", + "InstantMix": "Instant mix", + "InstallingPackage": "Memasang {0} (versi {1})", + "ImportMissingEpisodesHelp": "Informasi tentang episode yang hilang akan diimpor ke database Anda dan ditampilkan dalam musim dan serial. Ini dapat menyebabkan pemindaian pustaka jauh lebih lama.", + "ImportFavoriteChannelsHelp": "Hanya saluran yang ditandai sebagai favorit di perangkat tuner yang akan diimpor.", + "Images": "Gambar", + "Image": "Gambar", + "Identify": "Mengenali", + "HttpsRequiresCert": "Untuk mengaktifkan koneksi aman, Anda perlu memberikan sertifikat SSL terpercaya, seperti Let's Encrypt. Harap berikan sertifikat, atau nonaktifkan koneksi aman.", + "Horizontal": "Horisontal", + "Home": "Home", + "HideWatchedContentFromLatestMedia": "Sembunyikan konten yang ditonton dari media terbaru", + "Hide": "Sembunyikan", + "Help": "Tolong", + "HeaderYears": "Tahun", + "HeaderXmlSettings": "Pengaturan Xml", + "HeaderXmlDocumentAttributes": "Atribut Dokumen Xml", + "HeaderXmlDocumentAttribute": "Atribut Dokumen Xml", + "HeaderVideos": "Video", + "HeaderVideoTypes": "Jenis Video", + "HeaderVideoType": "Jenis Video", + "HeaderVideoQuality": "Kualitas video", + "HeaderUsers": "Pengguna", + "HeaderUser": "Pengguna", + "HeaderUploadImage": "Unggah Gambar", + "HeaderUpcomingOnTV": "Yang Akan Datang Di TV", + "HeaderTypeText": "Masukkan teks", + "HeaderTypeImageFetchers": "{0} Pengambil Gambar", + "HeaderTuners": "Tuner", + "HeaderTunerDevices": "Perangkat Tuner", + "HeaderTranscodingProfileHelp": "Tambahkan profil transcoding untuk menunjukkan format mana yang harus digunakan saat transcoding diperlukan.", + "HeaderTranscodingProfile": "Profil Transcoding", + "HeaderTracks": "Trek", + "HeaderThisUserIsCurrentlyDisabled": "Pengguna saat ini dinonaktifkan", + "HeaderTaskTriggers": "Pemicu Tugas", + "HeaderSystemDlnaProfiles": "Profil Sistem", + "HeaderSyncPlayEnabled": "SyncPlay diaktifkan", + "HeaderSyncPlaySelectGroup": "Bergabung dengan grup", + "HeaderSubtitleProfilesHelp": "Profil subtitle mendeskripsikan format subtitle yang didukung oleh perangkat.", + "HeaderSubtitleProfiles": "Profil Subtitle", + "HeaderSubtitleProfile": "Profil Subtitle", + "HeaderSubtitleDownloads": "Download Subtitle", + "HeaderSubtitleAppearance": "Penampilan Subtitle", + "HeaderStopRecording": "Berhenti Merekam", + "HeaderStatus": "Status", + "HeaderStartNow": "Mulai sekarang", + "HeaderSpecialEpisodeInfo": "Info Episode Spesial", + "HeaderSortOrder": "Urutan Sortir", + "HeaderSortBy": "Sortir dengan", + "HeaderSeriesStatus": "Status Seri", + "HeaderSeriesOptions": "Opsi Seri", + "HeaderSendMessage": "Mengirim pesan", + "HeaderSecondsValue": "{0} Detik", + "HeaderSeasons": "Musim", + "HeaderScenes": "Adegan", + "HeaderRunningTasks": "Menjalankan Tugas", + "HeaderRevisionHistory": "Jejak Revisi", + "HeaderRecordingPostProcessing": "Merekam Post Processing", + "PathNotFound": "Lokasi tidak dapat ditemukan. Harap pastikan lokasinya valid dan coba lagi.", + "XmlTvPathHelp": "Lokasi ke file XMLTV. Jellyfin akan membaca file ini dan secara berkala memeriksanya untuk pembaruan. Anda bertanggung jawab untuk membuat dan memperbarui file.", + "MessageChangeRecordingPath": "Mengubah folder rekaman Anda tidak akan memindahkan rekaman yang ada dari lokasi lama ke yang baru. Anda harus memindahkannya secara manual jika diinginkan.", + "MediaInfoPath": "Lokasi", + "LabelffmpegPathHelp": "Lokasi ke file aplikasi ffmpeg atau folder yang berisi ffmpeg.", + "LabelffmpegPath": "Lokasi FFmpeg :", + "LabelTranscodePath": "Lokasi transcode :", + "LabelSeriesRecordingPath": "Lokasi perekaman seri :", + "LabelRecordingPath": "Lokasi awal perekaman :", + "LabelPostProcessorArgumentsHelp": "Gunakan {path} sebagai lokasi ke file rekaman.", + "LabelPath": "Lokasi :", + "LabelOptionalNetworkPathHelp": "Jika folder ini dibagikan di jaringan Anda, menyediakan lokasi berbagi jaringan dapat memungkinkan klien di perangkat lain untuk mengakses file media secara langsung. Misalnya, {0} atau {1}.", + "LabelOptionalNetworkPath": "Folder jaringan bersama :", + "LabelMovieRecordingPath": "Lokasi perekaman film :", + "LabelMetadataPathHelp": "Tentukan lokasi khusus untuk karya seni dan metadata yang diunduh.", + "LabelMetadataPath": "Lokasi metadata :", + "LabelKodiMetadataSaveImagePathsHelp": "Ini disarankan jika Anda memiliki nama file gambar yang tidak sesuai dengan pedoman Kodi.", + "LabelKodiMetadataSaveImagePaths": "Simpan lokasi gambar dalam file nfo", + "LabelKodiMetadataEnablePathSubstitution": "Aktifkan substitusi lokasi", + "LabelCustomCertificatePathHelp": "Lokasi ke file PKCS #12 yang berisi sertifikat dan kunci pribadi untuk mengaktifkan dukungan TLS di domain khusus.", + "LabelCustomCertificatePath": "Lokasi khusus sertifikat SSL :", + "LabelCachePath": "Lokasi cache :", + "HeaderSelectTranscodingPathHelp": "Jelajahi atau masukkan lokasi yang akan digunakan untuk file transcode. Folder tersebut harus dapat ditulisi.", + "HeaderSelectMetadataPath": "Pilih Lokasi Metadata", + "HeaderSelectCertificatePath": "Pilih Lokasi Sertifikat", + "HeaderSelectTranscodingPath": "Pilih Lokasi Transcoding Temporary", + "HeaderSelectPath": "Pilih Lokasi", + "HeaderSelectMetadataPathHelp": "Jelajahi atau masukkan lokasi yang ingin Anda gunakan untuk metadata. Folder tersebut harus dapat ditulisi.", + "HeaderRemoteAccessSettings": "Pengaturan Akses Jarak Jauh", + "HeaderResponseProfile": "Profil Tanggapan", + "HeaderRemoveMediaLocation": "Hapus Lokasi Media", + "HeaderRemoveMediaFolder": "Hapus Folder Media", + "HeaderRemoteControl": "Kontrol Jarak Jauh", + "HeaderResponseProfileHelp": "Profil respons menyediakan cara untuk menyesuaikan informasi yang dikirim ke perangkat saat memutar jenis media tertentu.", + "HeaderRecordingOptions": "Opsi Perekaman", + "HeaderRecentlyPlayed": "Terakhir diputar", + "HeaderProfileInformation": "Informasi Profil", + "HeaderPreferredMetadataLanguage": "Bahasa Metadata Pilihan", + "HeaderPluginInstallation": "Instalasi Plugin", + "HeaderPleaseSignIn": "Silakan masuk", + "HeaderPlaybackError": "Kesalahan Pemutaran", + "HeaderPlayback": "Pemutaran Media", + "HeaderPlayOn": "Mainkan", + "HeaderPlayAll": "Mainkan Semua", + "HeaderPinCodeReset": "Atur Ulang Kode Pin", + "HeaderPhotoAlbums": "Album Foto", + "HeaderPaths": "Lokasi", + "HeaderPasswordReset": "Atur Ulang Kata Sandi", + "HeaderPassword": "Kata sandi", + "HeaderParentalRatings": "Peringkat Orang Tua", + "HeaderOtherItems": "Item Lainnya", + "HeaderOnNow": "Sekarang", + "HeaderNextVideoPlayingInValue": "Video Berikutnya Diputar di {0}", + "HeaderNextEpisodePlayingInValue": "Episode Berikutnya Diputar di {0}", + "HeaderNewDevices": "Perangkat Baru", + "HeaderNewApiKey": "Kunci API Baru", + "HeaderNavigation": "Navigasi", + "HeaderMyMediaSmall": "Media Saya (kecil)", + "HeaderMyMedia": "Media Saya", + "HeaderMyDevice": "Perangkat Saya", + "HeaderMusicQuality": "Kualitas Musik", + "HeaderMoreLikeThis": "Lainnya Seperti Ini", + "HeaderMetadataSettings": "Pengaturan Metadata", + "HeaderMediaFolders": "Folder Media", + "HeaderMedia": "Media", + "HeaderLoginFailure": "Kegagalan Login", + "HeaderLiveTvTunerSetup": "Penyiapan TV Tuner Langsung", + "HeaderLibrarySettings": "Pengaturan Pustaka", + "HeaderLibraryOrder": "Memesan Pustaka", + "HeaderLibraryFolders": "Folder Pustaka", + "HeaderLibraryAccess": "Akses Pustaka", + "HeaderLibraries": "Pustaka", + "HeaderLatestRecordings": "Rekaman Terbaru", + "HeaderLatestMusic": "Musik Terbaru", + "HeaderLatestMovies": "Film Terbaru", + "HeaderLatestMedia": "Media Terbaru", + "HeaderLatestEpisodes": "Episode Terbaru", + "HeaderKodiMetadataHelp": "Untuk mengaktifkan atau menonaktifkan metadata NFO, edit perpustakaan dan temukan bagian penghemat metadata.", + "HeaderKeepSeries": "Pertahankan Seri", + "HeaderKeepRecording": "Terus Rekam", + "HeaderInstantMix": "Mix Instan", + "HeaderInstall": "Install", + "HeaderImageSettings": "Pengaturan Gambar", + "HeaderImageOptions": "Opsi Gambar", + "HeaderIdentifyItemHelp": "Masukkan satu atau lebih kriteria pencarian. Hapus kriteria untuk meningkatkan hasil pencarian.", + "HeaderIdentificationHeader": "Header Identifikasi", + "HeaderIdentificationCriteriaHelp": "Masukkan setidaknya satu kriteria identifikasi.", + "HeaderIdentification": "Identifikasi", + "HeaderHttpsSettings": "Pengaturan HTTPS", + "HeaderHttpHeaders": "Header HTTP", + "HeaderGuideProviders": "Penyedia Data Panduan TV", + "HeaderFrequentlyPlayed": "Sering Dimainkan", + "HeaderForKids": "Untuk anak-anak", + "HeaderFetcherSettings": "Pengaturan Pengambil", + "HeaderFetchImages": "Ambil Gambar :", + "HeaderFeatureAccess": "Akses Fitur", + "HeaderExternalIds": "ID Eksternal :", + "HeaderError": "Kesalahan", + "HeaderEnabledFieldsHelp": "Hapus centang pada bidang untuk menguncinya dan mencegah datanya berubah.", + "HeaderEnabledFields": "Bidang Diaktifkan", + "HeaderEditImages": "Edit Gambar", + "HeaderDVR": "DVR", + "HeaderDownloadSync": "Unduh & Sinkronkan", + "HeaderDirectPlayProfileHelp": "Tambahkan profil putar langsung untuk menunjukkan format mana yang dapat ditangani perangkat secara asli.", + "HeaderDirectPlayProfile": "Profil Putar Langsung", + "HeaderDevices": "Perangkat", + "HeaderDeviceAccess": "Akses Perangkat", + "HeaderDeveloperInfo": "Info Pengembang", + "HeaderDetectMyDevices": "Deteksi Perangkat Saya", + "HeaderDeleteTaskTrigger": "Hapus Pemicu Tugas", + "HeaderDeleteProvider": "Hapus Penyedia", + "HeaderDeleteItems": "Hapus Item", + "HeaderDeleteItem": "Hapus Item", + "HeaderDeleteDevice": "Hapus Perangkat", + "HeaderDefaultRecordingSettings": "Pengaturan Awal Perekaman", + "HeaderDateIssued": "Tanggal diterbitkan", + "HeaderCustomDlnaProfiles": "Profil Kustom", + "HeaderContinueListening": "Lanjut Mendengarkan", + "HeaderContainerProfileHelp": "Wadah profil menunjukkan batasan perangkat saat memainkan format tertentu. Jika batasan berlaku maka media akan ditranskode, bahkan jika formatnya dikonfigurasi untuk pemutaran langsung.", + "HeaderContainerProfile": "Wadah Profil", + "HeaderConnectionFailure": "Koneksi Bermasalah", + "HeaderConfirmRevokeApiKey": "Cabut Kunci API", + "HeaderConfirmProfileDeletion": "Konfirmasi Penghapusan Profil", + "HeaderConfirmPluginInstallation": "Konfirmasi Instalasi Plugin", + "HeaderConfigureRemoteAccess": "Konfigurasi Akses Jarak Jauh", + "HeaderCodecProfileHelp": "Profil codec menunjukkan batasan perangkat saat memainkan codec tertentu. Jika batasan berlaku maka media akan ditranskode, meskipun codec dikonfigurasi untuk pemutaran langsung.", + "HeaderCodecProfile": "Profil Codec", + "HeaderChapterImages": "Gambar Bagian", + "Other": "Lainnya", + "Directors": "Direktur", + "Director": "Direktur", + "Depressed": "Murung", + "Data": "Data" } From 111820fe84f8b5e9333d00598372008817584359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Kucharczyk?= Date: Fri, 11 Sep 2020 13:28:07 +0000 Subject: [PATCH 055/281] Translated using Weblate (Czech) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/cs/ --- src/strings/cs.json | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/strings/cs.json b/src/strings/cs.json index 22a8c4ae12..697f13ea7f 100644 --- a/src/strings/cs.json +++ b/src/strings/cs.json @@ -1373,5 +1373,29 @@ "Other": "Ostatní", "Bwdif": "BWDIF", "UseDoubleRateDeinterlacingHelp": "Toto nastavení při odstranění prokládání zdvojnásobuje snímkovou frekvenci, aby výsledné video vypadalo stejně plynule, jako při přehrávání prokládaného obsahu v televizi.", - "UseDoubleRateDeinterlacing": "Zdvojnásobit snímkovou frekvenci při odstranění prokládání" + "UseDoubleRateDeinterlacing": "Zdvojnásobit snímkovou frekvenci při odstranění prokládání", + "LabelTonemappingParamHelp": "Pro ladění algoritmu mapování tónů. Doporučená a výchozí hodnota je NaN. Obecně je pole ponecháváno prázdné.", + "LabelTonemappingParam": "Parametr mapování tónů:", + "LabelTonemappingPeakHelp": "Tato hodnota nahradí signální/nominální/referenční vrchol. Užitečné, pokud je informace o vrcholu z metadat nespolehlivá, nebo při mapování tónů z nižšího rozsahu na vyšší. Doporučená a výchozí hodnota je 0.", + "LabelTonemappingPeak": "Vrchol mapování tónů:", + "LabelTonemappingThresholdHelp": "Parametry algoritmu mapování tónů jsou přizpůsobené jednotlivým scénám. Tato mez se používá pro zjištění, zda se scéna změnila. Pokud rozdíl mezi aktuální průměrnou světlostí snímku a průběžným průměrem tuto mez překročí, bude průměr a vrchol světlosti scény přepočítán. Doporučené a výchozí hodnoty jsou 0,8 a 0,2.", + "LabelTonemappingThreshold": "Mez mapování tónů:", + "LabelTonemappingDesatHelp": "Snižuje barevnost příliš světlých míst obrazu. Vyšší hodnoty umožňují zachovat více barevných informací. Nepřirozené barvy v příliš světlých místech budou nahrazeny plynulým přechodem na bílou barvu a obraz tak bude vypadat přirozeněji na úkor barevných detailů v těchto místech. Doporučené a výchozí hodnoty jsou 0 a 0,5.", + "LabelTonemappingDesat": "Snížení barevnosti při mapování tónů:", + "TonemappingRangeHelp": "Výstupní rozsah barev. Automaticky znamená stejný jako vstupní.", + "LabelTonemappingRange": "Rozsah mapování tónů:", + "TonemappingAlgorithmHelp": "Mapování tonů je možné dále ladit. Pokud možnostem zde nerozumíte, je možné ponechat vše ve výchozím nastavení.
    Doporučená hodnota je Reinhard.", + "LabelTonemappingAlgorithm": "Algoritmus mapování tónů:", + "AllowTonemappingHelp": "Mapování tónů umožňuje změnit dynamický rozsah videa z HDR na SDR bez ztráty důležitých informací původního obrazu, např. detailů a barev.", + "EnableTonemapping": "Zapnout mapování tónů", + "LabelOpenclDeviceHelp": "Zařízení OpenCL použité pro mapování tónů. Nalevo od tečky je číslo platformy, napravo pak číslo zařízení na této platformě. Výchozí hodnota je 0.0. Soubor aplikace ffmpeg, který obsahuje metodu pro hardwarovou akceleraci OpenCL, je povinný.", + "LabelOpenclDevice": "Zařízení OpenCL:", + "LabelColorPrimaries": "Primární barvy:", + "LabelColorTransfer": "Převod barev:", + "LabelColorSpace": "Barevný prostor:", + "LabelVideoRange": "Rozsah videa:", + "MediaInfoColorPrimaries": "Primární barvy", + "MediaInfoColorTransfer": "Převod barev", + "MediaInfoColorSpace": "Barevný prostor", + "MediaInfoVideoRange": "Rozsah videa" } From 81166cffe1f71335cb958cd7e5cdbc064171c4fc Mon Sep 17 00:00:00 2001 From: ben-dl Date: Fri, 11 Sep 2020 18:06:09 +0000 Subject: [PATCH 056/281] Translated using Weblate (German) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/de/ --- src/strings/de.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/strings/de.json b/src/strings/de.json index 4e3a002b86..4baee1cb69 100644 --- a/src/strings/de.json +++ b/src/strings/de.json @@ -1370,5 +1370,11 @@ "UseDoubleRateDeinterlacingHelp": "Diese Einstellung verwendet die Halbbildrate beim Deinterlacing, oft auch als Bob-Deinterlacing bezeichnet, die die Bildrate des Videos verdoppelt, um eine vollständige Bewegung wie beim Betrachten von Interlaced-Video auf einem Fernseher zu erzielen.", "UseDoubleRateDeinterlacing": "Verdoppelung der Bildfrequenz beim Deinterlacing", "LabelIconMaxResHelp": "Maximale Auflösung der Icons, die über die Eigenschaft upnp:icon bereitgestellt wird.", - "LabelAlbumArtMaxResHelp": "Maximale Auflösung des Albumcovers, die über die Eigenschaft upnp:albumArtURI bereitgestellt wird." + "LabelAlbumArtMaxResHelp": "Maximale Auflösung des Albumcovers, die über die Eigenschaft upnp:albumArtURI bereitgestellt wird.", + "EnableTonemapping": "Tone Mapping aktivieren", + "LabelOpenclDeviceHelp": "Dies ist das OpenCL-Gerät, welches für Tone Mapping genutzt wird. Die linke Seite des Punktes ist die Plattform-Nummer, und die rechte Seite ist die Gerätenummer. Der Standardwert ist 0.0. ffmpeg mit OpenCL-Hardwarebeschleunigung wird benötigt.", + "LabelOpenclDevice": "OpenCL-Gerät:", + "LabelColorSpace": "Farbraum:", + "MediaInfoColorSpace": "Farbraum", + "VideoAudio": "Videoton" } From eec822ef34085e079e66948e8915078cbd6957ff Mon Sep 17 00:00:00 2001 From: dkanada Date: Sat, 12 Sep 2020 05:44:06 +0900 Subject: [PATCH 057/281] enable prefer-const rule for eslint --- .eslintrc.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index dfb65cb4d4..dc8729fb2a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -44,10 +44,9 @@ module.exports = { 'no-restricted-globals': ['error'].concat(restrictedGlobals), 'no-trailing-spaces': ['error'], '@babel/no-unused-expressions': ['error', { 'allowShortCircuit': true, 'allowTernary': true, 'allowTaggedTemplates': true }], - //'no-unused-vars': ['error', { 'vars': 'all', 'args': 'none', 'ignoreRestSiblings': true }], 'one-var': ['error', 'never'], 'padded-blocks': ['error', 'never'], - //'prefer-const': ['error', {'destructuring': 'all'}], + 'prefer-const': ['error', {'destructuring': 'all'}], 'quotes': ['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': false }], '@babel/semi': ['error'], 'space-before-blocks': ['error'], From a5776e98a72bae941c9c3e9f3f909bbb9dfbdb85 Mon Sep 17 00:00:00 2001 From: dkanada Date: Sat, 12 Sep 2020 05:46:15 +0900 Subject: [PATCH 058/281] always use const when possible --- src/components/notifications/notifications.js | 32 ++++----- src/components/playback/playbackmanager.js | 8 +-- .../subtitleeditor/subtitleeditor.js | 70 +++++++++---------- src/components/viewContainer.js | 2 +- src/controllers/movies/movies.js | 8 +-- src/controllers/movies/moviesrecommended.js | 14 ++-- src/plugins/comicsPlayer/plugin.js | 24 +++---- src/scripts/clientUtils.js | 2 +- 8 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index cf3ae88345..7f0e68f1d9 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -31,7 +31,7 @@ function closeAfter(notification, timeoutMs) { function resetRegistration() { /* eslint-disable-next-line compat/compat */ - let serviceWorker = navigator.serviceWorker; + const serviceWorker = navigator.serviceWorker; if (serviceWorker) { serviceWorker.ready.then(function (registration) { serviceWorkerRegistration = registration; @@ -47,7 +47,7 @@ function showPersistentNotification(title, options, timeoutMs) { function showNonPersistentNotification(title, options, timeoutMs) { try { - let notif = new Notification(title, options); /* eslint-disable-line compat/compat */ + const notif = new Notification(title, options); /* eslint-disable-line compat/compat */ if (notif.show) { notif.show(); @@ -67,7 +67,7 @@ function showNonPersistentNotification(title, options, timeoutMs) { } function showNotification(options, timeoutMs, apiClient) { - let title = options.title; + const title = options.title; options.data = options.data || {}; options.data.serverId = apiClient.serverInfo().Id; @@ -95,7 +95,7 @@ function showNewItemNotification(item, apiClient) { body = item.SeriesName + ' - ' + body; } - let notification = { + const notification = { title: 'New ' + item.Type, body: body, vibrate: true, @@ -103,7 +103,7 @@ function showNewItemNotification(item, apiClient) { data: {} }; - let imageTags = item.ImageTags || {}; + const imageTags = item.ImageTags || {}; if (imageTags.Primary) { notification.icon = apiClient.getScaledImageUrl(item.Id, { @@ -117,7 +117,7 @@ function showNewItemNotification(item, apiClient) { } function onLibraryChanged(data, apiClient) { - let newItems = data.ItemsAdded; + const newItems = data.ItemsAdded; if (!newItems.length) { return; @@ -140,7 +140,7 @@ function onLibraryChanged(data, apiClient) { EnableTotalRecordCount: false }).then(function (result) { - let items = result.Items; + const items = result.Items; for (const item of items) { showNewItemNotification(item, apiClient); @@ -159,7 +159,7 @@ function showPackageInstallNotification(apiClient, installation, status) { return; } - let notification = { + const notification = { tag: 'install' + installation.Id, data: {} }; @@ -188,12 +188,12 @@ function showPackageInstallNotification(apiClient, installation, status) { } if (status === 'progress') { - let percentComplete = Math.round(installation.PercentComplete || 0); + const percentComplete = Math.round(installation.PercentComplete || 0); notification.body = percentComplete + '% complete.'; } - let timeout = status === 'cancelled' ? 5000 : 0; + const timeout = status === 'cancelled' ? 5000 : 0; showNotification(notification, timeout, apiClient); }); @@ -220,8 +220,8 @@ events.on(serverNotifications, 'PackageInstalling', function (e, apiClient, data }); events.on(serverNotifications, 'ServerShuttingDown', function (e, apiClient, data) { - let serverId = apiClient.serverInfo().Id; - let notification = { + const serverId = apiClient.serverInfo().Id; + const notification = { tag: 'restart' + serverId, title: globalize.translate('ServerNameIsShuttingDown', apiClient.serverInfo().Name) }; @@ -229,8 +229,8 @@ events.on(serverNotifications, 'ServerShuttingDown', function (e, apiClient, dat }); events.on(serverNotifications, 'ServerRestarting', function (e, apiClient, data) { - let serverId = apiClient.serverInfo().Id; - let notification = { + const serverId = apiClient.serverInfo().Id; + const notification = { tag: 'restart' + serverId, title: globalize.translate('ServerNameIsRestarting', apiClient.serverInfo().Name) }; @@ -238,8 +238,8 @@ events.on(serverNotifications, 'ServerRestarting', function (e, apiClient, data) }); events.on(serverNotifications, 'RestartRequired', function (e, apiClient) { - let serverId = apiClient.serverInfo().Id; - let notification = { + const serverId = apiClient.serverInfo().Id; + const notification = { tag: 'restart' + serverId, title: globalize.translate('PleaseRestartServerName', apiClient.serverInfo().Name) }; diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 82bce8075e..a68663a769 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1110,8 +1110,8 @@ class PlaybackManager { self.increasePlaybackRate = function (player) { player = player || self._currentPlayer; if (player) { - let current = self.getPlaybackRate(player); - let supported = self.getSupportedPlaybackRates(player); + const current = self.getPlaybackRate(player); + const supported = self.getSupportedPlaybackRates(player); let index = -1; for (let i = 0, length = supported.length; i < length; i++) { @@ -1129,8 +1129,8 @@ class PlaybackManager { self.decreasePlaybackRate = function (player) { player = player || self._currentPlayer; if (player) { - let current = self.getPlaybackRate(player); - let supported = self.getSupportedPlaybackRates(player); + const current = self.getPlaybackRate(player); + const supported = self.getSupportedPlaybackRates(player); let index = -1; for (let i = 0, length = supported.length; i < length; i++) { diff --git a/src/components/subtitleeditor/subtitleeditor.js b/src/components/subtitleeditor/subtitleeditor.js index 2ade9966cb..8697a9a747 100644 --- a/src/components/subtitleeditor/subtitleeditor.js +++ b/src/components/subtitleeditor/subtitleeditor.js @@ -18,9 +18,9 @@ let currentItem; let hasChanges; function downloadRemoteSubtitles(context, id) { - let url = 'Items/' + currentItem.Id + '/RemoteSearch/Subtitles/' + id; + const url = 'Items/' + currentItem.Id + '/RemoteSearch/Subtitles/' + id; - let apiClient = window.connectionManager.getApiClient(currentItem.ServerId); + const apiClient = window.connectionManager.getApiClient(currentItem.ServerId); apiClient.ajax({ type: 'POST', @@ -38,7 +38,7 @@ function downloadRemoteSubtitles(context, id) { } function deleteLocalSubtitle(context, index) { - let msg = globalize.translate('MessageAreYouSureDeleteSubtitles'); + const msg = globalize.translate('MessageAreYouSureDeleteSubtitles'); import('confirm').then(({default: confirm}) => { confirm({ @@ -51,10 +51,10 @@ function deleteLocalSubtitle(context, index) { }).then(function () { loading.show(); - let itemId = currentItem.Id; - let url = 'Videos/' + itemId + '/Subtitles/' + index; + const itemId = currentItem.Id; + const url = 'Videos/' + itemId + '/Subtitles/' + index; - let apiClient = window.connectionManager.getApiClient(currentItem.ServerId); + const apiClient = window.connectionManager.getApiClient(currentItem.ServerId); apiClient.ajax({ @@ -70,9 +70,9 @@ function deleteLocalSubtitle(context, index) { } function fillSubtitleList(context, item) { - let streams = item.MediaStreams || []; + const streams = item.MediaStreams || []; - let subs = streams.filter(function (s) { + const subs = streams.filter(function (s) { return s.Type === 'Subtitle'; }); @@ -86,7 +86,7 @@ function fillSubtitleList(context, item) { html += subs.map(function (s) { let itemHtml = ''; - let tagName = layoutManager.tv ? 'button' : 'div'; + const tagName = layoutManager.tv ? 'button' : 'div'; let className = layoutManager.tv && s.Path ? 'listItem listItem-border btnDelete' : 'listItem listItem-border'; if (layoutManager.tv) { @@ -126,7 +126,7 @@ function fillSubtitleList(context, item) { html += '
    '; } - let elem = context.querySelector('.subtitleList'); + const elem = context.querySelector('.subtitleList'); if (subs.length) { elem.classList.remove('hide'); @@ -137,18 +137,18 @@ function fillSubtitleList(context, item) { } function fillLanguages(context, apiClient, languages) { - let selectLanguage = context.querySelector('#selectLanguage'); + const selectLanguage = context.querySelector('#selectLanguage'); selectLanguage.innerHTML = languages.map(function (l) { return ''; }); - let lastLanguage = userSettings.get('subtitleeditor-language'); + const lastLanguage = userSettings.get('subtitleeditor-language'); if (lastLanguage) { selectLanguage.value = lastLanguage; } else { apiClient.getCurrentUser().then(function (user) { - let lang = user.Configuration.SubtitleLanguagePreference; + const lang = user.Configuration.SubtitleLanguagePreference; if (lang) { selectLanguage.value = lang; @@ -171,9 +171,9 @@ function renderSearchResults(context, results) { context.querySelector('.noSearchResults').classList.add('hide'); for (let i = 0, length = results.length; i < length; i++) { - let result = results[i]; + const result = results[i]; - let provider = result.ProviderName; + const provider = result.ProviderName; if (provider !== lastProvider) { if (i > 0) { @@ -184,7 +184,7 @@ function renderSearchResults(context, results) { lastProvider = provider; } - let tagName = layoutManager.tv ? 'button' : 'div'; + const tagName = layoutManager.tv ? 'button' : 'div'; let className = layoutManager.tv ? 'listItem listItem-border btnOptions' : 'listItem listItem-border'; if (layoutManager.tv) { className += ' listItem-focusscale listItem-button'; @@ -194,7 +194,7 @@ function renderSearchResults(context, results) { html += ''; - let bodyClass = result.Comment || result.IsHashMatch ? 'three-line' : 'two-line'; + const bodyClass = result.Comment || result.IsHashMatch ? 'three-line' : 'two-line'; html += '
    '; @@ -231,7 +231,7 @@ function renderSearchResults(context, results) { html += '
    '; } - let elem = context.querySelector('.subtitleResults'); + const elem = context.querySelector('.subtitleResults'); elem.innerHTML = html; loading.hide(); @@ -242,8 +242,8 @@ function searchForSubtitles(context, language) { loading.show(); - let apiClient = window.connectionManager.getApiClient(currentItem.ServerId); - let url = apiClient.getUrl('Items/' + currentItem.Id + '/RemoteSearch/Subtitles/' + language); + const apiClient = window.connectionManager.getApiClient(currentItem.ServerId); + const url = apiClient.getUrl('Items/' + currentItem.Id + '/RemoteSearch/Subtitles/' + language); apiClient.getJSON(url).then(function (results) { renderSearchResults(context, results); @@ -258,7 +258,7 @@ function reload(context, apiClient, itemId) { fillSubtitleList(context, item); let file = item.Path || ''; - let index = Math.max(file.lastIndexOf('/'), file.lastIndexOf('\\')); + const index = Math.max(file.lastIndexOf('/'), file.lastIndexOf('\\')); if (index > -1) { file = file.substring(index + 1); } @@ -282,9 +282,9 @@ function reload(context, apiClient, itemId) { } function onSearchSubmit(e) { - let form = this; + const form = this; - let lang = form.querySelector('#selectLanguage', form).value; + const lang = form.querySelector('#selectLanguage', form).value; searchForSubtitles(dom.parentWithClass(form, 'formDialogContent'), lang); @@ -293,10 +293,10 @@ function onSearchSubmit(e) { } function onSubtitleListClick(e) { - let btnDelete = dom.parentWithClass(e.target, 'btnDelete'); + const btnDelete = dom.parentWithClass(e.target, 'btnDelete'); if (btnDelete) { - let index = btnDelete.getAttribute('data-index'); - let context = dom.parentWithClass(btnDelete, 'subtitleEditorDialog'); + const index = btnDelete.getAttribute('data-index'); + const context = dom.parentWithClass(btnDelete, 'subtitleEditorDialog'); deleteLocalSubtitle(context, index); } } @@ -305,14 +305,14 @@ function onSubtitleResultsClick(e) { let subtitleId; let context; - let btnOptions = dom.parentWithClass(e.target, 'btnOptions'); + const btnOptions = dom.parentWithClass(e.target, 'btnOptions'); if (btnOptions) { subtitleId = btnOptions.getAttribute('data-subid'); context = dom.parentWithClass(btnOptions, 'subtitleEditorDialog'); showDownloadOptions(btnOptions, context, subtitleId); } - let btnDownload = dom.parentWithClass(e.target, 'btnDownload'); + const btnDownload = dom.parentWithClass(e.target, 'btnDownload'); if (btnDownload) { subtitleId = btnDownload.getAttribute('data-subid'); context = dom.parentWithClass(btnDownload, 'subtitleEditorDialog'); @@ -321,7 +321,7 @@ function onSubtitleResultsClick(e) { } function showDownloadOptions(button, context, subtitleId) { - let items = []; + const items = []; items.push({ name: globalize.translate('Download'), @@ -347,7 +347,7 @@ function showDownloadOptions(button, context, subtitleId) { function centerFocus(elem, horiz, on) { import('scrollHelper').then(({default: scrollHelper}) => { - let fn = on ? 'on' : 'off'; + const fn = on ? 'on' : 'off'; scrollHelper.centerFocus[fn](elem, horiz); }); } @@ -355,9 +355,9 @@ function centerFocus(elem, horiz, on) { function showEditorInternal(itemId, serverId, template) { hasChanges = false; - let apiClient = window.connectionManager.getApiClient(serverId); + const apiClient = window.connectionManager.getApiClient(serverId); return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) { - let dialogOptions = { + const dialogOptions = { removeOnClose: true, scrollY: false }; @@ -368,7 +368,7 @@ function showEditorInternal(itemId, serverId, template) { dialogOptions.size = 'small'; } - let dlg = dialogHelper.createDialog(dialogOptions); + const dlg = dialogHelper.createDialog(dialogOptions); dlg.classList.add('formDialog'); dlg.classList.add('subtitleEditorDialog'); @@ -379,7 +379,7 @@ function showEditorInternal(itemId, serverId, template) { dlg.querySelector('.subtitleSearchForm').addEventListener('submit', onSearchSubmit); - let btnSubmit = dlg.querySelector('.btnSubmit'); + const btnSubmit = dlg.querySelector('.btnSubmit'); if (layoutManager.tv) { centerFocus(dlg.querySelector('.formDialogContent'), false, true); @@ -388,7 +388,7 @@ function showEditorInternal(itemId, serverId, template) { btnSubmit.classList.add('hide'); } - let editorContent = dlg.querySelector('.formDialogContent'); + const editorContent = dlg.querySelector('.formDialogContent'); dlg.querySelector('.subtitleList').addEventListener('click', onSubtitleListClick); dlg.querySelector('.subtitleResults').addEventListener('click', onSubtitleResultsClick); diff --git a/src/components/viewContainer.js b/src/components/viewContainer.js index c39ad2ba84..0c0b705b52 100644 --- a/src/components/viewContainer.js +++ b/src/components/viewContainer.js @@ -14,7 +14,7 @@ import 'css!components/viewManager/viewContainer'; } controllerUrl = Dashboard.getPluginUrl(controllerUrl); - let apiUrl = ApiClient.getUrl('/web/' + controllerUrl); + const apiUrl = ApiClient.getUrl('/web/' + controllerUrl); return import(apiUrl).then((ControllerFactory) => { options.controllerFactory = ControllerFactory; }); diff --git a/src/controllers/movies/movies.js b/src/controllers/movies/movies.js index e05b1fa96a..01111d4c1b 100644 --- a/src/controllers/movies/movies.js +++ b/src/controllers/movies/movies.js @@ -163,11 +163,11 @@ import 'emby-itemscontainer'; itemsContainer.fetchData = fetchData; itemsContainer.getItemsHtml = getItemsHtml; itemsContainer.afterRefresh = afterRefresh; - let alphaPickerElement = tabContent.querySelector('.alphaPicker'); + const alphaPickerElement = tabContent.querySelector('.alphaPicker'); if (alphaPickerElement) { alphaPickerElement.addEventListener('alphavaluechanged', function (e) { - let newValue = e.detail.value; + const newValue = e.detail.value; query.NameStartsWith = newValue; query.StartIndex = 0; itemsContainer.refreshItems(); @@ -237,7 +237,7 @@ import 'emby-itemscontainer'; libraryBrowser.showLayoutMenu(e.target, this.getCurrentViewStyle, 'Banner,List,Poster,PosterCard,Thumb,ThumbCard'.split(',')); }); btnSelectView.addEventListener('layoutchange', function (e) { - let viewStyle = e.detail.viewStyle; + const viewStyle = e.detail.viewStyle; userSettings.set(savedViewKey, viewStyle); query.StartIndex = 0; onViewStyleChange(); @@ -274,7 +274,7 @@ import 'emby-itemscontainer'; this.showFilterMenu = function () { import('components/filterdialog/filterdialog').then(({default: filterDialogFactory}) => { - let filterDialog = new filterDialogFactory({ + const filterDialog = new filterDialogFactory({ query: query, mode: 'movies', serverId: ApiClient.serverId() diff --git a/src/controllers/movies/moviesrecommended.js b/src/controllers/movies/moviesrecommended.js index 5b85fbadae..4036128b51 100644 --- a/src/controllers/movies/moviesrecommended.js +++ b/src/controllers/movies/moviesrecommended.js @@ -58,7 +58,7 @@ import 'emby-button'; } function loadResume(page, userId, parentId) { - let screenWidth = dom.getWindowSize().innerWidth; + const screenWidth = dom.getWindowSize().innerWidth; const options = { SortBy: 'DatePlayed', SortOrder: 'Descending', @@ -154,8 +154,8 @@ import 'emby-button'; } function loadSuggestions(page, userId, parentId) { - let screenWidth = dom.getWindowSize().innerWidth; - let url = ApiClient.getUrl('Movies/Recommendations', { + const screenWidth = dom.getWindowSize().innerWidth; + const url = ApiClient.getUrl('Movies/Recommendations', { userId: userId, categoryLimit: 6, ItemLimit: screenWidth >= 1920 ? 8 : screenWidth >= 1600 ? 8 : screenWidth >= 1200 ? 6 : 5, @@ -172,7 +172,7 @@ import 'emby-button'; const html = recommendations.map(getRecommendationHtml).join(''); page.querySelector('.noItemsMessage').classList.add('hide'); - let recs = page.querySelector('.recommendations'); + const recs = page.querySelector('.recommendations'); recs.innerHTML = html; imageLoader.lazyChildren(recs); @@ -381,16 +381,16 @@ import 'emby-button'; const suggestionsTabIndex = 1; this.initTab = function () { - let tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']"); + const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']"); initSuggestedTab(view, tabContent); }; this.renderTab = function () { - let tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']"); + const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']"); loadSuggestionsTab(view, params, tabContent); }; - let tabControllers = []; + const tabControllers = []; let renderedTabs = []; view.addEventListener('viewshow', function (e) { initTabs(); diff --git a/src/plugins/comicsPlayer/plugin.js b/src/plugins/comicsPlayer/plugin.js index 7d0ac92df9..2928231391 100644 --- a/src/plugins/comicsPlayer/plugin.js +++ b/src/plugins/comicsPlayer/plugin.js @@ -19,14 +19,14 @@ export class ComicsPlayer { play(options) { this.progress = 0; - let elem = this.createMediaElement(); + const elem = this.createMediaElement(); return this.setCurrentSrc(elem, options); } stop() { this.unbindEvents(); - let elem = this.mediaElement; + const elem = this.mediaElement; if (elem) { dialogHelper.close(elem); this.mediaElement = null; @@ -40,7 +40,7 @@ export class ComicsPlayer { } onWindowKeyUp(e) { - let key = keyboardnavigation.getKeyName(e); + const key = keyboardnavigation.getKeyName(e); switch (key) { case 'Escape': this.stop(); @@ -87,20 +87,20 @@ export class ComicsPlayer { } setCurrentSrc(elem, options) { - let item = options.items[0]; + const item = options.items[0]; this.currentItem = item; loading.show(); - let serverId = item.ServerId; - let apiClient = window.connectionManager.getApiClient(serverId); + const serverId = item.ServerId; + const apiClient = window.connectionManager.getApiClient(serverId); libarchive.Archive.init({ workerUrl: appRouter.baseUrl() + '/libraries/worker-bundle.js' }); return new Promise((resolve, reject) => { - let downloadUrl = apiClient.getItemDownloadUrl(item.Id); + const downloadUrl = apiClient.getItemDownloadUrl(item.Id); const archiveSource = new ArchiveSource(downloadUrl); var instance = this; @@ -169,18 +169,18 @@ class ArchiveSource { } async load() { - let res = await fetch(this.url); + const res = await fetch(this.url); if (!res.ok) { return; } - let blob = await res.blob(); + const blob = await res.blob(); this.archive = await libarchive.Archive.open(blob); this.raw = await this.archive.getFilesArray(); this.numberOfFiles = this.raw.length; await this.archive.extractFiles(); - let files = await this.archive.getFilesArray(); + const files = await this.archive.getFilesArray(); files.sort((a, b) => { if (a.file.name < b.file.name) { return -1; @@ -189,9 +189,9 @@ class ArchiveSource { } }); - for (let file of files) { + for (const file of files) { /* eslint-disable-next-line compat/compat */ - let url = URL.createObjectURL(file.file); + const url = URL.createObjectURL(file.file); this.urls.push(url); } } diff --git a/src/scripts/clientUtils.js b/src/scripts/clientUtils.js index 4d3c049e8c..73801867c0 100644 --- a/src/scripts/clientUtils.js +++ b/src/scripts/clientUtils.js @@ -141,7 +141,7 @@ export function alert(options) { } export function capabilities(appHost) { - let capabilities = { + const capabilities = { PlayableMediaTypes: ['Audio', 'Video'], SupportedCommands: ['MoveUp', 'MoveDown', 'MoveLeft', 'MoveRight', 'PageUp', 'PageDown', 'PreviousLetter', 'NextLetter', 'ToggleOsd', 'ToggleContextMenu', 'Select', 'Back', 'SendKey', 'SendString', 'GoHome', 'GoToSettings', 'VolumeUp', 'VolumeDown', 'Mute', 'Unmute', 'ToggleMute', 'SetVolume', 'SetAudioStreamIndex', 'SetSubtitleStreamIndex', 'DisplayContent', 'GoToSearch', 'DisplayMessage', 'SetRepeatMode', 'SetShuffleQueue', 'ChannelUp', 'ChannelDown', 'PlayMediaSource', 'PlayTrailers'], SupportsPersistentIdentifier: window.appMode === 'cordova' || window.appMode === 'android', From 6b6841c8c81ab3c24da9b85f008e5601cd3758dd Mon Sep 17 00:00:00 2001 From: Cameron Date: Fri, 11 Sep 2020 22:39:53 +0100 Subject: [PATCH 059/281] Update CONTRIBUTORS.md --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 778d899ef7..672795cce1 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -39,6 +39,7 @@ - [Andrei Oanca](https://github.com/OancaAndrei) - [Cromefire_](https://github.com/cromefire) - [Orry Verducci](https://github.com/orryverducci) + - [Camc314](https://github.com/camc314) # Emby Contributors From 09c7d73c633938a0f25d4bf45462208bda870676 Mon Sep 17 00:00:00 2001 From: ben-dl Date: Fri, 11 Sep 2020 21:37:22 +0000 Subject: [PATCH 060/281] Translated using Weblate (German) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/de/ --- src/strings/de.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strings/de.json b/src/strings/de.json index 4baee1cb69..b0af47256e 100644 --- a/src/strings/de.json +++ b/src/strings/de.json @@ -1376,5 +1376,6 @@ "LabelOpenclDevice": "OpenCL-Gerät:", "LabelColorSpace": "Farbraum:", "MediaInfoColorSpace": "Farbraum", - "VideoAudio": "Videoton" + "VideoAudio": "Videoton", + "AllowTonemappingHelp": "Tone Mapping kann die Dynamic Range eines Videos von HDR zu SDR umwandeln und dabei Bilddetails und Farben beibehalten. Dies funktioniert zur Zeit nur mit dem NVENC HEVC-Decoder beim Transkodieren von HDR10 oder HLG-Videos." } From db98cf09b66b4a1fb6e3a0dfeb421e9fff29fa57 Mon Sep 17 00:00:00 2001 From: millallo Date: Sat, 12 Sep 2020 06:04:52 +0000 Subject: [PATCH 061/281] Translated using Weblate (Italian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/it/ --- src/strings/it.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/strings/it.json b/src/strings/it.json index e56bb17d6d..60f312a4c6 100644 --- a/src/strings/it.json +++ b/src/strings/it.json @@ -1370,5 +1370,7 @@ "Other": "Altro", "Data": "Dati", "Bwdif": "BWDIF", - "UseDoubleRateDeinterlacing": "Raddoppia il frame rate durante il deinterlacciamento" + "UseDoubleRateDeinterlacing": "Raddoppia il frame rate durante il deinterlacciamento", + "KnownProxiesHelp": "Lista degli IP separati da virgola dei proxy utilizzati per connettersi a Jellyfin. Ciò consente di gestire al meglio gli header X-Forwarded-For. Richiede il reboot.", + "LabelKnownProxies": "Proxy conosciuti:" } From 141787281a15bf1e6ae1df630893f715660c3b4b Mon Sep 17 00:00:00 2001 From: Oatavandi Date: Sat, 12 Sep 2020 07:20:25 +0000 Subject: [PATCH 062/281] Translated using Weblate (Tamil) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/ta/ --- src/strings/ta.json | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/strings/ta.json b/src/strings/ta.json index f17e623a7a..db359774fc 100644 --- a/src/strings/ta.json +++ b/src/strings/ta.json @@ -1388,5 +1388,33 @@ "Other": "மற்றவை", "Bwdif": "BWDIF", "UseDoubleRateDeinterlacingHelp": "டீஇன்டர்லேசிங் செய்யும் போது இந்த அமைப்பு புலம் வீதத்தைப் பயன்படுத்துகிறது, இது பெரும்பாலும் பாப் டீஇன்டர்லேசிங் என அழைக்கப்படுகிறது, இது டிவியில் ஒன்றோடொன்று இணைக்கப்பட்ட வீடியோவைப் பார்க்கும்போது நீங்கள் பார்ப்பது போன்ற முழு இயக்கத்தையும் வழங்க வீடியோவின் பிரேம் வீதத்தை இரட்டிப்பாக்குகிறது.", - "UseDoubleRateDeinterlacing": "செயலிழக்கும்போது பிரேம் வீதத்தை இரட்டிப்பாக்குங்கள்" + "UseDoubleRateDeinterlacing": "செயலிழக்கும்போது பிரேம் வீதத்தை இரட்டிப்பாக்குங்கள்", + "LabelMaxMuxingQueueSizeHelp": "அனைத்து ஸ்ட்ரீம்களையும் துவக்கக் காத்திருக்கும்போது இடையகப்படுத்தக்கூடிய அதிகபட்ச பாக்கெட்டுகள். Ffmpeg பதிவுகளில் \"வெளியீட்டு ஸ்ட்ரீமுக்கு இடையகப்படுத்தப்பட்ட பல பாக்கெட்டுகள்\" பிழையை நீங்கள் இன்னும் சந்தித்தால் அதை அதிகரிக்க முயற்சிக்கவும். பரிந்துரைக்கப்பட்ட மதிப்பு 2048 ஆகும்.", + "LabelMaxMuxingQueueSize": "அதிகபட்ச மக்ஸிங் வரிசை அளவு:", + "LabelTonemappingParamHelp": "டோன் மேப்பிங் வழிமுறையை டியூன் செய்யுங்கள். பரிந்துரைக்கப்பட்ட மற்றும் இயல்புநிலை மதிப்புகள் NaN ஆகும். பொதுவாக அதை காலியாக விடவும்.", + "LabelTonemappingParam": "டோன் மேப்பிங் அளவுரு:", + "LabelTonemappingPeakHelp": "இந்த மதிப்புடன் சமிக்ஞை / பெயரளவு / குறிப்பு உச்சத்தை மேலெழுதவும். காட்சி மெட்டாடேட்டாவில் உட்பொதிக்கப்பட்ட உச்ச தகவல் நம்பகத்தன்மையற்றதாக இருக்கும்போது அல்லது குறைந்த வரம்பிலிருந்து அதிக வரம்பிற்கு டோன் மேப்பிங் செய்யும்போது பயனுள்ளதாக இருக்கும். பரிந்துரைக்கப்பட்ட மற்றும் இயல்புநிலை மதிப்புகள் 0 ஆகும்.", + "LabelTonemappingPeak": "டோன் மேப்பிங் உச்சம்:", + "LabelTonemappingThresholdHelp": "டோன் மேப்பிங் அல்காரிதம் அளவுருக்கள் ஒவ்வொரு காட்சிக்கும் நன்றாக வடிவமைக்கப்பட்டுள்ளன. காட்சி மாறிவிட்டதா இல்லையா என்பதைக் கண்டறிய ஒரு வாசல் பயன்படுத்தப்படுகிறது. தற்போதைய சட்ட சராசரி பிரகாசத்திற்கும் தற்போதைய இயங்கும் சராசரிக்கும் இடையிலான தூரம் ஒரு நுழைவு மதிப்பை மீறினால், காட்சி சராசரி மற்றும் உச்ச பிரகாசத்தை மீண்டும் கணக்கிடுவோம். பரிந்துரைக்கப்பட்ட மற்றும் இயல்புநிலை மதிப்புகள் 0.8 மற்றும் 0.2 ஆகும்.", + "LabelTonemappingThreshold": "டோன் மேப்பிங் தொடக்கநிலை:", + "LabelTonemappingDesatHelp": "இந்த பிரகாசத்தின் அளவைத் தாண்டிய சிறப்பம்சங்களுக்கு தேய்மானத்தைப் பயன்படுத்துங்கள். அதிக அளவுரு, அதிக வண்ண தகவல்கள் பாதுகாக்கப்படும். இந்த அமைப்பு சூப்பர்-சிறப்பம்சங்களுக்கான இயற்கைக்கு மாறான வண்ணங்களைத் தடுக்க உதவுகிறது, அதற்கு பதிலாக (சுமூகமாக) வெள்ளை நிறமாக மாறுவதன் மூலம். இது வரம்பற்ற வண்ணங்களைப் பற்றிய தகவல்களைக் குறைக்கும் செலவில், படங்கள் மிகவும் இயல்பானதாக உணரவைக்கும். பரிந்துரைக்கப்பட்ட மற்றும் இயல்புநிலை மதிப்புகள் 0 மற்றும் 0.5 ஆகும்.", + "LabelTonemappingDesat": "டோன் மேப்பிங் டெசாட்:", + "TonemappingRangeHelp": "வெளியீட்டு வண்ண வரம்பைத் தேர்ந்தெடுக்கவும். ஆட்டோ என்பது உள்ளீட்டு வரம்பைப் போன்றது.", + "LabelTonemappingRange": "டோன் மேப்பிங் வரம்பு:", + "TonemappingAlgorithmHelp": "டோன் மேப்பிங் நன்றாக இருக்கும். இந்த விருப்பங்களை நீங்கள் அறிந்திருக்கவில்லை என்றால், இயல்புநிலையை வைத்திருங்கள்.
    பரிந்துரைக்கப்பட்ட மதிப்பு ரெய்ன்ஹார்ட்.", + "LabelTonemappingAlgorithm": "பயன்படுத்த டோன் மேப்பிங் வழிமுறையைத் தேர்ந்தெடுக்கவும்:", + "AllowTonemappingHelp": "டோன் மேப்பிங் ஒரு வீடியோவின் டைனமிக் வரம்பை எச்.டி.ஆரிலிருந்து எஸ்.டி.ஆருக்கு மாற்றும், அதே நேரத்தில் பட விவரங்களையும் வண்ணங்களையும் பராமரிக்கும், அவை அசல் காட்சியைக் குறிக்கும் மிக முக்கியமான தகவல்கள். தற்போது NVENC HEVC டிகோடரைப் பயன்படுத்தும்போது மற்றும் HDR10 அல்லது HLG வீடியோக்களை டிரான்ஸ்கோடிங் செய்யும் போது மட்டுமே செயல்படும்.", + "EnableTonemapping": "டோன் மேப்பிங்கை இயக்கு", + "LabelOpenclDeviceHelp": "இது ஓப்பன்சிஎல் சாதனம் ஆகும், இது டன்மேப்பிங்கிற்கு பயன்படுத்தப்படுகிறது. புள்ளியின் இடது புறம் இயங்குதள எண், மற்றும் வலது புறம் இயங்குதளத்தின் சாதன எண். இயல்புநிலை மதிப்பு 0.0. OpenCL வன்பொருள் முடுக்கம் முறையைக் கொண்ட ffmpeg பயன்பாட்டுக் கோப்பு தேவை.", + "LabelOpenclDevice": "OpenCL சாதனம்:", + "LabelColorPrimaries": "வண்ண முதன்மைகள்:", + "LabelColorTransfer": "வண்ண பரிமாற்றம்:", + "LabelColorSpace": "வண்ண இடம்:", + "LabelVideoRange": "வீடியோ வரம்பு:", + "MediaInfoColorPrimaries": "வண்ண முதன்மைகள்", + "MediaInfoColorTransfer": "வண்ண பரிமாற்றம்", + "MediaInfoColorSpace": "வண்ண இடம்", + "MediaInfoVideoRange": "வீடியோ வரம்பு", + "LabelKnownProxies": "அறியப்பட்ட பிரதிநிதிகள்:", + "KnownProxiesHelp": "உங்கள் ஜெல்லிஃபின் நிகழ்வோடு இணைக்கும்போது பயன்படுத்தப்படும் அறியப்பட்ட ப்ராக்ஸிகளின் ஐபி முகவரிகளின் கமாவால் பிரிக்கப்பட்ட பட்டியல். எக்ஸ்-ஃபார்வர்ட்-ஃபார் தலைப்புகளை முறையாகப் பயன்படுத்த இது தேவைப்படுகிறது. சேமித்த பிறகு மறுதொடக்கம் தேவை." } From 2023ce37eb8b760269c43df9e46d69208aeea69a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Kucharczyk?= Date: Sat, 12 Sep 2020 11:20:21 +0000 Subject: [PATCH 063/281] 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, 5 insertions(+), 1 deletion(-) diff --git a/src/strings/cs.json b/src/strings/cs.json index 697f13ea7f..15cb46f70a 100644 --- a/src/strings/cs.json +++ b/src/strings/cs.json @@ -1397,5 +1397,9 @@ "MediaInfoColorPrimaries": "Primární barvy", "MediaInfoColorTransfer": "Převod barev", "MediaInfoColorSpace": "Barevný prostor", - "MediaInfoVideoRange": "Rozsah videa" + "MediaInfoVideoRange": "Rozsah videa", + "LabelMaxMuxingQueueSizeHelp": "Maximální počet paketů, které je možné napřed načíst při čekání na spuštění všech proudů. Pokud se stále zobrazuje chyba \"Příliš mnoho paketů načtených napřed ve výstupním proudu\" v protokolech ffmpeg, zkuste hodnotu zvýšit. Doporučená hodnota je 2048.", + "LabelMaxMuxingQueueSize": "Maximální velikost muxovací fronty:", + "LabelKnownProxies": "Známé proxy servery:", + "KnownProxiesHelp": "Čárkami oddělený seznam IP adres známých proxy serverů pro připojení k instanci Jellyfin. Vyžadováno pro správné využití HTTP hlavičky X-Forwarded-For. Vyžaduje restart." } From 70d7a561c5f4e9508782774374fb518e52ae7cb7 Mon Sep 17 00:00:00 2001 From: Thomas Schwery Date: Sat, 12 Sep 2020 11:28:16 +0000 Subject: [PATCH 064/281] Translated using Weblate (French) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fr/ --- src/strings/fr.json | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/strings/fr.json b/src/strings/fr.json index 587bc1a555..907c67f23e 100644 --- a/src/strings/fr.json +++ b/src/strings/fr.json @@ -1373,5 +1373,22 @@ "PosterCard": "Affiche", "UseDoubleRateDeinterlacing": "Multiplier par deux la fréquence d'images lors du désentrelacement", "Bwdif": "BWDIF", - "UseDoubleRateDeinterlacingHelp": "Ce réglage utilise la fréquence de trame lors du désentrelacement, souvent appelé \"bob deinterlacing\", qui double la fréquence d'image de la vidéo pour fournir un mouvement fluide comme en regardant une vidéo entrelacée sur un téléviseur." + "UseDoubleRateDeinterlacingHelp": "Ce réglage utilise la fréquence de trame lors du désentrelacement, souvent appelé \"bob deinterlacing\", qui double la fréquence d'image de la vidéo pour fournir un mouvement fluide comme en regardant une vidéo entrelacée sur un téléviseur.", + "LabelTonemappingDesat": "Désaturation tonale :", + "TonemappingRangeHelp": "Sélectionnez la gamme de couleur de sortie. Auto représente la même gamme qu'en entrée.", + "LabelTonemappingRange": "Gamme de mappage tonal :", + "TonemappingAlgorithmHelp": "Le mappage tonal peut être affiné. Si vous n'êtes pas familier avec ces options, gardez les valeurs par défaut.
    La valeur recommandée est Reinhard.", + "LabelTonemappingAlgorithm": "Sélectionnez l'algorithme de mappage tonal à utiliser :", + "AllowTonemappingHelp": "Le mappage tonal peut transformer la gamme dynamique d'une vidéo de HDR à SDR tout en maintenant les détails et les couleurs d'image qui sont des informations importantes pour la représentation de la scène originale. Actuellement, ne fonctionne uniquement lorsque le décodeur NVENC HEVC est utilisé et que des vidéos HDR10 ou HLG sont transcodées.", + "EnableTonemapping": "Activer le mappage tonal", + "LabelOpenclDeviceHelp": "Ce dispositif OpenCL est utilisé pour le mappage tonal. La partie à gauche du point est le numéro de plate-forme et la partie à droite est le numéro du dispositif sur la plate-forme. La valeur par défaut est 0.0. Le fichier de l'application ffmpeg contenant l'accélération matérielle OpenCL est nécessaire.", + "LabelOpenclDevice": "Dispositif OpenCL :", + "LabelColorPrimaries": "Couleurs primaires :", + "LabelColorTransfer": "Transfert couleur :", + "LabelColorSpace": "Espace couleur :", + "MediaInfoColorPrimaries": "Couleurs primaires", + "MediaInfoColorTransfer": "Transfert couleur", + "MediaInfoColorSpace": "Espace couleur", + "LabelKnownProxies": "Proxies connus :", + "KnownProxiesHelp": "Liste séparée par des virgules d'adresses IP des proxies connus utilisés pour se connecter à l'instance Jellyfin. Ceci est nécessaire afin de pouvoir utiliser correctement les entêtes X-Forwarded-For. Nécessite un redémarrage après sauvegarde." } From 1dd771d446a3b55efabe1d18ecff62f527ca0388 Mon Sep 17 00:00:00 2001 From: Thomas Schwery Date: Sat, 12 Sep 2020 12:07:41 +0000 Subject: [PATCH 065/281] 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, 3 insertions(+), 1 deletion(-) diff --git a/src/strings/fr.json b/src/strings/fr.json index 907c67f23e..ed243f98a4 100644 --- a/src/strings/fr.json +++ b/src/strings/fr.json @@ -1390,5 +1390,7 @@ "MediaInfoColorTransfer": "Transfert couleur", "MediaInfoColorSpace": "Espace couleur", "LabelKnownProxies": "Proxies connus :", - "KnownProxiesHelp": "Liste séparée par des virgules d'adresses IP des proxies connus utilisés pour se connecter à l'instance Jellyfin. Ceci est nécessaire afin de pouvoir utiliser correctement les entêtes X-Forwarded-For. Nécessite un redémarrage après sauvegarde." + "KnownProxiesHelp": "Liste séparée par des virgules d'adresses IP des proxies connus utilisés pour se connecter à l'instance Jellyfin. Ceci est nécessaire afin de pouvoir utiliser correctement les entêtes X-Forwarded-For. Nécessite un redémarrage après sauvegarde.", + "LabelTonemappingThreshold": "Seuil de mappage tonal :", + "LabelTonemappingDesatHelp": "Désature les couleurs qui dépassent ce niveau de luminosité. Plus ce paramètre est élevé, plus les informations de couleur seront préservées. Ce paramètre permet d'éviter les couleurs anormalement éclatantes pour les couleurs super-lumineuses en les transformant (de manière lisse) en blanc. Ceci rend l'image plus naturelle au prix d'une réduction d'information dans les couleurs hors-gamme. Les valeurs recommandées et par défaut sont 0 et 0.5." } From 8f24c4d2c94b0e712028858b45ae8f7793578da1 Mon Sep 17 00:00:00 2001 From: Moritz Date: Sat, 12 Sep 2020 19:50:13 +0000 Subject: [PATCH 066/281] Translated using Weblate (German) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/de/ --- src/strings/de.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/strings/de.json b/src/strings/de.json index b0af47256e..d6104fba72 100644 --- a/src/strings/de.json +++ b/src/strings/de.json @@ -1377,5 +1377,10 @@ "LabelColorSpace": "Farbraum:", "MediaInfoColorSpace": "Farbraum", "VideoAudio": "Videoton", - "AllowTonemappingHelp": "Tone Mapping kann die Dynamic Range eines Videos von HDR zu SDR umwandeln und dabei Bilddetails und Farben beibehalten. Dies funktioniert zur Zeit nur mit dem NVENC HEVC-Decoder beim Transkodieren von HDR10 oder HLG-Videos." + "AllowTonemappingHelp": "Tone Mapping kann die Dynamic Range eines Videos von HDR zu SDR umwandeln und dabei Bilddetails und Farben beibehalten. Dies funktioniert zur Zeit nur mit dem NVENC HEVC-Decoder beim Transkodieren von HDR10 oder HLG-Videos.", + "TonemappingRangeHelp": "Wählen Sie den Ausgabefarbbereich aus. Auto ist derselbe wie der Eingabebereich.", + "TonemappingAlgorithmHelp": "Das Tonemapping kann fein abgestimmt werden. Wenn Sie mit diesen Optionen nicht vertraut sind, behalten Sie einfach den Standardwert bei.
    Der empfohlene Wert ist Reinhard.", + "LabelTonemappingAlgorithm": "Wählen Sie den zu verwendenden Tonemapping-Algorithmus aus:", + "LabelKnownProxies": "Bekannte Proxys:", + "KnownProxiesHelp": "Kommagetrennte Liste von IP-Adressen bekannter Proxys, die bei der Verbindung mit Ihrer Jellyfin-Instanz verwendet werden. Dies ist erforderlich, um die X-Forwarded-For-Header korrekt verwenden zu können. Erfordert nach dem Speichern einen Neustart." } From 1014c6cd352b0d702f341a761018e1ee2a513336 Mon Sep 17 00:00:00 2001 From: millallo Date: Sun, 13 Sep 2020 17:59:00 +0000 Subject: [PATCH 067/281] Translated using Weblate (Italian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/it/ --- src/strings/it.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/it.json b/src/strings/it.json index 60f312a4c6..f1e30b754f 100644 --- a/src/strings/it.json +++ b/src/strings/it.json @@ -568,7 +568,7 @@ "LabelModelName": "Nome Modello", "LabelModelNumber": "Numero Modello", "LabelModelUrl": "Modello URL", - "LabelMonitorUsers": "Monitora l'attività da:", + "LabelMonitorUsers": "Monitora l'attività di:", "LabelMovieCategories": "Categorie film:", "LabelMoviePrefix": "Prefisso film:", "LabelMoviePrefixHelp": "Se un prefisso viene applicato ai titoli di film, inseriscilo qui in modo che il server possa gestirlo correttamente.", From db76b40affa67fcec41d4daec0c6a4c79dee62f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=BE=D0=BB=D0=B0=D0=B9=20=D0=98=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Sun, 13 Sep 2020 19:55:51 +0000 Subject: [PATCH 068/281] Translated using Weblate (Bulgarian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/bg/ --- src/strings/bg-bg.json | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/strings/bg-bg.json b/src/strings/bg-bg.json index c0a63032f2..f4d6dfc317 100644 --- a/src/strings/bg-bg.json +++ b/src/strings/bg-bg.json @@ -1352,5 +1352,32 @@ "MessagePluginInstallError": "Възникна грешка при инсталирането на добавката.", "PlaybackRate": "Скорост на възпроизвеждане", "NextTrack": "Прескочи към следващ", - "LabelUnstable": "Нестабилна" + "LabelUnstable": "Нестабилна", + "LabelOpenclDevice": "Устройство OpenCL:", + "LabelColorPrimaries": "Цветни първични елементи:", + "LabelColorTransfer": "Цветен трансфер:", + "LabelColorSpace": "Цветово пространство:", + "LabelVideoRange": "Видео обхват:", + "MediaInfoColorPrimaries": "Цветни първични материали", + "MediaInfoColorTransfer": "Цветен трансфер", + "MediaInfoColorSpace": "Цветово пространство", + "MediaInfoVideoRange": "Видео обхват", + "Bwdif": "Филтър БВДИФ", + "VideoAudio": "Видео Аудио", + "Video": "Видео", + "ThumbCard": "Малък постер", + "Subtitle": "Субтитри", + "SpecialFeatures": "Специални функции", + "SelectServer": "Избери сървър", + "Restart": "Рестартирай", + "ResetPassword": "Нулира парола", + "Profile": "Профил", + "PosterCard": "Плакат карта", + "Poster": "Плакат", + "Photo": "Снимки", + "MusicVideos": "Музикални видеа", + "LabelKnownProxies": "Познати проксита:", + "Image": "Картинка", + "Other": "Други", + "Data": "Данни" } From 7d77cc9900d7adb434f38b4e718dbff0a97688b8 Mon Sep 17 00:00:00 2001 From: Franco Castillo Date: Sun, 13 Sep 2020 23:51:02 +0000 Subject: [PATCH 069/281] Translated using Weblate (Spanish (Argentina)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/es_AR/ --- src/strings/es-ar.json | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/strings/es-ar.json b/src/strings/es-ar.json index 521f4ef98f..5f303b1ce2 100644 --- a/src/strings/es-ar.json +++ b/src/strings/es-ar.json @@ -1373,5 +1373,22 @@ "Other": "Otro", "Bwdif": "BWDIF", "UseDoubleRateDeinterlacingHelp": "Esta configuración utiliza la velocidad de campo al desentrelazar, a menudo denominado desentrelazado bob, que duplica la velocidad de fotogramas del video para proporcionar un movimiento completo como lo que vería al ver un video entrelazado en un televisor.", - "UseDoubleRateDeinterlacing": "Duplique la velocidad de fotogramas al desentrelazar" + "UseDoubleRateDeinterlacing": "Duplique la velocidad de fotogramas al desentrelazar", + "LabelTonemappingParam": "Parámetro de mapeo de tonos:", + "LabelTonemappingPeak": "Pico de mapeo de tonos:", + "LabelTonemappingThreshold": "Umbral de mapeo de tonos:", + "LabelTonemappingRange": "Rango de mapeo de tonos:", + "LabelTonemappingAlgorithm": "Seleccione el algoritmo de mapeo de tonos para usar:", + "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 el archivo de aplicación ffmpeg que contiene el método de aceleración por hardware OpenCL.", + "LabelOpenclDevice": "Dispositivo OpenCL:", + "LabelColorPrimaries": "Primarias de color:", + "LabelColorTransfer": "Transferencia de color:", + "LabelColorSpace": "Espacio de color:", + "LabelVideoRange": "Rango de video:", + "MediaInfoColorPrimaries": "Primarias de color", + "MediaInfoColorTransfer": "Transferencia de color", + "MediaInfoColorSpace": "Espacio de color", + "MediaInfoVideoRange": "Rango de video", + "LabelKnownProxies": "Proxies conocidos:" } From 270f585b265f40012c76bc6e95553576cc8b285b Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Mon, 8 Jun 2020 17:44:55 +1000 Subject: [PATCH 070/281] Make book plugin render EPUBs continuously for mobile devices --- src/plugins/bookPlayer/plugin.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/plugins/bookPlayer/plugin.js b/src/plugins/bookPlayer/plugin.js index 0303275be2..8cde3f400f 100644 --- a/src/plugins/bookPlayer/plugin.js +++ b/src/plugins/bookPlayer/plugin.js @@ -1,3 +1,4 @@ +import browser from 'browser'; import loading from 'loading'; import keyboardnavigation from 'keyboardnavigation'; import dialogHelper from 'dialogHelper'; @@ -230,6 +231,23 @@ export class BookPlayer { return elem; } + render(elem, book) { + if (browser.mobile) { + return book.renderTo(elem, { + width: '100%', + height: '100%', + manager: 'continuous', + flow: 'scrolled-doc', + offset: 0 + }); + } else { + return book.renderTo(elem, { + width: '100%', + height: '100%' + }); + } + } + setCurrentSrc(elem, options) { const item = options.items[0]; this._currentItem = item; @@ -248,7 +266,7 @@ export class BookPlayer { import('epubjs').then(({default: epubjs}) => { const downloadHref = apiClient.getItemDownloadUrl(item.Id); const book = epubjs(downloadHref, {openAs: 'epub'}); - const rendition = book.renderTo(elem, {width: '100%', height: '97%'}); + const rendition = this.render(elem, book); this._currentSrc = downloadHref; this._rendition = rendition; From 14583cf18e824308f6e7741da95e3204129cf8d1 Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Mon, 14 Sep 2020 18:51:03 +1000 Subject: [PATCH 071/281] Add next/prev chapter buttons for mobile devices Also removes touch events as they interfere with continuous scrolling --- src/plugins/bookPlayer/plugin.js | 75 +++++++++++++++++--------------- src/plugins/bookPlayer/style.css | 46 ++++++++++++++++---- 2 files changed, 77 insertions(+), 44 deletions(-) diff --git a/src/plugins/bookPlayer/plugin.js b/src/plugins/bookPlayer/plugin.js index 8cde3f400f..0c3d6850aa 100644 --- a/src/plugins/bookPlayer/plugin.js +++ b/src/plugins/bookPlayer/plugin.js @@ -19,6 +19,8 @@ export class BookPlayer { this.onDialogClosed = this.onDialogClosed.bind(this); this.openTableOfContents = this.openTableOfContents.bind(this); + this.prevChapter = this.prevChapter.bind(this); + this.nextChapter = this.nextChapter.bind(this); this.onWindowKeyUp = this.onWindowKeyUp.bind(this); } @@ -123,26 +125,6 @@ export class BookPlayer { } } - onTouchStart(e) { - // TODO: depending on the event this can be the document or the rendition itself - const rendition = this._rendition || this; - const book = rendition.book; - - // check that the event is from the book or the document - if (!book || this._loaded === false) return; - - // epubjs stores pages off the screen or something for preloading - // get the modulus of the touch event to account for the increased width - if (!e.touches || e.touches.length === 0) return; - - const touch = e.touches[0].clientX % dom.getWindowSize().innerWidth; - if (touch < dom.getWindowSize().innerWidth / 2) { - book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev(); - } else { - book.package.metadata.direction === 'rtl' ? rendition.prev() : rendition.next(); - } - } - onDialogClosed() { this.stop(); } @@ -151,27 +133,33 @@ export class BookPlayer { const elem = this._mediaElement; elem.addEventListener('close', this.onDialogClosed, {once: true}); - elem.querySelector('.btnBookplayerExit').addEventListener('click', this.onDialogClosed, {once: true}); - elem.querySelector('.btnBookplayerToc').addEventListener('click', this.openTableOfContents); + elem.querySelector('#btnBookplayerExit').addEventListener('click', this.onDialogClosed, {once: true}); + elem.querySelector('#btnBookplayerToc').addEventListener('click', this.openTableOfContents); + if (browser.mobile) { + elem.querySelector('#btnBookplayerPrev').addEventListener('click', this.prevChapter); + elem.querySelector('#btnBookplayerNext').addEventListener('click', this.nextChapter); + } } bindEvents() { this.bindMediaElementEvents(); document.addEventListener('keyup', this.onWindowKeyUp); - document.addEventListener('touchstart', this.onTouchStart); // FIXME: I don't really get why document keyup event is not triggered when epub is in focus this._rendition.on('keyup', this.onWindowKeyUp); - this._rendition.on('touchstart', this.onTouchStart); } unbindMediaElementEvents() { const elem = this._mediaElement; elem.removeEventListener('close', this.onDialogClosed); - elem.querySelector('.btnBookplayerExit').removeEventListener('click', this.onDialogClosed); - elem.querySelector('.btnBookplayerToc').removeEventListener('click', this.openTableOfContents); + elem.querySelector('#btnBookplayerExit').removeEventListener('click', this.onDialogClosed); + elem.querySelector('#btnBookplayerToc').removeEventListener('click', this.openTableOfContents); + if (browser.mobile) { + elem.querySelector('#btnBookplayerPrev').removeEventListener('click', this.prevChapter); + elem.querySelector('#btnBookplayerNext').removeEventListener('click', this.nextChapter); + } } unbindEvents() { @@ -180,11 +168,9 @@ export class BookPlayer { } document.removeEventListener('keyup', this.onWindowKeyUp); - document.removeEventListener('touchstart', this.onTouchStart); if (this._rendition) { this._rendition.off('keyup', this.onWindowKeyUp); - this._rendition.off('touchstart', this.onTouchStart); } } @@ -194,6 +180,16 @@ export class BookPlayer { } } + prevChapter(e) { + this._rendition.prev(); + e.preventDefault(); + } + + nextChapter(e) { + this._rendition.next(); + e.preventDefault(); + } + createMediaElement() { let elem = this._mediaElement; if (elem) { @@ -214,13 +210,22 @@ export class BookPlayer { elem.id = 'bookPlayer'; let html = ''; - html += '
    '; - html += ''; + + if (browser.mobile) { + html += '
    '; + } + + html += '
    '; + html += '
    '; + html += ''; + html += ''; html += '
    '; - html += '
    '; - html += ''; html += '
    '; + if (browser.mobile) { + html += '
    '; + } + elem.innerHTML = html; dialogHelper.open(elem); @@ -236,9 +241,7 @@ export class BookPlayer { return book.renderTo(elem, { width: '100%', height: '100%', - manager: 'continuous', - flow: 'scrolled-doc', - offset: 0 + flow: 'scrolled-doc' }); } else { return book.renderTo(elem, { @@ -266,7 +269,7 @@ export class BookPlayer { import('epubjs').then(({default: epubjs}) => { const downloadHref = apiClient.getItemDownloadUrl(item.Id); const book = epubjs(downloadHref, {openAs: 'epub'}); - const rendition = this.render(elem, book); + const rendition = this.render('viewer', book); this._currentSrc = downloadHref; this._rendition = rendition; diff --git a/src/plugins/bookPlayer/style.css b/src/plugins/bookPlayer/style.css index e37b995f31..99aad62260 100644 --- a/src/plugins/bookPlayer/style.css +++ b/src/plugins/bookPlayer/style.css @@ -7,18 +7,20 @@ background: #fff; } -.topRightActionButtons { - right: 0.5vh; +.topButtons { top: 0.5vh; z-index: 1002; - position: absolute; + position: sticky; } -.topLeftActionButtons { - left: 0.5vh; - top: 0.5vh; - z-index: 1002; - position: absolute; +#btnBookplayerToc { + float: left; + margin-left: 2vw; +} + +#btnBookplayerExit { + float: right; + margin-right: 2vw; } .bookplayerButtonIcon { @@ -37,3 +39,31 @@ .bookplayerErrorMsg { text-align: center; } + +#viewer { + align-items: flex-start; +} + +#btnBookplayerPrev { + margin: 0.5vh 0.5vh; + color: black; +} + +#btnBookplayerNext { + margin: 0.5vh 0.5vh; + color: black; +} + +.button-wrapper { + text-align: center; + position: relative; + height: 0; +} + +.top-button { + margin: 0.5vh 2em; +} + +.bottom-button { + margin: 2em 0.5vh; +} From 0062a3b1b2ec550e8f6e688b61a42e9c07654d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Kucharczyk?= Date: Mon, 14 Sep 2020 08:48:35 +0000 Subject: [PATCH 072/281] Translated using Weblate (Czech) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/cs/ --- src/strings/cs.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/strings/cs.json b/src/strings/cs.json index 15cb46f70a..098cd9e3d2 100644 --- a/src/strings/cs.json +++ b/src/strings/cs.json @@ -187,8 +187,8 @@ "HeaderAdmin": "Administrátor", "HeaderAlbumArtists": "Umělci alba", "HeaderAlert": "Upozornění", - "HeaderApiKey": "Klíč Api", - "HeaderApiKeys": "Klíče API", + "HeaderApiKey": "Klíč k API", + "HeaderApiKeys": "Klíče k API", "HeaderApiKeysHelp": "Externí aplikace musí mít klíč k API, aby mohly komunikovat se serverem. Klíče jsou vydávány přihlášením k běžnému uživatelskému účtu nebo ruční žádostí o klíč.", "HeaderApp": "Aplikace", "HeaderAudioBooks": "Audio knihy", @@ -202,7 +202,7 @@ "HeaderCodecProfileHelp": "Kodek profily označují omezení daného zařízení pro přehrávání pomocí specifických kodeků. Jestliže je omezení aplikováno, média budou překódovany i v případě, že kodek je nakonfigurován pro přímé přehrávání.", "HeaderConfirmPluginInstallation": "Potvrzení instalace zásuvného modulu", "HeaderConfirmProfileDeletion": "Potvrdit smazání profilu", - "HeaderConfirmRevokeApiKey": "Odvolat klíč Api", + "HeaderConfirmRevokeApiKey": "Odvolat klíč k API", "HeaderConnectToServer": "Připojit k serveru", "HeaderConnectionFailure": "Připojení selhalo", "HeaderContainerProfile": "Profil obalů", @@ -261,7 +261,7 @@ "HeaderMyDevice": "Moje zařízení", "HeaderMyMedia": "Moje média", "HeaderMyMediaSmall": "Moje média (malé)", - "HeaderNewApiKey": "Nový klíč API", + "HeaderNewApiKey": "Nový klíč k API", "HeaderNextEpisodePlayingInValue": "Přehrávání další epizody za {0}", "HeaderNextVideoPlayingInValue": "Přehrávání dalšího videa za {0}", "HeaderOnNow": "Právě teď", @@ -1278,7 +1278,7 @@ "ButtonTogglePlaylist": "Playlist", "LabelStable": "Stabilní", "LabelChromecastVersion": "Verze Chromecastu", - "ApiKeysCaption": "Seznam povolených API klíčů", + "ApiKeysCaption": "Seznam povolených klíčů k API", "LabelEnableHttpsHelp": "Naslouchání na uvedeném portu HTTPS. K fungování je nutné nakonfigurovat i platný certifikát.", "LabelEnableHttps": "Povolit HTTPS", "HeaderServerAddressSettings": "Nastavení adresy serveru", From a5800ac2e3a932fcec3bdceeb66e355b926928c4 Mon Sep 17 00:00:00 2001 From: hoanghuy309 Date: Mon, 14 Sep 2020 12:34:11 +0000 Subject: [PATCH 073/281] Translated using Weblate (Vietnamese) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/vi/ --- src/strings/vi.json | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/strings/vi.json b/src/strings/vi.json index 57333b5a3a..5543564a11 100644 --- a/src/strings/vi.json +++ b/src/strings/vi.json @@ -147,7 +147,7 @@ "AllComplexFormats": "Tất cả các định dạng phức tạp (ASS, SSA, VOBSUB, PGS, SUB, IDX, ...)", "AllChannels": "Tất cả các kênh", "Alerts": "Cảnh Báo", - "Albums": "Albums", + "Albums": "Bộ Sưu Tập", "Aired": "Đã phát sóng", "AirDate": "Ngày phát sóng", "AdditionalNotificationServices": "Duyệt qua danh mục plugin để cài đặt các dịch vụ thông báo bổ sung.", @@ -193,7 +193,7 @@ "ColorTransfer": "Chuyển đổi màu", "ColorSpace": "Bộ mã màu", "ColorPrimaries": "Những màu chủ đạo", - "Collections": "Bộ sưu tập", + "Collections": "Bộ Sưu Tập", "ClientSettings": "Cài đặt thiết bị phát", "CinemaModeConfigurationHelp": "Chế độ Cinema giúp bạn mang lại trải nghiệm rạp chiếu phim ngay tại phòng khách với khả năng phát trailers và những đoạn mở đầu tuỳ chọn trước phần chính của bộ phim.", "ChannelNumber": "Kênh số", @@ -280,7 +280,7 @@ "HeaderApiKey": "API Key", "HeaderAllowMediaDeletionFrom": "Cho Phép Xoá Nội Dung", "HeaderAlert": "Thông Báo", - "HeaderAlbumArtists": "Nghệ Sĩ Album", + "HeaderAlbumArtists": "Bộ Sưu Tập Nghệ sĩ", "HeaderAdmin": "Quản Trị", "HeaderAdditionalParts": "Phần Bổ Sung", "HeaderAddUpdateImage": "Thêm/Thay Đổi Hình Ảnh", @@ -301,18 +301,18 @@ "GuestStar": "Ngôi sao khách mời", "GroupVersions": "Chia nhóm theo phiên bản", "GroupBySeries": "Chia nhóm theo bộ", - "Genres": "Thể loại", + "Genres": "Thể Loại", "Genre": "Thể loại", "General": "Tổng Hợp", "Fullscreen": "Toàn màn hình", "Friday": "Thứ Sáu", "FormatValue": "Định dạng: {0}", - "Folders": "Thư mục", + "Folders": "Thư Mục", "Filters": "Bộ lọc", "File": "Tập tin", "FetchingData": "Đang tải thêm thông tin", "Features": "Mục đặc trưng", - "Favorites": "Mục yêu thích", + "Favorites": "Sở Thích", "Favorite": "Mục yêu thích", "FastForward": "Tua nhanh", "FFmpegSavePathNotFound": "Máy chủ không thể tìm thấy chương trình FFmpeg trong đường dẫn bạn đã nhập. FFprobe thì cũng cần thiết và phải nằm trong cùng thư mục bên trên. Những phần mềm này thường được tổng hợp cùng nhau trong một lượt tải. Hãy thử lại sau khi kiểm tra đường dẫn.", @@ -701,5 +701,18 @@ "LabelPassword": "Mật khẩu:", "LabelNotificationEnabled": "Bật thông báo này", "LabelNewsCategories": "", - "LabelStable": "Ổn Định" + "LabelStable": "Ổn Định", + "LabelTonemappingAlgorithm": "Chọn thuật toán ánh xạ Tone màu để sử dụng:", + "TonemappingAlgorithmHelp": "Ánh xạ Tone màu có thể được tinh chỉnh. Nếu bạn không quen với tùy chọn này, hãy giữ mặc định.
    Giá trị mặc định: Reinhard.", + "TonemappingRangeHelp": "Chọn dải màu đầu ra. Tự động là giống như dải màu đầu vào.", + "StopPlayback": "Dừng Phát", + "Preview": "Xem Trước", + "SubtitleVerticalPositionHelp": "Số dòng nơi văn bản xuất hiện. Số dương cho biết từ trên xuống. Số âm cho biết từ dưới lên.", + "Movies": "Phim", + "Photos": "Ảnh", + "Playlists": "Danh Sách Chơi", + "Shows": "Các Chương Trình", + "Songs": "Các Bài Hát", + "Sync": "Đồng Bộ", + "ValueSpecialEpisodeName": "Đặc Biệt - {0}" } From d3d02af2a586900c5569bad1c5d7327cd7a1615e Mon Sep 17 00:00:00 2001 From: Serhiy Date: Mon, 14 Sep 2020 15:41:34 +0000 Subject: [PATCH 074/281] Translated using Weblate (Italian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/it/ --- src/strings/it.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/strings/it.json b/src/strings/it.json index f1e30b754f..5d794dbc2b 100644 --- a/src/strings/it.json +++ b/src/strings/it.json @@ -1372,5 +1372,11 @@ "Bwdif": "BWDIF", "UseDoubleRateDeinterlacing": "Raddoppia il frame rate durante il deinterlacciamento", "KnownProxiesHelp": "Lista degli IP separati da virgola dei proxy utilizzati per connettersi a Jellyfin. Ciò consente di gestire al meglio gli header X-Forwarded-For. Richiede il reboot.", - "LabelKnownProxies": "Proxy conosciuti:" + "LabelKnownProxies": "Proxy conosciuti:", + "LabelColorSpace": "Spazio colore:", + "LabelVideoRange": "Range video:", + "MediaInfoColorSpace": "Spazio colore", + "ThumbCard": "Miniatura", + "PosterCard": "Locandina", + "LabelOpenclDevice": "Dispositivo OpenCL:" } From 660f2216356c60fd7409054967d110a112f00934 Mon Sep 17 00:00:00 2001 From: hoanghuy309 Date: Mon, 14 Sep 2020 13:14:49 +0000 Subject: [PATCH 075/281] Translated using Weblate (Vietnamese) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/vi/ --- src/strings/vi.json | 113 +++++++++++++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 28 deletions(-) diff --git a/src/strings/vi.json b/src/strings/vi.json index 5543564a11..c4b3ce343d 100644 --- a/src/strings/vi.json +++ b/src/strings/vi.json @@ -29,7 +29,7 @@ "LabelDay": "Ngày:", "LabelEnableDlnaPlayTo": "Cho phép DLNA chạy để", "LabelEvent": "Sự kiện:", - "LabelFinish": "Kết thúc", + "LabelFinish": "Xong", "LabelLanguage": "Ngôn ngữ:", "LabelName": "Tên:", "LabelNewPassword": "Mật khẩu mới:", @@ -112,7 +112,7 @@ "BurnSubtitlesHelp": "Xác định xem máy chủ có nên ghi phụ đề khi chuyển đổi video hay không. Tránh thực hiện việc này sẽ cải thiện hiệu suất máy chủ đáng kể. Chọn Tự động để ghi các phụ đề có định dạng dựa trên hình ảnh (VOBSUB, PGS, SUB, IDX, ...) và một vài phụ đề ASS/SSA nhất định.", "Browse": "Duyệt", "BoxRear": "Hộp (mặt sau)", - "Books": "Sách", + "Books": "Các Quyển Sách", "BookLibraryHelp": "Âm thanh và sách văn bản được hỗ trợ. Xem lại {0} hướng dẫn đặt tên sách {1}.", "Blacklist": "Danh sách đen", "BirthPlaceValue": "Nơi sinh: {0}", @@ -121,13 +121,13 @@ "Backdrops": "Phông nền", "Backdrop": "Phông nền", "Auto": "Tự động", - "AuthProviderHelp": "Chọn Nhà cung cấp xác thực sẽ được sử dụng để xác thực mật khẩu người dùng này.", + "AuthProviderHelp": "Chọn nhà cung cấp xác thực được dùng để xác thực mật khẩu người dùng này.", "Audio": "Âm thanh", "AspectRatio": "Tỷ lệ khung hình", "AskAdminToCreateLibrary": "Yêu cầu quản trị viên tạo thư viện.", "Ascending": "Tăng dần", "AsManyAsPossible": "Càng nhiều càng tốt", - "Artists": "Nghệ Sĩ", + "Artists": "Các Nghệ Sĩ", "AroundTime": "Khoảng", "Anytime": "Bất cứ lúc nào", "AnyLanguage": "Ngôn Ngữ Bất Kỳ", @@ -187,7 +187,7 @@ "ConfirmDeleteItems": "Xoá những mục này sẽ xoá chúng khỏi ổ cứng và thư viện của bạn. Bạn có chắc chắn muốn tiếp tục?", "ConfirmDeleteItem": "Xoá mục này sẽ xoá nó khỏi ổ cứng và thư viện của bạn. Bạn có chắc chắn muốn tiếp tục?", "ConfirmDeleteImage": "Bạn có chắc chắn xoá ảnh này?", - "ConfigureDateAdded": "Thiết lập cách xác định \"ngày thêm vào\" trong mục cài đặt Thư Viện của phần quản lý máy chủ Jellyfin", + "ConfigureDateAdded": "Định cấu hình cách xác định ngày đã thêm trong trang tổng quan trong cài đặt thư viện máy chủ Jellyfin", "Composer": "Tác giả", "CommunityRating": "Đánh giá của cộng đồng", "ColorTransfer": "Chuyển đổi màu", @@ -197,7 +197,7 @@ "ClientSettings": "Cài đặt thiết bị phát", "CinemaModeConfigurationHelp": "Chế độ Cinema giúp bạn mang lại trải nghiệm rạp chiếu phim ngay tại phòng khách với khả năng phát trailers và những đoạn mở đầu tuỳ chọn trước phần chính của bộ phim.", "ChannelNumber": "Kênh số", - "Channels": "Kênh", + "Channels": "Các Kênh", "ChannelNameOnly": "Chỉ kênh {0}", "ChannelAccessHelp": "Chọn những kênh để chia vẻ với người dùng này. Người quản lý sẽ có thể thay đổi toàn bộ kênh bằng cách sử dụng bộ quản lý thông tin.", "ChangingMetadataImageSettingsNewContent": "Thay đổi về thiết lập của việc tải thông tin hoặc hình ảnh sẽ chỉ có tác dụng với những nội dung mới được thêm vào thư viện. Để những thiết lập mới có tác dụng với nội dung đã có sẵn, bạn sẽ phải cập nhật lại thông tin của chúng.", @@ -222,7 +222,7 @@ "Directors": "Đạo Diễn", "Director": "Đạo Diễn", "DirectStreaming": "Phát trực tuyến", - "DirectStreamHelp2": "Phát trực tuyến sử dụng rất ít tài nguyên máy chủ mà không giảm chất lượng video.", + "DirectStreamHelp2": "Phát trực tiếp sử dụng ít sức mạnh xử lý với chất lượng video bị giảm thiểu chút ít.", "DirectStreamHelp1": "Nội dung này tương thích với thiết bị về độ phân giải và dạng mã hoá (H.264, AC3, v.v.), nhưng lại không tương tích định dạng (mkv, avi, wmv, v.v.). Video sẽ được chuyển đổi định dạng trực tiếp ngay trước khi phát trên thiết bị.", "DirectPlaying": "Phát trực tiếp", "DeviceAccessHelp": "Thiết lập này chỉ áp dụng cho những thiết bị có thể định danh và sẽ không chặn được truy cập từ trình duyệt. Chọn lọc thiết bị người dùng sẽ chặn người dùng này truy cập từ những thiết bị mới cho đến khi được duyệt.", @@ -233,7 +233,7 @@ "DeleteUserConfirmation": "Bạn có chắc chắn muốn xoá người dùng này?", "DeleteMedia": "Xoá nội dung", "DeleteDeviceConfirmation": "Bạn có chắc chắn muốn xoá thiết bị này? Nó sẽ xuất hiện lại khi người dùng đăng nhập bằng thiết bị đó.", - "DeinterlaceMethodHelp": "Chọn phương pháp khử xen kẽ khi chuyển mã những nội dung sử dụng phương pháp quét xen kẽ.", + "DeinterlaceMethodHelp": "Chọn phương pháp khử xen kẽ để sử dụng khi phần mềm chuyển mã nội dung xen kẽ. Khi tăng tốc phần cứng hỗ trợ khử xen kẽ phần cứng được bật, trình khử xen kẽ phần cứng sẽ được sử dụng thay cho cài đặt này.", "DefaultSubtitlesHelp": "Phụ đề được sử dụng dựa vào thiết lập mặc định (default) và bắt buộc (forced) trong phần thông tin bổ trợ. Tuỳ chọn ưu tiên ngôn ngữ sẽ có tác dụng khi có nhiều phụ đề khác nhau.", "DefaultMetadataLangaugeDescription": "Đây là thiết lập mặc định chung, bạn có thể tuỳ chỉnh thiết lập riêng cho từng thư viện.", "DisplayModeHelp": "Chọn kiểu bố trí giao diện mà bạn muốn.", @@ -247,12 +247,12 @@ "EditImages": "Chỉnh sửa hình ảnh", "Edit": "Chỉnh sửa", "EasyPasswordHelp": "Mã PIN tiện lợi được sử dụng cho việc truy cập offline trên những thiết bị được hỗ trợ và cũng có thể sử dụng dành cho truy cập dễ dàng trong nội mạng.", - "DropShadow": "Đổ Bóng", + "DropShadow": "Bóng đổ", "DrmChannelsNotImported": "Những kênh được bảo vệ bản quyền sẽ không được nhập vào.", "DownloadsValue": "{0} đã tải xuống", "EnableColorCodedBackgrounds": "Màu nền theo loại kênh", "HeaderDateIssued": "Ngày Phát Hành", - "HeaderContinueWatching": "Tiếp Tục Xem", + "HeaderContinueWatching": "Tiếp Tục Xem Tiếp", "HeaderContinueListening": "Tiếp Tục Nghe", "HeaderCodecProfileHelp": "Bộ giải mã chỉ ra những kiểu mã hoá nhất định mà một thiết bị có thể phát. Nếu một nội dung không thể phát, nó sẽ được chuyển mã, thậm chí nếu kiểu mã hoá đó được thiết lập phát trực tiếp.", "HeaderContainerProfileHelp": "Bộ định dạng chỉ ra những định dạng nhất định mà một thiết bị có thể phát. Nếu nội dung có định dạng không thể phát, nội dung sẽ được chuyển đổi định dạng, kể cả khi định dạng đó được thiết lập phát trực tiếp.", @@ -275,7 +275,7 @@ "HeaderAudioBooks": "Sách Nói", "HeaderAppearsOn": "Xuất Bản Vào", "HeaderApp": "Ứng dụng", - "HeaderApiKeysHelp": "Những ứng dụng khác cần có \"API key\" để tương tác với máy chủ Jellyfin. Những mã này được tạo ra bằng cách đăng nhập vào máy chủ Jellyfin, hoặc bạn có thể cung cấp cho ứng dụng một mã truy cập.", + "HeaderApiKeysHelp": "Ứng dụng bên ngoài cần có \"khóa API\" để giao tiếp với máy chủ Jellyfin. Khóa được cấp theo cách đăng nhập bằng tài khoản người dùng thông thường hoặc cấp khóa cho ứng dụng theo cách thủ công.", "HeaderApiKeys": "API Keys", "HeaderApiKey": "API Key", "HeaderAllowMediaDeletionFrom": "Cho Phép Xoá Nội Dung", @@ -325,10 +325,10 @@ "ErrorPleaseSelectLineup": "Hãy chọn một danh sách và thử lại. Nếu không có danh sách nào sẵn sàng, hãy chắc chắn rằng thông tin tài khoản, mật khẩu, và mã bưu điện đều chính xác.", "ErrorStartHourGreaterThanEnd": "Thời gian kết thúc phải lớn hơn thời gian bắt đầu.", "ErrorGettingTvLineups": "Có lỗi xảy ra khi tải danh sách TV này. Hãy thử lại khi chắc chắn rằng thông tin của bạn chính xác.", - "ErrorDeletingItem": "Có lỗi xảy ra khi xoá mục này khỏi máy chủ Jellyfin. Hãy thử lại sau khi kiểm tra chắc chắn rằng máy chủ Jellyfin có quyền ghi/xoá vào thư mục nội dung.", + "ErrorDeletingItem": "Có lỗi xảy ra khi xoá mục này khỏi máy chủ Jellyfin. Hãy kiểm tra xem máy chủ Jellyfin có quyền ghi/xoá vào thư mục đa phương tiện và thử xóa lại sau.", "ErrorAddingXmlTvFile": "Có lỗi xảy ra khi truy cập tài liệu XMLTV. Hãy thử lại khi chắc chắn rằng tài liệu này tồn tại.", "ErrorAddingTunerDevice": "Có lỗi xảy ra khi thêm vào thiết bị bắt sóng này. Hãy thử lại khi chắc chắn rằng nó có thể truy cập.", - "ErrorAddingMediaPathToVirtualFolder": "Có lỗi xảy ra khi thêm đường dẫn này. Hãy chắc chắn rằng đường dẫn này đúng và máy chủ Jellyfin có quyền truy cập dữ liệu ở đường dẫn đó.", + "ErrorAddingMediaPathToVirtualFolder": "Có lỗi xảy ra khi thêm đường dẫn phương tiện này. Vui lòng đảm bảo đường dẫn chính xác và Jellyfin được phép truy cập vào vị trí đó.", "ErrorAddingListingsToSchedulesDirect": "Có lỗi xảy ra khi thêm danh sách này vào tài khoản Schedules Direct của bạn. Schedules Direct chỉ cho phép một số lượng danh sách nhất định mỗi tài khoản. Bạn có thể cần phải đăng nhập vào trang web của Schedules Direct và xoá những danh sách khác trước khi có thể thêm danh sách mới.", "Episodes": "Tập", "Episode": "Tập", @@ -385,7 +385,7 @@ "HeaderLatestRecordings": "Bản Ghi Âm/Ghi Hình Mới Nhất", "HeaderLatestMusic": "Âm Nhạc Mới Nhất", "HeaderLatestMedia": "Nội Dung Mới Nhất", - "HeaderKodiMetadataHelp": "Để bật hoặc tắt dữ liệu từ NFO, hãy chỉnh sửa thư viện trong phần cài đặt thư viện của Jellyfin và điều chỉnh phần lưu trữ dữ liệu bổ trợ.", + "HeaderKodiMetadataHelp": "Để bật hoặc tắt chức năng tệp thông tin chi tiết NFO, hãy chỉnh sửa thư viện và xác định vị trí nơi lưu tệp NFO.", "HeaderKeepSeries": "Lưu Series", "HeaderKeepRecording": "Tiếp Tục Ghi Âm/Ghi Hình", "HeaderInstantMix": "Trộn Lẫn Nhanh", @@ -421,7 +421,7 @@ "HeaderDeleteDevice": "Xoá Thiết Bị", "HeaderDefaultRecordingSettings": "Thiết Lập Ghi Âm/Ghi Hình Mặc Định", "HeaderRecordingOptions": "Tuỳ Chọn Ghi Âm/Ghi Hình", - "HeaderProfileServerSettingsHelp": "Những thông tin này về máy chủ Jellyfin sẽ hiển thị trên các thiết bị phát được kết nối.", + "HeaderProfileServerSettingsHelp": "Các giá trị này kiểm soát cách máy chủ sẽ tự hiển thị với máy khách.", "HeaderServerSettings": "Cài Đặt Máy Chủ", "HeaderSeriesStatus": "Trạng Thái Series", "HeaderSeriesOptions": "Tuỳ Chọn Series", @@ -513,15 +513,15 @@ "LabelAccessStart": "Thời gian bắt đầu:", "LabelAccessEnd": "Thời gian kết thúc:", "LabelAccessDay": "Ngày trong tuần:", - "LabelAbortedByServerShutdown": "(Đã huỷ bởi máy chủ ngừng hoạt động)", + "LabelAbortedByServerShutdown": "(Bị hủy bỏ do máy chủ ngừng hoạt động)", "Label3DFormat": "Định dạng 3D:", "Kids": "Trẻ Em", "Items": "Mục", "ItemCount": "{0} mục", "InstantMix": "Trộn Lẫn Nhanh", "InstallingPackage": "Đang cài đặt {0} (phiên bản {1})", - "ImportMissingEpisodesHelp": "Nếu bật tuỳ chọn này, thông tin bị thiếu trong các tập phim sẽ được nhập vào cơ sở dữ liệu của máy chủ Jellyfin và hiển thị trong các phần và series. Điều này có thể làm việc quét thư viện lâu hơn rất nhiều.", - "ImportFavoriteChannelsHelp": "Nếu bật tuỳ chọn này, chỉ những kênh yêu thích trong thiết bị bắt sóng sẽ được nhập vào.", + "ImportMissingEpisodesHelp": "Thông tin về các tập bị thiếu sẽ được nhập vào cơ sở dữ liệu của bạn và hiển thị trong các phần và loạt phim. Điều này có thể làm quá trình quét thư viện lâu hơn đáng kể.", + "ImportFavoriteChannelsHelp": "Chỉ các kênh được đánh dấu là ưa thích trên thiết bị dò kênh mới được nhập.", "Images": "Hình Ảnh", "Identify": "Nhận Dạng", "HttpsRequiresCert": "Để bật kết nối bảo mật, bạn cần phải cung cấp một Chứng Chỉ SSL đáng tin cậy, ví dụ như \"Let's Encrypt\". Hãy cung cấp Chứng Chỉ SSL hoặc là tắt tính năng kết nối bảo mật.", @@ -633,20 +633,20 @@ "LabelImportOnlyFavoriteChannels": "Giới hạn để chỉ nhập vào những kênh yêu thích", "LabelImageType": "Loại hình ảnh:", "LabelImageFetchersHelp": "Kích hoạt và xếp hạng chương trình tải hình ảnh theo thứ tự ưu tiên.", - "LabelIdentificationFieldHelp": "Một phần chuỗi không phân biệt viết hoa/thường hoặc regex expression.", + "LabelIdentificationFieldHelp": "Một chuỗi không phân biệt viết hoa/thường hoặc biểu thức chính quy.", "LabelIconMaxWidth": "Chiều ngang tối đa của biểu tượng:", "LabelIconMaxHeight": "Chiều cao tối đa của biểu tượng:", - "LabelHttpsPortHelp": "TCP port mà máy chủ Jellyfin HTTPS nên kết nối vào.", - "LabelHttpsPort": "HTTPS port trên máy chủ:", + "LabelHttpsPortHelp": "Số cổng TCP cho máy chủ HTTPS.", + "LabelHttpsPort": "Số cổng HTTPS cục bộ:", "LabelHomeScreenSectionValue": "Mục trên trang chủ {0}:", - "LabelHomeNetworkQuality": "Chất lượng mạng trong nhà:", + "LabelHomeNetworkQuality": "Chất lượng mạng nhà:", "LabelHardwareAccelerationTypeHelp": "Hỗ trợ phần cần những thiết lập bổ sung.", - "LabelHardwareAccelerationType": "Hỗ trợ phần cứng:", + "LabelHardwareAccelerationType": "Tăng tốc phần cứng:", "LabelEncoderPreset": "Thiết lập cài sẵn của mã H264 và H265:", "LabelH264Crf": "CRF của mã H264:", - "LabelGroupMoviesIntoCollectionsHelp": "Khi hiển thị danh sách phim, các bộ phim thuộc về một bộ sưu tập sẽ hiển thị trong một nhóm.", - "LabelGroupMoviesIntoCollections": "Nhóm phim vào bộ sưu tập", - "LabelServerNameHelp": "Tên này sẽ được sử dụng để phân biệt máy chủ và giá trị mặc định là tên của máy tính chủ.", + "LabelGroupMoviesIntoCollectionsHelp": "Khi hiển thị danh sách phim, các bộ phim trong một bộ sưu tập sẽ hiển thị như một mục được nhóm lại.", + "LabelGroupMoviesIntoCollections": "Gom nhóm các phim vào bộ sưu tập", + "LabelServerNameHelp": "Tên này sẽ được dùng để phân biệt máy chủ và sẽ mặc định là tên của máy tính chủ.", "LabelFriendlyName": "Tên thân thiện:", "LabelFormat": "Định dạng:", "LabelForgotPasswordUsernameHelp": "Nhập vào tên tài khoản nếu bạn nhớ nó.", @@ -703,7 +703,7 @@ "LabelNewsCategories": "", "LabelStable": "Ổn Định", "LabelTonemappingAlgorithm": "Chọn thuật toán ánh xạ Tone màu để sử dụng:", - "TonemappingAlgorithmHelp": "Ánh xạ Tone màu có thể được tinh chỉnh. Nếu bạn không quen với tùy chọn này, hãy giữ mặc định.
    Giá trị mặc định: Reinhard.", + "TonemappingAlgorithmHelp": "Ánh xạ Tone màu có thể được tinh chỉnh. Nếu bạn không quen với tùy chọn này, hãy giữ mặc định.
    Giá trị mặc định: Reinhard.", "TonemappingRangeHelp": "Chọn dải màu đầu ra. Tự động là giống như dải màu đầu vào.", "StopPlayback": "Dừng Phát", "Preview": "Xem Trước", @@ -714,5 +714,62 @@ "Shows": "Các Chương Trình", "Songs": "Các Bài Hát", "Sync": "Đồng Bộ", - "ValueSpecialEpisodeName": "Đặc Biệt - {0}" + "ValueSpecialEpisodeName": "Đặc Biệt - {0}", + "Filter": "Bộ lọc", + "New": "Mới", + "Shuffle": "Xáo trộn", + "Share": "Chia sẻ", + "ShowAdvancedSettings": "Hiển thị cài đặt nâng cao", + "ShowIndicatorsFor": "Hiển thị các chỉ số cho:", + "ShowLess": "Hiển thị ít hơn", + "ShowMore": "Hiển thị thêm", + "ShowYear": "Hiển thị năm", + "ShowTitle": "Hiển thị tiêu đề", + "RepeatEpisodes": "Lặp lại các tập", + "RepeatMode": "Chế Độ Lặp Lại", + "RepeatAll": "Lặp lại tất cả", + "Repeat": "Lặp lại", + "RemoveFromPlaylist": "Xóa khỏi danh sách phát", + "RemoveFromCollection": "Xóa khỏi bộ sưu tập", + "RememberMe": "Ghi nhớ Tôi", + "ReleaseDate": "Ngày phát hành", + "RefreshQueued": "Làm mới đã xếp hàng đợi.", + "RefreshMetadata": "Làm mới thông tin chi tiết", + "RecordingScheduled": "Ghi theo lịch trình.", + "RefreshDialogHelp": "Thông tin chi tiết được làm mới trên cài đặt và dịch vụ internet được bật trong trang tổng quan.", + "Refresh": "Làm mới", + "Record": "Ghi lại", + "RecommendationStarring": "Diễn Viên Chính {0}", + "RecommendationDirectedBy": "Do {0} đạo diễn", + "RecommendationBecauseYouWatched": "Bởi vì bạn đã xem {0}", + "RecommendationBecauseYouLike": "Bởi vì bạn thích {0}", + "RecentlyWatched": "Đã xem gần đây", + "Rate": "Đánh giá", + "OptionResumable": "Có thể tiếp tục", + "OptionSpecialEpisode": "Đặc biệt", + "OptionSubstring": "Chuỗi con", + "OptionResElement": "thành phần res", + "MessageItemsAdded": "Đã thêm vào các mục.", + "MessageInvalidForgotPasswordPin": "Đã nhập mã pin không hợp lệ hoặc hết hạn. Vui lòng thử lại.", + "MessageInvalidUser": "Sai tên đăng nhập hoặc mật khẩu. Vui lòng thử lại.", + "MessageItemSaved": "Mục đã được lưu.", + "LabelTVHomeScreen": "Màn hình chính chế độ TV:", + "OptionProtocolHttp": "HTTP", + "OptionPlainVideoItemsHelp": "Tất cả các video được trình bày trong DIDL như \"object.item.videoItem\" thay vì một loại cụ thể hơn, chẳng hạn như \"object.item.videoItem.movie\".", + "OptionPlainVideoItems": "Hiển thị tất cả video dưới dạng các mục video thuần túy", + "OptionPremiereDate": "Ngày công chiếu", + "OptionProtocolHls": "Luồng Trực Tiếp HTTP", + "OptionRandom": "Ngẫu Nhiên", + "OptionRegex": "Biểu thức chính quy", + "OptionRequirePerfectSubtitleMatch": "Chỉ tải xuống phụ đề phù hợp nhất với tệp video của tôi", + "OptionReportByteRangeSeekingWhenTranscodingHelp": "Điều này là bắt buộc đối với một số thiết bị không có thời gian tìm kiếm tốt.", + "OptionReportByteRangeSeekingWhenTranscoding": "Báo cáo máy chủ có hỗ trợ tìm kiếm byte khi chuyển mã", + "OptionReleaseDate": "Ngày Phát Hành", + "MessageForgotPasswordInNetworkRequired": "Vui lòng thử lại trong mạng nhà của bạn để bắt đầu quá trình đặt lại mật khẩu.", + "MessageImageTypeNotSelected": "Vui lòng chọn một kiểu ảnh từ menu thả xuống.", + "MessageImageFileTypeAllowed": "Chỉ các tệp JPEG và PNG được hỗ trợ.", + "LabelKnownProxies": "Các Proxy đã biết:", + "LabelIconMaxResHelp": "Độ phân giải tối đa của các biểu tượng được hiển thị thông qua thuộc tính upnp:icon .", + "KnownProxiesHelp": "Danh sách địa chỉ IP của các proxy đã biết được sử dụng khi kết nối với phiên bản Jellyfin của bạn được phân tách bằng dấu phẩy. Đây là bắt buộc để sử dụng đúng các tiêu đề X-Forwarded-For. Yêu cầu khởi động lại sau khi lưu.", + "Image": "Hình Ảnh" } From 3fa3f3e56b33f6b763467299ec7fca182f489a2a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 20:28:13 +0000 Subject: [PATCH 076/281] [Security] Bump bl from 1.2.2 to 1.2.3 Bumps [bl](https://github.com/rvagg/bl) from 1.2.2 to 1.2.3. **This update includes a security fix.** - [Release notes](https://github.com/rvagg/bl/releases) - [Commits](https://github.com/rvagg/bl/compare/v1.2.2...v1.2.3) Signed-off-by: dependabot-preview[bot] --- yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index 25e4d12c68..8fa0ad14ea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1896,9 +1896,9 @@ bindings@^1.5.0: file-uri-to-path "1.0.0" bl@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" - integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== + version "1.2.3" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" + integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== dependencies: readable-stream "^2.3.5" safe-buffer "^5.1.1" @@ -9880,9 +9880,9 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" - integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== safe-regex@^1.1.0: version "1.1.0" From 436dfb85e56821209a49e4a36dcc419e39510b75 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 20:31:20 +0000 Subject: [PATCH 077/281] Bump query-string from 6.13.1 to 6.13.2 Bumps [query-string](https://github.com/sindresorhus/query-string) from 6.13.1 to 6.13.2. - [Release notes](https://github.com/sindresorhus/query-string/releases) - [Commits](https://github.com/sindresorhus/query-string/compare/v6.13.1...v6.13.2) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3a74cd9d67..ebb5da98ec 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "material-design-icons-iconfont": "^6.1.0", "native-promise-only": "^0.8.0-a", "page": "^1.11.6", - "query-string": "^6.13.1", + "query-string": "^6.13.2", "resize-observer-polyfill": "^1.5.1", "screenfull": "^5.0.2", "sortablejs": "^1.10.2", diff --git a/yarn.lock b/yarn.lock index 25e4d12c68..0be2dcc996 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9237,10 +9237,10 @@ query-string@^5.0.1: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -query-string@^6.13.1: - version "6.13.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.1.tgz#d913ccfce3b4b3a713989fe6d39466d92e71ccad" - integrity sha512-RfoButmcK+yCta1+FuU8REvisx1oEzhMKwhLUNcepQTPGcNMp1sIqjnfCtfnvGSQZQEhaBHvccujtWoUV3TTbA== +query-string@^6.13.2: + version "6.13.2" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.2.tgz#3585aa9412c957cbd358fd5eaca7466f05586dda" + integrity sha512-BMmDaUiLDFU1hlM38jTFcRt7HYiGP/zt1sRzrIWm5zpeEuO1rkbPS0ELI3uehoLuuhHDCS8u8lhFN3fEN4JzPQ== dependencies: decode-uri-component "^0.2.0" split-on-first "^1.0.0" From b4386473e66291d082ba2d1566a6869bb0364176 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 20:31:59 +0000 Subject: [PATCH 078/281] Bump stylelint from 13.7.0 to 13.7.1 Bumps [stylelint](https://github.com/stylelint/stylelint) from 13.7.0 to 13.7.1. - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/master/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint/compare/13.7.0...13.7.1) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3a74cd9d67..a0fd03a962 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "postcss-loader": "^3.0.0", "postcss-preset-env": "^6.7.0", "style-loader": "^1.1.3", - "stylelint": "^13.7.0", + "stylelint": "^13.7.1", "stylelint-config-rational-order": "^0.1.2", "stylelint-no-browser-hacks": "^1.2.1", "stylelint-order": "^4.1.0", diff --git a/yarn.lock b/yarn.lock index 25e4d12c68..70a0e73330 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10830,10 +10830,10 @@ stylelint-order@^4.1.0: postcss "^7.0.31" postcss-sorting "^5.0.1" -stylelint@^13.7.0: - version "13.7.0" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-13.7.0.tgz#8d7a4233063b2f06e9f28b3405ff189e334547b5" - integrity sha512-1wStd4zVetnlHO98VjcHQbjSDmvcA39smkZQMct2cf+hom40H0xlQNdzzbswoG/jGBh61/Ue9m7Lu99PY51O6A== +stylelint@^13.7.1: + version "13.7.1" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-13.7.1.tgz#bee97ee78d778a3f1dbe3f7397b76414973e263e" + integrity sha512-qzqazcyRxrSRdmFuO0/SZOJ+LyCxYy0pwcvaOBBnl8/2VfHSMrtNIE+AnyJoyq6uKb+mt+hlgmVrvVi6G6XHfQ== dependencies: "@stylelint/postcss-css-in-js" "^0.37.2" "@stylelint/postcss-markdown" "^0.36.1" From 0bd89010d3780e5c77478c1545531f86fd4a230e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 20:32:26 +0000 Subject: [PATCH 079/281] Bump hls.js from 0.14.11 to 0.14.12 Bumps [hls.js](https://github.com/video-dev/hls.js) from 0.14.11 to 0.14.12. - [Release notes](https://github.com/video-dev/hls.js/releases) - [Changelog](https://github.com/video-dev/hls.js/blob/master/docs/release-process.md) - [Commits](https://github.com/video-dev/hls.js/compare/v0.14.11...v0.14.12) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3a74cd9d67..ac4ce520c9 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "fast-text-encoding": "^1.0.3", "flv.js": "^1.5.0", "headroom.js": "^0.11.0", - "hls.js": "^0.14.11", + "hls.js": "^0.14.12", "howler": "^2.2.0", "intersection-observer": "^0.11.0", "jellyfin-apiclient": "^1.4.1", diff --git a/yarn.lock b/yarn.lock index 25e4d12c68..96eb1f6d17 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5484,10 +5484,10 @@ hex-color-regex@^1.1.0: resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== -hls.js@^0.14.11: - version "0.14.11" - resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-0.14.11.tgz#b3d123c45b1feb8c5c19f70574074fa0a77e016b" - integrity sha512-l7fm8AAEIIVc9r+RZbVAPcpccWIk6oludZ7R78B/ZJsYvuL5LJF8h0o8iayoIcbPT8ArM8vBhOkWFbe9q46Kew== +hls.js@^0.14.12: + version "0.14.12" + resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-0.14.12.tgz#d57042115bee8570861482a8245cbd8b064a6cb4" + integrity sha512-ye0KUhGp/K36gUb49MV5sA+uvEy4GVX4mJur8Bd2uCyLKpZs2zVm6aPHLR8iF3SBKbDF6n/SDHVgrTQxKSmsZQ== dependencies: eventemitter3 "^4.0.3" url-toolkit "^2.1.6" From bc0c690defa9158335a6a11579dd8d7698fa0211 Mon Sep 17 00:00:00 2001 From: Thomas Schwery Date: Mon, 14 Sep 2020 19:58:47 +0000 Subject: [PATCH 080/281] Translated using Weblate (French) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fr/ --- src/strings/fr.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/strings/fr.json b/src/strings/fr.json index ed243f98a4..83490ba61a 100644 --- a/src/strings/fr.json +++ b/src/strings/fr.json @@ -1392,5 +1392,10 @@ "LabelKnownProxies": "Proxies connus :", "KnownProxiesHelp": "Liste séparée par des virgules d'adresses IP des proxies connus utilisés pour se connecter à l'instance Jellyfin. Ceci est nécessaire afin de pouvoir utiliser correctement les entêtes X-Forwarded-For. Nécessite un redémarrage après sauvegarde.", "LabelTonemappingThreshold": "Seuil de mappage tonal :", - "LabelTonemappingDesatHelp": "Désature les couleurs qui dépassent ce niveau de luminosité. Plus ce paramètre est élevé, plus les informations de couleur seront préservées. Ce paramètre permet d'éviter les couleurs anormalement éclatantes pour les couleurs super-lumineuses en les transformant (de manière lisse) en blanc. Ceci rend l'image plus naturelle au prix d'une réduction d'information dans les couleurs hors-gamme. Les valeurs recommandées et par défaut sont 0 et 0.5." + "LabelTonemappingDesatHelp": "Désature les couleurs qui dépassent ce niveau de luminosité. Plus ce paramètre est élevé, plus les informations de couleur seront préservées. Ce paramètre permet d'éviter les couleurs anormalement éclatantes pour les couleurs super-lumineuses en les transformant (de manière lisse) en blanc. Ceci rend l'image plus naturelle au prix d'une réduction d'information dans les couleurs hors-gamme. Les valeurs recommandées et par défaut sont 0 et 0.5.", + "LabelTonemappingParamHelp": "Affine l'algorithme de mappage tonal. Les valeurs recommandées et par défaut sont indéfinies. Laissez en général ces valeurs vides.", + "LabelTonemappingPeak": "Pic de mappage tonal :", + "LabelTonemappingThresholdHelp": "Les paramètres de l'algorithme de mappage tonal sont affinés pour chaque scène. Un seuil est utilisé pour détecter lorsque la scène change. Si la distance entre la moyenne actuelle de la luminosité du cadre et la moyenne mobile actuelle dépasse la valeur du seuil, la moyenne et le pic de la luminosité du cadre sont recalculés. Les valeurs recommandées et par défaut sont 0.8 et 0.2.", + "LabelVideoRange": "Plage vidéo :", + "MediaInfoVideoRange": "Plage vidéo" } From 7a6cbc6b609a734568ecfb347cc437a93544a568 Mon Sep 17 00:00:00 2001 From: Harry Sintonen Date: Tue, 15 Sep 2020 00:52:22 +0000 Subject: [PATCH 081/281] Translated using Weblate (Finnish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fi/ --- src/strings/fi.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/strings/fi.json b/src/strings/fi.json index 2c73fbcd14..861eda2698 100644 --- a/src/strings/fi.json +++ b/src/strings/fi.json @@ -61,7 +61,7 @@ "AllowMediaConversion": "Salli median muunto", "AllowMediaConversionHelp": "Salli tai kiellä pääsy median muunnostoimintoon.", "AllowOnTheFlySubtitleExtractionHelp": "Sisäiset tekstitykset voidaan lähettää päätelaitteille ilmitekstinä, jotta videota ei tarvitsisi uudelleenkoodata. Joissain järjestelmissä tämä voi viedä paljon aikaa ja aiheuttaa toiston pysähtymisen purun ajaksi. Poista tämä käytöstä polttaaksesi tekstiykset suoraan videoon, mikäli päätelaite ei tue tekstityksiä.", - "AllowRemoteAccess": "Salli etäyhteydet tähän Jellyfin palvelimeen.", + "AllowRemoteAccess": "Salli etäyhteydet tähän palvelimeen.", "AllowRemoteAccessHelp": "Jos merkki puuttuu, kaikki ulkopuoliset yhteydet estetään.", "AllowedRemoteAddressesHelp": "Pilkuilla eroteltu lista IP-osoitteista tai IP/verkonpeite merkinnöistä verkoille, joille sallitaan etäyhteys palvelimeen. Tyhjäksi jätetty lista tarkoittaa, että kaikki osoitteet sallitaan.", "AlwaysPlaySubtitles": "Näytä aina tekstitykset", @@ -145,10 +145,10 @@ "ColorTransfer": "Värien siirto", "CommunityRating": "Yhteisön arvosana", "Composer": "Säveltäjä", - "ConfigureDateAdded": "Lisäyspäivämäärän määritykset löytyvät kirjaston asetuksien alta Jellyfin-palvelimen kojelaudalla", + "ConfigureDateAdded": "Lisäyspäivämäärän määritykset löytyvät kirjaston asetuksien alta palvelimen kojelaudalla", "ConfirmDeleteImage": "Poista kuva?", - "ConfirmDeleteItem": "Tämän esineen poistaminen poistaa sen sekä tiedostojärjestelmästä että mediakirjastosta. Haluatko varmasti jatkaa?", - "ConfirmDeleteItems": "Näiden esineiden poistaminen poistaa ne sekä tiedostojärjestelmästä että mediakirjastosta. Haluatko varmasti jatkaa?", + "ConfirmDeleteItem": "Tämän kohteen poistaminen poistaa sen sekä tiedostojärjestelmästä että mediakirjastosta. Haluatko varmasti jatkaa?", + "ConfirmDeleteItems": "Näiden kohteiden poistaminen poistaa ne sekä tiedostojärjestelmästä että mediakirjastosta. Haluatko varmasti jatkaa?", "ConfirmDeletion": "Vahvista poistaminen", "ConfirmEndPlayerSession": "Haluaisitko sammuttaa Jellyfinin tähän aikaan {0}?", "Connect": "Yhdistä", From e529411c3804fa8971e28e48a3e30c643a08e370 Mon Sep 17 00:00:00 2001 From: "federico.antoniazzi.000" Date: Tue, 15 Sep 2020 00:29:46 +0000 Subject: [PATCH 082/281] Translated using Weblate (Italian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/it/ --- src/strings/it.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/strings/it.json b/src/strings/it.json index 5d794dbc2b..02ee3e0684 100644 --- a/src/strings/it.json +++ b/src/strings/it.json @@ -1373,10 +1373,12 @@ "UseDoubleRateDeinterlacing": "Raddoppia il frame rate durante il deinterlacciamento", "KnownProxiesHelp": "Lista degli IP separati da virgola dei proxy utilizzati per connettersi a Jellyfin. Ciò consente di gestire al meglio gli header X-Forwarded-For. Richiede il reboot.", "LabelKnownProxies": "Proxy conosciuti:", - "LabelColorSpace": "Spazio colore:", - "LabelVideoRange": "Range video:", + "LabelColorSpace": "Spazio colori:", + "LabelVideoRange": "Intervallo video:", "MediaInfoColorSpace": "Spazio colore", "ThumbCard": "Miniatura", "PosterCard": "Locandina", - "LabelOpenclDevice": "Dispositivo OpenCL:" + "LabelOpenclDevice": "Dispositivo OpenCL:", + "MediaInfoVideoRange": "Intervallo video", + "UseDoubleRateDeinterlacingHelp": "Questa opzione usa il campo frequenza durante il deinterlacciamento, detto anche \"bob deinterlacing\", il quale raddoppia il frame rate del video per fornire \"full motion\" come se guardassi un video interlacciato su una TV." } From 4533f8f1acebb4178b77618ebab72904c1a58b0d Mon Sep 17 00:00:00 2001 From: Harry Sintonen Date: Tue, 15 Sep 2020 01:30:26 +0000 Subject: [PATCH 083/281] Translated using Weblate (Finnish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fi/ --- src/strings/fi.json | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/strings/fi.json b/src/strings/fi.json index 861eda2698..fd4df6d781 100644 --- a/src/strings/fi.json +++ b/src/strings/fi.json @@ -4,7 +4,7 @@ "ButtonCancel": "Peruuta", "ButtonSignOut": "Sign out", "Delete": "Poista", - "DeleteImage": "Poista Kuva", + "DeleteImage": "Poista kuva", "DeleteImageConfirmation": "Oletko varma että haluat poistaa tämän kuvan?", "DeleteUser": "Poista käyttäjä", "DeleteUserConfirmation": "Oletko varma että haluat poistaa tämän käyttäjän?", @@ -150,7 +150,7 @@ "ConfirmDeleteItem": "Tämän kohteen poistaminen poistaa sen sekä tiedostojärjestelmästä että mediakirjastosta. Haluatko varmasti jatkaa?", "ConfirmDeleteItems": "Näiden kohteiden poistaminen poistaa ne sekä tiedostojärjestelmästä että mediakirjastosta. Haluatko varmasti jatkaa?", "ConfirmDeletion": "Vahvista poistaminen", - "ConfirmEndPlayerSession": "Haluaisitko sammuttaa Jellyfinin tähän aikaan {0}?", + "ConfirmEndPlayerSession": "Haluaisitko katkaista etätoiston kohteessa {0}?", "Connect": "Yhdistä", "ContinueWatching": "Jatka katselua", "Continuing": "Jatketaan", @@ -159,9 +159,9 @@ "DatePlayed": "Toistopäivämäärä", "Default": "Oletus", "ErrorDefault": "Pyynnön käsittelyssä tapahtui virhe. Yritä myöhemmin uudelleen.", - "DefaultMetadataLangaugeDescription": "Nämä ovat sinun oletuksetasetukset ja niitä voidaan muokata kirjastokohtaisesti.", + "DefaultMetadataLangaugeDescription": "Nämä ovat sinun oletusasetuksesi ja niitä voidaan muokata kirjastokohtaisesti.", "DefaultSubtitlesHelp": "Tekstitykset ladataan pakotettu- ja oletusmäärityksien upotetun metadatan mukaan. Kieliasetukset otetaan huomioon, kun on enemmän kuin yksi tekstitys josta valita.", - "DeleteDeviceConfirmation": "Oletko varma, että haluat positaa tämän laitteen? Se ilmaantuu uudelleen seuraavan kerran, kun jokin käyttäjä kirjautuu sillä.", + "DeleteDeviceConfirmation": "Oletko varma, että haluat poistaa tämän laitteen? Se ilmaantuu uudelleen seuraavan kerran, kun jokin käyttäjä kirjautuu sillä.", "DeleteMedia": "Poista media", "Descending": "Laskeva", "Desktop": "Työpöytä", @@ -1010,7 +1010,7 @@ "ValueCodec": "Codec: {0}", "ValueAudioCodec": "Audio Codec: {0}", "SeriesYearToPresent": "{0} - Nykyhetki", - "DeinterlaceMethodHelp": "Valitse lomituksen poistomenetelmä, jota käytetään lomitetun sisällön transkoodaukseen.", + "DeinterlaceMethodHelp": "Valitse lomituksen poistomenetelmä, jota käytetään lomitetun sisällön transkoodaukseen. Mikäli omituksen poiston hallitsevaa rautakiihdytettyä purkua käytetään, ei tätä asetusta oteta huomioon.", "FormatValue": "Muoto: {0}", "General": "Yleinen", "FetchingData": "Noudetaan lisätietoja", @@ -1045,5 +1045,6 @@ "ApiKeysCaption": "Lista aktiivisista API-avaimista", "HeaderApiKeysHelp": "Ulkoiset sovellukset tarvitsevat API-avaimen voidakseen toimia Jellyfin -palvelimen kanssa. Avaimet myönnetään joko kirjautumalla sisään Jellyfin -käyttäjätunnuksella tai myöntämällä sellainen sovellukselle manuaalisesti.", "HeaderAdditionalParts": "Muut osat", - "HeaderActiveRecordings": "Käynnissä olevat nauhoitukset" + "HeaderActiveRecordings": "Käynnissä olevat nauhoitukset", + "Data": "Tieto" } From 323be6152e5527cfeb11f0d2b99542ca71ca6ac1 Mon Sep 17 00:00:00 2001 From: Harry Sintonen Date: Tue, 15 Sep 2020 01:41:43 +0000 Subject: [PATCH 084/281] Translated using Weblate (Finnish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fi/ --- src/strings/fi.json | 164 ++++++++++++++++++++++++++++---------------- 1 file changed, 104 insertions(+), 60 deletions(-) diff --git a/src/strings/fi.json b/src/strings/fi.json index fd4df6d781..04348d5d4b 100644 --- a/src/strings/fi.json +++ b/src/strings/fi.json @@ -1,8 +1,8 @@ { "MessageBrowsePluginCatalog": "Selaa lisäosakuvastoamme katsoaksesi saatavilla olevia lisäosia.", - "ButtonAddUser": "Lisää Käyttäjä", + "ButtonAddUser": "Lisää käyttäjä", "ButtonCancel": "Peruuta", - "ButtonSignOut": "Sign out", + "ButtonSignOut": "Kirjaudu ulos", "Delete": "Poista", "DeleteImage": "Poista kuva", "DeleteImageConfirmation": "Oletko varma että haluat poistaa tämän kuvan?", @@ -10,10 +10,10 @@ "DeleteUserConfirmation": "Oletko varma että haluat poistaa tämän käyttäjän?", "FileNotFound": "Tiedostoa ei löydy.", "FileReadCancelled": "Tiedoston luku on peruutettu.", - "FileReadError": "Virhe tiedoston luvun aikana.", + "FileReadError": "Virhe tiedostoa luettaessa.", "LabelAudioLanguagePreference": "Äänen ensisijainen kieli:", "LabelCountry": "Maa:", - "LabelCurrentPassword": "Tämän hetkinen salsana:", + "LabelCurrentPassword": "Tämän hetkinen salasana:", "LabelFinish": "Valmis", "LabelLanguage": "Kieli:", "LabelMaxParentalRating": "Suurin sallittu ikäraja:", @@ -57,7 +57,7 @@ "AllowOnTheFlySubtitleExtraction": "Salli tekstitysten purkaminen lennossa", "AccessRestrictedTryAgainLater": "Pääsy on toistaiseksi estetty. Yritä myöhemmin uudelleen.", "Aired": "Esityspäivä", - "AllowHWTranscodingHelp": "Salli virittimen muuntaa bittivirtaa lennossa. Tämä voi vähentää muunnoksen tarvetta Jellyfin-palvelimella.", + "AllowHWTranscodingHelp": "Salli virittimen muuntaa bittivirtaa lennossa. Tämä voi vähentää videomuunnoksen tarvetta palvelimella.", "AllowMediaConversion": "Salli median muunto", "AllowMediaConversionHelp": "Salli tai kiellä pääsy median muunnostoimintoon.", "AllowOnTheFlySubtitleExtractionHelp": "Sisäiset tekstitykset voidaan lähettää päätelaitteille ilmitekstinä, jotta videota ei tarvitsisi uudelleenkoodata. Joissain järjestelmissä tämä voi viedä paljon aikaa ja aiheuttaa toiston pysähtymisen purun ajaksi. Poista tämä käytöstä polttaaksesi tekstiykset suoraan videoon, mikäli päätelaite ei tue tekstityksiä.", @@ -89,14 +89,14 @@ "Box": "Laatikko", "BoxRear": "Laatikko (takaa)", "Browse": "Selaa", - "ButtonAddMediaLibrary": "Lisää Mediakirjasto", - "ButtonAddScheduledTaskTrigger": "Lisää Liipaisin", - "ButtonAddServer": "Lisää Palvelin", + "ButtonAddMediaLibrary": "Lisää mediakirjasto", + "ButtonAddScheduledTaskTrigger": "Lisää liipaisin", + "ButtonAddServer": "Lisää palvelin", "ButtonArrowLeft": "Vasen", "ButtonArrowRight": "Oikea", "ButtonAudioTracks": "Ääniraidat", "ButtonBack": "Takaisin", - "ButtonChangeServer": "Vaihda Palvelinta", + "ButtonChangeServer": "Vaihda palvelinta", "ButtonEditOtherUserPreferences": "Muokkaa tämän käyttäjän profiilia, kuvaa ja henkilökohtaisia asetuksia.", "ButtonForgotPassword": "Unohtuiko salasana", "ButtonFullscreen": "Kokonäyttötila", @@ -136,7 +136,7 @@ "Categories": "Kategoriat", "ChangingMetadataImageSettingsNewContent": "Muutokset metadatan tai kuvituksien lataamisasetuksiin vaikuttaa ainoastaan tulevaan kirjaston sisältöön. Päivittääksesi myös vanhan sisällön sinun täytyy päivittää metadata manuaalisesti.", "ChannelAccessHelp": "Valitse kanavat jotka jaetaan tämän käyttäjän kanssa. Järjestelmänvalvojat pystyvät muuttamaan kaikkia kanavia käyttämällä metadatan hallintatyökalua.", - "ChannelNameOnly": "Kanava {0} ainoastaan", + "ChannelNameOnly": "Vain kanava {0}", "Channels": "Kanavat", "CinemaModeConfigurationHelp": "Elokuvatila tuo teatterikokemuksen suoraan olohuoneeseesi mahdollistamalla trailereiden ja omien introjen toistamisen ennen päänumeroa.", "Collections": "Kokoelmat", @@ -169,8 +169,8 @@ "DeviceAccessHelp": "Tämä pätee ainoastaan laitteisiin, jotka voidaan tunnistaa uniikkina ja ei estä selainpääsyä. Uusien laitteiden suodattaminen estää niiden käyttämisen ennen hyväksyntää täältä.", "DirectPlaying": "Suoraan toistaminen", "DirectStreamHelp1": "Tämä media on yhteensopiva laitteen kanssa katsoen resoluutiota ja mediatyyppiä (H.264, AC3, jne.), mutta se ei ole yhteensopivassa tiedostosäiliössä (mkv, avi, wmv, jne.). Tämä video uudelleenpakataan lennossa ennen laitteeseen lähetystä.", - "DirectStreamHelp2": "Tiedoston suoraan toistaminen käyttää erittäin vähän prosessorin resursseja ilman laadun heikentämistä.", - "DirectStreaming": "Suora suoratoisto", + "DirectStreamHelp2": "Tiedoston suoratoisto käyttää erittäin vähän prosessorin resursseja ilman laadun heikkenemistä.", + "DirectStreaming": "Suoratoisto", "Director": "Ohjaaja", "Directors": "Ohjaajat", "Disc": "Levy", @@ -178,7 +178,7 @@ "DisplayInMyMedia": "Näytä kotinäytöllä", "DisplayInOtherHomeScreenSections": "Näytä kotinäytöllä osastoja kuten viimeisin media ja jatka katselua", "DisplayMissingEpisodesWithinSeasons": "Näytä puuttuvat jaksot tuotantokausissa", - "DisplayMissingEpisodesWithinSeasonsHelp": "Tämän pitää aktivoida TV-kirjastoille myös palvelimen asetuksissa.", + "DisplayMissingEpisodesWithinSeasonsHelp": "Tämä pitää aktivoida TV-kirjastoille myös palvelimen asetuksissa.", "DisplayModeHelp": "Valitse ulkonäkö, jonka haluat käyttöliittymälle.", "DoNotRecord": "Älä tallenna", "Down": "Alas", @@ -193,7 +193,7 @@ "EditSubtitles": "Muokkaa tekstityksiä", "ChannelNumber": "Kanavan numero", "CancelSeries": "Peruuta sarja", - "CopyStreamURL": "Kopioi Toiston Osoite", + "CopyStreamURL": "Kopioi toisto-osoite", "ButtonAddImage": "Lisää kuva", "Movies": "Elokuvat", "HeaderContinueWatching": "Jatka katsomista", @@ -211,35 +211,35 @@ "CopyStreamURLSuccess": "Osoite kopioitu onnistuneesti.", "DeathDateValue": "Kuoli: {}", "CustomDlnaProfilesHelp": "Luo uusi profiili kohdistaaksesi uuteen laitteeseen tai ohittaaksesi järjestelmäprofiilin.", - "ErrorAddingMediaPathToVirtualFolder": "Media-polkua lisätessä ilmeni ongelma. Varmista, että polku on kirjoitettu oikein ja Jellyfin Palvelimella pääsy sijaintiin.", + "ErrorAddingMediaPathToVirtualFolder": "Media-polkua lisätessä ilmeni ongelma. Varmista, että polku on kirjoitettu oikein ja Jellyfinillä on pääsy tähän sijaintiin.", "Episodes": "Jaksot", "EndsAtValue": "Päättyy {0}", "Ended": "Päättynyt", "EnableThemeSongsHelp": "Soita tunnussäveliä taustalla selatessasi kirjastoa.", "EnableStreamLoopingHelp": "Laita tämä päälle, jos suoratoistot sisältävät vain muutaman sekuntin verran dataa jota tarvitsee pyytää jatkuvasti. Tämän päälle laittaminen ilman toiminnon tarvetta voi aiheuttaa ongelmia.", - "EnablePhotosHelp": "Kuvat tunnistetaan ja näytetään muiden media-tiedostojen ohessa.", + "EnablePhotosHelp": "Kuvat tunnistetaan ja näytetään muiden mediatiedostojen ohessa.", "EnablePhotos": "Näytä valokuvat", "EnableNextVideoInfoOverlay": "Näytä seuraavan videon tiedot toiston aikana", - "EnableHardwareEncoding": "Salli rauta-tason muunnoksen kiihdytys", + "EnableHardwareEncoding": "Salli videomuunnoksen rautakiihdytys", "EnableExternalVideoPlayers": "Ulkoiset videosoittimet", "EnableDisplayMirroring": "Näytön peilaus", - "EnableColorCodedBackgrounds": "Väri-koodatut taustat", - "EnableCinemaMode": "Teatteri-tila", + "EnableColorCodedBackgrounds": "Värikoodatut taustat", + "EnableCinemaMode": "Teatteritila", "EnableBackdropsHelp": "Näytä taustat tietyillä sivuilla selatessasi kirjastoa.", "EnableExternalVideoPlayersHelp": "Videota soitettaessa näytetään erillinen valikko.", "Depressed": "Painettu", - "ButtonSplit": "jaa", + "ButtonSplit": "Jaa", "AskAdminToCreateLibrary": "Pyydä järjestelmän ylläpitäjää luomaan kirjasto.", - "EnableStreamLooping": "Looppaa suoralähetykset", + "EnableStreamLooping": "Uudelleentoista suoralähetykset automaattisesti", "EnableNextVideoInfoOverlayHelp": "Näytä videon lopussa tietoja seuraavasta videosta soittolistalla.", - "ClientSettings": "Pääte-asetukset", + "ClientSettings": "Pääteasetukset", "AllowFfmpegThrottlingHelp": "Kun uudelleenkoodaus tai remux ehtii tarpeeksi toiston edelle, keskeytä laskenta jotta laskentaresursseja kuluu vähemmän. Tämä on hyödyllistä jos katselet hyppimättä eri kohtiin. Älä käytä jos toiston kanssa ilmenee ongelmia.", "AllowFfmpegThrottling": "Rajoita uudelleenkoodaus", - "ErrorDeletingItem": "Tiedostoa poistaessa Jellyfin Palvelimelta ilmeni virhe. Varmista, että Jellyfin Palvelimella on kirjoitusoikeudet mediakansioon ja kokeile uudestaan.", + "ErrorDeletingItem": "Tiedostoa palvelimelta poistaessa ilmeni virhe. Varmista, että Jellyfinillä on kirjoitusoikeudet mediakansioon ja kokeile uudestaan.", "ErrorAddingXmlTvFile": "XMLTV-tiedostoa käyttäessä tapahtui virhe. Varmista, että tiedosto on olemassa ja kokeile uudestaan.", "ErrorAddingTunerDevice": "Viritintä lisätessä ilmeni ongelma. Varmista, että se on kytketty oikein ja kokeile uudestaan.", - "EnableThemeVideosHelp": "Soita tunnusvideoita taustalla, selatessasi kirjastoa.", - "AlbumArtist": "Albumin Artisti", + "EnableThemeVideosHelp": "Soita tunnusvideoita taustalla selatessasi kirjastoa.", + "AlbumArtist": "Albumin artisti", "Album": "Albumi", "Played": "Toistetut", "PlayFromBeginning": "Toista alusta", @@ -321,7 +321,7 @@ "LabelPreferredDisplayLanguage": "Ensisijainen näyttökieli:", "LabelOriginalTitle": "Alkuperäinen nimi:", "LabelOriginalAspectRatio": "Alkuperäinen kuvasuhde:", - "LabelEnableAutomaticPortMapHelp": "Automaattisesti ohjaa reitittimesi julkiset portit palvelimesi paikallisiin portteihin UPnP:n kautta. Tämä ei välttämättä toimi kaikkien reitittimien tai verkkoasetusten kanssa. Muutokset tulevat voimaan vasta palvelimen uudelleenkäynnistyksen yhteydessä.", + "LabelEnableAutomaticPortMapHelp": "Ohjaa reitittimesi julkiset portit automaattisesti palvelimesi paikallisiin portteihin UPnP:n avulla. Tämä ei välttämättä toimi kaikkien reitittimien tai verkkoasetusten kanssa. Muutokset tulevat voimaan vasta palvelimen uudelleenkäynnistyksen yhteydessä.", "LabelEnableAutomaticPortMap": "Salli reitittimen porttien automaattinen avaaminen (UPnP)", "LabelDownloadLanguages": "Latauskielet:", "LabelDisplaySpecialsWithinSeasons": "Näytä erityiset jaksot kausien sisällä, jolloin ne ilmestyivät", @@ -331,13 +331,13 @@ "LabelDateTimeLocale": "Päivämäärä ja aika:", "LabelCustomRating": "Mukautettu luokitus:", "LabelCustomCss": "Mukautettu CSS:", - "LabelCertificatePassword": "Sertifikaatin salasana:", + "LabelCertificatePassword": "Varmenteen salasana:", "LabelArtistsHelp": "Erota useita käyttämällä ;", "LabelAppNameExample": "Esimerkiksi: Sickbeard, Sonarr", "LabelAppName": "Sovelluksen nimi", "LabelAllowedRemoteAddressesMode": "Etä-IP-osoitesuodattimen tila:", "LabelAllowedRemoteAddresses": "Etä-IP-osoitesuodatin:", - "LabelAllowHWTranscoding": "Salli laitteistolla transkoodaus", + "LabelAllowHWTranscoding": "Salli rautatranskoodaus", "LabelAlbumArtMaxWidth": "Albumin kuvan maksimileveys:", "LabelAlbumArtMaxHeight": "Albumin kuvan maksimikorkeus:", "LabelAbortedByServerShutdown": "(Keskeytetty palvelimen sammutuksen takia)", @@ -345,7 +345,7 @@ "Horizontal": "Horisontaalinen", "HideWatchedContentFromLatestMedia": "Piilota toistettu sisältö \"uusin media\"-luettelosta", "HeaderUpcomingOnTV": "Tulossa televisiossa", - "HeaderTypeImageFetchers": "{0} Kuvien hakijat", + "HeaderTypeImageFetchers": "{0} kuvien hakijaa", "HeaderTranscodingProfile": "Transkoodausprofiili", "HeaderTracks": "Raidat", "HeaderThisUserIsCurrentlyDisabled": "Tämä käyttäjä on poistettu käytöstä", @@ -362,7 +362,7 @@ "HeaderRemoveMediaLocation": "Poista mediasijainti", "HeaderRecordingOptions": "Tallennusasetukset", "HeaderRecentlyPlayed": "Äskettäin toistetut", - "HeaderProfileServerSettingsHelp": "Nämä arvot mukauttavat sitä, kuinka Jellyfin-palvelin esittää itsensä laitteelle.", + "HeaderProfileServerSettingsHelp": "Nämä arvot mukauttavat sitä, kuinka palvelin esittää itsensä laitteelle.", "HeaderProfileInformation": "Profiili-informaatio", "HeaderPreferredMetadataLanguage": "Ensisijainen metadatan kieli", "HeaderPinCodeReset": "Nollaa PIN-koodi", @@ -699,7 +699,7 @@ "InstallingPackage": "Asennetaan {0} (versio {1})", "HeaderVideoTypes": "Videotyypit", "HeaderVideoType": "Videotyyppi", - "HeaderUploadImage": "Lataa kuva", + "HeaderUploadImage": "Lähetä kuva", "HeaderTypeText": "Kirjoita teksti", "HeaderTunerDevices": "Viritinlaitteet", "HeaderTuners": "Virittimet", @@ -711,9 +711,9 @@ "HeaderSortBy": "Lajittele", "HeaderSelectServerCachePath": "Valitse palvelimen välimuistin polku", "HeaderSelectPath": "Valitse polku", - "HeaderSelectCertificatePath": "Valitse sertifikaatin polku", + "HeaderSelectCertificatePath": "Valitse varmenteen polku", "HeaderSelectMetadataPath": "Valitse metadatan polku", - "HeaderSecondsValue": "{0} Sekuntia", + "HeaderSecondsValue": "{0} sekuntia", "HeaderRunningTasks": "Käynnissä olevat tehtävät", "HeaderRevisionHistory": "Versiohistoria", "HeaderRemoveMediaFolder": "Poista mediakansio", @@ -726,8 +726,8 @@ "LabelLanNetworks": "Lähiverkot:", "LabelKodiMetadataDateFormat": "Julkaisupäivämäärän muoto:", "LabelImageType": "Kuvan tyyppi:", - "LabelIconMaxWidth": "Ikonin enimmäisleveys:", - "LabelIconMaxHeight": "Ikonin enimmäiskorkeus:", + "LabelIconMaxWidth": "Kuvakkeen enimmäisleveys:", + "LabelIconMaxHeight": "Kuvakkeen enimmäiskorkeus:", "LabelGroupMoviesIntoCollections": "Ryhmitä elokuvat kokoelmiin", "LabelFormat": "Muoto:", "LabelFont": "Kirjasinlaji:", @@ -782,7 +782,7 @@ "HeaderApiKeys": "API-avaimet", "HeaderApiKey": "API-avain", "HeaderAdmin": "Ylläpitäjä", - "HeaderAddUpdateImage": "Lisää/Päivitä kuva", + "HeaderAddUpdateImage": "Lisää/päivitä kuva", "HeaderAddToPlaylist": "Lisää soittolistaan", "HeaderAddToCollection": "Lisää kokoelmaan", "HeaderActiveDevices": "Aktiiviset laitteet", @@ -798,12 +798,12 @@ "LabelLocalHttpServerPortNumber": "Paikallisen HTTP-portin numero:", "LabelKodiMetadataSaveImagePaths": "Tallenna kuvien polut NFO-tiedostojen sisälle", "LabelKidsCategories": "Lasten kategoriat:", - "LabelHttpsPortHelp": "TCP-portin numero, jota Jellyfinin HTTPS-palvelimen tulee kuunnella.", + "LabelHttpsPortHelp": "HTTPS-palvelimen TCP-portin numero.", "LabelHttpsPort": "Paikallisen HTTPS-portin numero:", "LabelHardwareAccelerationTypeHelp": "Laitteistokiihdytys vaatii ylimääräistä määritystä.", "LabelHardwareAccelerationType": "Laitteistokiihdytys:", - "LabelEncoderPreset": "H264 and H265 encoding preset:", - "LabelH264Crf": "H264 encoding CRF:", + "LabelEncoderPreset": "H264- ja H265-enkoodaukset esiasetus:", + "LabelH264Crf": "H264-enkoodauksen CRF:", "LabelForgotPasswordUsernameHelp": "Anna käyttäjätunnuksesi, jos muistat sen.", "LabelEveryXMinutes": "Joka:", "LabelEndDate": "Päättymispäivä:", @@ -811,7 +811,7 @@ "LabelEnableDlnaDebugLoggingHelp": "Luo suuria lokitiedostoja ja tulisi käyttää vain tarvittaessa vianmääritystä varten.", "LabelEnableDlnaServerHelp": "Sallii verkon UPnP-laitteiden selata ja toistaa sisältöä tältä palvelimelta.", "LabelEnableDlnaServer": "Ota DLNA-palvelin käyttöön", - "LabelEnableDlnaPlayTo": "Salli DLNA toisto", + "LabelEnableDlnaPlayTo": "Salli DLNA-toisto", "LabelEnableDlnaDebugLogging": "Ota DLNA:n virheenjäljitys käyttöön", "LabelEnableBlastAliveMessages": "Lähetä hereilläolo -viesti", "LabelEnableBlastAliveMessagesHelp": "Ota tämä käyttöön, jos muilla verkon UPnP-laitteilla on ongelmia palvelimen havaitsemisessa.", @@ -824,11 +824,11 @@ "LabelDeviceDescription": "Laitteen kuvaus", "LabelDefaultScreen": "Oletusnäyttö:", "LabelDefaultUser": "Oletuskäyttäjä:", - "LabelCustomCertificatePathHelp": "Polku PKCS # 12-tiedostoon, joka sisältää sertifikaatin ja yksityisen avaimen, jotta TLS-tuki voidaan sallia henkilökohtaiselle verkkotunnukselle.", - "LabelCustomCertificatePath": "Mukautetun SSL-sertifikaatin polku:", + "LabelCustomCertificatePathHelp": "Polku PKCS #12-tiedostoon joka sisältää varmenteen ja yksityisen avaimen jolla TLS-tuki otetaan käyttöön omalle verkkotunnukselle.", + "LabelCustomCertificatePath": "Mukautetun SSL-varmenteen polku:", "LabelContentType": "Sisältötyyppi:", "LabelChannels": "Kanavat:", - "LabelCertificatePasswordHelp": "Jos sertifikaattisi vaatii salasanaa, laita se tähän.", + "LabelCertificatePasswordHelp": "Jos varmenteesi vaatii salasanaa, laita se tähän.", "LabelRuntimeMinutes": "Pituus (minuutteja):", "LabelReleaseDate": "Julkaisupäivä:", "Genre": "Tyylilaji", @@ -906,7 +906,7 @@ "LabelInternetQuality": "Verkkoyhteyden laatu:", "LabelEmbedAlbumArtDidl": "Upota albumin kuvamateriaali Didl:iin", "LabelDeinterlaceMethod": "Lomituksen poistamismenetelmä:", - "LabelAudioBitDepth": "Audion bittisyvyys:", + "LabelAudioBitDepth": "Äänen bittisyvyys:", "LabelAlbumArtists": "Albumin artistit:", "Items": "Kohteet", "ItemCount": "{0} kohdetta", @@ -919,7 +919,7 @@ "HeaderRecordingPostProcessing": "Tallennuksen jälkikäsittely", "HeaderParentalRatings": "Ikärajat", "HeaderOtherItems": "Muut kohteet", - "HeaderLiveTvTunerSetup": "Live-TV virittimen määritys", + "HeaderLiveTvTunerSetup": "Live-TV-virittimen määritys", "HeaderLibrarySettings": "Kirjaston asetukset", "HeaderGuideProviders": "TV-ohjelmaoppaiden tarjoajat", "HeaderEnabledFields": "Käytössä olevat kentät", @@ -941,19 +941,19 @@ "LabelEnableRealtimeMonitor": "Ota reaaliaikainen seuranta käyttöön", "LabelDropImageHere": "Pudota kuva tähän, tai paina selataksesi.", "LabelDroppedFrames": "Pudotettuja kuvia:", - "LabelDidlMode": "DIDL tila:", + "LabelDidlMode": "DIDL-tila:", "LabelCustomDeviceDisplayNameHelp": "Tätä nimeä käytetään laitteen tunnistamiseen. Jos tyhjä, käytetään laitteen nimeä.", - "LabelCustomCssHelp": "Käytä omaa CSS: ää web-käyttöliittymään.", + "LabelCustomCssHelp": "Käytä omia CSS-tyylimäärittelyjä web-käyttöliittymään.", "LabelCorruptedFrames": "Korruptoituneita kuvia:", "LabelCriticRating": "Kriitikoiden luokitus:", "LabelCommunityRating": "Yhteisön luokitus:", "LabelCancelled": "Peruttu", "LabelBlockContentWithTags": "Estä kohteet tunnisteilla:", - "LabelBitrate": "Bitrate:", - "LabelAudioSampleRate": "Audion näytteenottotaajuus:", - "LabelAudioChannels": "Audiokanavia:", - "LabelAudioBitrate": "Audion bitrate:", - "LabelAudioCodec": "Audio codec:", + "LabelBitrate": "Bittinopeus:", + "LabelAudioSampleRate": "Äänen näytteenottotaajuus:", + "LabelAudioChannels": "Äänikanavia:", + "LabelAudioBitrate": "Äänen bittinopeus:", + "LabelAudioCodec": "Äänen pakkauksenhallinta:", "LabelSubtitleDownloaders": "Tekstitysten lataajat:", "LabelSpecialSeasonsDisplayName": "Erikoiskauden näyttönimi:", "LabelSortTitle": "Lajitteluotsikko:", @@ -996,7 +996,7 @@ "LabelLibraryPageSize": "Kirjastosivun kohteiden määrä:", "LabelLibraryPageSizeHelp": "Asettaa kirjastosivulla näytettävien kohteiden määrän. Arvo 0 poistaa sivutuksen käytöstä.", "Unrated": "Luokittelematon", - "ExtractChapterImagesHelp": "Pikkukuvien luominen mahdollistaa sovellusten näyttää graafiikkaa valintavalikoissa. Prosessi voi olla hidas, prosessoria kuormittava ja saattaa vaatia useita gigatavuja tilaa. Se suoritetaan, kun videoita havaitaan, ja myös yöksi suunniteltuna tehtävänä. Aikataulu on konfiguroitavissa ajoitetuissa tehtävissä. Tätä tehtävää ei ole suositeltavaa suorittaa korkean kuormituksen aikana.", + "ExtractChapterImagesHelp": "Kappalekuvien luominen mahdollistaa sovellusten näyttää graafisia kohtausvalikoita. Prosessi voi olla hidas, prosessoria kuormittava ja saattaa vaatia useita gigatavuja tilaa. Se suoritetaan, kun videoita havaitaan, sekä myös yöksi suunniteltuna tehtävänä. Aikataulu on muokattavissa ajoitetuissa tehtävissä. Tätä tehtävää ei ole suositeltavaa suorittaa korkean kuormituksen aikana.", "OnWakeFromSleep": "Lepotilasta poistuttaessa", "WeeklyAt": "{0}sin klo {1}", "Whitelist": "Sallitut", @@ -1017,13 +1017,13 @@ "Features": "Ominaisuudet", "ErrorStartHourGreaterThanEnd": "Loppumisajan on oltava myöhemmin kuin aloitusaika.", "MediaInfoAnamorphic": "Anamorfinen", - "ErrorGettingTvLineups": "TV esiintyjälistan lataamisessa tapahtui virhe. Varmista, että tiedot on oikein ja yritä uudelleen.", + "ErrorGettingTvLineups": "TV-esiintyjälistan lataamisessa tapahtui virhe. Varmista, että tiedot on oikein ja yritä uudelleen.", "EnableDetailsBannerHelp": "Näyttää julistekuvan yksityiskohdat -sivun ylälaidassa.", - "EnableDetailsBanner": "Yksityiskohtien banneri", + "EnableDetailsBanner": "Yksityiskohtien julistekuva", "ButtonSyncPlay": "SyncPlay", "HeaderAccessSchedule": "Käyttöoikeusaikataulu", "HeaderAccessScheduleHelp": "Luo käyttöoikeusaikataulu rajoittaaksesi käyttöä tietylle aikavälille.", - "HardwareAccelerationWarning": "Hardwarekiihdytyksen käyttöönotto voi aiheuttaa epävakautta joissain ympäristöissä. Varmista että sekä käyttöjärjestelmäsi että videoajurisi ovat ajan tasalla. Mikäli huomaat ongelmia videotoistossa säädettyäsi tätä asetusta, sinun täytyy muuttaa asetus takaisin kohtaan \"Ei mitään\".", + "HardwareAccelerationWarning": "Rautakiihdytyksen käyttöönotto voi aiheuttaa epävakautta joissain ympäristöissä. Varmista että sekä käyttöjärjestelmäsi että videoajurisi ovat ajan tasalla. Mikäli huomaat ongelmia videotoistossa säädettyäsi tätä asetusta, sinun täytyy muuttaa asetus takaisin kohtaan \"Ei mitään\".", "EncoderPresetHelp": "Valitse nopeampi arvo kohentaaksesi suorituskykyä tai hitaampi arvo parantaaksesi kuvanlaatua.", "H264CrfHelp": "Constant Rate Factor (CRF) on x264 -enkooderin kuvanlaadun vakioasetus. Voit valita arvon lukujen 0 ja 51 väliltä, jossa matalammat arvot tarkoittavat parempaa kuvanlaatua (suurempien tiedostokokojen hinnalla). Järkevät arvot ovat väliltä 18-28. Vakioarvo x264:lle on 23, joten voit käyttää sitä lähtökohtana.", "GuideProviderSelectListings": "Valitse listaukset", @@ -1034,8 +1034,8 @@ "ErrorSavingTvProvider": "TV-palveluntarjoajaa lisättäessä tapahtui virhe. Varmista sen saatavuus ja yritä uudestaan.", "ErrorPleaseSelectLineup": "Valitse lineup ja yritä uudestaan. Mikäli lineuppeja ei ole saatavilla, varmista että käyttäjätunnuksesi, salasanasi sekä postinumerosi ovat oikein.", "ErrorAddingListingsToSchedulesDirect": "Lineuppia Schedules Direct -käyttäjätunnuksellesi lisättäessä ilmeni virhe. Schedules Direct sallii vain rajallisen määrän lineuppeja yhdelle käyttäjätunnukselle. Mikäli haluat jatkaa, voit esimerkiksi kirjautua Schedules Direct -sivustolle ja poistaa muita listauksia käyttäjätunnukseltasi.", - "EnableDecodingColorDepth10Vp9": "Salli 10-bittinen hardware dekoodaus (VP9)", - "EnableDecodingColorDepth10Hevc": "Salli 10-bittinen hardware dekoodaus (HEVC)", + "EnableDecodingColorDepth10Vp9": "Salli 10-bittinen rautapurku (VP9)", + "EnableDecodingColorDepth10Hevc": "Salli 10-bittinen rautapurku (HEVC)", "HeaderCastAndCrew": "Näyttelijät ja henkilökunta", "HeaderCancelSeries": "Peruuta sarja", "HeaderCancelRecording": "Peruuta tallennus", @@ -1043,8 +1043,52 @@ "HeaderBlockItemsWithNoRating": "Estä kaikki joissa ei ole luokitusta tai jonka luokitusta ei voida tunnistaa:", "HeaderAppearsOn": "Esiintyy seuraavissa", "ApiKeysCaption": "Lista aktiivisista API-avaimista", - "HeaderApiKeysHelp": "Ulkoiset sovellukset tarvitsevat API-avaimen voidakseen toimia Jellyfin -palvelimen kanssa. Avaimet myönnetään joko kirjautumalla sisään Jellyfin -käyttäjätunnuksella tai myöntämällä sellainen sovellukselle manuaalisesti.", + "HeaderApiKeysHelp": "Ulkoiset sovellukset tarvitsevat API-avaimen voidakseen toimia palvelimen kanssa. Avaimet myönnetään joko kirjautumalla sisään normaalilla käyttäjätunnuksella tai myöntämällä sellainen sovellukselle manuaalisesti.", "HeaderAdditionalParts": "Muut osat", "HeaderActiveRecordings": "Käynnissä olevat nauhoitukset", - "Data": "Tieto" + "Data": "Tieto", + "LabelImportOnlyFavoriteChannels": "Rajaa vain suosikkikanaviin", + "LabelHomeNetworkQuality": "Kotiverkon laatu:", + "LabelFriendlyName": "Käyttäjäystävällinen nimi:", + "LabelFileOrUrl": "Tiedosto tai URL:", + "LabelFailed": "Epäonnistui", + "LabelExtractChaptersDuringLibraryScan": "Tallenna kappalekuvat kirjastojen skannauksen yhteydessä", + "LabelBaseUrl": "Perus-URL:", + "LabelEvent": "Tapahtuma:", + "LabelEnableSingleImageInDidlLimit": "Rajoita yhteen upotettuun kuvaan", + "LabelEnableHttps": "Ota HTTPS käyttöön", + "LabelEnableHardwareDecodingFor": "Ota rautapurku käyttöön:", + "LabelDownMixAudioScale": "Äänen tehostus alasmiksatessa:", + "LabelDateAddedBehavior": "Lisäyspäivämääräkäytös uudelle sisällölle:", + "LabelBlastMessageInterval": "Hereiläolo-viestin väli", + "LabelBindToLocalNetworkAddress": "Kiinnitä verkko-osoitteeseen:", + "LabelAirsBeforeSeason": "Lähetetään ennen kautta:", + "LabelAirsBeforeEpisode": "Lähetetään ennen jaksoa:", + "LabelAirsAfterSeason": "Lähetetään kauden jälkeen:", + "LabelAirDays": "Lähetyspäivät:", + "LabelAccessStart": "Aloitusaika:", + "LabelAccessEnd": "Lopetusaika:", + "InstantMix": "Välitön miksaus", + "Image": "Kuva", + "HttpsRequiresCert": "Ottaaksesi suojatut yhteydet käyttöösi tulee sinun toimittaa luotettu SSL-varmenne (esim. Let's Encrypt). Ole hyvä ja toimita varmenne tai ota suojattu yhteys pois käytöstä.", + "HeaderSyncPlayEnabled": "Ryhmäkatselu päällä", + "HeaderSyncPlaySelectGroup": "Liity ryhmään", + "HeaderServerAddressSettings": "Palvelimen osoiteasetukset", + "HeaderOnNow": "Nyt lähetyksessä", + "HeaderLibraryOrder": "Kirjaston järjestys", + "HeaderLibraryAccess": "Kirjastopääsy", + "HeaderKeepSeries": "Pidä sarja", + "HeaderKeepRecording": "Jatka tallennusta", + "HeaderInstantMix": "Välitön miksaus", + "HeaderImageSettings": "Kuva-asetukset", + "HeaderImageOptions": "Kuvaoptiot", + "HeaderIdentificationHeader": "Tunnistusotsake", + "HeaderHttpsSettings": "HTTPS-asetukset", + "HeaderHttpHeaders": "HTTP-otsakkeet", + "HeaderFeatureAccess": "Pääsy toimintoihin", + "HeaderDVR": "DVR", + "HeaderDeviceAccess": "Laitepääsy", + "HeaderDeleteTaskTrigger": "Poista tehtävälaukaisin", + "HeaderChannelAccess": "Kanavapääsy", + "Other": "Muu" } From 55a083106159b7cd7a527a62ad7ef948eae43fd4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2020 05:44:46 +0000 Subject: [PATCH 085/281] Bump css-loader from 4.2.2 to 4.3.0 Bumps [css-loader](https://github.com/webpack-contrib/css-loader) from 4.2.2 to 4.3.0. - [Release notes](https://github.com/webpack-contrib/css-loader/releases) - [Changelog](https://github.com/webpack-contrib/css-loader/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack-contrib/css-loader/compare/v4.2.2...v4.3.0) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- yarn.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 24ea42c72a..4e6af20e55 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "browser-sync": "^2.26.12", "confusing-browser-globals": "^1.0.9", "copy-webpack-plugin": "^5.1.1", - "css-loader": "^4.2.2", + "css-loader": "^4.3.0", "cssnano": "^4.1.10", "del": "^5.1.0", "eslint": "^7.8.1", diff --git a/yarn.lock b/yarn.lock index d8e766ba12..ffe1e37d36 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3034,10 +3034,10 @@ css-has-pseudo@^0.10.0: postcss "^7.0.6" postcss-selector-parser "^5.0.0-rc.4" -css-loader@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-4.2.2.tgz#b668b3488d566dc22ebcf9425c5f254a05808c89" - integrity sha512-omVGsTkZPVwVRpckeUnLshPp12KsmMSLqYxs12+RzM9jRR5Y+Idn/tBffjXRvOE+qW7if24cuceFJqYR5FmGBg== +css-loader@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-4.3.0.tgz#c888af64b2a5b2e85462c72c0f4a85c7e2e0821e" + integrity sha512-rdezjCjScIrsL8BSYszgT4s476IcNKt6yX69t0pHjJVnPUTDpn4WfIpDQTN3wCJvUvfsz/mFjuGOekf3PY3NUg== dependencies: camelcase "^6.0.0" cssesc "^3.0.0" @@ -3049,7 +3049,7 @@ css-loader@^4.2.2: postcss-modules-scope "^2.2.0" postcss-modules-values "^3.0.0" postcss-value-parser "^4.1.0" - schema-utils "^2.7.0" + schema-utils "^2.7.1" semver "^7.3.2" css-prefers-color-scheme@^3.1.1: @@ -9930,7 +9930,7 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -schema-utils@^2.6.5, schema-utils@^2.6.6, schema-utils@^2.7.0, schema-utils@^2.7.1: +schema-utils@^2.6.5, schema-utils@^2.6.6, schema-utils@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== From 504519e4c83c5575d342239fb08e1a433841895a Mon Sep 17 00:00:00 2001 From: Harry Sintonen Date: Tue, 15 Sep 2020 03:39:57 +0000 Subject: [PATCH 086/281] Translated using Weblate (Finnish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fi/ --- src/strings/fi.json | 89 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 7 deletions(-) diff --git a/src/strings/fi.json b/src/strings/fi.json index 04348d5d4b..7529df6202 100644 --- a/src/strings/fi.json +++ b/src/strings/fi.json @@ -220,7 +220,7 @@ "EnablePhotosHelp": "Kuvat tunnistetaan ja näytetään muiden mediatiedostojen ohessa.", "EnablePhotos": "Näytä valokuvat", "EnableNextVideoInfoOverlay": "Näytä seuraavan videon tiedot toiston aikana", - "EnableHardwareEncoding": "Salli videomuunnoksen rautakiihdytys", + "EnableHardwareEncoding": "Salli videomuunnoksen laitteistokiihdytys", "EnableExternalVideoPlayers": "Ulkoiset videosoittimet", "EnableDisplayMirroring": "Näytön peilaus", "EnableColorCodedBackgrounds": "Värikoodatut taustat", @@ -794,7 +794,7 @@ "LabelMaxScreenshotsPerItem": "Kuvakaappausten enimmäismäärä per kohde:", "LabelLoginDisclaimerHelp": "Viesti, joka näytetään kirjautumissivun alareunassa.", "LabelLockItemToPreventChanges": "Lukitse tämä kohde estääksesi tulevat muutokset", - "LabelLocalHttpServerPortNumberHelp": "TCP-portin numero, jota Jellyfinin HTTP-palvelimen tulee kuunnella.", + "LabelLocalHttpServerPortNumberHelp": "HTTP-palvelimen TCP-portin numero.", "LabelLocalHttpServerPortNumber": "Paikallisen HTTP-portin numero:", "LabelKodiMetadataSaveImagePaths": "Tallenna kuvien polut NFO-tiedostojen sisälle", "LabelKidsCategories": "Lasten kategoriat:", @@ -1010,7 +1010,7 @@ "ValueCodec": "Codec: {0}", "ValueAudioCodec": "Audio Codec: {0}", "SeriesYearToPresent": "{0} - Nykyhetki", - "DeinterlaceMethodHelp": "Valitse lomituksen poistomenetelmä, jota käytetään lomitetun sisällön transkoodaukseen. Mikäli omituksen poiston hallitsevaa rautakiihdytettyä purkua käytetään, ei tätä asetusta oteta huomioon.", + "DeinterlaceMethodHelp": "Valitse lomituksen poistomenetelmä, jota käytetään lomitetun sisällön transkoodaukseen. Mikäli omituksen poiston hallitsevaa laitteistokiihdytettyä purkua käytetään, ei tätä asetusta oteta huomioon.", "FormatValue": "Muoto: {0}", "General": "Yleinen", "FetchingData": "Noudetaan lisätietoja", @@ -1023,7 +1023,7 @@ "ButtonSyncPlay": "SyncPlay", "HeaderAccessSchedule": "Käyttöoikeusaikataulu", "HeaderAccessScheduleHelp": "Luo käyttöoikeusaikataulu rajoittaaksesi käyttöä tietylle aikavälille.", - "HardwareAccelerationWarning": "Rautakiihdytyksen käyttöönotto voi aiheuttaa epävakautta joissain ympäristöissä. Varmista että sekä käyttöjärjestelmäsi että videoajurisi ovat ajan tasalla. Mikäli huomaat ongelmia videotoistossa säädettyäsi tätä asetusta, sinun täytyy muuttaa asetus takaisin kohtaan \"Ei mitään\".", + "HardwareAccelerationWarning": "Laitteistokiihdytyksen käyttöönotto voi aiheuttaa epävakautta joissain ympäristöissä. Varmista että sekä käyttöjärjestelmäsi että videoajurisi ovat ajan tasalla. Mikäli huomaat ongelmia videotoistossa säädettyäsi tätä asetusta, sinun täytyy muuttaa asetus takaisin kohtaan \"Ei mitään\".", "EncoderPresetHelp": "Valitse nopeampi arvo kohentaaksesi suorituskykyä tai hitaampi arvo parantaaksesi kuvanlaatua.", "H264CrfHelp": "Constant Rate Factor (CRF) on x264 -enkooderin kuvanlaadun vakioasetus. Voit valita arvon lukujen 0 ja 51 väliltä, jossa matalammat arvot tarkoittavat parempaa kuvanlaatua (suurempien tiedostokokojen hinnalla). Järkevät arvot ovat väliltä 18-28. Vakioarvo x264:lle on 23, joten voit käyttää sitä lähtökohtana.", "GuideProviderSelectListings": "Valitse listaukset", @@ -1034,8 +1034,8 @@ "ErrorSavingTvProvider": "TV-palveluntarjoajaa lisättäessä tapahtui virhe. Varmista sen saatavuus ja yritä uudestaan.", "ErrorPleaseSelectLineup": "Valitse lineup ja yritä uudestaan. Mikäli lineuppeja ei ole saatavilla, varmista että käyttäjätunnuksesi, salasanasi sekä postinumerosi ovat oikein.", "ErrorAddingListingsToSchedulesDirect": "Lineuppia Schedules Direct -käyttäjätunnuksellesi lisättäessä ilmeni virhe. Schedules Direct sallii vain rajallisen määrän lineuppeja yhdelle käyttäjätunnukselle. Mikäli haluat jatkaa, voit esimerkiksi kirjautua Schedules Direct -sivustolle ja poistaa muita listauksia käyttäjätunnukseltasi.", - "EnableDecodingColorDepth10Vp9": "Salli 10-bittinen rautapurku (VP9)", - "EnableDecodingColorDepth10Hevc": "Salli 10-bittinen rautapurku (HEVC)", + "EnableDecodingColorDepth10Vp9": "Salli 10-bittinen laitteistopurku (VP9)", + "EnableDecodingColorDepth10Hevc": "Salli 10-bittinen laitteistopurku (HEVC)", "HeaderCastAndCrew": "Näyttelijät ja henkilökunta", "HeaderCancelSeries": "Peruuta sarja", "HeaderCancelRecording": "Peruuta tallennus", @@ -1090,5 +1090,80 @@ "HeaderDeviceAccess": "Laitepääsy", "HeaderDeleteTaskTrigger": "Poista tehtävälaukaisin", "HeaderChannelAccess": "Kanavapääsy", - "Other": "Muu" + "Other": "Muu", + "Writers": "Kirjoittajat", + "Video": "Video", + "Upload": "Lähetä", + "TabAccess": "Pääsy", + "Subtitle": "Tekstitys", + "ShowMore": "Näytä lisää", + "ShowLess": "Näytä vähemmän", + "SeriesSettings": "Sarjan asetukset", + "SelectServer": "Valitse palvelin", + "RepeatMode": "Toistomoodi", + "RepeatOne": "Toista yksi", + "ResetPassword": "Nollaa salasana", + "Restart": "Aloita alusta", + "Rewind": "Kelaa alkuun", + "SaveChanges": "Tallenna muutokset", + "Profile": "Profiili", + "ProductionLocations": "Tuotantosijainnit", + "PreviousTrack": "Hyppää edelliseen", + "PlaybackRate": "Toistonopeus", + "PictureInPicture": "Kuva kuvassa", + "Photo": "Valokuva", + "Person": "Henkilö", + "PackageInstallFailed": "{0} (version {1}) asennus epäonnistui.", + "PackageInstallCompleted": "{0} (version {1}) asennus valmis.", + "PackageInstallCancelled": "{0} (version {1}) asennus peruttu.", + "NextTrack": "Hyppää seuraavaan", + "MusicVideos": "Musiikkivideot", + "MinutesAfter": "minuuttia jälkeen", + "MinutesBefore": "minuuttia ennen", + "MessageSyncPlayErrorMedia": "Ryhmäkatselun päällekytkentä epäonnistui! Mediavirhe.", + "MessageSyncPlayErrorNoActivePlayer": "Ei aktiivista soitinta. Ryhmäkatselu on kytketty pois päältä.", + "MessageSyncPlayErrorMissingSession": "Ryhmäkatselun päällekytkentä epäonnistui! Puuttuva istunto.", + "MessageSyncPlayErrorAccessingGroups": "Virhe ryhmälistaa luettaessa.", + "MessageSyncPlayLibraryAccessDenied": "Pääsy sisältöön on rajattu.", + "MessageSyncPlayJoinGroupDenied": "Lupa ryhmäkatselun käyttöön tarvitaan.", + "MessageSyncPlayCreateGroupDenied": "Lupa ryhmän luomiseen vaaditaan.", + "MessageSyncPlayGroupDoesNotExist": "Ryhmään liittyminen epäonnistui koska sitä ei ole olemassa.", + "MessageSyncPlayPlaybackPermissionRequired": "Toistolupa tarvitaan.", + "MessageSyncPlayNoGroupsAvailable": "Ei ryhmiä. Aloita ensin jokin toisto.", + "MessageSyncPlayGroupWait": "{0} puskuroi…", + "MessageSyncPlayUserLeft": "{0} poistui ryhmästä.", + "MessageSyncPlayUserJoined": "{0} liittyi ryhmään.", + "MessageSyncPlayDisabled": "Ryhmäkatselu otettu pois käytöstä.", + "MessageSyncPlayEnabled": "Ryhmäkatselu otettu käyttöön.", + "MediaInfoBitDepth": "Bittisyvyys", + "LabelVaapiDevice": "VA API-laite:", + "LabelUserLoginAttemptsBeforeLockout": "Väärien kirjautumisyritysten määrä ennen tilin lukitsemista:", + "LabelSyncPlayAccess": "Ryhmäkatselupääsy", + "LabelSyncPlayAccessNone": "Pois käytöstä tälle käyttäjälle", + "LabelSyncPlayAccessJoinGroups": "Salli käyttäjän liittyä ryhmiin", + "LabelSyncPlayAccessCreateAndJoinGroups": "Salli käyttäjän luoda ryhmiä ja liittyä niihin", + "LabelSyncPlayLeaveGroupDescription": "Poista ryhmäkatselu käytöstä", + "LabelSyncPlayLeaveGroup": "Poistu ryhmästä", + "LabelSyncPlayNewGroupDescription": "Luo uusi ryhmä", + "LabelSyncPlayNewGroup": "Uusi ryhmä", + "LabelSportsCategories": "Urheilukategoriat:", + "LabelSortBy": "Järjestä:", + "LabelServerHost": "Isäntä:", + "EnableFasterAnimations": "Nopeammat animaatiot", + "LabelRequireHttps": "Vaadi HTTPS", + "LabelRecord": "Tallenna:", + "LabelPlayMethod": "Toistotapa:", + "LabelKodiMetadataEnablePathSubstitution": "Salli polkujen korvaaminen", + "LabelKnownProxies": "Tunnetut välityspalvelimet:", + "LabelKeepUpTo": "Pidä tallessa:", + "HeaderRemoteAccessSettings": "Etäkäytön asetukset", + "LabelNewsCategories": "Uutiskategoriat:", + "LabelUnstable": "Epävakaa", + "LabelStable": "Vakaa", + "LabelChromecastVersion": "Chromecastin versio", + "LabelModelUrl": "Malli-URL", + "LabelModelName": "Mallinimi", + "LabelModelDescription": "Mallikuvaus", + "LabelModelNumber": "Mallinumero", + "LabelInNetworkSignInWithEasyPassword": "Salli sisäverkkokirjautuminen helpolla PIN-koodilla" } From 69d7feeb481b34a782f4fa5f96a5f120cfb27563 Mon Sep 17 00:00:00 2001 From: Hilman Maulana Date: Tue, 15 Sep 2020 04:23:27 +0000 Subject: [PATCH 087/281] Translated using Weblate (Indonesian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/id/ --- src/strings/id.json | 61 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/src/strings/id.json b/src/strings/id.json index c7a83a9efa..858b8169a1 100644 --- a/src/strings/id.json +++ b/src/strings/id.json @@ -6,7 +6,7 @@ "LabelContentType": "Tipe konten :", "LabelCountry": "Negara :", "LabelFinish": "Selesai", - "LabelLanguage": "Bahasa:", + "LabelLanguage": "Bahasa :", "LabelSaveLocalMetadata": "Simpan artwork dan metadata ke dalam folder media", "LabelSaveLocalMetadataHelp": "Menyimpan artwork dan metadata langsung ke folder media akan meletakkan mereka di tempat yang mudah diedit.", "LabelTimeLimitHours": "Batas waktu (jam):", @@ -647,5 +647,62 @@ "Directors": "Direktur", "Director": "Direktur", "Depressed": "Murung", - "Data": "Data" + "Data": "Data", + "LabelMaxResumePercentageHelp": "Judul dianggap diputar penuh jika dihentikan setelah waktu ini.", + "LabelMaxResumePercentage": "Persentase lanjutkan maksimum :", + "LabelMaxParentalRating": "Rating orang tua maksimum yang diizinkan :", + "LabelMaxChromecastBitrate": "Kualitas streaming Chromecast :", + "LabelMaxBackdropsPerItem": "Jumlah maksimum tampilan latar per item :", + "LabelMatchType": "Jenis kecocokan :", + "LabelManufacturerUrl": "Produsen URL", + "LabelManufacturer": "Produsen :", + "LabelLogs": "Log :", + "LabelLoginDisclaimerHelp": "Sebuah pesan yang akan ditampilkan di bagian bawah halaman login.", + "LabelLoginDisclaimer": "Penolakan login :", + "LabelLockItemToPreventChanges": "Kunci item ini untuk mencegah perubahan di masa mendatang", + "LabelLineup": "Berbaris :", + "LabelLibraryPageSizeHelp": "Menetapkan jumlah item untuk ditampilkan di halaman psutaka. Setel ke 0 untuk menonaktifkan paging.", + "LabelLibraryPageSize": "Ukuran halaman pustaka :", + "LabelLanNetworks": "Jaringan LAN :", + "LabelKodiMetadataUserHelp": "Simpan data menonton ke file NFO untuk digunakan aplikasi lain.", + "LabelKodiMetadataUser": "Simpan data menonton pengguna ke file NFO untuk :", + "LabelKodiMetadataEnableExtraThumbsHelp": "Saat mengunduh gambar, mereka dapat disimpan ke extrafanart dan extrathumbs untuk kompatibilitas tema Kodi yang maksimal.", + "LabelKodiMetadataEnableExtraThumbs": "Salin extrafanart ke bidang extrathumbs", + "LabelKodiMetadataDateFormatHelp": "Semua tanggal dalam file NFO akan diurai menggunakan format ini.", + "LabelKodiMetadataDateFormat": "Format tanggal rilis :", + "LabelKidsCategories": "Kategori anak-anak :", + "LabelKnownProxies": "Proksi yang dikenal :", + "LabelKeepUpTo": "Ikuti terus :", + "LabelInternetQuality": "Kualitas internet :", + "LabelInNetworkSignInWithEasyPasswordHelp": "Gunakan kode pin yang mudah untuk masuk ke klien dalam jaringan lokal Anda. Kata sandi biasa Anda hanya akan dibutuhkan di luar rumah. Jika kode pin dibiarkan kosong, Anda tidak memerlukan kata sandi di dalam jaringan rumah Anda.", + "LabelInNetworkSignInWithEasyPassword": "Aktifkan masuk jaringan dengan kode pin mudah saya", + "LabelImportOnlyFavoriteChannels": "Batasi untuk saluran yang ditandai sebagai favorit", + "LabelImageType": "Jenis gambar :", + "LabelImageFetchersHelp": "Aktifkan dan beri peringkat pada pengambil gambar pilihan Anda dalam urutan prioritas.", + "LabelIdentificationFieldHelp": "Substring atau ekspresi ekspresi reguler tidak peka huruf besar kecil.", + "LabelIconMaxWidth": "Lebar maksimum ikon :", + "LabelIconMaxHeight": "Tinggi maksimum ikon :", + "LabelIconMaxResHelp": "Resolusi maksimum ikon yang diekspos melalui properti ikon upnp.", + "LabelExtractChaptersDuringLibraryScanHelp": "Hasilkan gambar bab saat video diimpor selama pemindaian pustaka. Jika tidak, mereka akan diekstraksi selama tugas terjadwal gambar bab, memungkinkan pemindaian pustaka biasa selesai lebih cepat.", + "LabelExtractChaptersDuringLibraryScan": "Ekstrak gambar bab selama pemindaian pustaka", + "LabelBaseUrl": "URL Dasar :", + "LabelEveryXMinutes": "Setiap :", + "LabelEvent": "Peristiwa :", + "LabelEpisodeNumber": "Nomor episode :", + "LabelEndDate": "Tanggal akhir :", + "LabelEnableSingleImageInDidlLimitHelp": "Beberapa perangkat tidak akan merender dengan baik jika beberapa gambar disematkan dalam Didl.", + "LabelEnableSingleImageInDidlLimit": "Batasi untuk satu gambar yang disematkan", + "LabelEnableRealtimeMonitorHelp": "Perubahan file akan segera diproses pada sistem file yang didukung.", + "LabelEnableRealtimeMonitor": "Aktifkan pemantauan waktu nyata", + "LabelEnableHttpsHelp": "Dengarkan di port HTTPS yang dikonfigurasi. Sertifikat yang valid juga harus diberikan agar ini berlaku.", + "LabelEnableHttps": "Aktifkan HTTPS", + "LabelEnableHardwareDecodingFor": "Aktifkan decoding perangkat keras untuk :", + "LabelEnableDlnaPlayToHelp": "Deteksi perangkat dalam jaringan Anda dan tawarkan kemampuan untuk mengontrolnya dari jarak jauh.", + "LabelEnableDlnaPlayTo": "Aktifkan DLNA Play To", + "LabelEnableDlnaDebugLoggingHelp": "Buat file log besar dan sebaiknya hanya digunakan seperlunya untuk tujuan pemecahan masalah.", + "LabelEnableDlnaDebugLogging": "Aktifkan logging debug DLNA", + "LabelEnableDlnaClientDiscoveryIntervalHelp": "Menentukan durasi dalam detik antara pencarian SSDP.", + "LabelEnableDlnaClientDiscoveryInterval": "Interval penemuan klien", + "LabelEnableBlastAliveMessages": "Ledakan pesan hidup", + "KnownProxiesHelp": "Daftar alamat IP yang dipisahkan koma dari proxy yang diketahui digunakan saat menghubungkan ke instance Jellyfin Anda. Ini diperlukan untuk menggunakan header X-Forwarded-For dengan benar. Membutuhkan reboot setelah menyimpan." } From 1ca4a9960559d43644e69f823e4c1b508fab7c3f Mon Sep 17 00:00:00 2001 From: dkanada Date: Tue, 15 Sep 2020 15:03:06 +0900 Subject: [PATCH 088/281] minor style changes --- src/controllers/session/login/index.html | 2 +- src/quickconnect.html | 2 +- src/scripts/libraryMenu.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllers/session/login/index.html b/src/controllers/session/login/index.html index d22d903a1d..8c69456168 100644 --- a/src/controllers/session/login/index.html +++ b/src/controllers/session/login/index.html @@ -43,7 +43,7 @@ ${ButtonManualLogin} - diff --git a/src/quickconnect.html b/src/quickconnect.html index b5b6d48991..2b646837c6 100644 --- a/src/quickconnect.html +++ b/src/quickconnect.html @@ -7,7 +7,7 @@
    - ${LabelCurrentStatus} +
    ${LabelCurrentStatus}
    '; if (autocast.supported()) { - html += '
    '; @@ -236,7 +236,7 @@ class FilterMenu { dlg.innerHTML = globalize.translateHtml(html, 'core'); - var settingElements = dlg.querySelectorAll('.viewSetting'); + const settingElements = dlg.querySelectorAll('.viewSetting'); for (let i = 0, length = settingElements.length; i < length; i++) { if (options.visibleSettings.indexOf(settingElements[i].getAttribute('data-settingname')) === -1) { settingElements[i].classList.add('hide'); @@ -257,7 +257,7 @@ class FilterMenu { centerFocus(dlg.querySelector('.formDialogContent'), false, true); } - var submitted; + let submitted; dlg.querySelector('form').addEventListener('change', function () { submitted = true; diff --git a/src/components/focusManager.js b/src/components/focusManager.js index a9ec377cce..90ff8b0703 100644 --- a/src/components/focusManager.js +++ b/src/components/focusManager.js @@ -3,7 +3,7 @@ import dom from 'dom'; import scrollManager from 'scrollManager'; - var scopes = []; + const scopes = []; function pushScope(elem) { scopes.push(elem); } @@ -15,7 +15,7 @@ import scrollManager from 'scrollManager'; } function autoFocus(view, defaultToFirst, findAutoFocusElement) { - var element; + let element; if (findAutoFocusElement !== false) { element = view.querySelector('*[autofocus]'); if (element) { @@ -46,9 +46,9 @@ import scrollManager from 'scrollManager'; } } - var focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A']; - var focusableContainerTagNames = ['BODY', 'DIALOG']; - var focusableQuery = focusableTagNames.map(function (t) { + const focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A']; + const focusableContainerTagNames = ['BODY', 'DIALOG']; + const focusableQuery = focusableTagNames.map(function (t) { if (t === 'INPUT') { t += ':not([type="range"]):not([type="file"])'; } @@ -69,7 +69,7 @@ import scrollManager from 'scrollManager'; function normalizeFocusable(elem, originalElement) { if (elem) { - var tagName = elem.tagName; + const tagName = elem.tagName; if (!tagName || tagName === 'HTML' || tagName === 'BODY') { elem = originalElement; } @@ -79,10 +79,10 @@ import scrollManager from 'scrollManager'; } function focusableParent(elem) { - var originalElement = elem; + const originalElement = elem; while (!isFocusable(elem)) { - var parent = elem.parentNode; + const parent = elem.parentNode; if (!parent) { return normalizeFocusable(elem, originalElement); @@ -115,7 +115,7 @@ import scrollManager from 'scrollManager'; } if (elem.tagName === 'INPUT') { - var type = elem.type; + const type = elem.type; if (type === 'range') { return false; } @@ -132,11 +132,11 @@ import scrollManager from 'scrollManager'; } function getFocusableElements(parent, limit, excludeClass) { - var elems = (parent || getDefaultScope()).querySelectorAll(focusableQuery); - var focusableElements = []; + const elems = (parent || getDefaultScope()).querySelectorAll(focusableQuery); + const focusableElements = []; - for (var i = 0, length = elems.length; i < length; i++) { - var elem = elems[i]; + for (let i = 0, length = elems.length; i < length; i++) { + const elem = elems[i]; if (excludeClass && elem.classList.contains(excludeClass)) { continue; @@ -159,7 +159,7 @@ import scrollManager from 'scrollManager'; return true; } - var classList = elem.classList; + const classList = elem.classList; if (classList.contains('focuscontainer')) { return true; @@ -208,7 +208,7 @@ import scrollManager from 'scrollManager'; } function getOffset(elem) { - var box; + let box; // Support: BlackBerry 5, iOS 3 (original iPhone) // If we don't have gBCR, just use 0,0 rather than error @@ -225,7 +225,7 @@ import scrollManager from 'scrollManager'; if (box.right === null) { // Create a new object because some browsers will throw an error when trying to set data onto the Rect object - var newBox = { + const newBox = { top: box.top, left: box.left, width: box.width, @@ -255,27 +255,27 @@ import scrollManager from 'scrollManager'; return; } - var focusableContainer = dom.parentWithClass(activeElement, 'focusable'); + const focusableContainer = dom.parentWithClass(activeElement, 'focusable'); - var rect = getOffset(activeElement); + const rect = getOffset(activeElement); // Get elements and work out x/y points - var point1x = parseFloat(rect.left) || 0; - var point1y = parseFloat(rect.top) || 0; - var point2x = parseFloat(point1x + rect.width - 1) || point1x; - var point2y = parseFloat(point1y + rect.height - 1) || point1y; + const point1x = parseFloat(rect.left) || 0; + const point1y = parseFloat(rect.top) || 0; + const point2x = parseFloat(point1x + rect.width - 1) || point1x; + const point2y = parseFloat(point1y + rect.height - 1) || point1y; - var sourceMidX = rect.left + (rect.width / 2); - var sourceMidY = rect.top + (rect.height / 2); + const sourceMidX = rect.left + (rect.width / 2); + const sourceMidY = rect.top + (rect.height / 2); - var focusable = focusableElements || container.querySelectorAll(focusableQuery); + const focusable = focusableElements || container.querySelectorAll(focusableQuery); - var maxDistance = Infinity; - var minDistance = maxDistance; - var nearestElement; + const maxDistance = Infinity; + let minDistance = maxDistance; + let nearestElement; - for (var i = 0, length = focusable.length; i < length; i++) { - var curr = focusable[i]; + for (let i = 0, length = focusable.length; i < length; i++) { + const curr = focusable[i]; if (curr === activeElement) { continue; @@ -285,7 +285,7 @@ import scrollManager from 'scrollManager'; continue; } - var elementRect = getOffset(curr); + const elementRect = getOffset(curr); // not currently visible if (!elementRect.width && !elementRect.height) { @@ -333,16 +333,16 @@ import scrollManager from 'scrollManager'; break; } - var x = elementRect.left; - var y = elementRect.top; - var x2 = x + elementRect.width - 1; - var y2 = y + elementRect.height - 1; + const x = elementRect.left; + const y = elementRect.top; + const x2 = x + elementRect.width - 1; + const y2 = y + elementRect.height - 1; - var intersectX = intersects(point1x, point2x, x, x2); - var intersectY = intersects(point1y, point2y, y, y2); + const intersectX = intersects(point1x, point2x, x, x2); + const intersectY = intersects(point1y, point2y, y, y2); - var midX = elementRect.left + (elementRect.width / 2); - var midY = elementRect.top + (elementRect.height / 2); + const midX = elementRect.left + (elementRect.width / 2); + const midY = elementRect.top + (elementRect.height / 2); var distX; var distY; @@ -372,7 +372,7 @@ import scrollManager from 'scrollManager'; break; } - var dist = Math.sqrt(distX * distX + distY * distY); + const dist = Math.sqrt(distX * distX + distY * distY); if (dist < minDistance) { nearestElement = curr; @@ -383,7 +383,7 @@ import scrollManager from 'scrollManager'; if (nearestElement) { // See if there's a focusable container, and if so, send the focus command to that if (activeElement) { - var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable'); + const nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable'); if (nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement) { if (focusableContainer !== nearestElementFocusableParent) { nearestElement = nearestElementFocusableParent; @@ -403,16 +403,16 @@ import scrollManager from 'scrollManager'; } function sendText(text) { - var elem = document.activeElement; + const elem = document.activeElement; elem.value = text; } function focusFirst(container, focusableSelector) { - var elems = container.querySelectorAll(focusableSelector); + const elems = container.querySelectorAll(focusableSelector); - for (var i = 0, length = elems.length; i < length; i++) { - var elem = elems[i]; + for (let i = 0, length = elems.length; i < length; i++) { + const elem = elems[i]; if (isCurrentlyFocusableInternal(elem)) { focus(elem); @@ -422,10 +422,10 @@ import scrollManager from 'scrollManager'; } function focusLast(container, focusableSelector) { - var elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse(); + const elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse(); - for (var i = 0, length = elems.length; i < length; i++) { - var elem = elems[i]; + for (let i = 0, length = elems.length; i < length; i++) { + const elem = elems[i]; if (isCurrentlyFocusableInternal(elem)) { focus(elem); @@ -435,11 +435,11 @@ import scrollManager from 'scrollManager'; } function moveFocus(sourceElement, container, focusableSelector, offset) { - var elems = container.querySelectorAll(focusableSelector); - var list = []; - var i; - var length; - var elem; + const elems = container.querySelectorAll(focusableSelector); + const list = []; + let i; + let length; + let elem; for (i = 0, length = elems.length; i < length; i++) { elem = elems[i]; @@ -449,7 +449,7 @@ import scrollManager from 'scrollManager'; } } - var currentIndex = -1; + let currentIndex = -1; for (i = 0, length = list.length; i < length; i++) { elem = list[i]; @@ -464,11 +464,11 @@ import scrollManager from 'scrollManager'; return; } - var newIndex = currentIndex + offset; + let newIndex = currentIndex + offset; newIndex = Math.max(0, newIndex); newIndex = Math.min(newIndex, list.length - 1); - var newElem = list[newIndex]; + const newElem = list[newIndex]; if (newElem) { focus(newElem); } @@ -482,23 +482,23 @@ export default { focusableParent: focusableParent, getFocusableElements: getFocusableElements, moveLeft: function (sourceElement, options) { - var container = options ? options.container : null; - var focusableElements = options ? options.focusableElements : null; + const container = options ? options.container : null; + const focusableElements = options ? options.focusableElements : null; nav(sourceElement, 0, container, focusableElements); }, moveRight: function (sourceElement, options) { - var container = options ? options.container : null; - var focusableElements = options ? options.focusableElements : null; + const container = options ? options.container : null; + const focusableElements = options ? options.focusableElements : null; nav(sourceElement, 1, container, focusableElements); }, moveUp: function (sourceElement, options) { - var container = options ? options.container : null; - var focusableElements = options ? options.focusableElements : null; + const container = options ? options.container : null; + const focusableElements = options ? options.focusableElements : null; nav(sourceElement, 2, container, focusableElements); }, moveDown: function (sourceElement, options) { - var container = options ? options.container : null; - var focusableElements = options ? options.focusableElements : null; + const container = options ? options.container : null; + const focusableElements = options ? options.focusableElements : null; nav(sourceElement, 3, container, focusableElements); }, sendText: sendText, diff --git a/src/components/groupedcards.js b/src/components/groupedcards.js index 38d08d129b..947b3b8569 100644 --- a/src/components/groupedcards.js +++ b/src/components/groupedcards.js @@ -4,19 +4,19 @@ import dom from 'dom'; import appRouter from 'appRouter'; function onGroupedCardClick(e, card) { - var itemId = card.getAttribute('data-id'); - var serverId = card.getAttribute('data-serverid'); - var apiClient = window.connectionManager.getApiClient(serverId); - var userId = apiClient.getCurrentUserId(); - var playedIndicator = card.querySelector('.playedIndicator'); - var playedIndicatorHtml = playedIndicator ? playedIndicator.innerHTML : null; - var options = { + const itemId = card.getAttribute('data-id'); + const serverId = card.getAttribute('data-serverid'); + const apiClient = window.connectionManager.getApiClient(serverId); + const userId = apiClient.getCurrentUserId(); + const playedIndicator = card.querySelector('.playedIndicator'); + const playedIndicatorHtml = playedIndicator ? playedIndicator.innerHTML : null; + const options = { Limit: parseInt(playedIndicatorHtml || '10'), Fields: 'PrimaryImageAspectRatio,DateCreated', ParentId: itemId, GroupItems: false }; - var actionableParent = dom.parentWithTag(e.target, ['A', 'BUTTON', 'INPUT']); + const actionableParent = dom.parentWithTag(e.target, ['A', 'BUTTON', 'INPUT']); if (!actionableParent || actionableParent.classList.contains('cardContent')) { apiClient.getJSON(apiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) { @@ -24,7 +24,7 @@ import appRouter from 'appRouter'; return void appRouter.showItem(items[0]); } - var url = 'details?id=' + itemId + '&serverId=' + serverId; + const url = 'details?id=' + itemId + '&serverId=' + serverId; Dashboard.navigate(url); }); e.stopPropagation(); @@ -34,7 +34,7 @@ import appRouter from 'appRouter'; } export default function onItemsContainerClick(e) { - var groupedCard = dom.parentWithClass(e.target, 'groupedCard'); + const groupedCard = dom.parentWithClass(e.target, 'groupedCard'); if (groupedCard) { onGroupedCardClick(e, groupedCard); diff --git a/src/components/htmlMediaHelper.js b/src/components/htmlMediaHelper.js index 4095502aae..31fc4c29c8 100644 --- a/src/components/htmlMediaHelper.js +++ b/src/components/htmlMediaHelper.js @@ -23,7 +23,7 @@ import events from 'events'; } function canPlayNativeHls() { - var media = document.createElement('video'); + const media = document.createElement('video'); if (media.canPlayType('application/x-mpegURL').replace(/no/, '') || media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, '')) { @@ -71,16 +71,16 @@ import events from 'events'; return true; } - var recoverDecodingErrorDate; - var recoverSwapAudioCodecDate; + let recoverDecodingErrorDate; + let recoverSwapAudioCodecDate; export function handleHlsJsMediaError(instance, reject) { - var hlsPlayer = instance._hlsPlayer; + const hlsPlayer = instance._hlsPlayer; if (!hlsPlayer) { return; } - var now = Date.now(); + let now = Date.now(); if (window.performance && window.performance.now) { now = performance.now(); // eslint-disable-line compat/compat @@ -136,7 +136,7 @@ import events from 'events'; } export function seekOnPlaybackStart(instance, element, ticks, onMediaReady) { - var seconds = (ticks || 0) / 10000000; + const seconds = (ticks || 0) / 10000000; if (seconds) { // Appending #t=xxx to the query string doesn't seem to work with HLS @@ -148,7 +148,7 @@ import events from 'events'; if (onMediaReady) onMediaReady(); } else { // update video player position when media is ready to be sought - var events = ['durationchange', 'loadeddata', 'play', 'loadedmetadata']; + const events = ['durationchange', 'loadeddata', 'play', 'loadedmetadata']; var onMediaChange = function(e) { if (element.currentTime === 0 && element.duration >= seconds) { // seek only when video position is exactly zero, @@ -173,10 +173,10 @@ import events from 'events'; export function applySrc(elem, src, options) { if (window.Windows && options.mediaSource && options.mediaSource.IsLocal) { return Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function (file) { - var playlist = new Windows.Media.Playback.MediaPlaybackList(); + const playlist = new Windows.Media.Playback.MediaPlaybackList(); - var source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file); - var startTime = (options.playerStartPositionTicks || 0) / 10000; + const source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file); + const startTime = (options.playerStartPositionTicks || 0) / 10000; playlist.items.append(new Windows.Media.Playback.MediaPlaybackItem(source1, startTime)); elem.src = URL.createObjectURL(playlist, { oneTimeOnly: true }); return Promise.resolve(); @@ -194,11 +194,11 @@ import events from 'events'; export function playWithPromise(elem, onErrorFn) { try { - var promise = elem.play(); + const promise = elem.play(); if (promise && promise.then) { // Chrome now returns a promise return promise.catch(function (e) { - var errorName = (e.name || '').toLowerCase(); + const errorName = (e.name || '').toLowerCase(); // safari uses aborterror if (errorName === 'notallowederror' || errorName === 'aborterror') { @@ -219,7 +219,7 @@ import events from 'events'; } export function destroyCastPlayer(instance) { - var player = instance._castPlayer; + const player = instance._castPlayer; if (player) { try { player.unload(); @@ -232,7 +232,7 @@ import events from 'events'; } export function destroyHlsPlayer(instance) { - var player = instance._hlsPlayer; + const player = instance._hlsPlayer; if (player) { try { player.destroy(); @@ -245,7 +245,7 @@ import events from 'events'; } export function destroyFlvPlayer(instance) { - var player = instance._flvPlayer; + const player = instance._flvPlayer; if (player) { try { player.unload(); @@ -356,7 +356,7 @@ import events from 'events'; destroyFlvPlayer(instance); destroyCastPlayer(instance); - var stopInfo = { + const stopInfo = { src: instance._currentSrc }; @@ -368,20 +368,20 @@ import events from 'events'; } export function getBufferedRanges(instance, elem) { - var ranges = []; - var seekable = elem.buffered || []; + const ranges = []; + const seekable = elem.buffered || []; - var offset; - var currentPlayOptions = instance._currentPlayOptions; + let offset; + const currentPlayOptions = instance._currentPlayOptions; if (currentPlayOptions) { offset = currentPlayOptions.transcodingOffsetTicks; } offset = offset || 0; - for (var i = 0, length = seekable.length; i < length; i++) { - var start = seekable.start(i); - var end = seekable.end(i); + for (let i = 0, length = seekable.length; i < length; i++) { + let start = seekable.start(i); + let end = seekable.end(i); if (!isValidDuration(start)) { start = 0; diff --git a/src/components/imageOptionsEditor/imageOptionsEditor.js b/src/components/imageOptionsEditor/imageOptionsEditor.js index 41fe9b4c94..d112dd65cc 100644 --- a/src/components/imageOptionsEditor/imageOptionsEditor.js +++ b/src/components/imageOptionsEditor/imageOptionsEditor.js @@ -93,7 +93,7 @@ import 'emby-input'; const response = await fetch('components/imageOptionsEditor/imageOptionsEditor.template.html'); const template = await response.text(); - var dlg = dialogHelper.createDialog({ + const dlg = dialogHelper.createDialog({ size: 'small', removeOnClose: true, scrollY: false diff --git a/src/components/imageeditor/imageeditor.js b/src/components/imageeditor/imageeditor.js index a21fb76270..e5b59cfb22 100644 --- a/src/components/imageeditor/imageeditor.js +++ b/src/components/imageeditor/imageeditor.js @@ -58,8 +58,8 @@ import 'css!./imageeditor'; currentItem = item; apiClient.getRemoteImageProviders(getBaseRemoteOptions()).then(function (providers) { - var btnBrowseAllImages = page.querySelectorAll('.btnBrowseAllImages'); - for (var i = 0, length = btnBrowseAllImages.length; i < length; i++) { + const btnBrowseAllImages = page.querySelectorAll('.btnBrowseAllImages'); + for (let i = 0, length = btnBrowseAllImages.length; i < length; i++) { if (providers.length) { btnBrowseAllImages[i].classList.remove('hide'); } else { diff --git a/src/components/images/imageLoader.js b/src/components/images/imageLoader.js index b0ffecd64f..9dc708098d 100644 --- a/src/components/images/imageLoader.js +++ b/src/components/images/imageLoader.js @@ -56,7 +56,7 @@ import 'css!./style'; throw new Error('entry cannot be null'); } const target = entry.target; - var source = undefined; + let source = undefined; if (target) { source = target.getAttribute('data-src'); @@ -106,7 +106,7 @@ import 'css!./style'; } function emptyImageElement(elem) { - var url; + let url; if (elem.tagName !== 'IMG') { url = elem.style.backgroundImage.slice(4, -1).replace(/"/g, ''); @@ -137,10 +137,10 @@ import 'css!./style'; } export function getPrimaryImageAspectRatio(items) { - var values = []; + const values = []; - for (var i = 0, length = items.length; i < length; i++) { - var ratio = items[i].PrimaryImageAspectRatio || 0; + for (let i = 0, length = items.length; i < length; i++) { + const ratio = items[i].PrimaryImageAspectRatio || 0; if (!ratio) { continue; @@ -158,9 +158,9 @@ import 'css!./style'; return a - b; }); - var half = Math.floor(values.length / 2); + const half = Math.floor(values.length / 2); - var result; + let result; if (values.length % 2) { result = values[half]; @@ -169,13 +169,13 @@ import 'css!./style'; } // If really close to 2:3 (poster image), just return 2:3 - var aspect2x3 = 2 / 3; + const aspect2x3 = 2 / 3; if (Math.abs(aspect2x3 - result) <= 0.15) { return aspect2x3; } // If really close to 16:9 (episode image), just return 16:9 - var aspect16x9 = 16 / 9; + const aspect16x9 = 16 / 9; if (Math.abs(aspect16x9 - result) <= 0.2) { return aspect16x9; } @@ -186,7 +186,7 @@ import 'css!./style'; } // If really close to 4:3 (poster image), just return 2:3 - var aspect4x3 = 4 / 3; + const aspect4x3 = 4 / 3; if (Math.abs(aspect4x3 - result) <= 0.15) { return aspect4x3; } @@ -195,8 +195,8 @@ import 'css!./style'; } export function fillImages(elems) { - for (var i = 0, length = elems.length; i < length; i++) { - var elem = elems[0]; + for (let i = 0, length = elems.length; i < length; i++) { + const elem = elems[0]; fillImage(elem); } } diff --git a/src/components/listview/listview.js b/src/components/listview/listview.js index 7837003250..e0fbc2fd2e 100644 --- a/src/components/listview/listview.js +++ b/src/components/listview/listview.js @@ -256,8 +256,8 @@ import 'emby-playstatebutton'; } if (options.image !== false) { - var imgUrl = options.imageSource === 'channel' ? getChannelImageUrl(item, downloadWidth) : getImageUrl(item, downloadWidth); - var imageClass = isLargeStyle ? 'listItemImage listItemImage-large' : 'listItemImage'; + const imgUrl = options.imageSource === 'channel' ? getChannelImageUrl(item, downloadWidth) : getImageUrl(item, downloadWidth); + let imageClass = isLargeStyle ? 'listItemImage listItemImage-large' : 'listItemImage'; if (isLargeStyle && layoutManager.tv) { imageClass += ' listItemImage-large-tv'; diff --git a/src/components/metadataEditor/metadataEditor.js b/src/components/metadataEditor/metadataEditor.js index e2ff2a6b56..b768e77c4f 100644 --- a/src/components/metadataEditor/metadataEditor.js +++ b/src/components/metadataEditor/metadataEditor.js @@ -239,7 +239,7 @@ import 'flexStyles'; } function afterDeleted(context, item) { - var parentId = item.ParentId || item.SeasonId || item.SeriesId; + const parentId = item.ParentId || item.SeasonId || item.SeriesId; if (parentId) { reload(context, parentId, item.ServerId); @@ -252,7 +252,7 @@ import 'flexStyles'; function showMoreMenu(context, button, user) { import('itemContextMenu').then(({default: itemContextMenu}) => { - var item = currentItem; + const item = currentItem; itemContextMenu.show({ item: item, diff --git a/src/components/nowPlayingBar/nowPlayingBar.js b/src/components/nowPlayingBar/nowPlayingBar.js index d9521c4c9e..6218197700 100644 --- a/src/components/nowPlayingBar/nowPlayingBar.js +++ b/src/components/nowPlayingBar/nowPlayingBar.js @@ -582,7 +582,7 @@ import 'emby-ratingbutton'; function onPlaybackStart(e, state) { console.debug('nowplaying event: ' + e.type); - var player = this; + const player = this; onStateChanged.call(player, e, state); } diff --git a/src/components/packageManager.js b/src/components/packageManager.js index 2a15a14f34..c4b4701e9d 100644 --- a/src/components/packageManager.js +++ b/src/components/packageManager.js @@ -8,7 +8,7 @@ import pluginManager from 'pluginManager'; init() { console.groupCollapsed('loading packages'); - var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]'); + const manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]'); return Promise.all(manifestUrls.map((url) => { return this.loadPackage(url); @@ -30,7 +30,7 @@ import pluginManager from 'pluginManager'; install(url) { return this.loadPackage(url, true).then((pkg) => { - var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]'); + const manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]'); if (!manifestUrls.includes(url)) { manifestUrls.push(url); @@ -42,7 +42,7 @@ import pluginManager from 'pluginManager'; } uninstall(name) { - var pkg = this.#packagesList.filter((p) => { + const pkg = this.#packagesList.filter((p) => { return p.name === name; })[0]; @@ -58,12 +58,12 @@ import pluginManager from 'pluginManager'; } mapPath(pkg, pluginUrl) { - var urlLower = pluginUrl.toLowerCase(); + const urlLower = pluginUrl.toLowerCase(); if (urlLower.startsWith('http:') || urlLower.startsWith('https:') || urlLower.startsWith('file:')) { return pluginUrl; } - var packageUrl = pkg.url; + let packageUrl = pkg.url; packageUrl = packageUrl.substring(0, packageUrl.lastIndexOf('/')); packageUrl += '/'; @@ -81,7 +81,7 @@ import pluginManager from 'pluginManager'; } removeUrl(url) { - var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]'); + let manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]'); manifestUrls = manifestUrls.filter((i) => { return i !== url; @@ -92,14 +92,14 @@ import pluginManager from 'pluginManager'; loadPackage(url, throwError = false) { return new Promise((resolve, reject) => { - var xhr = new XMLHttpRequest(); - var originalUrl = url; + const xhr = new XMLHttpRequest(); + const originalUrl = url; url += url.indexOf('?') === -1 ? '?' : '&'; url += 't=' + new Date().getTime(); xhr.open('GET', url, true); - var onError = () => { + const onError = () => { if (throwError === true) { reject(); } else { @@ -110,16 +110,16 @@ import pluginManager from 'pluginManager'; xhr.onload = () => { if (this.status < 400) { - var pkg = JSON.parse(this.response); + const pkg = JSON.parse(this.response); pkg.url = originalUrl; this.addPackage(pkg); - var plugins = pkg.plugins || []; + const plugins = pkg.plugins || []; if (pkg.plugin) { plugins.push(pkg.plugin); } - var promises = plugins.map((pluginUrl) => { + const promises = plugins.map((pluginUrl) => { return pluginManager.loadPlugin(this.mapPath(pkg, pluginUrl)); }); Promise.all(promises).then(resolve, resolve); diff --git a/src/components/playback/brightnessosd.js b/src/components/playback/brightnessosd.js index 9d5db62fe0..78c40d10c1 100644 --- a/src/components/playback/brightnessosd.js +++ b/src/components/playback/brightnessosd.js @@ -5,15 +5,15 @@ import browser from 'browser'; import 'css!./iconosd'; import 'material-icons'; -var currentPlayer; -var osdElement; -var iconElement; -var progressElement; +let currentPlayer; +let osdElement; +let iconElement; +let progressElement; -var enableAnimation; +let enableAnimation; function getOsdElementHtml() { - var html = ''; + let html = ''; html += ''; @@ -23,7 +23,7 @@ function getOsdElementHtml() { } function ensureOsdElement() { - var elem = osdElement; + let elem = osdElement; if (!elem) { enableAnimation = browser.supportsCssAnimation(); @@ -46,11 +46,11 @@ function onHideComplete() { this.classList.add('hide'); } -var hideTimeout; +let hideTimeout; function showOsd() { clearHideTimeout(); - var elem = osdElement; + const elem = osdElement; dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { once: true @@ -78,7 +78,7 @@ function clearHideTimeout() { function hideOsd() { clearHideTimeout(); - var elem = osdElement; + const elem = osdElement; if (elem) { if (enableAnimation) { // trigger reflow @@ -118,7 +118,7 @@ function updateElementsFromPlayer(brightness) { } function releaseCurrentPlayer() { - var player = currentPlayer; + const player = currentPlayer; if (player) { events.off(player, 'brightnesschange', onBrightnessChanged); @@ -128,7 +128,7 @@ function releaseCurrentPlayer() { } function onBrightnessChanged(e) { - var player = this; + const player = this; ensureOsdElement(); diff --git a/src/components/playback/nowplayinghelper.js b/src/components/playback/nowplayinghelper.js index d7f9d04865..a2b72ca84f 100644 --- a/src/components/playback/nowplayinghelper.js +++ b/src/components/playback/nowplayinghelper.js @@ -1,7 +1,7 @@ export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) { - var topItem = nowPlayingItem; - var bottomItem = null; - var topText = nowPlayingItem.Name; + let topItem = nowPlayingItem; + let bottomItem = null; + let topText = nowPlayingItem.Name; if (nowPlayingItem.AlbumId && nowPlayingItem.MediaType === 'Audio') { topItem = { @@ -21,7 +21,7 @@ export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) { } } - var bottomText = ''; + let bottomText = ''; if (nowPlayingItem.ArtistItems && nowPlayingItem.ArtistItems.length) { bottomItem = { @@ -56,7 +56,7 @@ export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) { bottomText = nowPlayingItem.ProductionYear; } - var list = []; + const list = []; list.push({ text: topText, diff --git a/src/components/playback/playbackorientation.js b/src/components/playback/playbackorientation.js index b73377bade..f585f25ae1 100644 --- a/src/components/playback/playbackorientation.js +++ b/src/components/playback/playbackorientation.js @@ -2,7 +2,7 @@ import playbackManager from 'playbackManager'; import layoutManager from 'layoutManager'; import events from 'events'; -var orientationLocked; +let orientationLocked; function onOrientationChangeSuccess() { orientationLocked = true; @@ -14,15 +14,15 @@ function onOrientationChangeError(err) { } events.on(playbackManager, 'playbackstart', function (e, player, state) { - var isLocalVideo = player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player); + const isLocalVideo = player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player); if (isLocalVideo && layoutManager.mobile) { /* eslint-disable-next-line compat/compat */ - var lockOrientation = window.screen.lockOrientation || window.screen.mozLockOrientation || window.screen.msLockOrientation || (window.screen.orientation && window.screen.orientation.lock); + const lockOrientation = window.screen.lockOrientation || window.screen.mozLockOrientation || window.screen.msLockOrientation || (window.screen.orientation && window.screen.orientation.lock); if (lockOrientation) { try { - var promise = lockOrientation('landscape'); + const promise = lockOrientation('landscape'); if (promise.then) { promise.then(onOrientationChangeSuccess, onOrientationChangeError); } else { @@ -39,7 +39,7 @@ events.on(playbackManager, 'playbackstart', function (e, player, state) { events.on(playbackManager, 'playbackstop', function (e, playbackStopInfo) { if (orientationLocked && !playbackStopInfo.nextMediaType) { /* eslint-disable-next-line compat/compat */ - var unlockOrientation = window.screen.unlockOrientation || window.screen.mozUnlockOrientation || window.screen.msUnlockOrientation || (window.screen.orientation && window.screen.orientation.unlock); + const unlockOrientation = window.screen.unlockOrientation || window.screen.mozUnlockOrientation || window.screen.msUnlockOrientation || (window.screen.orientation && window.screen.orientation.unlock); if (unlockOrientation) { try { diff --git a/src/components/playback/playerSelectionMenu.js b/src/components/playback/playerSelectionMenu.js index 0afa56faf4..38ff399a9e 100644 --- a/src/components/playback/playerSelectionMenu.js +++ b/src/components/playback/playerSelectionMenu.js @@ -9,7 +9,7 @@ import appHost from 'apphost'; import * as autocast from 'autocast'; function mirrorItem(info, player) { - var item = info.item; + const item = info.item; playbackManager.displayContent({ @@ -22,7 +22,7 @@ function mirrorItem(info, player) { function mirrorIfEnabled(info) { if (info && playbackManager.enableDisplayMirroring()) { - var getPlayerInfo = playbackManager.getPlayerInfo(); + const getPlayerInfo = playbackManager.getPlayerInfo(); if (getPlayerInfo) { if (!getPlayerInfo.isLocalPlayer && getPlayerInfo.supportedCommands.indexOf('DisplayContent') !== -1) { @@ -45,7 +45,7 @@ function getTargetSecondaryText(target) { } function getIcon(target) { - var deviceType = target.deviceType; + let deviceType = target.deviceType; if (!deviceType && target.isLocalPlayer) { if (browser.tv) { @@ -78,7 +78,7 @@ function getIcon(target) { } export function show(button) { - var currentPlayerInfo = playbackManager.getPlayerInfo(); + const currentPlayerInfo = playbackManager.getPlayerInfo(); if (currentPlayerInfo) { if (!currentPlayerInfo.isLocalPlayer) { @@ -87,13 +87,13 @@ export function show(button) { } } - var currentPlayerId = currentPlayerInfo ? currentPlayerInfo.id : null; + const currentPlayerId = currentPlayerInfo ? currentPlayerInfo.id : null; loading.show(); playbackManager.getTargets().then(function (targets) { - var menuItems = targets.map(function (t) { - var name = t.name; + const menuItems = targets.map(function (t) { + let name = t.name; if (t.appName && t.appName !== t.name) { name += ' - ' + t.appName; @@ -111,7 +111,7 @@ export function show(button) { import('actionsheet').then(({default: actionsheet}) => { loading.hide(); - var menuOptions = { + const menuOptions = { title: globalize.translate('HeaderPlayOn'), items: menuItems, positionTo: button, @@ -127,7 +127,7 @@ export function show(button) { } actionsheet.show(menuOptions).then(function (id) { - var target = targets.filter(function (t) { + const target = targets.filter(function (t) { return t.id === id; })[0]; @@ -153,7 +153,7 @@ function showActivePlayerMenu(playerInfo) { function disconnectFromPlayer(currentDeviceName) { if (playbackManager.getSupportedCommands().indexOf('EndSession') !== -1) { import('dialog').then(({default: dialog}) => { - var menuItems = []; + const menuItems = []; menuItems.push({ name: globalize.translate('Yes'), @@ -188,9 +188,9 @@ function disconnectFromPlayer(currentDeviceName) { } function showActivePlayerMenuInternal(dialogHelper, playerInfo) { - var html = ''; + let html = ''; - var dialogOptions = { + const dialogOptions = { removeOnClose: true }; @@ -199,11 +199,11 @@ function showActivePlayerMenuInternal(dialogHelper, playerInfo) { dialogOptions.exitAnimationDuration = 160; dialogOptions.autoFocus = false; - var dlg = dialogHelper.createDialog(dialogOptions); + const dlg = dialogHelper.createDialog(dialogOptions); dlg.classList.add('promptDialog'); - var currentDeviceName = (playerInfo.deviceName || playerInfo.name); + const currentDeviceName = (playerInfo.deviceName || playerInfo.name); html += '
    '; html += '

    '; @@ -214,7 +214,7 @@ function showActivePlayerMenuInternal(dialogHelper, playerInfo) { if (playerInfo.supportedCommands.indexOf('DisplayContent') !== -1) { html += ''; @@ -224,7 +224,7 @@ function showActivePlayerMenuInternal(dialogHelper, playerInfo) { if (autocast.supported()) { html += '
    '; @@ -240,21 +240,21 @@ function showActivePlayerMenuInternal(dialogHelper, playerInfo) { html += '

    '; dlg.innerHTML = html; - var chkMirror = dlg.querySelector('.chkMirror'); + const chkMirror = dlg.querySelector('.chkMirror'); if (chkMirror) { chkMirror.addEventListener('change', onMirrorChange); } - var chkAutoCast = dlg.querySelector('.chkAutoCast'); + const chkAutoCast = dlg.querySelector('.chkAutoCast'); if (chkAutoCast) { chkAutoCast.addEventListener('change', onAutoCastChange); } - var destination = ''; + let destination = ''; - var btnRemoteControl = dlg.querySelector('.btnRemoteControl'); + const btnRemoteControl = dlg.querySelector('.btnRemoteControl'); if (btnRemoteControl) { btnRemoteControl.addEventListener('click', function () { destination = 'nowplaying'; @@ -289,8 +289,8 @@ function onAutoCastChange() { } document.addEventListener('viewshow', function (e) { - var state = e.detail.state || {}; - var item = state.item; + const state = e.detail.state || {}; + const item = state.item; if (item && item.ServerId) { mirrorIfEnabled({ diff --git a/src/components/playback/playersettingsmenu.js b/src/components/playback/playersettingsmenu.js index 77f22b6b6c..40819f62ea 100644 --- a/src/components/playback/playersettingsmenu.js +++ b/src/components/playback/playersettingsmenu.js @@ -4,13 +4,13 @@ import globalize from 'globalize'; import qualityoptions from 'qualityoptions'; function showQualityMenu(player, btn) { - var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { + const videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { return stream.Type === 'Video'; })[0]; - var videoWidth = videoStream ? videoStream.Width : null; - var videoHeight = videoStream ? videoStream.Height : null; + const videoWidth = videoStream ? videoStream.Width : null; + const videoHeight = videoStream ? videoStream.Height : null; - var options = qualityoptions.getVideoQualityOptions({ + const options = qualityoptions.getVideoQualityOptions({ currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player), isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player), videoWidth: videoWidth, @@ -18,8 +18,8 @@ function showQualityMenu(player, btn) { enableAuto: true }); - var menuItems = options.map(function (o) { - var opt = { + const menuItems = options.map(function (o) { + const opt = { name: o.name, id: o.bitrate, asideText: o.secondaryText @@ -32,7 +32,7 @@ function showQualityMenu(player, btn) { return opt; }); - var selectedId = options.filter(function (o) { + let selectedId = options.filter(function (o) { return o.selected; }); @@ -42,7 +42,7 @@ function showQualityMenu(player, btn) { items: menuItems, positionTo: btn }).then(function (id) { - var bitrate = parseInt(id); + const bitrate = parseInt(id); if (bitrate !== selectedId) { playbackManager.setMaxStreamingBitrate({ enableAutomaticBitrateDetection: bitrate ? false : true, @@ -53,8 +53,8 @@ function showQualityMenu(player, btn) { } function showRepeatModeMenu(player, btn) { - var menuItems = []; - var currentValue = playbackManager.getRepeatMode(player); + const menuItems = []; + const currentValue = playbackManager.getRepeatMode(player); menuItems.push({ name: globalize.translate('RepeatAll'), @@ -85,16 +85,16 @@ function showRepeatModeMenu(player, btn) { } function getQualitySecondaryText(player) { - var state = playbackManager.getPlayerState(player); + const state = playbackManager.getPlayerState(player); - var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { + const videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { return stream.Type === 'Video'; })[0]; - var videoWidth = videoStream ? videoStream.Width : null; - var videoHeight = videoStream ? videoStream.Height : null; + const videoWidth = videoStream ? videoStream.Width : null; + const videoHeight = videoStream ? videoStream.Height : null; - var options = qualityoptions.getVideoQualityOptions({ + const options = qualityoptions.getVideoQualityOptions({ currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player), isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player), videoWidth: videoWidth, @@ -102,7 +102,7 @@ function getQualitySecondaryText(player) { enableAuto: true }); - var selectedOption = options.filter(function (o) { + let selectedOption = options.filter(function (o) { return o.selected; }); @@ -111,7 +111,7 @@ function getQualitySecondaryText(player) { } selectedOption = selectedOption[0]; - var text = selectedOption.name; + let text = selectedOption.name; if (selectedOption.autoText) { if (state.PlayState && state.PlayState.PlayMethod !== 'Transcode') { @@ -126,8 +126,8 @@ function getQualitySecondaryText(player) { function showAspectRatioMenu(player, btn) { // each has a name and id - var currentId = playbackManager.getAspectRatio(player); - var menuItems = playbackManager.getSupportedAspectRatios(player).map(function (i) { + const currentId = playbackManager.getAspectRatio(player); + const menuItems = playbackManager.getSupportedAspectRatios(player).map(function (i) { return { id: i.id, name: i.name, @@ -171,12 +171,12 @@ function showPlaybackRateMenu(player, btn) { } function showWithUser(options, player, user) { - var supportedCommands = playbackManager.getSupportedCommands(player); + const supportedCommands = playbackManager.getSupportedCommands(player); - var menuItems = []; + const menuItems = []; if (supportedCommands.indexOf('SetAspectRatio') !== -1) { - var currentAspectRatioId = playbackManager.getAspectRatio(player); - var currentAspectRatio = playbackManager.getSupportedAspectRatios(player).filter(function (i) { + const currentAspectRatioId = playbackManager.getAspectRatio(player); + const currentAspectRatio = playbackManager.getSupportedAspectRatios(player).filter(function (i) { return i.id === currentAspectRatioId; })[0]; @@ -199,7 +199,7 @@ function showWithUser(options, player, user) { } if (user && user.Policy.EnableVideoPlaybackTranscoding) { - var secondaryQualityText = getQualitySecondaryText(player); + const secondaryQualityText = getQualitySecondaryText(player); menuItems.push({ name: globalize.translate('Quality'), @@ -208,7 +208,7 @@ function showWithUser(options, player, user) { }); } - var repeatMode = playbackManager.getRepeatMode(player); + const repeatMode = playbackManager.getRepeatMode(player); if (supportedCommands.indexOf('SetRepeatMode') !== -1 && playbackManager.currentMediaSource(player).RunTimeTicks) { menuItems.push({ @@ -243,14 +243,14 @@ function showWithUser(options, player, user) { } export function show(options) { - var player = options.player; - var currentItem = playbackManager.currentItem(player); + const player = options.player; + const currentItem = playbackManager.currentItem(player); if (!currentItem || !currentItem.ServerId) { return showWithUser(options, player, null); } - var apiClient = window.connectionManager.getApiClient(currentItem.ServerId); + const apiClient = window.connectionManager.getApiClient(currentItem.ServerId); return apiClient.getCurrentUser().then(function (user) { return showWithUser(options, player, user); }); diff --git a/src/components/playback/volumeosd.js b/src/components/playback/volumeosd.js index 8a6f534b52..c35914b192 100644 --- a/src/components/playback/volumeosd.js +++ b/src/components/playback/volumeosd.js @@ -5,15 +5,15 @@ import browser from 'browser'; import 'css!./iconosd'; import 'material-icons'; -var currentPlayer; -var osdElement; -var iconElement; -var progressElement; +let currentPlayer; +let osdElement; +let iconElement; +let progressElement; -var enableAnimation; +let enableAnimation; function getOsdElementHtml() { - var html = ''; + let html = ''; html += ''; @@ -23,7 +23,7 @@ function getOsdElementHtml() { } function ensureOsdElement() { - var elem = osdElement; + let elem = osdElement; if (!elem) { enableAnimation = browser.supportsCssAnimation(); @@ -46,11 +46,11 @@ function onHideComplete() { this.classList.add('hide'); } -var hideTimeout; +let hideTimeout; function showOsd() { clearHideTimeout(); - var elem = osdElement; + const elem = osdElement; dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { once: true @@ -78,7 +78,7 @@ function clearHideTimeout() { function hideOsd() { clearHideTimeout(); - var elem = osdElement; + const elem = osdElement; if (elem) { if (enableAnimation) { // trigger reflow @@ -108,7 +108,7 @@ function updatePlayerVolumeState(isMuted, volume) { } function releaseCurrentPlayer() { - var player = currentPlayer; + const player = currentPlayer; if (player) { events.off(player, 'volumechange', onVolumeChanged); @@ -118,7 +118,7 @@ function releaseCurrentPlayer() { } function onVolumeChanged(e) { - var player = this; + const player = this; ensureOsdElement(); diff --git a/src/components/playerstats/playerstats.js b/src/components/playerstats/playerstats.js index 5345ed8bcc..e100dee594 100644 --- a/src/components/playerstats/playerstats.js +++ b/src/components/playerstats/playerstats.js @@ -413,7 +413,7 @@ import 'css!./playerstats'; name: 'Original Media Info' }); - var apiClient = window.connectionManager.getApiClient(playbackManager.currentItem(player).ServerId); + const apiClient = window.connectionManager.getApiClient(playbackManager.currentItem(player).ServerId); if (syncPlayManager.isSyncPlayEnabled() && apiClient.isMinServerVersion('10.6.0')) { categories.push({ stats: getSyncPlayStats(), diff --git a/src/components/playmenu.js b/src/components/playmenu.js index c537993ef6..57ee5ca6e3 100644 --- a/src/components/playmenu.js +++ b/src/components/playmenu.js @@ -4,11 +4,11 @@ import playbackManager from 'playbackManager'; import globalize from 'globalize'; export function show(options) { - var item = options.item; + const item = options.item; - var resumePositionTicks = item.UserData ? item.UserData.PlaybackPositionTicks : null; + const resumePositionTicks = item.UserData ? item.UserData.PlaybackPositionTicks : null; - var playableItemId = item.Type === 'Program' ? item.ChannelId : item.Id; + const playableItemId = item.Type === 'Program' ? item.ChannelId : item.Id; if (!resumePositionTicks || item.IsFolder) { playbackManager.play({ @@ -18,7 +18,7 @@ export function show(options) { return; } - var menuItems = []; + const menuItems = []; menuItems.push({ name: globalize.translate('ResumeAt', datetime.getDisplayRunningTime(resumePositionTicks)), diff --git a/src/components/pluginManager.js b/src/components/pluginManager.js index 55a5c230ff..c07c77b736 100644 --- a/src/components/pluginManager.js +++ b/src/components/pluginManager.js @@ -3,7 +3,7 @@ import globalize from 'globalize'; /* eslint-disable indent */ // TODO: replace with each plugin version - var cacheParam = new Date().getTime(); + const cacheParam = new Date().getTime(); class PluginManager { pluginsList = []; @@ -13,7 +13,7 @@ import globalize from 'globalize'; } #loadStrings(plugin) { - var strings = plugin.getTranslations ? plugin.getTranslations() : []; + const strings = plugin.getTranslations ? plugin.getTranslations() : []; return globalize.loadStrings({ name: plugin.id || plugin.packageName, strings: strings @@ -56,10 +56,10 @@ import globalize from 'globalize'; return new Promise((resolve, reject) => { require([pluginSpec], (pluginFactory) => { - var plugin = pluginFactory.default ? new pluginFactory.default() : new pluginFactory(); + const plugin = pluginFactory.default ? new pluginFactory.default() : new pluginFactory(); // See if it's already installed - var existing = this.pluginsList.filter(function (p) { + const existing = this.pluginsList.filter(function (p) { return p.id === plugin.id; })[0]; @@ -69,10 +69,10 @@ import globalize from 'globalize'; plugin.installUrl = pluginSpec; - var separatorIndex = Math.max(pluginSpec.lastIndexOf('/'), pluginSpec.lastIndexOf('\\')); + const separatorIndex = Math.max(pluginSpec.lastIndexOf('/'), pluginSpec.lastIndexOf('\\')); plugin.baseUrl = pluginSpec.substring(0, separatorIndex); - var paths = {}; + const paths = {}; paths[plugin.id] = plugin.baseUrl; requirejs.config({ @@ -135,7 +135,7 @@ import globalize from 'globalize'; })[0]; } - var url = plugin.baseUrl + '/' + path; + let url = plugin.baseUrl + '/' + path; if (addCacheParam) { url += url.includes('?') ? '&' : '?'; diff --git a/src/components/qualityOptions.js b/src/components/qualityOptions.js index 63d9557c7b..93a8d5fe73 100644 --- a/src/components/qualityOptions.js +++ b/src/components/qualityOptions.js @@ -1,9 +1,9 @@ import globalize from 'globalize'; export function getVideoQualityOptions(options) { - var maxStreamingBitrate = options.currentMaxBitrate; - var videoWidth = options.videoWidth; - var videoHeight = options.videoHeight; + const maxStreamingBitrate = options.currentMaxBitrate; + let videoWidth = options.videoWidth; + const videoHeight = options.videoHeight; // If the aspect ratio is less than 16/9 (1.77), set the width as if it were pillarboxed. // 4:3 1440x1080 -> 1920x1080 @@ -11,9 +11,9 @@ export function getVideoQualityOptions(options) { videoWidth = videoHeight * (16 / 9); } - var maxAllowedWidth = videoWidth || 4096; + const maxAllowedWidth = videoWidth || 4096; - var qualityOptions = []; + const qualityOptions = []; if (maxAllowedWidth >= 3800) { qualityOptions.push({ name: '4K - 120 Mbps', maxHeight: 2160, bitrate: 120000000 }); @@ -65,7 +65,7 @@ export function getVideoQualityOptions(options) { qualityOptions.push({ name: '240p', maxHeight: 240, bitrate: 320000 }); qualityOptions.push({ name: '144p', maxHeight: 144, bitrate: 192000 }); - var autoQualityOption = { + const autoQualityOption = { name: globalize.translate('Auto'), bitrate: 0, selected: options.isAutomaticBitrateEnabled @@ -76,9 +76,9 @@ export function getVideoQualityOptions(options) { } if (maxStreamingBitrate) { - var selectedIndex = -1; - for (var i = 0, length = qualityOptions.length; i < length; i++) { - var option = qualityOptions[i]; + let selectedIndex = -1; + for (let i = 0, length = qualityOptions.length; i < length; i++) { + const option = qualityOptions[i]; if (selectedIndex === -1 && option.bitrate <= maxStreamingBitrate) { selectedIndex = i; @@ -89,7 +89,7 @@ export function getVideoQualityOptions(options) { selectedIndex = qualityOptions.length - 1; } - var currentQualityOption = qualityOptions[selectedIndex]; + const currentQualityOption = qualityOptions[selectedIndex]; if (!options.isAutomaticBitrateEnabled) { currentQualityOption.selected = true; @@ -102,9 +102,9 @@ export function getVideoQualityOptions(options) { } export function getAudioQualityOptions(options) { - var maxStreamingBitrate = options.currentMaxBitrate; + const maxStreamingBitrate = options.currentMaxBitrate; - var qualityOptions = []; + const qualityOptions = []; qualityOptions.push({ name: '2 Mbps', bitrate: 2000000 }); qualityOptions.push({ name: '1.5 Mbps', bitrate: 1500000 }); @@ -116,7 +116,7 @@ export function getAudioQualityOptions(options) { qualityOptions.push({ name: '96 kbps', bitrate: 96000 }); qualityOptions.push({ name: '64 kbps', bitrate: 64000 }); - var autoQualityOption = { + const autoQualityOption = { name: globalize.translate('Auto'), bitrate: 0, selected: options.isAutomaticBitrateEnabled @@ -127,9 +127,9 @@ export function getAudioQualityOptions(options) { } if (maxStreamingBitrate) { - var selectedIndex = -1; - for (var i = 0, length = qualityOptions.length; i < length; i++) { - var option = qualityOptions[i]; + let selectedIndex = -1; + for (let i = 0, length = qualityOptions.length; i < length; i++) { + const option = qualityOptions[i]; if (selectedIndex === -1 && option.bitrate <= maxStreamingBitrate) { selectedIndex = i; @@ -140,7 +140,7 @@ export function getAudioQualityOptions(options) { selectedIndex = qualityOptions.length - 1; } - var currentQualityOption = qualityOptions[selectedIndex]; + const currentQualityOption = qualityOptions[selectedIndex]; if (!options.isAutomaticBitrateEnabled) { currentQualityOption.selected = true; diff --git a/src/components/require/requirecss.js b/src/components/require/requirecss.js index 8aaa04d689..ca6910e319 100644 --- a/src/components/require/requirecss.js +++ b/src/components/require/requirecss.js @@ -1,7 +1,7 @@ define(function () { 'use strict'; - var requireCss = {}; + const requireCss = {}; requireCss.normalize = function (name, normalize) { if (name.substr(name.length - 4, 4) === '.css') { @@ -11,7 +11,7 @@ define(function () { return normalize(name); }; - var importedCss = []; + let importedCss = []; function isLoaded(url) { return importedCss.indexOf(url) !== -1; @@ -27,14 +27,14 @@ define(function () { requireCss.load = function (cssId, req, load, config) { // Somehow if the url starts with /css, require will get all screwed up since this extension is also called css - var srch = 'components/require/requirecss'; - var index = cssId.indexOf(srch); + const srch = 'components/require/requirecss'; + const index = cssId.indexOf(srch); if (index !== -1) { cssId = 'css' + cssId.substring(index + srch.length); } - var url = cssId + '.css'; + let url = cssId + '.css'; if (url.indexOf('://') === -1) { url = config.baseUrl + url; @@ -43,13 +43,13 @@ define(function () { if (!isLoaded(url)) { importedCss.push(url); - var link = document.createElement('link'); + const link = document.createElement('link'); link.setAttribute('rel', 'stylesheet'); link.setAttribute('type', 'text/css'); link.onload = load; - var linkUrl = url; + let linkUrl = url; if (config.urlArgs) { linkUrl += config.urlArgs(cssId, url); diff --git a/src/components/require/requiretext.js b/src/components/require/requiretext.js index 28ddeb21c8..12822a29e7 100644 --- a/src/components/require/requiretext.js +++ b/src/components/require/requiretext.js @@ -2,7 +2,7 @@ define(function () { 'use strict'; // hack to work around the server's auto-redirection feature - var addRedirectPrevention = window.dashboardVersion != null && window.Dashboard && !window.AppInfo.isNativeApp; + const addRedirectPrevention = window.dashboardVersion != null && window.Dashboard && !window.AppInfo.isNativeApp; return { @@ -25,7 +25,7 @@ define(function () { url += 'r=0'; } - var xhr = new XMLHttpRequest(); + const xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onload = function (e) { diff --git a/src/components/serviceworker/notifications.js b/src/components/serviceworker/notifications.js index 9b50553244..cc2ee65320 100644 --- a/src/components/serviceworker/notifications.js +++ b/src/components/serviceworker/notifications.js @@ -2,7 +2,7 @@ (function () { 'use strict'; - var connectionManager; + let connectionManager; function getApiClient(serverId) { if (connectionManager) { @@ -28,12 +28,12 @@ /* eslint-disable-next-line no-restricted-globals -- self is valid in a serviceworker environment */ self.addEventListener('notificationclick', function (event) { - var notification = event.notification; + const notification = event.notification; notification.close(); - var data = notification.data; - var serverId = data.serverId; - var action = event.action; + const data = notification.data; + const serverId = data.serverId; + const action = event.action; if (!action) { clients.openWindow('/'); diff --git a/src/components/syncPlay/groupSelectionMenu.js b/src/components/syncPlay/groupSelectionMenu.js index 655dc76010..b554817b8c 100644 --- a/src/components/syncPlay/groupSelectionMenu.js +++ b/src/components/syncPlay/groupSelectionMenu.js @@ -12,7 +12,7 @@ import playbackPermissionManager from 'playbackPermissionManager'; * @returns {string} The player's id. */ function getActivePlayerId () { - var info = playbackManager.getPlayerInfo(); + const info = playbackManager.getPlayerInfo(); return info ? info.id : null; } @@ -38,7 +38,7 @@ function showNewJoinGroupSelection (button, user, apiClient) { apiClient.getSyncPlayGroups().then(function (response) { response.json().then(function (groups) { - var menuItems = groups.map(function (group) { + const menuItems = groups.map(function (group) { return { name: group.PlayingItemName, icon: 'group', @@ -72,7 +72,7 @@ function showNewJoinGroupSelection (button, user, apiClient) { return; } - var menuOptions = { + const menuOptions = { title: globalize.translate('HeaderSyncPlaySelectGroup'), items: menuItems, positionTo: button, @@ -129,7 +129,7 @@ function showLeaveGroupSelection (button, user, apiClient) { secondaryText: globalize.translate('LabelSyncPlayLeaveGroupDescription') }]; - var menuOptions = { + const menuOptions = { title: globalize.translate('HeaderSyncPlayEnabled'), items: menuItems, positionTo: button, diff --git a/src/components/syncPlay/syncPlayManager.js b/src/components/syncPlay/syncPlayManager.js index 3be3a3cedf..c72d20a111 100644 --- a/src/components/syncPlay/syncPlayManager.js +++ b/src/components/syncPlay/syncPlayManager.js @@ -40,7 +40,7 @@ function waitForEventOnce(emitter, eventType, timeout) { * @returns {string} The player's id. */ function getActivePlayerId() { - var info = playbackManager.getPlayerInfo(); + const info = playbackManager.getPlayerInfo(); return info ? info.id : null; } @@ -276,7 +276,7 @@ class SyncPlayManager { * Removes the bindings to the current player's events. */ releaseCurrentPlayer () { - var player = this.currentPlayer; + const player = this.currentPlayer; if (player) { events.off(player, 'unpause', this._onPlayerUnpause); events.off(player, 'pause', this._onPlayerPause); @@ -426,7 +426,7 @@ class SyncPlayManager { serverId: serverId }).then(() => { waitForEventOnce(this, 'playbackstart', WaitForEventDefaultTimeout).then(() => { - var sessionId = getActivePlayerId(); + const sessionId = getActivePlayerId(); if (!sessionId) { console.error('Missing sessionId!'); toast({ @@ -659,7 +659,7 @@ class SyncPlayManager { * Overrides PlaybackManager's unpause method. */ playRequest (player) { - var apiClient = window.connectionManager.currentApiClient(); + const apiClient = window.connectionManager.currentApiClient(); apiClient.requestSyncPlayStart(); } @@ -667,7 +667,7 @@ class SyncPlayManager { * Overrides PlaybackManager's pause method. */ pauseRequest (player) { - var apiClient = window.connectionManager.currentApiClient(); + const apiClient = window.connectionManager.currentApiClient(); apiClient.requestSyncPlayPause(); // Pause locally as well, to give the user some little control playbackManager._localUnpause(player); @@ -677,7 +677,7 @@ class SyncPlayManager { * Overrides PlaybackManager's seek method. */ seekRequest (PositionTicks, player) { - var apiClient = window.connectionManager.currentApiClient(); + const apiClient = window.connectionManager.currentApiClient(); apiClient.requestSyncPlaySeek({ PositionTicks: PositionTicks }); diff --git a/src/components/tabbedview/tabbedview.js b/src/components/tabbedview/tabbedview.js index 710a0e3c40..4e7ccb6529 100644 --- a/src/components/tabbedview/tabbedview.js +++ b/src/components/tabbedview/tabbedview.js @@ -4,7 +4,7 @@ import layoutManager from 'layoutManager'; import 'emby-tabs'; function onViewDestroy(e) { - var tabControllers = this.tabControllers; + const tabControllers = this.tabControllers; if (tabControllers) { tabControllers.forEach(function (t) { @@ -32,9 +32,9 @@ class TabbedView { this.view = view; this.params = params; - var self = this; + const self = this; - var currentTabIndex = parseInt(params.tab || this.getDefaultTabIndex(params.parentId)); + let currentTabIndex = parseInt(params.tab || this.getDefaultTabIndex(params.parentId)); this.initialTabIndex = currentTabIndex; function validateTabLoad(index) { @@ -44,7 +44,7 @@ class TabbedView { function loadTab(index, previousIndex) { validateTabLoad(index).then(function () { self.getTabController(index).then(function (controller) { - var refresh = !controller.refreshed; + const refresh = !controller.refreshed; controller.onResume({ autoFocus: previousIndex == null && layoutManager.tv, @@ -64,10 +64,10 @@ class TabbedView { } function onTabChange(e) { - var newIndex = parseInt(e.detail.selectedTabIndex); - var previousIndex = e.detail.previousIndex; + const newIndex = parseInt(e.detail.selectedTabIndex); + const previousIndex = e.detail.previousIndex; - var previousTabController = previousIndex == null ? null : self.tabControllers[previousIndex]; + const previousTabController = previousIndex == null ? null : self.tabControllers[previousIndex]; if (previousTabController && previousTabController.onPause) { previousTabController.onPause(); } @@ -92,7 +92,7 @@ class TabbedView { this.setTitle(); backdrop.clearBackdrop(); - var currentTabController = this.currentTabController; + const currentTabController = this.currentTabController; if (!currentTabController) { mainTabsManager.selectedTabIndex(this.initialTabIndex); @@ -102,7 +102,7 @@ class TabbedView { } onPause() { - var currentTabController = this.currentTabController; + const currentTabController = this.currentTabController; if (currentTabController && currentTabController.onPause) { currentTabController.onPause(); diff --git a/src/controllers/dashboard/logs.js b/src/controllers/dashboard/logs.js index 7bf2785d50..e28c2ac12f 100644 --- a/src/controllers/dashboard/logs.js +++ b/src/controllers/dashboard/logs.js @@ -9,21 +9,21 @@ import 'flexStyles'; export default function(view, params) { view.addEventListener('viewbeforeshow', function() { loading.show(); - var apiClient = ApiClient; + const apiClient = ApiClient; apiClient.getJSON(apiClient.getUrl('System/Logs')).then(function(logs) { - var html = ''; + let html = ''; html += '
    '; html += logs.map(function(log) { - var logUrl = apiClient.getUrl('System/Logs/Log', { + let logUrl = apiClient.getUrl('System/Logs/Log', { name: log.Name }); logUrl += '&api_key=' + apiClient.accessToken(); - var logHtml = ''; + let logHtml = ''; logHtml += ''; logHtml += '
    '; logHtml += "

    " + log.Name + '

    '; - var date = datetime.parseISO8601Date(log.DateModified, true); - var text = datetime.toLocaleDateString(date); + const date = datetime.parseISO8601Date(log.DateModified, true); + let text = datetime.toLocaleDateString(date); text += ' ' + datetime.getDisplayTime(date); logHtml += '
    ' + text + '
    '; logHtml += '
    '; diff --git a/src/controllers/dashboard/plugins/repositories/index.js b/src/controllers/dashboard/plugins/repositories/index.js index 8d1cbf3164..3abee6c90f 100644 --- a/src/controllers/dashboard/plugins/repositories/index.js +++ b/src/controllers/dashboard/plugins/repositories/index.js @@ -42,10 +42,10 @@ function saveList(page) { } function populateList(options) { - var html = ''; + let html = ''; html += '
    '; - for (var i = 0; i < options.repositories.length; i++) { + for (let i = 0; i < options.repositories.length; i++) { html += getRepositoryHtml(options.repositories[i]); } @@ -59,7 +59,7 @@ function populateList(options) { } function getRepositoryHtml(repository) { - var html = ''; + let html = ''; html += '
    '; html += ``; @@ -93,9 +93,9 @@ export default function(view, params) { libraryMenu.setTabs('plugins', 2, getTabs); reloadList(this); - var save = this; + const save = this; $('#repositories', view).on('click', '.btnDelete', function() { - var button = this; + const button = this; repositories = repositories.filter(function (r) { return r.Url !== button.id; }); diff --git a/src/controllers/edititemmetadata.js b/src/controllers/edititemmetadata.js index 57c72dda28..dd51ba2581 100644 --- a/src/controllers/edititemmetadata.js +++ b/src/controllers/edititemmetadata.js @@ -20,7 +20,7 @@ export default function (view, params) { }); MetadataEditor.setCurrentItemId(null); view.querySelector('.libraryTree').addEventListener('itemclicked', function (event) { - var data = event.detail; + const data = event.detail; if (data.id != MetadataEditor.getCurrentItemId()) { MetadataEditor.setCurrentItemId(data.id); diff --git a/src/controllers/movies/moviesrecommended.js b/src/controllers/movies/moviesrecommended.js index 4036128b51..a53fa65437 100644 --- a/src/controllers/movies/moviesrecommended.js +++ b/src/controllers/movies/moviesrecommended.js @@ -395,7 +395,7 @@ import 'emby-button'; view.addEventListener('viewshow', function (e) { initTabs(); if (!view.getAttribute('data-title')) { - var parentId = params.topParentId; + const parentId = params.topParentId; if (parentId) { ApiClient.getItem(ApiClient.getCurrentUserId(), parentId).then(function (item) { diff --git a/src/controllers/music/musicrecommended.js b/src/controllers/music/musicrecommended.js index a93bfea4e3..580578e68d 100644 --- a/src/controllers/music/musicrecommended.js +++ b/src/controllers/music/musicrecommended.js @@ -56,7 +56,7 @@ import 'flexStyles'; EnableTotalRecordCount: false }; ApiClient.getJSON(ApiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) { - var elem = page.querySelector('#recentlyAddedSongs'); + const elem = page.querySelector('#recentlyAddedSongs'); elem.innerHTML = cardBuilder.getCardsHtml({ items: items, showUnplayedIndicator: false, @@ -103,7 +103,7 @@ import 'flexStyles'; elem.classList.add('hide'); } - var itemsContainer = elem.querySelector('.itemsContainer'); + const itemsContainer = elem.querySelector('.itemsContainer'); itemsContainer.innerHTML = cardBuilder.getCardsHtml({ items: result.Items, showUnplayedIndicator: false, @@ -145,7 +145,7 @@ import 'flexStyles'; elem.classList.add('hide'); } - var itemsContainer = elem.querySelector('.itemsContainer'); + const itemsContainer = elem.querySelector('.itemsContainer'); itemsContainer.innerHTML = cardBuilder.getCardsHtml({ items: result.Items, showUnplayedIndicator: false, diff --git a/src/controllers/session/login/index.js b/src/controllers/session/login/index.js index 274d752e49..1592e6b112 100644 --- a/src/controllers/session/login/index.js +++ b/src/controllers/session/login/index.js @@ -16,7 +16,7 @@ import 'emby-checkbox'; function authenticateUserByName(page, apiClient, username, password) { loading.show(); apiClient.authenticateUserByName(username, password).then(function (result) { - var user = result.User; + const user = result.User; loading.hide(); onLoginSuccessful(user.Id, result.AccessToken, apiClient); diff --git a/src/elements/emby-progressring/emby-progressring.js b/src/elements/emby-progressring/emby-progressring.js index 929b80a573..63b9f73f10 100644 --- a/src/elements/emby-progressring/emby-progressring.js +++ b/src/elements/emby-progressring/emby-progressring.js @@ -14,14 +14,14 @@ import 'webcomponents'; if (window.MutationObserver) { // create an observer instance - var observer = new MutationObserver(function (mutations) { + const observer = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { instance.setProgress(parseFloat(instance.getAttribute('data-progress') || '0')); }); }); // configuration of the observer: - var config = { attributes: true, childList: false, characterData: false }; + const config = { attributes: true, childList: false, characterData: false }; // pass in the target node, as well as the observer options observer.observe(instance, config); diff --git a/src/elements/emby-slider/emby-slider.js b/src/elements/emby-slider/emby-slider.js index 40d2e69bbb..555394af0d 100644 --- a/src/elements/emby-slider/emby-slider.js +++ b/src/elements/emby-slider/emby-slider.js @@ -54,7 +54,7 @@ import 'emby-input'; // Snap to step if (range.step !== 'any') { - var step = range.step || 1; + const step = range.step || 1; value = Math.round(value / step) * step; } diff --git a/src/legacy/focusPreventScroll.js b/src/legacy/focusPreventScroll.js index 93f53dca29..8f912207b5 100644 --- a/src/legacy/focusPreventScroll.js +++ b/src/legacy/focusPreventScroll.js @@ -2,16 +2,16 @@ if (HTMLElement.prototype.nativeFocus === undefined) { (function () { - var supportsPreventScrollOption = false; + let supportsPreventScrollOption = false; try { - var focusElem = document.createElement('div'); + const focusElem = document.createElement('div'); focusElem.addEventListener('focus', function(event) { event.preventDefault(); event.stopPropagation(); }, true); - var opts = Object.defineProperty({}, 'preventScroll', { + const opts = Object.defineProperty({}, 'preventScroll', { // eslint-disable-next-line getter-return get: function () { supportsPreventScrollOption = true; @@ -27,8 +27,8 @@ if (HTMLElement.prototype.nativeFocus === undefined) { HTMLElement.prototype.nativeFocus = HTMLElement.prototype.focus; HTMLElement.prototype.focus = function(options) { - var scrollX = window.scrollX; - var scrollY = window.scrollY; + const scrollX = window.scrollX; + const scrollY = window.scrollY; this.nativeFocus(); diff --git a/src/libraries/navdrawer/navdrawer.js b/src/libraries/navdrawer/navdrawer.js index 965b68aee4..ab50ec5831 100644 --- a/src/libraries/navdrawer/navdrawer.js +++ b/src/libraries/navdrawer/navdrawer.js @@ -14,26 +14,26 @@ export default function (options) { function onMenuTouchStart(e) { options.target.classList.remove('transition'); - var touches = getTouches(e); - var touch = touches[0] || {}; + const touches = getTouches(e); + const touch = touches[0] || {}; menuTouchStartX = touch.clientX; menuTouchStartY = touch.clientY; menuTouchStartTime = new Date().getTime(); } function setVelocity(deltaX) { - var time = new Date().getTime() - (menuTouchStartTime || 0); + const time = new Date().getTime() - (menuTouchStartTime || 0); velocity = Math.abs(deltaX) / time; } function onMenuTouchMove(e) { - var isOpen = self.visible; - var touches = getTouches(e); - var touch = touches[0] || {}; - var endX = touch.clientX || 0; - var endY = touch.clientY || 0; - var deltaX = endX - (menuTouchStartX || 0); - var deltaY = endY - (menuTouchStartY || 0); + const isOpen = self.visible; + const touches = getTouches(e); + const touch = touches[0] || {}; + const endX = touch.clientX || 0; + const endY = touch.clientY || 0; + const deltaX = endX - (menuTouchStartX || 0); + const deltaY = endY - (menuTouchStartY || 0); setVelocity(deltaX); if (isOpen && dragMode !== 1 && deltaX > 0) { @@ -58,12 +58,12 @@ export default function (options) { options.target.classList.add('transition'); scrollContainer.removeEventListener('scroll', disableEvent); dragMode = 0; - var touches = getTouches(e); - var touch = touches[0] || {}; - var endX = touch.clientX || 0; - var endY = touch.clientY || 0; - var deltaX = endX - (menuTouchStartX || 0); - var deltaY = endY - (menuTouchStartY || 0); + const touches = getTouches(e); + const touch = touches[0] || {}; + const endX = touch.clientX || 0; + const endY = touch.clientY || 0; + const deltaX = endX - (menuTouchStartX || 0); + const deltaY = endY - (menuTouchStartY || 0); currentPos = deltaX; self.checkMenuState(deltaX, deltaY); } @@ -105,20 +105,20 @@ export default function (options) { } function onBackgroundTouchStart(e) { - var touches = getTouches(e); - var touch = touches[0] || {}; + const touches = getTouches(e); + const touch = touches[0] || {}; backgroundTouchStartX = touch.clientX; backgroundTouchStartTime = new Date().getTime(); } function onBackgroundTouchMove(e) { - var touches = getTouches(e); - var touch = touches[0] || {}; - var endX = touch.clientX || 0; + const touches = getTouches(e); + const touch = touches[0] || {}; + const endX = touch.clientX || 0; if (endX <= options.width && self.isVisible) { countStart++; - var deltaX = endX - (backgroundTouchStartX || 0); + const deltaX = endX - (backgroundTouchStartX || 0); if (countStart == 1) { startPoint = deltaX; @@ -127,7 +127,7 @@ export default function (options) { dragMode = 1; newPos = deltaX - startPoint + options.width; self.changeMenuPos(); - var time = new Date().getTime() - (backgroundTouchStartTime || 0); + const time = new Date().getTime() - (backgroundTouchStartTime || 0); velocity = Math.abs(deltaX) / time; } } @@ -137,25 +137,25 @@ export default function (options) { } function onBackgroundTouchEnd(e) { - var touches = getTouches(e); - var touch = touches[0] || {}; - var endX = touch.clientX || 0; - var deltaX = endX - (backgroundTouchStartX || 0); + const touches = getTouches(e); + const touch = touches[0] || {}; + const endX = touch.clientX || 0; + const deltaX = endX - (backgroundTouchStartX || 0); self.checkMenuState(deltaX); countStart = 0; } function onMaskTransitionEnd() { - var classList = mask.classList; + const classList = mask.classList; if (!classList.contains('backdrop')) { classList.add('hide'); } } - var self; - var defaults; - var mask; + let self; + let defaults; + let mask; var newPos = 0; var currentPos = 0; var startPoint = 0; @@ -166,7 +166,7 @@ export default function (options) { var scrollContainer = options.target.querySelector('.mainDrawer-scrollContainer'); scrollContainer.classList.add('scrollY'); - var TouchMenuLA = function () { + const TouchMenuLA = function () { self = this; defaults = { width: 260, @@ -193,9 +193,9 @@ export default function (options) { } }; - var menuTouchStartX; - var menuTouchStartY; - var menuTouchStartTime; + let menuTouchStartX; + let menuTouchStartY; + let menuTouchStartTime; var edgeContainer = document.querySelector('.mainDrawerHandle'); var isPeeking = false; @@ -261,8 +261,8 @@ export default function (options) { } }; - var backgroundTouchStartX; - var backgroundTouchStartTime; + let backgroundTouchStartX; + let backgroundTouchStartTime; TouchMenuLA.prototype.showMask = function () { mask.classList.remove('hide'); @@ -280,7 +280,7 @@ export default function (options) { } }; - var _edgeSwipeEnabled; + let _edgeSwipeEnabled; TouchMenuLA.prototype.setEdgeSwipeEnabled = function (enabled) { if (!options.disableEdgeSwipe) { diff --git a/src/libraries/scroller.js b/src/libraries/scroller.js index dbb3de16e3..de6469c743 100644 --- a/src/libraries/scroller.js +++ b/src/libraries/scroller.js @@ -56,14 +56,14 @@ function within(number, min, max) { } // Other global values -var dragMouseEvents = ['mousemove', 'mouseup']; -var dragTouchEvents = ['touchmove', 'touchend']; -var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel'); -var interactiveElements = ['INPUT', 'SELECT', 'TEXTAREA']; +const dragMouseEvents = ['mousemove', 'mouseup']; +const dragTouchEvents = ['touchmove', 'touchend']; +const wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel'); +const interactiveElements = ['INPUT', 'SELECT', 'TEXTAREA']; -var scrollerFactory = function (frame, options) { +const scrollerFactory = function (frame, options) { // Extend options - var o = Object.assign({}, { + const o = Object.assign({}, { slidee: null, // Selector, DOM element, or jQuery object with DOM element representing SLIDEE. horizontal: false, // Switch to horizontal mode. @@ -83,7 +83,7 @@ var scrollerFactory = function (frame, options) { }, options); - var isSmoothScrollSupported = 'scrollBehavior' in document.documentElement.style; + const isSmoothScrollSupported = 'scrollBehavior' in document.documentElement.style; // native scroll is a must with touch input // also use native scroll when scrolling vertically in desktop mode - excluding horizontal because the mouse wheel support is choppy at the moment @@ -106,11 +106,11 @@ var scrollerFactory = function (frame, options) { } // Private variables - var self = this; + const self = this; self.options = o; // Frame - var slideeElement = o.slidee ? o.slidee : sibling(frame.firstChild)[0]; + const slideeElement = o.slidee ? o.slidee : sibling(frame.firstChild)[0]; self._pos = { start: 0, center: 0, @@ -119,15 +119,15 @@ var scrollerFactory = function (frame, options) { dest: 0 }; - var transform = !options.enableNativeScroll; + const transform = !options.enableNativeScroll; // Miscellaneous - var scrollSource = frame; - var dragSourceElement = o.dragSource ? o.dragSource : frame; - var dragging = { + const scrollSource = frame; + const dragSourceElement = o.dragSource ? o.dragSource : frame; + const dragging = { released: 1 }; - var scrolling = { + const scrolling = { last: 0, delta: 0, resetTime: 200 @@ -139,10 +139,10 @@ var scrollerFactory = function (frame, options) { self.options = o; self.dragging = dragging; - var nativeScrollElement = frame; + const nativeScrollElement = frame; function sibling(n, elem) { - var matched = []; + const matched = []; for (; n; n = n.nextSibling) { if (n.nodeType === 1 && n !== elem) { @@ -152,10 +152,10 @@ var scrollerFactory = function (frame, options) { return matched; } - var requiresReflow = true; + let requiresReflow = true; - var frameSize = 0; - var slideeSize = 0; + let frameSize = 0; + let slideeSize = 0; function ensureSizeInfo() { if (requiresReflow) { requiresReflow = false; @@ -185,13 +185,13 @@ var scrollerFactory = function (frame, options) { ensureSizeInfo(); // Fix possible overflowing - var pos = self._pos; + const pos = self._pos; self.slideTo(within(pos.dest, pos.start, pos.end)); } } function initFrameResizeObserver() { - var observerOptions = {}; + const observerOptions = {}; self.frameResizeObserver = new ResizeObserver(onResize, observerOptions); @@ -242,7 +242,7 @@ var scrollerFactory = function (frame, options) { } } - var lastAnimate; + let lastAnimate; /** * Animate to a position. @@ -254,7 +254,7 @@ var scrollerFactory = function (frame, options) { */ self.slideTo = function (newPos, immediate, fullItemPos) { ensureSizeInfo(); - var pos = self._pos; + const pos = self._pos; if (layoutManager.tv) { newPos = within(newPos, pos.start); @@ -268,10 +268,10 @@ var scrollerFactory = function (frame, options) { } // Update the animation object - var from = pos.cur; + const from = pos.cur; immediate = immediate || dragging.init || !o.speed; - var now = new Date().getTime(); + const now = new Date().getTime(); if (o.autoImmediate) { if (!immediate && (now - (lastAnimate || 0)) <= 50) { @@ -291,7 +291,7 @@ var scrollerFactory = function (frame, options) { }; function setStyleProperty(elem, name, value, speed, resetTransition) { - var style = elem.style; + const style = elem.style; if (resetTransition || browser.edge) { style.transition = 'none'; @@ -312,7 +312,7 @@ var scrollerFactory = function (frame, options) { } function renderAnimateWithTransform(fromPosition, toPosition, immediate) { - var speed = o.speed; + let speed = o.speed; if (immediate) { speed = o.immediateSpeed || 50; @@ -346,18 +346,18 @@ var scrollerFactory = function (frame, options) { * @return {Object} */ self.getPos = function (item) { - var scrollElement = transform ? slideeElement : nativeScrollElement; - var slideeOffset = getBoundingClientRect(scrollElement); - var itemOffset = getBoundingClientRect(item); + const scrollElement = transform ? slideeElement : nativeScrollElement; + const slideeOffset = getBoundingClientRect(scrollElement); + const itemOffset = getBoundingClientRect(item); - var offset = o.horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top; + let offset = o.horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top; - var size = o.horizontal ? itemOffset.width : itemOffset.height; + let size = o.horizontal ? itemOffset.width : itemOffset.height; if (!size && size !== 0) { size = item[o.horizontal ? 'offsetWidth' : 'offsetHeight']; } - var centerOffset = o.centerOffset || 0; + let centerOffset = o.centerOffset || 0; if (!transform) { centerOffset = 0; @@ -370,11 +370,11 @@ var scrollerFactory = function (frame, options) { ensureSizeInfo(); - var currentStart = self._pos.cur; - var currentEnd = currentStart + frameSize; + const currentStart = self._pos.cur; + const currentEnd = currentStart + frameSize; console.debug('offset:' + offset + ' currentStart:' + currentStart + ' currentEnd:' + currentEnd); - var isVisible = offset >= currentStart && (offset + size) <= currentEnd; + const isVisible = offset >= currentStart && (offset + size) <= currentEnd; return { start: offset, @@ -388,12 +388,12 @@ var scrollerFactory = function (frame, options) { self.getCenterPosition = function (item) { ensureSizeInfo(); - var pos = self.getPos(item); + const pos = self.getPos(item); return within(pos.center, pos.start, pos.end); }; function dragInitSlidee(event) { - var isTouch = event.type === 'touchstart'; + const isTouch = event.type === 'touchstart'; // Ignore when already in progress, or interactive element in non-touch navivagion if (dragging.init || !isTouch && isInteractive(event.target)) { @@ -417,7 +417,7 @@ var scrollerFactory = function (frame, options) { dragging.init = 0; dragging.source = event.target; dragging.touch = isTouch; - var pointer = isTouch ? event.touches[0] : event; + const pointer = isTouch ? event.touches[0] : event; dragging.initX = pointer.pageX; dragging.initY = pointer.pageY; dragging.initPos = self._pos.cur; @@ -455,7 +455,7 @@ var scrollerFactory = function (frame, options) { */ function dragHandler(event) { dragging.released = event.type === 'mouseup' || event.type === 'touchend'; - var pointer = dragging.touch ? event[dragging.released ? 'changedTouches' : 'touches'][0] : event; + const pointer = dragging.touch ? event[dragging.released ? 'changedTouches' : 'touches'][0] : event; dragging.pathX = pointer.pageX - dragging.initX; dragging.pathY = pointer.pageY - dragging.initY; dragging.path = Math.sqrt(Math.pow(dragging.pathX, 2) + Math.pow(dragging.pathY, 2)); @@ -570,12 +570,12 @@ var scrollerFactory = function (frame, options) { */ function scrollHandler(event) { ensureSizeInfo(); - var pos = self._pos; + const pos = self._pos; // Ignore if there is no scrolling to be done if (!o.scrollBy || pos.start === pos.end) { return; } - var delta = normalizeWheelDelta(event); + let delta = normalizeWheelDelta(event); if (transform) { // Trap scrolling only when necessary and/or requested @@ -635,13 +635,13 @@ var scrollerFactory = function (frame, options) { return self; }; - var contentRect = {}; + let contentRect = {}; function onResize(entries) { - var entry = entries[0]; + const entry = entries[0]; if (entry) { - var newRect = entry.contentRect; + const newRect = entry.contentRect; // handle element being hidden if (newRect.width === 0 || newRect.height === 0) { @@ -666,7 +666,7 @@ var scrollerFactory = function (frame, options) { function onFrameClick(e) { if (e.which === 1) { - var focusableParent = focusManager.focusableParent(e.target); + const focusableParent = focusManager.focusableParent(e.target); if (focusableParent && focusableParent !== document.activeElement) { focusableParent.focus(); } @@ -838,7 +838,7 @@ scrollerFactory.prototype.to = function (location, item, immediate) { if (item === undefined) { this.slideTo(this._pos[location], immediate); } else { - var itemPos = this.getPos(item); + const itemPos = this.getPos(item); if (itemPos) { this.slideTo(itemPos[location], immediate, itemPos); @@ -883,7 +883,7 @@ scrollerFactory.prototype.toCenter = function (item, immediate) { }; scrollerFactory.create = function (frame, options) { - var instance = new scrollerFactory(frame, options); + const instance = new scrollerFactory(frame, options); return Promise.resolve(instance); }; diff --git a/src/plugins/comicsPlayer/plugin.js b/src/plugins/comicsPlayer/plugin.js index 2928231391..8cdf3db5e6 100644 --- a/src/plugins/comicsPlayer/plugin.js +++ b/src/plugins/comicsPlayer/plugin.js @@ -103,7 +103,7 @@ export class ComicsPlayer { const downloadUrl = apiClient.getItemDownloadUrl(item.Id); const archiveSource = new ArchiveSource(downloadUrl); - var instance = this; + const instance = this; import('swiper').then(({default: Swiper}) => { archiveSource.load().then(() => { loading.hide(); diff --git a/src/plugins/photoPlayer/plugin.js b/src/plugins/photoPlayer/plugin.js index a7a4ab3760..c40477778e 100644 --- a/src/plugins/photoPlayer/plugin.js +++ b/src/plugins/photoPlayer/plugin.js @@ -10,11 +10,11 @@ export default class PhotoPlayer { play(options) { return new Promise(function (resolve, reject) { import('slideshow').then(({default: slideshow}) => { - var index = options.startIndex || 0; + const index = options.startIndex || 0; - var apiClient = window.connectionManager.currentApiClient(); + const apiClient = window.connectionManager.currentApiClient(); apiClient.getCurrentUser().then(function(result) { - var newSlideShow = new slideshow({ + const newSlideShow = new slideshow({ showTitle: false, cover: false, items: options.items, diff --git a/src/scripts/autocast.js b/src/scripts/autocast.js index 84e07b32cd..8d90451268 100644 --- a/src/scripts/autocast.js +++ b/src/scripts/autocast.js @@ -32,7 +32,7 @@ function onOpen() { const playerId = localStorage.getItem('autocastPlayerId'); playbackManager.getTargets().then(function (targets) { - for (var i = 0; i < targets.length; i++) { + for (let i = 0; i < targets.length; i++) { if (targets[i].id == playerId) { playbackManager.trySetActivePlayer(targets[i].playerName, targets[i]); break; diff --git a/src/scripts/browserDeviceProfile.js b/src/scripts/browserDeviceProfile.js index 9e4a410cea..03663b2884 100644 --- a/src/scripts/browserDeviceProfile.js +++ b/src/scripts/browserDeviceProfile.js @@ -23,7 +23,7 @@ define(['browser'], function (browser) { videoTestElement.canPlayType('video/mp4; codecs="hev1.1.0.L120"').replace(/no/, '')); } - var _supportsTextTracks; + let _supportsTextTracks; function supportsTextTracks() { if (browser.tizen) { return true; @@ -37,7 +37,7 @@ define(['browser'], function (browser) { return _supportsTextTracks; } - var _canPlayHls; + let _canPlayHls; function canPlayHls() { if (_canPlayHls == null) { _canPlayHls = canPlayNativeHls() || canPlayHlsWithMSE(); @@ -51,7 +51,7 @@ define(['browser'], function (browser) { return true; } - var media = document.createElement('video'); + const media = document.createElement('video'); if (media.canPlayType('application/x-mpegURL').replace(/no/, '') || media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, '')) { return true; @@ -107,7 +107,7 @@ define(['browser'], function (browser) { } function canPlayAudioFormat(format) { - var typeString; + let typeString; if (format === 'flac') { if (browser.tizen || browser.web0s || browser.edgeUwp) { @@ -192,9 +192,9 @@ define(['browser'], function (browser) { } function getDirectPlayProfileForVideoContainer(container, videoAudioCodecs, videoTestElement, options) { - var supported = false; - var profileContainer = container; - var videoCodecs = []; + let supported = false; + let profileContainer = container; + const videoCodecs = []; switch (container) { case 'asf': @@ -277,10 +277,10 @@ define(['browser'], function (browser) { } function getGlobalMaxVideoBitrate() { - var isTizenFhd = false; + let isTizenFhd = false; if (browser.tizen) { try { - var isTizenUhd = webapis.productinfo.isUdPanelSupported(); + const isTizenUhd = webapis.productinfo.isUdPanelSupported(); isTizenFhd = !isTizenUhd; console.debug('isTizenFhd = ' + isTizenFhd); } catch (error) { @@ -297,19 +297,19 @@ define(['browser'], function (browser) { return function (options) { options = options || {}; - var physicalAudioChannels = options.audioChannels || (browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2); + const physicalAudioChannels = options.audioChannels || (browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2); - var bitrateSetting = getMaxBitrate(); + const bitrateSetting = getMaxBitrate(); - var videoTestElement = document.createElement('video'); + const videoTestElement = document.createElement('video'); - var canPlayVp8 = videoTestElement.canPlayType('video/webm; codecs="vp8"').replace(/no/, ''); - var canPlayVp9 = videoTestElement.canPlayType('video/webm; codecs="vp9"').replace(/no/, ''); - var webmAudioCodecs = ['vorbis']; + const canPlayVp8 = videoTestElement.canPlayType('video/webm; codecs="vp8"').replace(/no/, ''); + const canPlayVp9 = videoTestElement.canPlayType('video/webm; codecs="vp9"').replace(/no/, ''); + const webmAudioCodecs = ['vorbis']; - var canPlayMkv = testCanPlayMkv(videoTestElement); + const canPlayMkv = testCanPlayMkv(videoTestElement); - var profile = {}; + const profile = {}; profile.MaxStreamingBitrate = bitrateSetting; profile.MaxStaticBitrate = 100000000; @@ -317,18 +317,18 @@ define(['browser'], function (browser) { profile.DirectPlayProfiles = []; - var videoAudioCodecs = []; - var hlsVideoAudioCodecs = []; + let videoAudioCodecs = []; + let hlsVideoAudioCodecs = []; - var supportsMp3VideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"').replace(/no/, '') + const supportsMp3VideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"').replace(/no/, '') || videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"').replace(/no/, '') || videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp3"').replace(/no/, ''); // Not sure how to test for this - var supportsMp2VideoAudio = browser.edgeUwp || browser.tizen || browser.web0s; + const supportsMp2VideoAudio = browser.edgeUwp || browser.tizen || browser.web0s; /* eslint-disable compat/compat */ - var maxVideoWidth = browser.xboxOne ? + let maxVideoWidth = browser.xboxOne ? (window.screen ? window.screen.width : null) : null; @@ -337,7 +337,7 @@ define(['browser'], function (browser) { maxVideoWidth = options.maxVideoWidth; } - var canPlayAacVideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"').replace(/no/, ''); + const canPlayAacVideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"').replace(/no/, ''); // Only put mp3 first if mkv support is there // Otherwise with HLS and mp3 audio we're seeing some browsers @@ -345,7 +345,7 @@ define(['browser'], function (browser) { if (supportsAc3(videoTestElement)) { videoAudioCodecs.push('ac3'); - var eAc3 = supportsEac3(videoTestElement); + const eAc3 = supportsEac3(videoTestElement); if (eAc3) { videoAudioCodecs.push('eac3'); } @@ -394,7 +394,7 @@ define(['browser'], function (browser) { videoAudioCodecs.push('mp2'); } - var supportsDts = browser.tizen || browser.web0s || options.supportsDts || videoTestElement.canPlayType('video/mp4; codecs="dts-"').replace(/no/, '') || videoTestElement.canPlayType('video/mp4; codecs="dts+"').replace(/no/, ''); + let supportsDts = browser.tizen || browser.web0s || options.supportsDts || videoTestElement.canPlayType('video/mp4; codecs="dts-"').replace(/no/, '') || videoTestElement.canPlayType('video/mp4; codecs="dts+"').replace(/no/, ''); // DTS audio not supported in 2018 models (Tizen 4.0) if (browser.tizenVersion >= 4) { @@ -437,9 +437,9 @@ define(['browser'], function (browser) { return (options.disableHlsVideoAudioCodecs || []).indexOf(c) === -1; }); - var mp4VideoCodecs = []; - var webmVideoCodecs = []; - var hlsVideoCodecs = []; + const mp4VideoCodecs = []; + const webmVideoCodecs = []; + const hlsVideoCodecs = []; if (canPlayH264(videoTestElement)) { mp4VideoCodecs.push('h264'); @@ -555,7 +555,7 @@ define(['browser'], function (browser) { profile.TranscodingProfiles = []; - var hlsBreakOnNonKeyFrames = browser.iOS || browser.osx || browser.edge || !canPlayNativeHls() ? true : false; + const hlsBreakOnNonKeyFrames = browser.iOS || browser.osx || browser.edge || !canPlayNativeHls() ? true : false; if (canPlayHls() && browser.enableHlsAudio !== false) { profile.TranscodingProfiles.push({ @@ -661,9 +661,9 @@ define(['browser'], function (browser) { profile.CodecProfiles = []; - var supportsSecondaryAudio = browser.tizen || videoTestElement.audioTracks; + const supportsSecondaryAudio = browser.tizen || videoTestElement.audioTracks; - var aacCodecProfileConditions = []; + const aacCodecProfileConditions = []; // Handle he-aac not supported if (!videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.5"').replace(/no/, '')) { @@ -706,8 +706,8 @@ define(['browser'], function (browser) { }); } - var maxH264Level = 42; - var h264Profiles = 'high|main|baseline|constrained baseline'; + let maxH264Level = 42; + let h264Profiles = 'high|main|baseline|constrained baseline'; if (browser.tizen || browser.web0s || videoTestElement.canPlayType('video/mp4; codecs="avc1.640833"').replace(/no/, '')) { @@ -766,9 +766,9 @@ define(['browser'], function (browser) { }); } - var globalMaxVideoBitrate = (getGlobalMaxVideoBitrate() || '').toString(); + const globalMaxVideoBitrate = (getGlobalMaxVideoBitrate() || '').toString(); - var h264MaxVideoBitrate = globalMaxVideoBitrate; + const h264MaxVideoBitrate = globalMaxVideoBitrate; if (h264MaxVideoBitrate) { h264CodecProfileConditions.push({ @@ -806,7 +806,7 @@ define(['browser'], function (browser) { Conditions: h264CodecProfileConditions }); - var globalVideoConditions = []; + const globalVideoConditions = []; if (globalMaxVideoBitrate) { globalVideoConditions.push({ diff --git a/src/scripts/editorsidebar.js b/src/scripts/editorsidebar.js index b6a45ccf2c..7e8abbe2f9 100644 --- a/src/scripts/editorsidebar.js +++ b/src/scripts/editorsidebar.js @@ -5,8 +5,8 @@ import 'material-icons'; /* eslint-disable indent */ function getNode(item, folderState, selected) { - var htmlName = getNodeInnerHtml(item); - var node = { + const htmlName = getNodeInnerHtml(item); + const node = { id: item.Id, text: htmlName, state: { @@ -37,14 +37,14 @@ import 'material-icons'; } function getNodeInnerHtml(item) { - var name = item.Name; + let name = item.Name; if (item.Number) { name = item.Number + ' - ' + name; } if (item.IndexNumber != null && item.Type != 'Season') { name = item.IndexNumber + ' - ' + name; } - var htmlName = "
    "; + let htmlName = "
    "; if (item.IsFolder) { htmlName += ''; } else if (item.MediaType === 'Video') { @@ -70,7 +70,7 @@ import 'material-icons'; ApiClient.getLiveTvChannels({ limit: 0 }).then(function (result) { - var nodes = []; + const nodes = []; nodes.push({ id: 'MediaFolders', text: globalize.translate('HeaderMediaFolders'), @@ -110,8 +110,8 @@ import 'material-icons'; ServiceName: service, AddCurrentProgram: false }).then(function (result) { - var nodes = result.Items.map(function (i) { - var state = openItems.indexOf(i.Id) == -1 ? 'closed' : 'open'; + const nodes = result.Items.map(function (i) { + const state = openItems.indexOf(i.Id) == -1 ? 'closed' : 'open'; return getNode(i, state, false); }); callback(nodes); @@ -120,12 +120,12 @@ import 'material-icons'; function loadMediaFolders(page, scope, openItems, callback) { ApiClient.getJSON(ApiClient.getUrl('Library/MediaFolders')).then(function (result) { - var nodes = result.Items.map(function (n) { - var state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open'; + const nodes = result.Items.map(function (n) { + const state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open'; return getNode(n, state, false); }); callback.call(scope, nodes); - for (var i = 0, length = nodes.length; i < length; i++) { + for (let i = 0, length = nodes.length; i < length; i++) { if (nodes[i].state.opened) { nodesToLoad.push(nodes[i].id); } @@ -134,7 +134,7 @@ import 'material-icons'; } function loadNode(page, scope, node, openItems, selectedId, currentUser, callback) { - var id = node.id; + const id = node.id; if (id == '#') { loadChildrenOfRootNode(page, scope, callback); return; @@ -147,7 +147,7 @@ import 'material-icons'; loadMediaFolders(page, scope, openItems, callback); return; } - var query = { + const query = { ParentId: id, Fields: 'Settings', IsVirtualUnaired: false, @@ -156,17 +156,17 @@ import 'material-icons'; EnableImages: false, EnableUserData: false }; - var itemtype = node.li_attr.itemtype; + const itemtype = node.li_attr.itemtype; if (itemtype != 'Season' && itemtype != 'Series') { query.SortBy = 'SortName'; } ApiClient.getItems(Dashboard.getCurrentUserId(), query).then(function (result) { - var nodes = result.Items.map(function (n) { - var state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open'; + const nodes = result.Items.map(function (n) { + const state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open'; return getNode(n, state, n.Id == selectedId); }); callback.call(scope, nodes); - for (var i = 0, length = nodes.length; i < length; i++) { + for (let i = 0, length = nodes.length; i < length; i++) { if (nodes[i].state.opened) { nodesToLoad.push(nodes[i].id); } @@ -175,7 +175,7 @@ import 'material-icons'; } function scrollToNode(id) { - var elem = $('#' + id)[0]; + const elem = $('#' + id)[0]; if (elem) { elem.scrollIntoView(); } @@ -188,8 +188,8 @@ import 'material-icons'; } function onNodeSelect(event, data) { - var node = data.node; - var eventData = { + const node = data.node; + const eventData = { id: node.id, itemType: node.li_attr.itemtype, serverItemType: node.li_attr.serveritemtype, @@ -210,8 +210,8 @@ import 'material-icons'; } function onNodeOpen(event, data) { - var page = $(this).parents('.page')[0]; - var node = data.node; + const page = $(this).parents('.page')[0]; + const node = data.node; if (node.children) { loadNodesToLoad(page, node); } @@ -222,8 +222,8 @@ import 'material-icons'; } function onNodeLoad(event, data) { - var page = $(this).parents('.page')[0]; - var node = data.node; + const page = $(this).parents('.page')[0]; + const node = data.node; if (node.children) { loadNodesToLoad(page, node); } @@ -252,8 +252,8 @@ import 'material-icons'; } function loadNodesToLoad(page, node) { - var children = node.children; - for (var i = 0, length = children.length; i < length; i++) { + const children = node.children; + for (let i = 0, length = children.length; i < length; i++) { var child = children[i]; if (nodesToLoad.indexOf(child) != -1) { nodesToLoad = nodesToLoad.filter(function (n) { @@ -273,15 +273,15 @@ import 'material-icons'; } function updateEditorNode(page, item) { - var elem = $('#' + item.Id + '>a', page)[0]; + const elem = $('#' + item.Id + '>a', page)[0]; if (elem == null) { return; } $('.editorNode', elem).remove(); $(elem).append(getNodeInnerHtml(item)); if (item.IsFolder) { - var tree = jQuery.jstree._reference('.libraryTree'); - var currentNode = tree._get_node(null, false); + const tree = jQuery.jstree._reference('.libraryTree'); + const currentNode = tree._get_node(null, false); tree.refresh(currentNode); } } @@ -294,23 +294,23 @@ import 'material-icons'; if (itemId) { return itemId; } - var url = window.location.hash || window.location.href; + const url = window.location.hash || window.location.href; return getParameterByName('id', url); } var nodesToLoad = []; - var selectedNodeId; + let selectedNodeId; $(document).on('itemsaved', '.metadataEditorPage', function (e, item) { updateEditorNode(this, item); }).on('pagebeforeshow', '.metadataEditorPage', function () { /* eslint-disable-next-line @babel/no-unused-expressions */ import('css!assets/css/metadataeditor.css'); }).on('pagebeforeshow', '.metadataEditorPage', function () { - var page = this; + const page = this; Dashboard.getCurrentUser().then(function (user) { - var id = getCurrentItemId(); + const id = getCurrentItemId(); if (id) { ApiClient.getAncestorItems(id, user.Id).then(function (ancestors) { - var ids = ancestors.map(function (i) { + const ids = ancestors.map(function (i) { return i.Id; }); initializeTree(page, user, ids, id); @@ -320,13 +320,13 @@ import 'material-icons'; } }); }).on('pagebeforehide', '.metadataEditorPage', function () { - var page = this; + const page = this; $('.libraryTree', page).off('select_node.jstree', onNodeSelect).off('open_node.jstree', onNodeOpen).off('load_node.jstree', onNodeLoad); }); - var itemId; + let itemId; window.MetadataEditor = { getItemPromise: function () { - var currentItemId = getCurrentItemId(); + const currentItemId = getCurrentItemId(); if (currentItemId) { return ApiClient.getItem(Dashboard.getCurrentUserId(), currentItemId); } diff --git a/src/scripts/gamepadtokey.js b/src/scripts/gamepadtokey.js index b6f25f1eea..8451326974 100644 --- a/src/scripts/gamepadtokey.js +++ b/src/scripts/gamepadtokey.js @@ -22,47 +22,47 @@ import appHost from 'apphost'; -var _GAMEPAD_A_BUTTON_INDEX = 0; -var _GAMEPAD_B_BUTTON_INDEX = 1; -var _GAMEPAD_DPAD_UP_BUTTON_INDEX = 12; -var _GAMEPAD_DPAD_DOWN_BUTTON_INDEX = 13; -var _GAMEPAD_DPAD_LEFT_BUTTON_INDEX = 14; -var _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX = 15; -var _GAMEPAD_A_KEY = 'GamepadA'; -var _GAMEPAD_B_KEY = 'GamepadB'; -var _GAMEPAD_DPAD_UP_KEY = 'GamepadDPadUp'; -var _GAMEPAD_DPAD_DOWN_KEY = 'GamepadDPadDown'; -var _GAMEPAD_DPAD_LEFT_KEY = 'GamepadDPadLeft'; -var _GAMEPAD_DPAD_RIGHT_KEY = 'GamepadDPadRight'; -var _GAMEPAD_LEFT_THUMBSTICK_UP_KEY = 'GamepadLeftThumbStickUp'; -var _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEY = 'GamepadLeftThumbStickDown'; -var _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEY = 'GamepadLeftThumbStickLeft'; -var _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEY = 'GamepadLeftThumbStickRight'; -var _GAMEPAD_A_KEYCODE = 0; -var _GAMEPAD_B_KEYCODE = 27; -var _GAMEPAD_DPAD_UP_KEYCODE = 38; -var _GAMEPAD_DPAD_DOWN_KEYCODE = 40; -var _GAMEPAD_DPAD_LEFT_KEYCODE = 37; -var _GAMEPAD_DPAD_RIGHT_KEYCODE = 39; -var _GAMEPAD_LEFT_THUMBSTICK_UP_KEYCODE = 38; -var _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEYCODE = 40; -var _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEYCODE = 37; -var _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEYCODE = 39; -var _THUMB_STICK_THRESHOLD = 0.75; +const _GAMEPAD_A_BUTTON_INDEX = 0; +const _GAMEPAD_B_BUTTON_INDEX = 1; +const _GAMEPAD_DPAD_UP_BUTTON_INDEX = 12; +const _GAMEPAD_DPAD_DOWN_BUTTON_INDEX = 13; +const _GAMEPAD_DPAD_LEFT_BUTTON_INDEX = 14; +const _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX = 15; +const _GAMEPAD_A_KEY = 'GamepadA'; +const _GAMEPAD_B_KEY = 'GamepadB'; +const _GAMEPAD_DPAD_UP_KEY = 'GamepadDPadUp'; +const _GAMEPAD_DPAD_DOWN_KEY = 'GamepadDPadDown'; +const _GAMEPAD_DPAD_LEFT_KEY = 'GamepadDPadLeft'; +const _GAMEPAD_DPAD_RIGHT_KEY = 'GamepadDPadRight'; +const _GAMEPAD_LEFT_THUMBSTICK_UP_KEY = 'GamepadLeftThumbStickUp'; +const _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEY = 'GamepadLeftThumbStickDown'; +const _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEY = 'GamepadLeftThumbStickLeft'; +const _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEY = 'GamepadLeftThumbStickRight'; +const _GAMEPAD_A_KEYCODE = 0; +const _GAMEPAD_B_KEYCODE = 27; +const _GAMEPAD_DPAD_UP_KEYCODE = 38; +const _GAMEPAD_DPAD_DOWN_KEYCODE = 40; +const _GAMEPAD_DPAD_LEFT_KEYCODE = 37; +const _GAMEPAD_DPAD_RIGHT_KEYCODE = 39; +const _GAMEPAD_LEFT_THUMBSTICK_UP_KEYCODE = 38; +const _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEYCODE = 40; +const _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEYCODE = 37; +const _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEYCODE = 39; +const _THUMB_STICK_THRESHOLD = 0.75; -var _leftThumbstickUpPressed = false; -var _leftThumbstickDownPressed = false; -var _leftThumbstickLeftPressed = false; -var _leftThumbstickRightPressed = false; -var _dPadUpPressed = false; -var _dPadDownPressed = false; -var _dPadLeftPressed = false; -var _dPadRightPressed = false; -var _gamepadAPressed = false; -var _gamepadBPressed = false; +let _leftThumbstickUpPressed = false; +let _leftThumbstickDownPressed = false; +let _leftThumbstickLeftPressed = false; +let _leftThumbstickRightPressed = false; +let _dPadUpPressed = false; +let _dPadDownPressed = false; +let _dPadLeftPressed = false; +let _dPadRightPressed = false; +let _gamepadAPressed = false; +let _gamepadBPressed = false; // The set of buttons on the gamepad we listen for. -var ProcessedButtons = [ +const ProcessedButtons = [ _GAMEPAD_DPAD_UP_BUTTON_INDEX, _GAMEPAD_DPAD_DOWN_BUTTON_INDEX, _GAMEPAD_DPAD_LEFT_BUTTON_INDEX, @@ -71,7 +71,7 @@ var ProcessedButtons = [ _GAMEPAD_B_BUTTON_INDEX ]; -var _ButtonPressedState = {}; +const _ButtonPressedState = {}; _ButtonPressedState.getgamepadA = function () { return _gamepadAPressed; }; @@ -162,11 +162,11 @@ _ButtonPressedState.setdPadRight = function (newPressedState) { _dPadRightPressed = newPressedState; }; -var times = {}; +const times = {}; function throttle(key) { - var time = times[key] || 0; - var now = new Date().getTime(); + const time = times[key] || 0; + const now = new Date().getTime(); if ((now - time) >= 200) { //times[key] = now; @@ -180,7 +180,7 @@ function resetThrottle(key) { times[key] = new Date().getTime(); } -var isElectron = navigator.userAgent.toLowerCase().indexOf('electron') !== -1; +const isElectron = navigator.userAgent.toLowerCase().indexOf('electron') !== -1; function allowInput() { // This would be nice but always seems to return true with electron if (!isElectron && document.hidden) { /* eslint-disable-line compat/compat */ @@ -199,7 +199,7 @@ function raiseEvent(name, key, keyCode) { return; } - var event = document.createEvent('Event'); + const event = document.createEvent('Event'); event.initEvent(name, true, true); event.key = key; event.keyCode = keyCode; @@ -218,7 +218,7 @@ function raiseKeyEvent(oldPressedState, newPressedState, key, keyCode, enableRep // No-op if oldPressedState === newPressedState if (newPressedState === true) { // button down - var fire = false; + let fire = false; // always fire if this is the initial down press if (oldPressedState === false) { @@ -244,19 +244,19 @@ function raiseKeyEvent(oldPressedState, newPressedState, key, keyCode, enableRep } } -var inputLoopTimer; +let inputLoopTimer; function runInputLoop() { // Get the latest gamepad state. - var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */ + const gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */ for (var i = 0, len = gamepads.length; i < len; i++) { - var gamepad = gamepads[i]; + const gamepad = gamepads[i]; if (!gamepad) { continue; } // Iterate through the axes - var axes = gamepad.axes; - var leftStickX = axes[0]; - var leftStickY = axes[1]; + const axes = gamepad.axes; + const leftStickX = axes[0]; + const leftStickY = axes[1]; if (leftStickX > _THUMB_STICK_THRESHOLD) { // Right _ButtonPressedState.setleftThumbstickRight(true); } else if (leftStickX < -_THUMB_STICK_THRESHOLD) { // Left @@ -272,7 +272,7 @@ function runInputLoop() { _ButtonPressedState.setleftThumbstickDown(false); } // Iterate through the buttons to see if Left thumbstick, DPad, A and B are pressed. - var buttons = gamepad.buttons; + const buttons = gamepad.buttons; for (var j = 0, len = buttons.length; j < len; j++) { if (ProcessedButtons.indexOf(j) !== -1) { if (buttons[j].pressed) { @@ -355,9 +355,9 @@ function stopInputLoop() { } function isGamepadConnected() { - var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */ - for (var i = 0, len = gamepads.length; i < len; i++) { - var gamepad = gamepads[i]; + const gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */ + for (let i = 0, len = gamepads.length; i < len; i++) { + const gamepad = gamepads[i]; if (gamepad && gamepad.connected) { return true; } diff --git a/src/scripts/imagehelper.js b/src/scripts/imagehelper.js index c79f721738..9b356f0350 100644 --- a/src/scripts/imagehelper.js +++ b/src/scripts/imagehelper.js @@ -2,7 +2,7 @@ /* eslint-disable indent */ export function getDeviceIcon(device) { - var baseUrl = 'assets/img/devices/'; + const baseUrl = 'assets/img/devices/'; switch (device.AppName || device.Client) { case 'Samsung Smart TV': return baseUrl + 'samsung.svg'; diff --git a/src/scripts/libraryBrowser.js b/src/scripts/libraryBrowser.js index 151cb7ff57..5c6db19258 100644 --- a/src/scripts/libraryBrowser.js +++ b/src/scripts/libraryBrowser.js @@ -6,7 +6,7 @@ export function getSavedQueryKey(modifier) { } export function loadSavedQueryValues(key, query) { - var values = userSettings.get(key); + let values = userSettings.get(key); if (values) { values = JSON.parse(values); @@ -17,7 +17,7 @@ export function loadSavedQueryValues(key, query) { } export function saveQueryValues(key, query) { - var values = {}; + const values = {}; if (query.SortBy) { values.SortBy = query.SortBy; @@ -39,7 +39,7 @@ export function getSavedView (key) { } export function showLayoutMenu (button, currentLayout, views) { - var dispatchEvent = true; + let dispatchEvent = true; if (!views) { dispatchEvent = false; @@ -47,7 +47,7 @@ export function showLayoutMenu (button, currentLayout, views) { views = views ? views.split(',') : ['List', 'Poster', 'PosterCard', 'Thumb', 'ThumbCard']; } - var menuItems = views.map(function (v) { + const menuItems = views.map(function (v) { return { name: globalize.translate(v), id: v, @@ -79,12 +79,12 @@ export function showLayoutMenu (button, currentLayout, views) { } export function getQueryPagingHtml (options) { - var startIndex = options.startIndex; - var limit = options.limit; - var totalRecordCount = options.totalRecordCount; - var html = ''; - var recordsEnd = Math.min(startIndex + limit, totalRecordCount); - var showControls = limit < totalRecordCount; + const startIndex = options.startIndex; + const limit = options.limit; + const totalRecordCount = options.totalRecordCount; + let html = ''; + const recordsEnd = Math.min(startIndex + limit, totalRecordCount); + const showControls = limit < totalRecordCount; if (html += '
    ', showControls) { html += ''; @@ -124,10 +124,10 @@ export function showSortMenu (options) { import('emby-radio') ]).then(([{default: dialogHelper}]) => { function onSortByChange() { - var newValue = this.value; + const newValue = this.value; if (this.checked) { - var changed = options.query.SortBy != newValue; + const changed = options.query.SortBy != newValue; options.query.SortBy = newValue.replace('_', ','); options.query.StartIndex = 0; @@ -138,10 +138,10 @@ export function showSortMenu (options) { } function onSortOrderChange() { - var newValue = this.value; + const newValue = this.value; if (this.checked) { - var changed = options.query.SortOrder != newValue; + const changed = options.query.SortOrder != newValue; options.query.SortOrder = newValue; options.query.StartIndex = 0; @@ -151,7 +151,7 @@ export function showSortMenu (options) { } } - var dlg = dialogHelper.createDialog({ + const dlg = dialogHelper.createDialog({ removeOnClose: true, modal: false, entryAnimationDuration: 160, @@ -160,18 +160,18 @@ export function showSortMenu (options) { dlg.classList.add('ui-body-a'); dlg.classList.add('background-theme-a'); dlg.classList.add('formDialog'); - var html = ''; + let html = ''; html += '
    '; html += '

    '; html += globalize.translate('HeaderSortBy'); html += '

    '; - var i; - var length; - var isChecked; + let i; + let length; + let isChecked; html += '
    '; for (i = 0, length = options.items.length; i < length; i++) { - var option = options.items[i]; - var radioValue = option.id.replace(',', '_'); + const option = options.items[i]; + const radioValue = option.id.replace(',', '_'); isChecked = (options.query.SortBy || '').replace(',', '_') == radioValue ? ' checked' : ''; html += ''; } @@ -189,13 +189,13 @@ export function showSortMenu (options) { html += '
    '; dlg.innerHTML = html; dialogHelper.open(dlg); - var sortBys = dlg.querySelectorAll('.menuSortBy'); + const sortBys = dlg.querySelectorAll('.menuSortBy'); for (i = 0, length = sortBys.length; i < length; i++) { sortBys[i].addEventListener('change', onSortByChange); } - var sortOrders = dlg.querySelectorAll('.menuSortOrder'); + const sortOrders = dlg.querySelectorAll('.menuSortOrder'); for (i = 0, length = sortOrders.length; i < length; i++) { sortOrders[i].addEventListener('change', onSortOrderChange); diff --git a/src/scripts/multiDownload.js b/src/scripts/multiDownload.js index d1c717af0e..270c474965 100644 --- a/src/scripts/multiDownload.js +++ b/src/scripts/multiDownload.js @@ -1,10 +1,10 @@ import browser from 'browser'; function fallback(urls) { - var i = 0; + let i = 0; (function createIframe() { - var frame = document.createElement('iframe'); + const frame = document.createElement('iframe'); frame.style.display = 'none'; frame.src = urls[i++]; document.documentElement.appendChild(frame); @@ -28,14 +28,14 @@ function fallback(urls) { } function sameDomain(url) { - var a = document.createElement('a'); + const a = document.createElement('a'); a.href = url; return window.location.hostname === a.hostname && window.location.protocol === a.protocol; } function download(url) { - var a = document.createElement('a'); + const a = document.createElement('a'); a.download = ''; a.href = url; // firefox doesn't support `a.click()`... @@ -51,7 +51,7 @@ export default function (urls) { return fallback(urls); } - var delay = 0; + let delay = 0; urls.forEach(function (url) { // the download init has to be sequential for firefox if the urls are not on the same domain diff --git a/src/scripts/playlistedit.js b/src/scripts/playlistedit.js index 636a7ef056..a4b519e045 100644 --- a/src/scripts/playlistedit.js +++ b/src/scripts/playlistedit.js @@ -3,7 +3,7 @@ define(['listView'], function (listView) { function getFetchPlaylistItemsFn(itemId) { return function () { - var query = { + const query = { Fields: 'PrimaryImageAspectRatio,UserData', EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', UserId: ApiClient.getCurrentUserId() @@ -28,7 +28,7 @@ define(['listView'], function (listView) { } function init(page, item) { - var elem = page.querySelector('#childrenContent .itemsContainer'); + const elem = page.querySelector('#childrenContent .itemsContainer'); elem.classList.add('vertical-list'); elem.classList.remove('vertical-wrap'); elem.enableDragReordering(true); diff --git a/src/scripts/routes.js b/src/scripts/routes.js index 8e2440b140..5651102655 100644 --- a/src/scripts/routes.js +++ b/src/scripts/routes.js @@ -17,7 +17,7 @@ import 'detailtablecss'; console.groupCollapsed('defining core routes'); function defineRoute(newRoute) { - var path = newRoute.alias ? newRoute.alias : newRoute.path; + const path = newRoute.alias ? newRoute.alias : newRoute.path; console.debug('defining route: ' + path); newRoute.dictionary = 'core'; Emby.Page.addRoute(path, newRoute); diff --git a/src/scripts/site.js b/src/scripts/site.js index d386243138..0dbdcb4c61 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -1,10 +1,10 @@ window.getWindowLocationSearch = function(win) { 'use strict'; - var search = (win || window).location.search; + let search = (win || window).location.search; if (!search) { - var index = window.location.href.indexOf('?'); + const index = window.location.href.indexOf('?'); if (index != -1) { search = window.location.href.substring(index); @@ -18,9 +18,9 @@ window.getParameterByName = function(name, url) { 'use strict'; name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); - var regexS = '[\\?&]' + name + '=([^&#]*)'; - var regex = new RegExp(regexS, 'i'); - var results = regex.exec(url || getWindowLocationSearch()); + const regexS = '[\\?&]' + name + '=([^&#]*)'; + const regex = new RegExp(regexS, 'i'); + const results = regex.exec(url || getWindowLocationSearch()); if (results == null) { return ''; @@ -33,7 +33,7 @@ window.pageClassOn = function(eventName, className, fn) { 'use strict'; document.addEventListener(eventName, function (event) { - var target = event.target; + const target = event.target; if (target.classList.contains(className)) { fn.call(target, event); @@ -45,7 +45,7 @@ window.pageIdOn = function(eventName, id, fn) { 'use strict'; document.addEventListener(eventName, function (event) { - var target = event.target; + const target = event.target; if (target.id === id) { fn.call(target, event); @@ -53,7 +53,7 @@ window.pageIdOn = function(eventName, id, fn) { }); }; -var AppInfo = {}; +const AppInfo = {}; function initClient() { function bindConnectionManagerEvents(connectionManager, events, userSettings) { @@ -61,7 +61,7 @@ function initClient() { window.connectionManager.currentApiClient = function () { if (!localApiClient) { - var server = window.connectionManager.getLastUsedServer(); + const server = window.connectionManager.getLastUsedServer(); if (server) { localApiClient = window.connectionManager.getApiClient(server.Id); @@ -86,11 +86,11 @@ function initClient() { return require(['connectionManagerFactory', 'apphost', 'credentialprovider', 'events', 'userSettings'], function (ConnectionManager, appHost, credentialProvider, events, userSettings) { appHost = appHost.default || appHost; - var credentialProviderInstance = new credentialProvider(); - var promises = [appHost.init()]; + const credentialProviderInstance = new credentialProvider(); + const promises = [appHost.init()]; return Promise.all(promises).then(function (responses) { - var capabilities = Dashboard.capabilities(appHost); + const capabilities = Dashboard.capabilities(appHost); window.connectionManager = new ConnectionManager(credentialProviderInstance, appHost.appName(), appHost.appVersion(), appHost.deviceName(), appHost.deviceId(), capabilities); @@ -102,7 +102,7 @@ function initClient() { return require(['apiclient', 'clientUtils'], function (apiClientFactory, clientUtils) { console.debug('creating ApiClient singleton'); - var apiClient = new apiClientFactory(Dashboard.serverAddress(), appHost.appName(), appHost.appVersion(), appHost.deviceName(), appHost.deviceId()); + const apiClient = new apiClientFactory(Dashboard.serverAddress(), appHost.appName(), appHost.appVersion(), appHost.deviceName(), appHost.deviceId()); apiClient.enableAutomaticNetworking = false; apiClient.manualAddressOnly = true; @@ -194,7 +194,7 @@ function initClient() { require(['clientUtils']); - var promises = []; + const promises = []; if (!window.fetch) { promises.push(require(['fetch'])); } @@ -226,8 +226,8 @@ function initClient() { } function loadCoreDictionary(globalize) { - var languages = ['ar', 'be-by', 'bg-bg', 'ca', 'cs', 'da', 'de', 'el', 'en-gb', 'en-us', 'es', 'es-ar', 'es-mx', 'fa', 'fi', 'fr', 'fr-ca', 'gsw', 'he', 'hi-in', 'hr', 'hu', 'id', 'it', 'kk', 'ko', 'lt-lt', 'ms', 'nb', 'nl', 'pl', 'pt-br', 'pt-pt', 'ro', 'ru', 'sk', 'sl-si', 'sv', 'tr', 'uk', 'vi', 'zh-cn', 'zh-hk', 'zh-tw']; - var translations = languages.map(function (language) { + const languages = ['ar', 'be-by', 'bg-bg', 'ca', 'cs', 'da', 'de', 'el', 'en-gb', 'en-us', 'es', 'es-ar', 'es-mx', 'fa', 'fi', 'fr', 'fr-ca', 'gsw', 'he', 'hi-in', 'hr', 'hu', 'id', 'it', 'kk', 'ko', 'lt-lt', 'ms', 'nb', 'nl', 'pl', 'pt-br', 'pt-pt', 'ro', 'ru', 'sk', 'sl-si', 'sv', 'tr', 'uk', 'vi', 'zh-cn', 'zh-hk', 'zh-tw']; + const translations = languages.map(function (language) { return { lang: language, path: 'strings/' + language + '.json' @@ -367,7 +367,7 @@ function initClient() { require(['playerSelectionMenu']); - var apiClient = window.connectionManager && window.connectionManager.currentApiClient(); + const apiClient = window.connectionManager && window.connectionManager.currentApiClient(); if (apiClient) { fetch(apiClient.getUrl('Branding/Css')) .then(function(response) { @@ -410,8 +410,8 @@ function initClient() { } function onWebComponentsReady() { - var componentsPath = getComponentsPath(); - var scriptsPath = getScriptsPath(); + const componentsPath = getComponentsPath(); + const scriptsPath = getScriptsPath(); define('filesystem', [scriptsPath + '/filesystem'], returnFirstDependency); @@ -441,18 +441,18 @@ function initClient() { init(); } - var promise; - var localApiClient; + let promise; + let localApiClient; function initRequireJs() { - var urlArgs = 'v=' + (window.dashboardVersion || new Date().getDate()); + const urlArgs = 'v=' + (window.dashboardVersion || new Date().getDate()); - var bowerPath = getBowerPath(); - var componentsPath = getComponentsPath(); - var elementsPath = getElementsPath(); - var scriptsPath = getScriptsPath(); + const bowerPath = getBowerPath(); + const componentsPath = getComponentsPath(); + const elementsPath = getElementsPath(); + const scriptsPath = getScriptsPath(); - var paths = { + const paths = { browserdeviceprofile: 'scripts/browserDeviceProfile', browser: 'scripts/browser', libraryBrowser: 'scripts/libraryBrowser', diff --git a/src/scripts/themeManager.js b/src/scripts/themeManager.js index 03ca621749..56d3362219 100644 --- a/src/scripts/themeManager.js +++ b/src/scripts/themeManager.js @@ -1,10 +1,10 @@ import * as webSettings from 'webSettings'; -var themeStyleElement = document.querySelector('#cssTheme'); -var currentThemeId; +let themeStyleElement = document.querySelector('#cssTheme'); +let currentThemeId; function unloadTheme() { - var elem = themeStyleElement; + const elem = themeStyleElement; if (elem) { elem.removeAttribute('href'); currentThemeId = null; @@ -17,7 +17,7 @@ function getThemes() { function getThemeStylesheetInfo(id) { return getThemes().then(themes => { - var theme = themes.find(theme => { + const theme = themes.find(theme => { return id ? theme.id === id : theme.default; }); @@ -41,7 +41,7 @@ function setTheme(id) { return; } - var linkUrl = info.stylesheetPath; + const linkUrl = info.stylesheetPath; unloadTheme(); let link = themeStyleElement; From 237e8ddc4c60bd5d35f3691d91b4aa8f978a5cba Mon Sep 17 00:00:00 2001 From: dkanada Date: Thu, 8 Oct 2020 00:47:23 +0900 Subject: [PATCH 260/281] manual changes for no-var eslint rule --- .eslintrc.js | 1 + src/components/focusManager.js | 4 ++-- src/components/htmlMediaHelper.js | 5 ++--- src/components/serviceworker/notifications.js | 3 +-- src/libraries/navdrawer/navdrawer.js | 2 ++ src/scripts/editorsidebar.js | 4 ++-- src/scripts/gamepadtokey.js | 4 ++-- src/scripts/multiDownload.js | 2 +- 8 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index dc8729fb2a..e5ee2dfe86 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -49,6 +49,7 @@ module.exports = { 'prefer-const': ['error', {'destructuring': 'all'}], 'quotes': ['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': false }], '@babel/semi': ['error'], + 'no-var': ['error'], 'space-before-blocks': ['error'], 'space-infix-ops': 'error', 'yoda': 'error' diff --git a/src/components/focusManager.js b/src/components/focusManager.js index 90ff8b0703..d45984bf58 100644 --- a/src/components/focusManager.js +++ b/src/components/focusManager.js @@ -344,8 +344,8 @@ import scrollManager from 'scrollManager'; const midX = elementRect.left + (elementRect.width / 2); const midY = elementRect.top + (elementRect.height / 2); - var distX; - var distY; + let distX; + let distY; switch (direction) { case 0: diff --git a/src/components/htmlMediaHelper.js b/src/components/htmlMediaHelper.js index 31fc4c29c8..be506b449d 100644 --- a/src/components/htmlMediaHelper.js +++ b/src/components/htmlMediaHelper.js @@ -149,7 +149,7 @@ import events from 'events'; } else { // update video player position when media is ready to be sought const events = ['durationchange', 'loadeddata', 'play', 'loadedmetadata']; - var onMediaChange = function(e) { + const onMediaChange = function(e) { if (element.currentTime === 0 && element.duration >= seconds) { // seek only when video position is exactly zero, // as this is true only if video hasn't started yet or @@ -322,9 +322,8 @@ import events from 'events'; break; case Hls.ErrorTypes.MEDIA_ERROR: console.debug('fatal media error encountered, try to recover'); - var currentReject = reject; + handleHlsJsMediaError(instance, reject); reject = null; - handleHlsJsMediaError(instance, currentReject); break; default: diff --git a/src/components/serviceworker/notifications.js b/src/components/serviceworker/notifications.js index cc2ee65320..51623b56f7 100644 --- a/src/components/serviceworker/notifications.js +++ b/src/components/serviceworker/notifications.js @@ -15,8 +15,7 @@ return getApiClient(serverId).then(function (apiClient) { switch (action) { case 'cancel-install': - var id = data.id; - return apiClient.cancelPackageInstallation(id); + return apiClient.cancelPackageInstallation(data.id); case 'restart': return apiClient.restartServer(); default: diff --git a/src/libraries/navdrawer/navdrawer.js b/src/libraries/navdrawer/navdrawer.js index ab50ec5831..6dcf6783d1 100644 --- a/src/libraries/navdrawer/navdrawer.js +++ b/src/libraries/navdrawer/navdrawer.js @@ -2,6 +2,7 @@ * and will be replaced soon by a Vue component. */ +/* eslint-disable no-var */ import browser from 'browser'; import dom from 'dom'; import 'css!./navdrawer'; @@ -355,3 +356,4 @@ export default function (options) { return new TouchMenuLA(); } +/* eslint-enable no-var */ diff --git a/src/scripts/editorsidebar.js b/src/scripts/editorsidebar.js index 7e8abbe2f9..3711520f02 100644 --- a/src/scripts/editorsidebar.js +++ b/src/scripts/editorsidebar.js @@ -254,7 +254,7 @@ import 'material-icons'; function loadNodesToLoad(page, node) { const children = node.children; for (let i = 0, length = children.length; i < length; i++) { - var child = children[i]; + const child = children[i]; if (nodesToLoad.indexOf(child) != -1) { nodesToLoad = nodesToLoad.filter(function (n) { return n != child; @@ -297,7 +297,7 @@ import 'material-icons'; const url = window.location.hash || window.location.href; return getParameterByName('id', url); } - var nodesToLoad = []; + let nodesToLoad = []; let selectedNodeId; $(document).on('itemsaved', '.metadataEditorPage', function (e, item) { updateEditorNode(this, item); diff --git a/src/scripts/gamepadtokey.js b/src/scripts/gamepadtokey.js index 8451326974..b1976e1f6b 100644 --- a/src/scripts/gamepadtokey.js +++ b/src/scripts/gamepadtokey.js @@ -248,7 +248,7 @@ let inputLoopTimer; function runInputLoop() { // Get the latest gamepad state. const gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */ - for (var i = 0, len = gamepads.length; i < len; i++) { + for (let i = 0, len = gamepads.length; i < len; i++) { const gamepad = gamepads[i]; if (!gamepad) { continue; @@ -273,7 +273,7 @@ function runInputLoop() { } // Iterate through the buttons to see if Left thumbstick, DPad, A and B are pressed. const buttons = gamepad.buttons; - for (var j = 0, len = buttons.length; j < len; j++) { + for (let j = 0, len = buttons.length; j < len; j++) { if (ProcessedButtons.indexOf(j) !== -1) { if (buttons[j].pressed) { switch (j) { diff --git a/src/scripts/multiDownload.js b/src/scripts/multiDownload.js index 270c474965..6d47427ed8 100644 --- a/src/scripts/multiDownload.js +++ b/src/scripts/multiDownload.js @@ -10,7 +10,7 @@ function fallback(urls) { document.documentElement.appendChild(frame); // the download init has to be sequential otherwise IE only use the first - var interval = setInterval(function () { + const interval = setInterval(function () { if (frame.contentWindow.document.readyState === 'complete' || frame.contentWindow.document.readyState === 'interactive') { clearInterval(interval); From 33a60320a1b25d2d4b72428a93565224932780af Mon Sep 17 00:00:00 2001 From: SaddFox Date: Wed, 7 Oct 2020 22:49:50 +0000 Subject: [PATCH 261/281] Translated using Weblate (Slovenian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/sl/ --- src/strings/sl-si.json | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/strings/sl-si.json b/src/strings/sl-si.json index 652e3e77be..73500ac287 100644 --- a/src/strings/sl-si.json +++ b/src/strings/sl-si.json @@ -1332,11 +1332,20 @@ "Image": "Slika", "HeaderRecordingPostProcessing": "Obdelava snemanja", "Other": "Drugo", - "EnableQuickConnect": "Omogoči Quick Connect za ta server", + "EnableQuickConnect": "Omogoči Quick Connect za ta strežnik", "EnableAutoCast": "Nastavi kot privzeto", "Data": "Podatki", "ButtonUseQuickConnect": "Uporabi Quick Connect", "ButtonActivate": "Aktiviraj", "Authorize": "Pooblasti", - "HeaderBranding": "Promocija" + "HeaderBranding": "Promocija", + "UseDoubleRateDeinterlacing": "Podvoji hitrost sličic pri razpletanju", + "SystemDlnaProfilesHelp": "Sistemski profili so samo za branje. Spremembe sistemskega profila bodo shranjene kot nov profil po meri.", + "LabelColorSpace": "Barvni prostor:", + "MediaInfoColorSpace": "Barvni prostor", + "ButtonPlayer": "Predvajalnik", + "Whitelist": "Seznam želja", + "SubtitleVerticalPositionHelp": "Številka vrstice kjer se pojavi besedilo. Pozitivne številke predstavljajo od zgoraj navzdol. Negativne številke predstavljajo od spodaj navzgor.", + "TonemappingRangeHelp": "Izberite barvni razpon izhoda. Auto je isto kot razpon vhoda.", + "LabelOpenclDevice": "OpenCL naprava:" } From 7adc288ca63fa89a4fe349cb2f1a11ad311d0a25 Mon Sep 17 00:00:00 2001 From: Maxr1998 Date: Tue, 28 Jul 2020 23:54:27 +0200 Subject: [PATCH 262/281] Improve NativeShell integration - Move NativeShell calls into shell.js where possible to better group them - Add "updateVolumeLevel" API (not used yet) --- src/components/playback/mediasession.js | 6 ++-- src/scripts/fileDownloader.js | 7 ++--- src/scripts/shell.js | 37 ++++++++++++++++++++----- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/components/playback/mediasession.js b/src/components/playback/mediasession.js index 2478c52d6e..b75fa69a8c 100644 --- a/src/components/playback/mediasession.js +++ b/src/components/playback/mediasession.js @@ -1,5 +1,6 @@ import playbackManager from 'playbackManager'; import nowPlayingHelper from 'nowPlayingHelper'; +import shell from 'shell'; import events from 'events'; /* eslint-disable indent */ @@ -127,8 +128,7 @@ import events from 'events'; }); } else { const itemImageUrl = seriesImageUrl(item, { maxHeight: 3000 }) || imageUrl(item, { maxHeight: 3000 }); - - window.NativeShell.updateMediaSession({ + shell.updateMediaSession({ action: eventName, isLocalPlayer: isLocalPlayer, itemId: itemId, @@ -182,7 +182,7 @@ import events from 'events'; /* eslint-disable-next-line compat/compat */ navigator.mediaSession.metadata = null; } else { - window.NativeShell.hideMediaSession(); + shell.hideMediaSession(); } } diff --git a/src/scripts/fileDownloader.js b/src/scripts/fileDownloader.js index f4179dcef8..c99a6c3e35 100644 --- a/src/scripts/fileDownloader.js +++ b/src/scripts/fileDownloader.js @@ -1,11 +1,8 @@ import multiDownload from 'multi-download'; +import shell from 'shell'; export function download(items) { - if (window.NativeShell) { - items.map(function (item) { - window.NativeShell.downloadFile(item); - }); - } else { + if (!shell.downloadFiles(items)) { multiDownload(items.map(function (item) { return item.url; })); diff --git a/src/scripts/shell.js b/src/scripts/shell.js index e42c7792a0..3b3635c7f4 100644 --- a/src/scripts/shell.js +++ b/src/scripts/shell.js @@ -1,20 +1,43 @@ // TODO: This seems like a good candidate for deprecation export default { - openUrl: function (url, target) { + enableFullscreen: function() { + window.NativeShell?.enableFullscreen(); + }, + disableFullscreen: function() { + window.NativeShell?.disableFullscreen(); + }, + openUrl: function(url, target) { if (window.NativeShell) { window.NativeShell.openUrl(url, target); } else { window.open(url, target || '_blank'); } }, - enableFullscreen: function () { - if (window.NativeShell) { - window.NativeShell.enableFullscreen(); - } + updateMediaSession(mediaInfo) { + window.NativeShell?.updateMediaSession(mediaInfo); }, - disableFullscreen: function () { + hideMediaSession() { + window.NativeShell?.hideMediaSession(); + }, + /** + * Notify the NativeShell about volume level changes. + * Useful for e.g. remote playback. + */ + updateVolumeLevel(volume) { + window.NativeShell?.updateVolumeLevel(volume); + }, + /** + * Download specified files with NativeShell if possible + * + * @returns true on success + */ + downloadFiles(items) { if (window.NativeShell) { - window.NativeShell.disableFullscreen(); + items.map(function(item) { + window.NativeShell.downloadFile(item); + }); + return true; } + return false; } }; From bb97896868d2cb8bc0bc3883a386701d4a62cb08 Mon Sep 17 00:00:00 2001 From: millallo Date: Thu, 8 Oct 2020 12:28:06 +0000 Subject: [PATCH 263/281] Translated using Weblate (Italian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/it/ --- src/strings/it.json | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/strings/it.json b/src/strings/it.json index e4641db41d..88fbaac2f1 100644 --- a/src/strings/it.json +++ b/src/strings/it.json @@ -1380,7 +1380,7 @@ "PosterCard": "Locandina", "LabelOpenclDevice": "Dispositivo OpenCL:", "MediaInfoVideoRange": "Intervallo video", - "UseDoubleRateDeinterlacingHelp": "Questa opzione usa il campo frequenza durante il deinterlacciamento, detto anche \"bob deinterlacing\", il quale raddoppia il frame rate del video per fornire \"full motion\" come se guardassi un video interlacciato su una TV.", + "UseDoubleRateDeinterlacingHelp": "Questa opzione usa il campo frequenza durante il deinterlacciamento, detto anche \"bob deinterlacing\", il quale raddoppia il frame rate del video per fornire \"full motion\" come se guardassi un video interlacciato in TV.", "QuickConnectAuthorizeFail": "Codice Quick Connect sconosciuto", "QuickConnectAuthorizeCode": "Inserisci {0} per completare il login", "EnableQuickConnect": "Attiva Quick Connect su questo server", @@ -1388,13 +1388,19 @@ "QuickConnectNotActive": "Quick connect non è attivo in questo server", "QuickConnectNotAvailable": "Chiedi all'amministratore del server di abilitare Quick Connect", "QuickConnectInvalidCode": "Codice Quick Connect non valido", - "QuickConnectDescription": "Per registrarsi usando Quick Connect, seleziona il pulsante Quick Connect nel dispositivo che stai usando per accedere e inserisci il codice scritto sottostante.", - "QuickConnectDeactivated": "Quick Connect è stato disattivato prima che il login venisse approvato", + "QuickConnectDescription": "Per registrarsi usando Quick Connect, seleziona il pulsante Quick Connect nel dispositivo che stai usando per accedere ed inserisci il codice sottostante.", + "QuickConnectDeactivated": "Quick Connect è stato disattivato prima che la richiesta di login venisse approvata", "QuickConnectAuthorizeSuccess": "Richiesta autorizzata", "QuickConnectActivationSuccessful": "Attivato con successo", "QuickConnect": "Quick Connect", "LabelQuickConnectCode": "Codice Quick Connect:", "LabelCurrentStatus": "Stato attuale:", "ButtonActivate": "Attiva", - "Authorize": "Autorizza" + "Authorize": "Autorizza", + "LabelTonemappingAlgorithm": "Seleziona l'algoritmo di Tone mapping da usare:", + "EnableTonemapping": "Abilita il Tone mapping", + "OptionMaxActiveSessionsHelp": "Il valore 0 disabilita la funzionalità.", + "OptionMaxActiveSessions": "Imposta il numero massimo di connessioni utente simultanee.", + "LabelUserMaxActiveSessions": "Numero massimo di sessioni utente contemporanee:", + "EnableAutoCast": "Imposta come Default" } From c0e4f38738e98fe09d5ebb09157fce63da71d268 Mon Sep 17 00:00:00 2001 From: a a Date: Thu, 8 Oct 2020 18:48:22 +0000 Subject: [PATCH 264/281] Translated using Weblate (Swedish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/sv/ --- src/strings/sv.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/strings/sv.json b/src/strings/sv.json index 9f4afd6cc0..707784509e 100644 --- a/src/strings/sv.json +++ b/src/strings/sv.json @@ -227,7 +227,7 @@ "HeaderConfirmPluginInstallation": "Bekräfta installation av tillägg", "HeaderConfirmProfileDeletion": "Bekräfta radering av profil", "HeaderConfirmRevokeApiKey": "Återkalla API-nyckel", - "HeaderConnectToServer": "Anslut till Server", + "HeaderConnectToServer": "Anslut till server", "HeaderConnectionFailure": "Misslyckad anslutning", "HeaderContainerProfile": "Behållareprofil", "HeaderContainerProfileHelp": "Behållareprofiler bestämmer begränsningarna hos en enhet när den spelar upp olika filformat. Om en begränsning är aktuell kommer innehållet att kodas om, även om formatet i sig är inställt för direkt avspelning.", @@ -1351,5 +1351,9 @@ "LabelUnstable": "Ostabil", "LabelIconMaxResHelp": "Högsta tillåtna upplösning för ikoner som visas via egenskapen upnp:icon.", "LabelAlbumArtMaxResHelp": "Högsta tillåtna upplösning för albumomslag som visas via egenskapen upnp:albumArtURI.", - "Image": "Bild" + "Image": "Bild", + "Data": "Data", + "ButtonUseQuickConnect": "Använd Quick Connect", + "ButtonActivate": "Aktivera", + "Authorize": "Auktorisera" } From 171a0485975fe2f9ca3463f776b2e56ac448ee23 Mon Sep 17 00:00:00 2001 From: hanka456 Date: Fri, 9 Oct 2020 09:31:09 +0000 Subject: [PATCH 265/281] Translated using Weblate (Swedish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/sv/ --- src/strings/sv.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/strings/sv.json b/src/strings/sv.json index 707784509e..d5343d6051 100644 --- a/src/strings/sv.json +++ b/src/strings/sv.json @@ -1276,7 +1276,7 @@ "UnsupportedPlayback": "Jellyfin kan inte dekryptera inehåll skyddat av DRM men allt inehåll kommer ändå försökas, även skyddade titlar. Vissa filer kan se helt svarta ut på grund av kryptering eller andra funktioner som inte stöds, till exempel interaktiva titlar.", "LabelLibraryPageSizeHelp": "Sätter en begränsad sidstorlek i bibliotek. Sätt 0 för att avaktivera begränsad sidstorlek.", "ApiKeysCaption": "Lista av aktiva API-nycklar", - "DeinterlaceMethodHelp": "Välj metod för borttagning av inflätning vid konvertering av inflätat inehåll.", + "DeinterlaceMethodHelp": "Välj metod för avflätning vid mjukvarukonvertering av inflätat innehåll. När hårdvaruacceleration med stöd för hårdvarustödd avflätning används så kommer hårdvarustödd avflätning användas istället.", "SaveChanges": "Spara ändringar", "LabelRequireHttps": "Kräv HTTPS", "LabelChromecastVersion": "Chromecast-version", @@ -1355,5 +1355,6 @@ "Data": "Data", "ButtonUseQuickConnect": "Använd Quick Connect", "ButtonActivate": "Aktivera", - "Authorize": "Auktorisera" + "Authorize": "Auktorisera", + "EnableAutoCast": "Markera som standard" } From 62e226a3868b921488e3d5894ec55f63703c2755 Mon Sep 17 00:00:00 2001 From: Page Asgardius Date: Fri, 9 Oct 2020 21:15:32 +0000 Subject: [PATCH 266/281] Translated using Weblate (Spanish (Mexico)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/es_MX/ --- src/strings/es-mx.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/strings/es-mx.json b/src/strings/es-mx.json index 6b7c5ed6f1..5542131a7b 100644 --- a/src/strings/es-mx.json +++ b/src/strings/es-mx.json @@ -1418,5 +1418,8 @@ "LabelUnstable": "Inestable", "LabelKnownProxies": "Proxies conocidos:", "LabelIconMaxResHelp": "Resolución máxima de los íconos expuestos por medio de la propiedad upnp:icon.", - "LabelCurrentStatus": "Estatus actual:" + "LabelCurrentStatus": "Estatus actual:", + "OptionMaxActiveSessionsHelp": "Fijar este valor en 0 desactivará esta característica.", + "OptionMaxActiveSessions": "Determina la cantidad máxima de sesiones simultaneas que puede tener cada usuario.", + "LabelUserMaxActiveSessions": "Límite de sesiones simultaneas:" } From 5d7705d4ab4f5648277645a073ff688c5c9e2c66 Mon Sep 17 00:00:00 2001 From: Page Asgardius Date: Fri, 9 Oct 2020 21:08:25 +0000 Subject: [PATCH 267/281] Translated using Weblate (Spanish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/es/ --- src/strings/es.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/strings/es.json b/src/strings/es.json index 0ca1c361b3..dbe062078a 100644 --- a/src/strings/es.json +++ b/src/strings/es.json @@ -1418,5 +1418,8 @@ "LabelOpenclDeviceHelp": "Este es el dispositivo OpenCL que se usará para el mapeo de tonos. La parte izquierda del punto es el número de plataforma, la derecha es el número de dispositivo en la plataforma. El valor predeterminado es 0.0. Se requiere especificar el archivo ejecutable ffmpeg con el método de aceleración por Hardware para OpenCL.", "LabelMaxMuxingQueueSizeHelp": "El número máximo de paquetes que se pueden almacenar en buffer mientras se espera a que se inicialicen todos los flujos. Intente aumentar este valor si aún encuentra el mensaje de error \"Demasiados paquetes en buffer para transmitir\" en las bitácoras de ffmpeg. El valor recomendado es 2048.", "LabelTonemappingPeakHelp": "Se omitirán los picos de referencia con este valor. Util cuando la información de pico incrustada en los metadatos de imagen no es confiable o cuando se hace un mapeo de tonos de un rango bajo a uno más alto. Se recomienda el valor predeterminado 0.", - "LabelTonemappingThresholdHelp": "Los parámetros del algoritmo de mapeo de tonos se ajustan en cada escena. Se usa un umbral para detectar si la escena ha cambiado o no. Si el brillo promedio se sale del umbral entre el fotograma actual y el próximo, se volveran a calcular los valores de brillo promedio y de pico. Se recomiendan los valores predeterminados 0.8 y 0.2." + "LabelTonemappingThresholdHelp": "Los parámetros del algoritmo de mapeo de tonos se ajustan en cada escena. Se usa un umbral para detectar si la escena ha cambiado o no. Si el brillo promedio se sale del umbral entre el fotograma actual y el próximo, se volveran a calcular los valores de brillo promedio y de pico. Se recomiendan los valores predeterminados 0.8 y 0.2.", + "OptionMaxActiveSessionsHelp": "Un valor de 0 desactivará esta característica.", + "OptionMaxActiveSessions": "Fija el número máximo de sesiones que puede tener cada usuario.", + "LabelUserMaxActiveSessions": "Número máximo de sesiones simultaneas por usuario:" } From ffbda03e3261754130a7b6c456165ae2f566beb8 Mon Sep 17 00:00:00 2001 From: GoldyyDev Date: Fri, 9 Oct 2020 16:30:23 +0000 Subject: [PATCH 268/281] Translated using Weblate (Hebrew) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/he/ --- src/strings/he.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/strings/he.json b/src/strings/he.json index aa9e89590b..86cad06f80 100644 --- a/src/strings/he.json +++ b/src/strings/he.json @@ -827,5 +827,7 @@ "Data": "נתונים", "ColorPrimaries": "צבעים ראשיים", "ClientSettings": "הגדרות לקוח", - "BoxSet": "מארז" + "BoxSet": "מארז", + "ButtonActivate": "הפעל", + "Authorize": "הרשה" } From 96226172a7146c8e3d8837ddde41f0a29d6b8f17 Mon Sep 17 00:00:00 2001 From: GoldyyDev Date: Fri, 9 Oct 2020 16:29:46 +0000 Subject: [PATCH 269/281] Translated using Weblate (Galician) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/gl/ --- src/strings/gl.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strings/gl.json b/src/strings/gl.json index 534ed0b4eb..d8f8e427b4 100644 --- a/src/strings/gl.json +++ b/src/strings/gl.json @@ -16,5 +16,6 @@ "Collections": "Colecións", "Channels": "Canles", "Books": "Libros", - "Artists": "Artistas" + "Artists": "Artistas", + "Absolute": "" } From c97de933be6ab9ea271e1db6842db0309c12229b Mon Sep 17 00:00:00 2001 From: Page Asgardius Date: Fri, 9 Oct 2020 21:11:30 +0000 Subject: [PATCH 270/281] 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 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/strings/es_419.json b/src/strings/es_419.json index 23940195e6..0d2c8b1610 100644 --- a/src/strings/es_419.json +++ b/src/strings/es_419.json @@ -1418,5 +1418,8 @@ "LabelQuickConnectCode": "Código 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" + "EnableAutoCast": "Establecer como Predeterminado", + "OptionMaxActiveSessionsHelp": "fijar esto en 0 desactivará esta característica.", + "OptionMaxActiveSessions": "Determina el número máximo de sesiones que puede tener cada usuario de forma simultnea.", + "LabelUserMaxActiveSessions": "Límite de sesiones simultaneas:" } From 470ae8f5e465247ccce819a0c9a1520502fd1bf6 Mon Sep 17 00:00:00 2001 From: shakesac Date: Sat, 10 Oct 2020 01:48:57 +0000 Subject: [PATCH 271/281] Translated using Weblate (Portuguese (Portugal)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/pt_PT/ --- src/strings/pt-pt.json | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index 502f2952ba..89cc8891d0 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -614,7 +614,7 @@ "Albums": "Álbuns", "Alerts": "Alertas", "AllChannels": "Todos os canais", - "AllComplexFormats": "Todos os formatos complexos (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", + "AllComplexFormats": "Todos os Formatos Complexos (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", "AllEpisodes": "Todos os episódios", "AllLanguages": "Todos os idiomas", "AllLibraries": "Todas as bibliotecas", @@ -623,7 +623,7 @@ "AllowMediaConversionHelp": "Permitir ou negar acesso à funcionalidade de conversão multimédia.", "AllowOnTheFlySubtitleExtraction": "Permitir a extração de legendas em tempo real", "AllowOnTheFlySubtitleExtractionHelp": "Legendas integradas podem ser extraídas do vídeo e enviadas como texto simples para os clientes para evitar transcodificação. Em certos dispositivos, esta poderá ser uma operação demorada e pode causar interrupções de reprodução durante o processo de extração. Desative esta opção para que as legendas sejam integradas no vídeo durante a conversão para um formato suportado pelo dispositivo de destino.", - "AllowRemoteAccess": "Permitir ligações remotas a este Jellyfin Server.", + "AllowRemoteAccess": "Permitir ligações remotas a este servidor.", "AllowRemoteAccessHelp": "Se inativo, todas as ligações remotas serão bloqueadas.", "AllowedRemoteAddressesHelp": "Lista de IP ou IP/Máscara, separados por vírgulas, com permissão para se ligar remotamente. Se deixado em branco, todos os endereços remotos serão permitidos.", "AlwaysPlaySubtitles": "Reproduzir Sempre", @@ -656,7 +656,7 @@ "ContinueWatching": "Continuar a ver", "ConfirmEndPlayerSession": "Deseja encerrar o Servidor Jellyfin em {0}?", "ConfirmDeleteImage": "Apagar a imagem?", - "ConfigureDateAdded": "Configure a forma como é atribuída a data de adição, no painel de controlo do Servidor Jellyfin, em definições da Biblioteca", + "ConfigureDateAdded": "Configure a forma como é atribuída a data de adição, no painel de controlo, nas definições de biblioteca", "CommunityRating": "Avaliação da comunidade", "ChannelNumber": "Número do canal", "ChannelNameOnly": "Apenas canal {0}", @@ -813,7 +813,7 @@ "HeaderLiveTvTunerSetup": "Configurar Sintonizador de TV", "RecordSeries": "Gravar série", "LabelKeepUpTo": "Manter, no máximo:", - "AroundTime": "Por volta das {0}", + "AroundTime": "Por volta de {0}", "SeriesDisplayOrderHelp": "Ordenar episódios por data de estreia, ordem no DVD ou numeração absoluta.", "SearchResults": "Resultados da Pesquisa", "SearchForMissingMetadata": "Procurar metadados em falta", @@ -1278,5 +1278,9 @@ "BoxSet": "Coleção", "Artist": "Artista", "AlbumArtist": "Artista do Álbum", - "Album": "Álbum" + "Album": "Álbum", + "Data": "Dados", + "ButtonUseQuickConnect": "Usar Quick Connect", + "ButtonActivate": "Ativar", + "Authorize": "Autorizar" } From c1945d058062cfa3ed9cb6f9f2994df0dd1f8aca Mon Sep 17 00:00:00 2001 From: shakesac Date: Sat, 10 Oct 2020 08:57:23 +0000 Subject: [PATCH 272/281] Translated using Weblate (Portuguese (Portugal)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/pt_PT/ --- src/strings/pt-pt.json | 257 ++++++++++++++++++++++++++++++----------- 1 file changed, 188 insertions(+), 69 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index 89cc8891d0..ad2a45c381 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -66,7 +66,7 @@ "Edit": "Editar", "EnableCinemaMode": "Modo cinema", "Ended": "Terminado", - "ErrorAddingMediaPathToVirtualFolder": "Ocorreu um erro ao adicionar a localização dos seus ficheiros. Por favor, assegure-se que o local é valido e que o processo do Jellyfin Server tenha acesso a essa localização.", + "ErrorAddingMediaPathToVirtualFolder": "Ocorreu um erro ao adicionar o caminho dos ficheiros. Por favor, assegure-se que o caminho é valido e que o Jellyfin tem acesso a ele.", "ErrorGettingTvLineups": "Ocorreu um erro ao transferir a programação de TV. Por favor, certifique-se que a sua informação está correta e tente novamente.", "ErrorPleaseSelectLineup": "Por favor selecione a programação e tente novamente. Se não houver programações disponíveis, verifique se o seu nome de utilizador, senha e código postal estão corretos.", "ExitFullscreen": "Sair do ecrã inteiro", @@ -87,7 +87,7 @@ "HeaderAdditionalParts": "Partes Adicionais", "HeaderApiKey": "Chave da API", "HeaderApiKeys": "Chaves da API", - "HeaderApiKeysHelp": "As aplicações externas necessitam de uma chave da API para comunicar com o Jellyfin Server. As chaves são emitidas ao entrar com uma conta Jellyfin ou concedendo manualmente a chave à aplicação.", + "HeaderApiKeysHelp": "As aplicações externas necessitam de uma chave da API para comunicar com o servidor. As chaves são emitidas ao entrar com uma conta Jellyfin ou concedendo manualmente a chave à aplicação.", "HeaderApp": "Aplicação", "HeaderAudioSettings": "Configurações de Áudio", "HeaderBlockItemsWithNoRating": "Bloquear conteúdo sem informação de classificação etária ou com informação desconhecida:", @@ -153,7 +153,7 @@ "HeaderPleaseSignIn": "Iniciar Sessão", "HeaderPreferredMetadataLanguage": "Idioma Preferencial dos Metadados", "HeaderProfileInformation": "Informação do Perfil", - "HeaderProfileServerSettingsHelp": "Estes valores controlam como o Servidor Jellyfin se apresenta a si mesmo para o dispositivo.", + "HeaderProfileServerSettingsHelp": "Estes valores controlam a forma como o servidor se apresenta ao dispositivo.", "HeaderRecentlyPlayed": "Reproduzido Recentemente", "HeaderRemoteControl": "Controlo Remoto", "HeaderRemoveMediaFolder": "Remover Pasta Multimédia", @@ -165,12 +165,12 @@ "HeaderScenes": "Cenas", "HeaderSelectCertificatePath": "Selecione a Localização do Certificado", "HeaderSelectMetadataPath": "Selecione a Localização dos Metadados", - "HeaderSelectMetadataPathHelp": "Procure ou introduza a localização da pasta para guardar os metadados. O Servidor Jellyfin deve ter acesso de escrita a essa pasta.", + "HeaderSelectMetadataPathHelp": "Procure ou introduza a localização da pasta para guardar os metadados. A pasta deve ter permissões de escrita.", "HeaderSelectPath": "Selecione o Local", "HeaderSelectServerCachePath": "Selecione a Localização da Cache do Servidor", "HeaderSelectServerCachePathHelp": "Procure ou introduza a localização da pasta para guardar a cache do servidor. O Servidor Jellyfin deve ter acesso de escrita a essa pasta.", "HeaderSelectTranscodingPath": "Selecione o Local Temporário da Transcodificação", - "HeaderSelectTranscodingPathHelp": "Procure ou introduza a localização da pasta para guardar os ficheiros temporários de transcodificação. O Servidor Jellyfin deve ter acesso de escrita a essa pasta.", + "HeaderSelectTranscodingPathHelp": "Procure ou introduza a localização da pasta para guardar os ficheiros temporários de transcodificação. A pasta deve ter permissões de escrita.", "HeaderSendMessage": "Enviar mensagem", "HeaderServerSettings": "Configurações do Servidor", "HeaderSetupLibrary": "Configurar Bibliotecas Multimédia", @@ -197,8 +197,8 @@ "Help": "Ajuda", "Identify": "Identificar", "Images": "Imagens", - "ImportFavoriteChannelsHelp": "Se ativado, apenas canais que estão marcados como favoritos no sintonizador serão importados.", - "ImportMissingEpisodesHelp": "Se ativado, a informação acerca dos episódios em falta será importada para a base de dados do Servidor Jellyfin e mostrada dentro das temporadas e séries. Isto pode aumentar significativamente a duração da análise da biblioteca.", + "ImportFavoriteChannelsHelp": "Apenas serão importados canais marcados como favoritos no sintonizador.", + "ImportMissingEpisodesHelp": "Informação sobre episódios em falta será importada para a base de dados e estará visível entre as temporadas e séries. Poderá aumentar a duração da análise de bibliotecas.", "InstantMix": "Mix instântaneo", "ItemCount": "{0} itens", "Label3DFormat": "Formato 3D:", @@ -218,9 +218,9 @@ "LabelAppName": "Nome da aplicação", "LabelAppNameExample": "Exemplo: Sickbeard, Sonarr", "LabelArtists": "Artistas:", - "LabelArtistsHelp": "Separe múltiplos com ;", + "LabelArtistsHelp": "Separe múltiplos artistas com ponto e virgula (;).", "LabelAudioLanguagePreference": "Idioma de áudio preferido:", - "LabelBlastMessageInterval": "Intervalo para envio de mensagens de reconhecimento (segundos)", + "LabelBlastMessageInterval": "Intervalo para envio de mensagens de reconhecimento", "LabelBlastMessageIntervalHelp": "Determina a duração em segundos entre as mensagens de exploração enviadas pelo servidor.", "LabelBlockContentWithTags": "Bloquear conteúdo com as tags:", "LabelCachePath": "Localização da cache:", @@ -235,12 +235,12 @@ "LabelCustomCertificatePath": "Localização do certificado SSL personalizado:", "LabelCustomCertificatePathHelp": "Localização do ficheiro PKCS #12 que contém um certificado e um chave privada, que permite ativar o suporte a ligações TLS em domínios privados.", "LabelCustomCss": "CSS personalizado:", - "LabelCustomCssHelp": "Aplica um ficheiro de estilos customizado à interface web.", + "LabelCustomCssHelp": "Aplique um ficheiro de estilo personalizado à interface web.", "LabelCustomDeviceDisplayNameHelp": "Forneça um nome a ser mostrado, ou deixe em branco para utilizar o nome reportado pelo dispositivo.", "LabelCustomRating": "Classificação personalizada:", "LabelDateAdded": "Adicionado a:", "LabelDateAddedBehavior": "Comportamento da data de adição para conteúdo novo:", - "LabelDateAddedBehaviorHelp": "Se um valor estiver presente nos metadados, será utilizado antes destas opções.", + "LabelDateAddedBehaviorHelp": "Caso os metadados tenham um valor presente, este terá prioridade sobre estas opções.", "LabelDay": "Dia:", "LabelDefaultUser": "Utilizador por defeito:", "LabelDefaultUserHelp": "Determina que biblioteca será apresentada aos dispositivos ligados. Pode ser redefinido para cada dispositivo utilizando perfis.", @@ -259,17 +259,17 @@ "LabelEnableAutomaticPortMapHelp": "Automaticamente encaminha o porto público para o porto local através de UPnP. Isto poderá não funcionar em alguns modelos de routers ou devido às configurações da rede. As alterações só serão aplicadas após o reiniciar do servidor", "LabelEnableBlastAliveMessages": "Enviar mensagens de reconhecimento", "LabelEnableBlastAliveMessagesHelp": "Ativar esta opção se o servidor não for convenientemente detetado por outros dispositivos UPnP na rede.", - "LabelEnableDlnaClientDiscoveryInterval": "Intervalo para descoberta de clientes (segundos)", - "LabelEnableDlnaClientDiscoveryIntervalHelp": "Determina o tempo em segundos entre procuras SSDP executadas pelo Servidor Jellyfin.", + "LabelEnableDlnaClientDiscoveryInterval": "Intervalo para descoberta de clientes", + "LabelEnableDlnaClientDiscoveryIntervalHelp": "Determina o tempo em segundos entre procuras SSDP.", "LabelEnableDlnaDebugLogging": "Ativar log de depuração do DLNA", "LabelEnableDlnaDebugLoggingHelp": "Esta opção irá criar ficheiros de log grandes e deve apenas ser usado quando é necessário para depurar problemas.", "LabelEnableDlnaPlayTo": "Ativar DLNA Play-To", - "LabelEnableDlnaPlayToHelp": "Detetar dispositivos na rede e oferecer a possibilidade de os controlar.", + "LabelEnableDlnaPlayToHelp": "Detetar dispositivos na rede e oferecer a possibilidade de os controla remotamente.", "LabelEnableDlnaServer": "Ativar servidor DLNA", "LabelEnableDlnaServerHelp": "Permite que dispositivos UPnP na rede naveguem e reproduzam conteúdo.", "LabelEnableHardwareDecodingFor": "Ativar descodificação por hardware para:", "LabelEnableRealtimeMonitor": "Ativar monitorização em tempo real", - "LabelEnableRealtimeMonitorHelp": "As alterações serão processadas imediatamente em sistemas de ficheiros suportados.", + "LabelEnableRealtimeMonitorHelp": "Alterações aos ficheiros serão processadas imediatamente em sistemas de ficheiros suportados.", "LabelEnableSingleImageInDidlLimit": "Limitar a uma imagem incorporada", "LabelEnableSingleImageInDidlLimitHelp": "Alguns dispositivos não interpretarão apropriadamente se múltiplas imagens estiverem incorporadas no DIDL.", "LabelEndDate": "Data de fim:", @@ -283,13 +283,13 @@ "LabelForgotPasswordUsernameHelp": "Introduza o seu nome de utilizador, se se recordar.", "LabelFormat": "Formato:", "LabelFriendlyName": "Nome amigável:", - "LabelServerNameHelp": "Este nome será utilizado para identificar o servidor. Por defeito, é usado o nome do computador.", + "LabelServerNameHelp": "Este nome será utilizado para identificar o servidor. Hostname do servidor usado por defeito.", "LabelGroupMoviesIntoCollections": "Agrupar filmes em coleções", - "LabelGroupMoviesIntoCollectionsHelp": "Ao mostrar listas de filmes, filmes que pertençam a uma coleção serão mostrados como um único item agrupado.", + "LabelGroupMoviesIntoCollectionsHelp": "Ao mostrar listas de filmes, aqueles que pertençam a uma coleção serão apresentados como um único item agrupado.", "LabelHardwareAccelerationType": "Aceleração por hardware:", "LabelHardwareAccelerationTypeHelp": "Aceleração via hardware requer configurações adicionais.", "LabelHttpsPort": "Número do porto HTTPS local:", - "LabelHttpsPortHelp": "Número do porto TCP em que o servidor HTTPS do Jellyfin ficará à escuta.", + "LabelHttpsPortHelp": "Número do porto TCP do servidor HTTPS.", "LabelIconMaxHeight": "Altura máxima do ícone:", "LabelIconMaxWidth": "Largura máxima do ícone:", "LabelIdentificationFieldHelp": "Uma substring ou expressão regex que não diferencia maiúscula de minúsculas.", @@ -308,7 +308,7 @@ "LabelLanguage": "Idioma:", "LabelLineup": "Programação:", "LabelLocalHttpServerPortNumber": "Número do porto HTTP local:", - "LabelLocalHttpServerPortNumberHelp": "Número do porto TCP em que o servidor HTTP do Jellyfin ficará à escuta.", + "LabelLocalHttpServerPortNumberHelp": "Número do porto TCP do servidor HTTP.", "LabelLockItemToPreventChanges": "Bloquear este item para evitar alterações futuras", "LabelLoginDisclaimer": "Aviso legal de login:", "LabelLoginDisclaimerHelp": "Este aviso será mostrado na parte inferior da página de login.", @@ -340,7 +340,7 @@ "LabelModelUrl": "URL do modelo", "LabelMonitorUsers": "Monitorizar atividade de:", "LabelMusicStreamingTranscodingBitrate": "Taxa de transcodificação de música:", - "LabelMusicStreamingTranscodingBitrateHelp": "Defina a taxa máxima ao fazer transmissão de música.", + "LabelMusicStreamingTranscodingBitrateHelp": "Defina a taxa máxima de transmissão de música.", "LabelName": "Nome:", "LabelNewPassword": "Nova palavra-passe:", "LabelNewPasswordConfirm": "Confirmar nova palavra-passe:", @@ -373,7 +373,7 @@ "LabelRecordingPath": "Localização predefinida das gravações:", "LabelReleaseDate": "Data de lançamento:", "LabelRemoteClientBitrateLimit": "Taxa de bits máxima para transmissão para a Internet (Mbps):", - "LabelRuntimeMinutes": "Duração (minutos):", + "LabelRuntimeMinutes": "Tempo de execução:", "LabelSaveLocalMetadata": "Guardar capas de álbum nas pastas multimédia", "LabelSaveLocalMetadataHelp": "Guardar capas de álbum diretamente nas pastas multimédia, vai colocá-las num local de fácil acesso para edição.", "LabelScheduledTaskLastRan": "Última execução há {0}. Tempo de execução {1}.", @@ -426,11 +426,11 @@ "MessageAreYouSureYouWishToRemoveMediaFolder": "Tem a certeza de que deseja remover esta pasta?", "MessageConfirmProfileDeletion": "Tem a certeza de que deseja remover este perfil?", "MessageConfirmRecordingCancellation": "Cancelar a gravação?", - "MessageConfirmRestart": "Tem a certeza de que deseja reiniciar o Servidor Jellyfin?", - "MessageConfirmRevokeApiKey": "Tem a certeza de que deseja revogar esta chave da API? A ligação da aplicação ao Servidor Jellyfin vai ser terminada de imediato.", + "MessageConfirmRestart": "Tem a certeza de que deseja reiniciar o Jellyfin?", + "MessageConfirmRevokeApiKey": "Tem a certeza de que deseja revogar esta chave da API? A ligação da aplicação ao servidor terminará abruptamente.", "MessageConfirmShutdown": "Tem a certeza de que deseja encerrar o servidor?", "MessageDeleteTaskTrigger": "Tem a certeza de que deseja remover o agendamento desta tarefa?", - "MessageDirectoryPickerBSDInstruction": "Num sistema operativo BSD, é necessário configurar o disco Jail FreeNAS para permitir o acesso do Servidor Jellyfin.", + "MessageDirectoryPickerBSDInstruction": "Num sistema operativo BSD, é necessário configurar o disco Jail FreeNAS para permitir o acesso aos conteúdos.", "MessageDirectoryPickerLinuxInstruction": "Em sistemas operativos como Arch Linux, CentOS, Debian, Fedora, openSUSE, ou Ubuntu, é necessário dar permissão ao utilizador que executa o processo Jellyfin para ter, no mínimo, acesso de leitura à pasta.", "MessageEnablingOptionLongerScans": "Ativar esta opção pode aumentar significativamente a duração da análise da biblioteca.", "MessageFileReadError": "Ocorreu um erro ao ler este ficheiro.", @@ -441,7 +441,7 @@ "MessageNoAvailablePlugins": "Não existem extensões disponíveis.", "MessageNoMovieSuggestionsAvailable": "De momento, não existem sugestões de filmes disponíveis. Veja filmes e avalie-os, e regresse para ver as recomendações.", "MessageNoPluginsInstalled": "Não existe nenhuma extensão instalada.", - "MessageNoTrailersFound": "Nenhum trailer encontrado. Instale o canal Trailer para melhorar sua experiência com filmes, adicionando uma biblioteca de trailers da Internet.", + "MessageNoTrailersFound": "Instale o canal de trailers para melhorar a sua experiência, adicionando uma biblioteca de trailers da internet.", "MessageNothingHere": "Nada aqui.", "MessagePasswordResetForUsers": "As palavras-passe dos utilizadores seguintes foram repostas. Deverão utilizar o PIN de reposição de palavra-passe para fazer login.", "MessagePleaseEnsureInternetMetadata": "Certifique-se que a transferência de metadados da Internet está ativa.", @@ -450,7 +450,7 @@ "MinutesAfter": "minutos depois", "MinutesBefore": "minutos antes", "Monday": "Segunda", - "MoreUsersCanBeAddedLater": "É possível adicionar utilizadores mais tarde no Painel Principal.", + "MoreUsersCanBeAddedLater": "É possível adicionar utilizadores posteriormente através do Painel Principal.", "Mute": "Desativar Som", "NewCollection": "Nova Coleção", "NewCollectionNameExample": "Exemplo: Coleção Guerra das Estrelas", @@ -463,7 +463,7 @@ "OptionAllowLinkSharing": "Permitir partilha nas redes sociais", "OptionAllowManageLiveTv": "Permitir gestão de gravações de TV em Direto", "OptionAllowMediaPlayback": "Permitir reprodução de média", - "OptionAllowMediaPlaybackTranscodingHelp": "Restringir o acesso à transcodificação pode causar falhas de reprodução nas aplicações do Jellyfin devido a formatos multimédia não suportados.", + "OptionAllowMediaPlaybackTranscodingHelp": "Restringir o acesso à transcodificação pode causar falhas de reprodução nos clientes Jellyfin devido a formatos multimédia não suportados.", "OptionAllowRemoteControlOthers": "Permitir controlo remoto de outros utilizadores", "OptionAllowRemoteSharedDevices": "Permitir controlo remoto de dispositivos compartilhados", "OptionAllowRemoteSharedDevicesHelp": "Dispositivos DLNA são considerados como partilhados até que um utilizador comece a controlá-lo.", @@ -478,9 +478,9 @@ "OptionDateAddedImportTime": "Usar a data de importação para a biblioteca", "OptionDatePlayed": "Data de reprodução", "OptionDisableUser": "Desativar este utilizador", - "OptionDisableUserHelp": "Se desativado, o servidor não permite nenhuma ligação com este nome de utilizador. Ligações existentes serão terminadas.", + "OptionDisableUserHelp": "O servidor não permitirá nenhuma ligação com este nome de utilizador. Ligações existentes serão terminadas.", "OptionDislikes": "Não gostos", - "OptionDownloadImagesInAdvanceHelp": "Por defeito, a maioria das imagens são transferidas só quando uma aplicação do Jellyfin as solicita. Ative esta opção para descarregar todas as imagens antencipadamente, assim que os novos ficheiros multimédia são importados. Isto pode aumentar significativamente a duração da análise da biblioteca.", + "OptionDownloadImagesInAdvanceHelp": "Por defeito, a maioria das imagens só são transferidas quando solicitadas por um cliente Jellyfin. Ative esta opção para descarregar todas as imagens durante a importação de novos ficheiros multimédia. Isto pode aumentar significativamente a duração da análise da biblioteca.", "OptionDvd": "DVD", "OptionEmbedSubtitles": "Incorporar no contentor", "OptionEnableAccessFromAllDevices": "Ativar acesso de todos os dispositivos", @@ -498,7 +498,7 @@ "OptionHideUserFromLoginHelp": "Útil para contas de administrador privadas ou ocultas. O utilizador necessita de entrar manualmente, introduzindo o seu nome de utilizador e palavra-passe.", "OptionHlsSegmentedSubtitles": "Legendas segmentadas HLS", "OptionIgnoreTranscodeByteRangeRequests": "Ignorar requisições de extensão do byte de transcodificação", - "OptionIgnoreTranscodeByteRangeRequestsHelp": "Se ativadas, estas requisições serão honradas mas irão ignorar o cabeçalho da extensão do byte.", + "OptionIgnoreTranscodeByteRangeRequestsHelp": "Estes pedidos serão cumpridos mas irão ignorar o cabeçalho da extensão do byte.", "OptionImdbRating": "Classificação no IMDb", "OptionLikes": "Gostos", "OptionMax": "Máx", @@ -507,9 +507,9 @@ "OptionOnInterval": "Num intervalo", "OptionParentalRating": "Classificação Parental", "OptionPlainStorageFolders": "Mostrar todas as pastas como pastas de armazenamento simples", - "OptionPlainStorageFoldersHelp": "Se ativado, todas as pastas são representadas no DIDL como \"object.container.storageFolder\" ao invés de um tipo mais específico como, por exemplo, \"object.container.person.musicArtist\".", + "OptionPlainStorageFoldersHelp": "Todas as pastas são representadas no DIDL como \"object.container.storageFolder\" ao invés de um tipo mais específico como, por exemplo, \"object.container.person.musicArtist\".", "OptionPlainVideoItems": "Mostrar todos os vídeos como itens de vídeo simples", - "OptionPlainVideoItemsHelp": "Se ativado, todos os vídeos são representados no DIDL como \"object.item.videoItem\" ao invés de um tipo mais específico como, por exemplo, \"object.item.videoItem.movie\".", + "OptionPlainVideoItemsHelp": "Todos os vídeos são representados no DIDL como \"object.item.videoItem\" ao invés de um tipo mais específico como, por exemplo, \"object.item.videoItem.movie\".", "OptionPlayCount": "N.º de Visualizações", "OptionPremiereDate": "Data de Estreia", "OptionReleaseDate": "Data de Lançamento", @@ -557,7 +557,7 @@ "SearchForSubtitles": "Procurar Legendas", "SendMessage": "Enviar mensagem", "Series": "Séries", - "ServerUpdateNeeded": "Este Servidor Jellyfin precisa de ser atualizado. Para transferir a versão mais recente, por favor visite {0}", + "ServerUpdateNeeded": "Este servidor tem que ser atualizado. Para transferir a versão mais recente, por favor visite {0}", "Settings": "Configurações", "SettingsSaved": "Configurações guardadas.", "Share": "Partilhar", @@ -651,7 +651,7 @@ "Shows": "Séries", "Songs": "Músicas", "Sync": "Sincronização", - "Absolute": "Absoluto", + "Absolute": "Completo", "CriticRating": "Avaliação da crítica", "ContinueWatching": "Continuar a ver", "ConfirmEndPlayerSession": "Deseja encerrar o Servidor Jellyfin em {0}?", @@ -675,7 +675,7 @@ "Browse": "Procurar", "BoxRear": "Caixa (verso)", "Box": "Caixa", - "BookLibraryHelp": "Livros digitais e áudio livros são suportados. Consulte o guia de nomenclatura de livros{1}.", + "BookLibraryHelp": "Livros digitais e áudio livros são suportados. Consulte o {0} guia de nomenclatura de livros{1}.", "BirthLocation": "Local de nascimento", "AsManyAsPossible": "Tantos quanto possível", "Art": "Capa", @@ -721,7 +721,7 @@ "EveryNDays": "A cada {0} dias", "ErrorSavingTvProvider": "Ocorreu um erro ao guardar o provedor do serviços de TV. Por favor, garanta que está acessível e tente de novo.", "ErrorStartHourGreaterThanEnd": "A hora de fim deve ser superior à hora de início.", - "ErrorDeletingItem": "Ocorreu um erro ao apagar o item do Servidor Jellyfin. Por favor, verifique o acesso de escrita do Servidor Jellyfin à pasta e tente de novo.", + "ErrorDeletingItem": "Ocorreu um erro ao apagar o item do servidor. Por favor, verifique o acesso de escrita do Jellyfin à pasta e tente de novamente.", "ErrorAddingTunerDevice": "Ocorreu um erro ao adicionar o dispositivo de sintonização. Por favor, garanta que está acessível e tente de novo.", "ErrorAddingXmlTvFile": "Ocorreu um erro ao aceder ao ficheiro XMLTV. Por favor, certifique-se que o ficheiro está acessível e tente de novo.", "Episodes": "Episódios", @@ -742,14 +742,14 @@ "DownloadsValue": "{0} transferências", "Download": "Transferir", "DoNotRecord": "Não gravar", - "DisplayModeHelp": "Selecione o tipo de ecrã onde o Jellyfin será utilizado.", + "DisplayModeHelp": "Selecione o estilo de apresentação da interface.", "DisplayMissingEpisodesWithinSeasonsHelp": "Deve também ser ativado para as bibliotecas de TV nas configurações do servidor.", "DisplayMissingEpisodesWithinSeasons": "Mostrar episódios em falta numa série", "DisplayInOtherHomeScreenSections": "Mostrar no ecrã principal em secções como multimédia recente ou continue a ver", "DisplayInMyMedia": "Mostrar no ecrã principal", "Disconnect": "Desligar", "DirectStreaming": "Reprodução direta", - "DirectStreamHelp2": "Reprodução direta de um ficheiro requer pouco processamento e não implica perda de qualidade num vídeo.", + "DirectStreamHelp2": "Reprodução direta de um ficheiro requer pouco processamento e implica uma perda de qualidade mínima.", "DefaultSubtitlesHelp": "As legendas são carregadas com base nas definições por defeito ou forçado nos metadados. As preferências de idioma são consideradas quando existem múltiplas opções disponíveis.", "DefaultMetadataLangaugeDescription": "Estes são os valores por defeito que podem ser customizados para cada uma das bibliotecas.", "ErrorDefault": "Ocorreu um erro a processar o pedido. Por favor, tente novamente mais tarde.", @@ -783,7 +783,7 @@ "LabelBurnSubtitles": "Integrar legendas:", "LabelBirthYear": "Ano de nascimento:", "LabelBirthDate": "Data de nascimento:", - "LabelBindToLocalNetworkAddressHelp": "Opcional. Indique um endereço IP de uma interface de rede local para colocar o servidor à escuta. Se deixado em branco, o servidor ficará à escuta em todas as interfaces de rede disponíveis. Alterar este parâmetro implica reiniciar o Servidor Jellyfin.", + "LabelBindToLocalNetworkAddressHelp": "Indique um endereço IP de uma interface de rede local para colocar o servidor à escuta. Caso deixe em branco, o servidor ficará à escuta em todas as interfaces de rede disponíveis. Alterar este parâmetro requer reinicio do servidor.", "LabelBindToLocalNetworkAddress": "Endereço local para colocar o servidor à escuta:", "LabelAutomaticallyRefreshInternetMetadataEvery": "Atualizar metadados automaticamente a partir da Internet:", "LabelAuthProvider": "Provedor de autenticação:", @@ -796,7 +796,7 @@ "Items": "Itens", "InstallingPackage": "A instalar {0} (version {1})", "HttpsRequiresCert": "Para activar ligações seguras, é necessário fornecer um certificado SSL confiável. Forneça um certificado SSL ou desactive as ligações seguras.", - "DirectStreamHelp1": "O tipo de multimédia (H.264, AC3, etc.) e a sua resolução são compatíveis com o dispositivo, no entanto, o formato (mkv, avi, wmv, etc.) não é. O conteúdo é reempacotado em tempo real antes de ser enviado para o dispositivo.", + "DirectStreamHelp1": "O tipo de multimédia (H.264, AC3, etc.) e a sua resolução são compatíveis com o dispositivo, no entanto, o formato (mkv, avi, wmv, etc.) não é. O conteúdo será reempacotado em tempo real antes de ser enviado para o dispositivo.", "DirectPlaying": "Reprodução direta", "Backdrop": "Imagem de Fundo", "SortChannelsBy": "Ordenar canais por:", @@ -828,13 +828,13 @@ "ReplaceAllMetadata": "Substituir todos os metadados", "RepeatOne": "Repetir este", "RepeatMode": "Modo de Repetição", - "ServerRestartNeededAfterPluginInstall": "O Servidor Jellyfin necessitará de reiniciar depois de instalar uma extensão.", + "ServerRestartNeededAfterPluginInstall": "O Jellyfin terá que reiniciar após instalar uma extensão.", "MessageNoPluginConfiguration": "Esta extensão não é configurável.", - "MessagePluginInstallDisclaimer": "As extensões desenvolvidas pela comunidade Jellyfin são uma ótima forma de melhorar a experiência de utilização do Jellyfin, adicionando novas funcionalidades e benefícios. Antes de proceder à instalação, tenha em atenção que estas podem alterar determinados comportamentos no Servidor Jellyfin e provocar efeitos como tempos de atualização da Biblioteca mais longos, processamento adicional em segundo plano e estabilidade do sistema reduzida.", + "MessagePluginInstallDisclaimer": "As extensões desenvolvidas por membros da comunidade são uma ótima maneira de melhorar a experiência com funcionalidades adicionais. Antes de proceder à instalação, tenha em atenção que estas podem alterar determinados comportamentos no servidor, como o aumento da duração de análise de bibliotecas, processamento adicional em segundo plano e redução da estabilidade do sistema.", "MessagePluginConfigurationRequiresLocalAccess": "Para configurar esta extensão, inicie sessão localmente no servidor.", "HeaderPluginInstallation": "Instalação de Extensão", - "MessagePluginInstalled": "A extensão foi instalada com sucesso. O Servidor Jellyfin necessitará de reiniciar para aplicar as alterações.", - "PleaseRestartServerName": "Por favor, reinicie o Servidor Jellyfin - {0}.", + "MessagePluginInstalled": "A extensão foi instalada com sucesso. O servidor terá que reiniciar para aplicar as alterações.", + "PleaseRestartServerName": "Por favor, reinicie o Jellyfin no {0}.", "PleaseConfirmPluginInstallation": "Por favor clique em OK para confirmar que leu o conteúdo acima, e que deseja prosseguir com a instalação da extensão.", "PleaseAddAtLeastOneFolder": "Por favor, adicione pelo menos uma pasta a esta Biblioteca, utilizando para isso o botão Adicionar.", "Played": "Reproduzido", @@ -845,10 +845,10 @@ "PlayAllFromHere": "Reproduzir todos a partir daqui", "PerfectMatch": "Correspondência perfeita", "People": "Pessoas", - "PasswordResetProviderHelp": "Selecione um provedor de reposição de palavra-passe a ser usado quando um utilizador requisita uma reposição de palavra-passe", - "PackageInstallFailed": "Instalação de {0} falhada.", - "PackageInstallCompleted": "Instalação de {0} terminada.", - "PackageInstallCancelled": "Instalação de {0} cancelada.", + "PasswordResetProviderHelp": "Selecione um fornecedor de reposição de senha a ser usado quando um utilizador solicitar a reposição da sua senha.", + "PackageInstallFailed": "Instalação de {0} (version {1}) falhou.", + "PackageInstallCompleted": "Instalação de {0} (version {1}) terminada.", + "PackageInstallCancelled": "Instalação de {0} (version {1}) cancelada.", "Overview": "Resumo", "OriginalAirDateValue": "Data de estreia original: {0}", "OptionSubstring": "Parte de palavra", @@ -917,13 +917,13 @@ "HeaderVideoQuality": "Qualidade do Vídeo", "HeaderVideoType": "Tipo de Vídeo", "LabelFolder": "Pasta:", - "LabelOptionalNetworkPath": "(Opcional) Pasta partilhada de rede:", + "LabelOptionalNetworkPath": "Pasta de rede partilhada:", "ColorSpace": "Espaço de cores", "HeaderMyMediaSmall": "O Meu Conteúdo (pequeno)", "HeaderNewDevices": "Novos Dispositivos", "HeaderRecordingOptions": "Opções de Gravação", "HeaderSortOrder": "Direção de Ordenação", - "LabelBaseUrlHelp": "Adiciona uma sub-pasta personalizada ao URL do servidor. Por exemplo: http://exemplo.com/<baseurl>", + "LabelBaseUrlHelp": "Adiciona uma sub-pasta personalizada ao URL do servidor. Por exemplo: http://exemplo.com/<baseurl>", "LabelMoviePrefixHelp": "Se aplicar um prefixo aos títulos dos filmes, introduza-o aqui para que o servidor consiga tratá-los corretamente.", "LabelPleaseRestart": "As alterações produzirão efeito depois de recarregar a página web.", "LabelRecordingPathHelp": "Especifique a localização por defeito para guardar as gravações. Se for deixado em branco, será utilizada a pasta base do servidor.", @@ -933,7 +933,7 @@ "HeaderMusicQuality": "Qualidade da Música", "HeaderMyDevice": "O Meu Dispositivo", "HeaderSortBy": "Ordenar Por", - "LabelOptionalNetworkPathHelp": "Se esta pasta estiver partilhada na rede, fornecer o caminho de rede pode permitir aos clientes aceder diretamente aos ficheiros multimédia. For example, {0} or {1}.", + "LabelOptionalNetworkPathHelp": "Caso a pasta esteja partilhada, fornecer o caminho de rede pode permitir aos clientes aceder diretamente aos ficheiros multimédia. For example, {0} or {1}.", "LabelPersonRoleHelp": "Exemplo: motorista da carrinha de gelados", "LabelPlayer": "Reprodutor:", "LabelServerName": "Nome do servidor:", @@ -959,7 +959,7 @@ "LabelKidsCategories": "Categorias para crianças:", "LabelMovieCategories": "Categorias para filmes:", "LabelMoviePrefix": "Prefixo para filmes:", - "LabelMovieRecordingPath": "Caminho para gravação de filmes (opcional):", + "LabelMovieRecordingPath": "Caminho para gravação de filmes:", "LabelNewsCategories": "Categorias para notícias:", "LabelNumber": "Número:", "LabelPlayMethod": "Método de reprodução:", @@ -969,7 +969,7 @@ "LabelProfileCodecs": "Codecs:", "LabelReasonForTranscoding": "Razão para transcodificação:", "LabelScreensaver": "Proteção de Ecrã:", - "LabelSeriesRecordingPath": "Caminho para gravação de séries (opcional):", + "LabelSeriesRecordingPath": "Caminho para gravação de séries:", "ColorPrimaries": "Cores primárias", "MessageInvalidForgotPasswordPin": "Foi inserido um código PIN inválido ou expirado. Por favor, tente de novo.", "MessageImageTypeNotSelected": "Por favor, selecione um tipo de imagem da lista.", @@ -1001,7 +1001,7 @@ "HeaderTypeImageFetchers": "{0} fornecedores de imagens", "LabelImageFetchersHelp": "Active e ordene os fornecedores de imagens por ordem de preferência.", "LabelKodiMetadataUserHelp": "Autorizar que outras aplicações usem dados de visualização gaurdados em ficheiros NFO.", - "LabelMetadataSaversHelp": "Escolha o formato em que deseja guardar metadados.", + "LabelMetadataSaversHelp": "Escolha o formato a utilizar ao guardar metadados.", "LabelRefreshMode": "Modo de actualização:", "LabelRemoteClientBitrateLimitHelp": "Valor-limite de taxa de transmissão para todos os dispositivos fora da rede local. Este valor é opcional e aplica-se a cada transmissão individual. Ao definir este valor previne que dispositivos peçam uma taxa de transmissão acima da sua ligação à internet. Pedir uma taxa de transmissão acima do limite da ligação implica a necessidade de transcodificar o vídeo e num aumento da carga da CPU.", "Home": "Início", @@ -1031,15 +1031,15 @@ "OptionEnableForAllTuners": "Ativar para todos os sintonizadores", "OptionEnableExternalContentInSuggestions": "Ativar conteúdo externo nas sugestões", "OptionBluray": "Blu-Ray", - "OptionAutomaticallyGroupSeriesHelp": "Se ativado, sérias que estejam espalhadas por várias pastas nesta biblioteca, serão automaticamente combinadas numa única série.", + "OptionAutomaticallyGroupSeriesHelp": "Séries que estejam espalhadas por várias pastas nesta biblioteca, serão automaticamente combinadas numa única série.", "OptionAutomaticallyGroupSeries": "Combinar automaticamente séries que estejam espalhadas por várias pastas", "OptionAllowVideoPlaybackRemuxing": "Permitir a reprodução de vídeo que requeira conversão sem transcodificação", "OptionAllowSyncTranscoding": "Permitir a transferência e sincronização de conteúdos que requeiram transcodificação", "OptionAllowLinkSharingHelp": "Apenas serão partilhadas páginas que contenham informação sobre os conteúdos. Os conteúdos nunca serão partilhados. As partilhas são limitadas no tempo e expiram após {0} dias.", "Option3D": "3D", - "OnlyImageFormats": "Apenas formatos de imagem (VOBSUB, PGS, SUB, etc)", + "OnlyImageFormats": "Apenas Formatos de Imagem (VOBSUB, PGS, SUB, etc)", "OnlyForcedSubtitlesHelp": "Só serão carregadas legendas marcadas como forçadas.", - "OnlyForcedSubtitles": "Apenas legendas forçadas", + "OnlyForcedSubtitles": "Apenas Legendas Forçadas", "Off": "Desligado", "NumLocationsValue": "{0} pastas", "Normal": "Normal", @@ -1077,7 +1077,7 @@ "MoveLeft": "Mover para a esquerda", "MoreFromValue": "Mais de {0}", "Mobile": "Móvel", - "MetadataSettingChangeHelp": "Alterar as definições de metadados irá afetar conteúdo adicionado futuramente. Para refrescar o conteúdo existente, abra o painel de detalhes e clique no botão Refrescar, ou execute refrescamentos em massa utilizando o gestor de metadados.", + "MetadataSettingChangeHelp": "Alterar as definições de metadados afetarão conteúdos adicionados futuramente. Para atualizar o conteúdo existente, abra o painel de detalhes e clique no botão Recarregar metadados, ou execute atualizações em massa utilizando o gestor de metadados.", "MetadataManager": "Gestor de Metadados", "Metadata": "Metadados", "MessageYouHaveVersionInstalled": "Neste momento está instalada a versão {0}.", @@ -1098,7 +1098,7 @@ "LearnHowYouCanContribute": "Veja como pode contribuir.", "Large": "Grande", "LanNetworksHelp": "Lista separada por vírgulas de endereços IP ou IP/máscara que serão considerados como locais quando se aplicam restrições de largura de banda. Se preenchido, todos os outros endereços serão considerados externos e estarão sujeitos às restrições de largura de banda para dispositivos externos. Se deixado em branco, apenas serão consideradas locais as sub-redes do servidor.", - "LabelffmpegPathHelp": "Caminho para o binário ffmpeg, ou para a pasta que o contém.", + "LabelffmpegPathHelp": "Caminho para a aplicação ou pasta que contém o ffmgeg.", "LabelffmpegPath": "Caminho FFmpeg:", "LabelYear": "Ano:", "LabelWeb": "Web:", @@ -1131,7 +1131,7 @@ "NewEpisodes": "Novos episódios", "Never": "Nunca", "Name": "Nome", - "MusicVideo": "Videoclip", + "MusicVideo": "Videoclipe", "MusicArtist": "Artista de Música", "MusicAlbum": "Álbum de Música", "MoreMediaInfo": "Informações", @@ -1171,8 +1171,8 @@ "Small": "Pequeno", "ShowTitle": "Mostrar título", "ShowIndicatorsFor": "Mostrar indicadores para:", - "ServerNameIsShuttingDown": "Jellyfin Server - {0} está a desligar.", - "ServerNameIsRestarting": "Jellyfin Server - {0} está a reiniciar.", + "ServerNameIsShuttingDown": "O servidor {0} está a desligar.", + "ServerNameIsRestarting": "O servidor {0} está a reiniciar.", "SeriesYearToPresent": "{0} - Presente", "SeriesSettings": "Configuração de série", "SeriesCancelled": "Série cancelada.", @@ -1196,8 +1196,8 @@ "PictureInPicture": "Imagem em imagem", "OptionDisplayFolderView": "Mostre em vista de pasta para ver pastas de mídia", "NewCollectionHelp": "Coleções permitem criar grupos personalizados de filmes e outros tipos de conteúdo.", - "MusicLibraryHelp": "Reveja o {0}guia de nomeação de música{1}.", - "MovieLibraryHelp": "Reveja o {0} guia de nomeação de filmes {1}.", + "MusicLibraryHelp": "Consulte o {0}guia de nomenclatura de música{1}.", + "MovieLibraryHelp": "Consulte o {0}guia de nomenclatura de filmes{1}.", "MessageConfirmAppExit": "Quer sair?", "MediaInfoRefFrames": "Ref quadros", "MediaInfoLayout": "Disposição", @@ -1219,7 +1219,7 @@ "EnableStreamLooping": "Auto-cíclico de streams ao vivo", "Down": "Baixo", "ButtonSplit": "Dividir", - "NoCreatedLibraries": "Parece que ainda não foi criada nenhuma biblioteca por enquanto. {0} Gostaria de criar uma biblioteca agora? {1}", + "NoCreatedLibraries": "Parece que ainda não foi criada nenhuma biblioteca. {0} Deseja criar uma biblioteca agora? {1}", "AskAdminToCreateLibrary": "Pergunte a um administrador para criar uma biblioteca.", "LabelVideoResolution": "Resolução de vídeo:", "LabelPlayerDimensions": "Dimensões de leitor:", @@ -1232,7 +1232,7 @@ "AllowFfmpegThrottlingHelp": "Suspende o processo de transcodificação assim que este avance o suficiente após o ponto de reprodução atual, para poupança de recursos. Esta funcionalidade é mais útil quando a reprodução é maioritariamente contínua, sem avançar ou recuar manualmente. Desative esta opção caso haja problemas de reprodução.", "AllowFfmpegThrottling": "Reduzir Taxa de Transcodificação", "PreferEmbeddedTitlesOverFileNamesHelp": "Determina o título a apresentar por defeito quando não é possível carregar metadados locais nem da Internet.", - "OptionSaveMetadataAsHiddenHelp": "Alterar esta definição apenas afetará metadados guardados futuramente. Ficheiros existentes serão atualizados assim que forem alterados pelo Servidor Jellyfin.", + "OptionSaveMetadataAsHiddenHelp": "Alterar esta definição apenas afetará metadados guardados futuramente. Ficheiros existentes serão atualizados assim que forem alterados pelo servidor.", "ButtonSyncPlay": "SyncPlay", "LabelRepositoryUrl": "URL do Repositório", "HeaderNewRepository": "Novo Repositório", @@ -1257,7 +1257,7 @@ "LabelChromecastVersion": "Versão do \"Chromecast\"", "LabelLibraryPageSizeHelp": "Define a quantidade de items a apresentar na página de uma Biblioteca. Para desativar a existência de paginação, introduza o valor 0.", "LabelLibraryPageSize": "Tamanho da página da Biblioteca:", - "LabelEnableHttpsHelp": "Permite que o servidor escute na porta HTTPS configurada. Um certificado válido também deve ser configurado para que isso entre em vigor.", + "LabelEnableHttpsHelp": "Escuta na porta HTTPS configurada. Um certificado válido também deverá ser configurado para funcionar.", "LabelEnableHttps": "Ativar HTTPS", "LabelDeinterlaceMethod": "Método de desentrelaçamento:", "HeaderSyncPlayEnabled": "SyncPlay ativado", @@ -1272,7 +1272,7 @@ "EnableDetailsBanner": "Cartaz de Detalhes", "EnableDecodingColorDepth10Vp9": "Ativar descodificação de hardware de 10-Bits para VP9", "EnableDecodingColorDepth10Hevc": "Ativar descodificação de hardware de 10-Bits para HEVC", - "DeinterlaceMethodHelp": "Selecionar um método de desentrelaçamento para converter conteúdo entrelaçado.", + "DeinterlaceMethodHelp": "Selecionar um método de desentrelaçamento ao transcodificar conteúdo entrelaçado através de software. Caso esteja ativo, o desentrelaçamento através de aceleração por hardware terá prioridade sobre esta opção.", "ClientSettings": "Definições do Cliente", "ButtonTogglePlaylist": "Lista de Reprodução", "BoxSet": "Coleção", @@ -1282,5 +1282,124 @@ "Data": "Dados", "ButtonUseQuickConnect": "Usar Quick Connect", "ButtonActivate": "Ativar", - "Authorize": "Autorizar" + "Authorize": "Autorizar", + "LabelMaxMuxingQueueSize": "Tamanho máximo da fila de muxing:", + "Preview": "Pré-visualizar", + "SubtitleVerticalPositionHelp": "Número da linha onde o texto é exibido. Números positivos representam ordem descendente. Números negativos representam ordem ascendente.", + "LabelSubtitleVerticalPosition": "Posição vertical:", + "ClearQueue": "Limpar fila", + "StopPlayback": "Parar reprodução", + "LabelTonemappingAlgorithm": "Selecione o algoritmo de mapeamento de tonalidade a usar:", + "EnableTonemapping": "Ativar mapeamento de tonalidade", + "LabelOpenclDeviceHelp": "Este é o dispositivo OpenCL usado para o mapeamento de tonalidades. O lado esquerdo do ponto representa o número da plataforma e no lado direito é representado o número do dispositivo na plataforma. O valor padrão é 0.0. É necessário o ficheiro da aplicação ffmpeg que contêm o método de aceleração por hardware OpenCL.", + "LabelOpenclDevice": "Dispositivo OpenCL:", + "LabelColorPrimaries": "Cor primária:", + "LabelColorTransfer": "Transferência de cor:", + "LabelColorSpace": "Espaço de cor:", + "LabelVideoRange": "Intervalo do vídeo:", + "MediaInfoColorPrimaries": "Cores primárias", + "MediaInfoColorTransfer": "Transferência da cor", + "MediaInfoColorSpace": "Espaço de cor", + "MediaInfoVideoRange": "Intervalo do vídeo", + "ButtonPlayer": "Reprodutor", + "ButtonCast": "Elenco", + "EnableBlurHashHelp": "Imagens que ainda estão a ser descarregadas serão apresentadas num espaço reservado.", + "EnableBlurHash": "Ativar espaço desfocado para imagens", + "UnsupportedPlayback": "O Jellyfin não consegue descodificar conteúdo protegido por DRM, mas tentará de qualquer forma, incluindo títulos protegidos. Alguns ficheiros reproduziram um ecrã preto devido à encriptação ou a outras funcionalidades não suportadas, como títulos interativos.", + "OnApplicationStartup": "No arranque da aplicação", + "EveryXHours": "A cada {0} horas", + "EveryHour": "A cada hora", + "EveryXMinutes": "A cada {0} minutos", + "OnWakeFromSleep": "Ao acordar da suspensão", + "DailyAt": "Diariamente no {0}", + "LastSeen": "Última visita a {0}", + "PersonRole": "como {0}", + "ListPaging": "{0}-{1} de {2}", + "WriteAccessRequired": "O Jellyfin necessita de acesso de escrita a esta pasta. Garanta acesso de escrita e tente novamente.", + "PathNotFound": "O caminho não foi encontrado. Verifique se o caminho é válido e tente novamente.", + "Writers": "Argumentistas", + "ViewAlbumArtist": "Ver artista do álbum", + "Video": "Vídeo", + "UseDoubleRateDeinterlacingHelp": "Esta definição usa o field rate durante o desentrelaçamento, referido frequentemente como desentrelaçamento bob, que duplica a taxa de frames do vídeo de forma proporcionar um movimento fluído como quando visualiza um vídeo desentrelaçado numa televisão.", + "UseDoubleRateDeinterlacing": "Duplicar o frame rate durante desentrelaçamento", + "TvLibraryHelp": "Consulte o {0}guia de nomenclatura de TV{1}.", + "TabNetworking": "Rede", + "TabRepositories": "Repositórios", + "SyncPlayAccessHelp": "Selecione o nível de acesso deste utilizador à funcionalidade SyncPlay. O SyncPlay permite a reprodução sincronizada com outros dispositivos.", + "Subtitle": "Legenda", + "SubtitleOffset": "Desvio das Legendas", + "SubtitleDownloadersHelp": "Ative e classifique os fornecedores de legendas por ordem de prioridade.", + "SubtitleAppearanceSettingsDisclaimer": "Estas definições não se aplicam a legendas gráficas (PGS, DVD, etc) ou a legendas ASS/SSA com estilos próprios incorporados.", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Estas definições também se aplicam à reprodução através de um Chromecast iniciada por este dispositivo.", + "SpecialFeatures": "Funcionalidades Especiais", + "Filter": "Filtro", + "New": "Novo", + "ShowMore": "Mostrar mais", + "ShowLess": "Mostrar menos", + "SettingsWarning": "Alterar estes valores poderá causar instabilidade ou falhas de ligação. Caso ocorra algum problema recomendamos que volte a alterar para os valores padrão.", + "SelectServer": "Selecionar Servidor", + "Season": "Temporada", + "SaveChanges": "Guardar alterações", + "Restart": "Reiniciar", + "ResetPassword": "Repor Senha", + "RefreshDialogHelp": "Os metadados são atualizados consoante as configurações e serviços de internet ativos no Painel Principal.", + "QuickConnectNotActive": "O Quick Connect não está ativo neste servidor", + "QuickConnectNotAvailable": "Solicite a ativação do Quick Connect ao administrador do servidor", + "QuickConnectInvalidCode": "Código Quick Connect inválido", + "QuickConnectDescription": "Para iniciar sessão com o Quick Connect, prima o botão Quick Connect no dispositivo com o qual está a iniciar sessão e introduza o seguinte código.", + "QuickConnectDeactivated": "O Quick Connect foi desativado antes do pedido de inicio de sessão ser aprovado", + "QuickConnectAuthorizeFail": "Código de quick connect desconhecido", + "QuickConnectAuthorizeSuccess": "Pedido autorizado", + "QuickConnectAuthorizeCode": "Introduza o código {0} para iniciar sessão", + "QuickConnectActivationSuccessful": "Ativado com sucesso", + "Profile": "Perfil", + "PreviousTrack": "Voltar ao anterior", + "PreferEmbeddedEpisodeInfosOverFileNames": "Dar preferência à informação embutida em vez do nome do ficheiro", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Utiliza as informações do episódio dos metadados embutidos, caso existam.", + "MessageGetInstalledPluginsError": "Ocorreu um erro ao listar as extensões instaladas.", + "MessagePluginInstallError": "Ocorreu um erro durante a instalação da extensão.", + "PosterCard": "Cartão do Cartaz", + "Poster": "Cartaz", + "PlaybackErrorNoCompatibleStream": "Este cliente não é compatível com o formato multimédia e o servidor não envia um formato que seja compatível.", + "PlaybackRate": "Taxa de Reprodução", + "Photo": "Fotografia", + "Person": "Pessoa", + "OptionRequirePerfectSubtitleMatchHelp": "Solicitar uma combinação perfeita filtrará as legendas para apenas as que tenham sido testadas e verificadas com seu ficheiro de vídeo. Desmarcar esta opção aumenta a probabilidade de transferência de legendas, aumentando também o número de casos de dessincronia de tempos ou textos incorrectos.", + "OptionMaxActiveSessionsHelp": "O valor 0 desativa esta funcionalidade.", + "OptionMaxActiveSessions": "Atribuir número máximo de sessões de utilizador simultâneas.", + "LabelAlbumArtMaxResHelp": "Resolução máxima da arte do álbum exposta através da propriedade upnp:albumArtURI.", + "Other": "Outro", + "EnableQuickConnect": "Ativar quick connect neste servidor", + "EnableAutoCast": "Definir como padrão", + "NextTrack": "Ir para o próximo", + "MusicVideos": "Videoclipes", + "Movie": "Filme", + "MessageSyncPlayErrorMedia": "A ativação do SyncPlay falhou! Erro de média.", + "MessageSyncPlayErrorMissingSession": "A ativação do SyncPlay falhou! Sessão em falta.", + "MessageSyncPlayErrorNoActivePlayer": "Não foi encontrado nenhum reprodutor ativo. O SyncPlay foi desativado.", + "MessageSyncPlayErrorAccessingGroups": "Ocorreu um erro ao aceder à lista de grupos.", + "MessageSyncPlayLibraryAccessDenied": "Conteúdo de acesso restrito.", + "MessageSyncPlayJoinGroupDenied": "É necessário permissão para utilizar o SyncPlay.", + "MessageSyncPlayCreateGroupDenied": "É necessário permissão para criar um grupo.", + "MessageSyncPlayGroupDoesNotExist": "A entrada no grupo falhou porque não existe.", + "MessageSyncPlayPlaybackPermissionRequired": "É necessário permissão de reprodução.", + "MessageSyncPlayNoGroupsAvailable": "Não existem grupos disponíveis. Comece por reproduzir algo primeiro.", + "MessageSyncPlayGroupWait": "{0} está em buffering…", + "MessageSyncPlayUserLeft": "{0} saiu do grupo.", + "MessageSyncPlayUserJoined": "{0} juntou-se ao grupo.", + "MessageSyncPlayDisabled": "SyncPlay desativado.", + "MessageSyncPlayEnabled": "SyncPlay ativo.", + "MessageNoGenresAvailable": "Ative alguns fornecedores de metadados para obter géneros da internet.", + "MessageAddRepository": "Caso deseje adicionar um repositório, carregue no botão ao lado do cabeçalho e preencha a informação pedida.", + "LabelRepositoryNameHelp": "Nome personalizado para distinguir este repositório de outros presentes no servidor.", + "LabelRepositoryName": "Nome do Repositório", + "LabelRepositoryUrlHelp": "Localização do manifesto do repositório que deseja incluir.", + "LabelUserMaxActiveSessions": "Número máximo de sessões de utilizador em simultâneo:", + "LabelQuickConnectCode": "Código Quick Connect:", + "LabelUnstable": "Instável", + "LabelKnownProxies": "Proxies conhecidas:", + "LabelIconMaxResHelp": "Resolução máxima dos ícones expostos através da propriedade upnp:icon.", + "LabelCurrentStatus": "Ponto da situação:", + "KnownProxiesHelp": "Lista de endereços IP, separada por virgulas, de proxies conhecidas que são usadas ao ligar à sua instância Jellyfin. É necessário para usar adequadamente o cabeçalho X-Forwarded-For. Requer reinicio após alterar.", + "Image": "Imagem" } From a096f4d5138272008a3ad0b497d494b0053d9c92 Mon Sep 17 00:00:00 2001 From: hoanghuy309 Date: Sat, 10 Oct 2020 04:30:21 +0000 Subject: [PATCH 273/281] Translated using Weblate (Vietnamese) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/vi/ --- src/strings/vi.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/strings/vi.json b/src/strings/vi.json index 8acfbde253..084cbdf3e6 100644 --- a/src/strings/vi.json +++ b/src/strings/vi.json @@ -50,7 +50,7 @@ "OptionDvd": "DVD", "OptionHasThemeSong": "Hình nền bài hát", "OptionHasThemeVideo": "Hình nền Video", - "OptionHideUser": "Ẩn người dùng này từ màn hình đăng nhập", + "OptionHideUser": "Ẩn người dùng này khỏi màn hình đăng nhập", "OptionImdbRating": "Đánh giá IMDb", "OptionIsHD": "Độ nét cao", "OptionIsSD": "Độ nét tiêu chuẩn", @@ -164,7 +164,7 @@ "ButtonWebsite": "Trang web", "ButtonUninstall": "Gỡ cài đặt", "ButtonTrailer": "Tóm tắt", - "ButtonSubmit": "Đăng", + "ButtonSubmit": "Gửi đi", "ButtonSplit": "Tách", "ButtonStop": "Ngưng", "ButtonStart": "Bắt đầu", @@ -329,7 +329,7 @@ "ErrorAddingXmlTvFile": "Có lỗi xảy ra khi truy cập tài liệu XMLTV. Hãy thử lại khi chắc chắn rằng tài liệu này tồn tại.", "ErrorAddingTunerDevice": "Đã xảy ra lỗi khi thêm thiết bị dò. Hãy đảm bảo rằng nó có thể truy cập được và thử lại.", "ErrorAddingMediaPathToVirtualFolder": "Có lỗi xảy ra khi thêm đường dẫn phương tiện này. Vui lòng đảm bảo đường dẫn chính xác và Jellyfin được phép truy cập vào vị trí đó.", - "ErrorAddingListingsToSchedulesDirect": "Có lỗi xảy ra khi thêm danh sách này vào tài khoản Schedules Direct của bạn. Schedules Direct chỉ cho phép một số lượng danh sách nhất định mỗi tài khoản. Bạn có thể cần phải đăng nhập vào trang web của Schedules Direct và xoá những danh sách khác trước khi có thể thêm danh sách mới.", + "ErrorAddingListingsToSchedulesDirect": "Có lỗi xảy ra khi thêm nội dung này vào tài khoản Schedules Direct của bạn. Lên lịch trực tiếp chỉ cho phép một số lượng danh sách nhất định mỗi tài khoản. Bạn có thể cần phải đăng nhập vào trang web của Schedules Direct và xoá những danh sách khác trước khi có thể thêm danh sách mới.", "Episodes": "Tập Phim", "Episode": "Tập", "EndsAtValue": "Kết thúc lúc {0}", @@ -375,7 +375,7 @@ "HeaderMetadataSettings": "Cài Đặt Dữ Liệu Mô Tả", "HeaderMediaFolders": "Thư Mục Chứa Nội Dung", "HeaderMedia": "Nội Dung", - "HeaderLoginFailure": "Đăng Nhập Không Thành Công", + "HeaderLoginFailure": "Đăng nhập thất bại", "HeaderLiveTvTunerSetup": "Thiết lập Bộ dò TV Trực tiếp", "HeaderLibrarySettings": "Cài Đặt Thư Viện", "HeaderLibraryOrder": "Thứ Tự Thư Viện", @@ -606,7 +606,7 @@ "LabelExtractChaptersDuringLibraryScanHelp": "Tạo hình ảnh phân cảnh khi video được nhập trong quá trình quét thư viện. Nếu không thì hình này này sẽ được trích xuất thông qua những tác vụ định kì, giúp cho quá trình quét thư viện diễn ra nhanh hơn.", "LabelExtractChaptersDuringLibraryScan": "Trích xuất hình ảnh phân cảnh khi quét thư viện", "LabelBaseUrlHelp": "Thêm một thư mục con tùy chỉnh vào đường dẫn máy chủ. Ví dụ: http://example.com/<baseurl>", - "LabelLoginDisclaimerHelp": "Một tin nhắn sẽ hiển thị ở phía cuối của trang đăng nhập.", + "LabelLoginDisclaimerHelp": "Một thông báo sẽ được hiển thị ở cuối trang đăng nhập.", "LabelLoginDisclaimer": "Hiển thị khi đăng nhập:", "LabelLockItemToPreventChanges": "Khoá mục này để ngăn những thay đổi trong tương lai", "LabelLocalHttpServerPortNumberHelp": "Số cổng TCP cho máy chủ HTTP.", @@ -982,7 +982,7 @@ "LabelVaapiDevice": "API Thiết bị tăng tốc Video:", "LabelUsername": "Tên đăng nhập:", "LabelUserRemoteClientBitrateLimitHelp": "Ghi đè giá trị chung mặc định được đặt trong cài đặt phát lại trên máy chủ.", - "LabelUserLoginAttemptsBeforeLockout": "Lần đăng nhập không thành công trước khi người dùng bị khóa:", + "LabelUserLoginAttemptsBeforeLockout": "Số lần đăng nhập thất bại trước khi người dùng bị khóa:", "LabelUserLibraryHelp": "Chọn thư viện người dùng để hiển thị cho thiết bị. Để trống để giữ nguyên cài đặt mặc định.", "LabelUserLibrary": "Thư viện người dùng:", "LabelUserAgent": "Hành động người dùng:", @@ -1028,7 +1028,7 @@ "OptionMissingEpisode": "Thiếu Tập Phim", "OptionMax": "Tối đa", "OptionLoginAttemptsBeforeLockoutHelp": "Giá trị bằng 0 có nghĩa là giữ mặc định ba lần thử đối với người dùng bình thường và năm lần thử đối với quản trị viên. Đặt giá trị này thành -1 sẽ tắt tính năng này.", - "OptionLoginAttemptsBeforeLockout": "Xác định số lần đăng nhập không chính xác có thể được thực hiện trước khi xảy ra khóa người dùng.", + "OptionLoginAttemptsBeforeLockout": "Xác định số lần đăng nhập thất bại có thể thử trước khi người dùng bị khóa.", "OptionIgnoreTranscodeByteRangeRequestsHelp": "Các yêu cầu này sẽ được thực hiện nhưng sẽ bỏ qua phần đầu dải byte.", "OptionIgnoreTranscodeByteRangeRequests": "Bỏ qua các yêu cầu phạm vi byte chuyển mã", "OptionHlsSegmentedSubtitles": "Phụ đề phân đoạn HLS", @@ -1141,7 +1141,7 @@ "MessageTheFollowingLocationWillBeRemovedFromLibrary": "Các vị trí phương tiện sau sẽ bị xóa khỏi thư viện của bạn:", "MessageReenableUser": "Xem bên dưới để kích hoạt lại", "MessagePluginInstallDisclaimer": "Các plugin do các thành viên cộng đồng xây dựng là một cách tuyệt vời để nâng cao trải nghiệm của bạn với các tính năng và lợi ích bổ sung. Trước khi cài đặt, hãy lưu ý về những ảnh hưởng mà chúng có thể có trên máy chủ của bạn, chẳng hạn như quét thư viện lâu hơn, xử lý nền bổ sung và giảm độ ổn định của hệ thống.", - "MessagePluginConfigurationRequiresLocalAccess": "Để cấu hình plugin này, vui lòng đăng nhập trực tiếp vào máy chủ cục bộ của bạn.", + "MessagePluginConfigurationRequiresLocalAccess": "Để cấu hình plugin này, hãy đăng nhập trực tiếp vào máy chủ của bạn.", "MessagePleaseWait": "Vui lòng đợi. Việc này có thể phải mất một ít thời gian.", "MessagePleaseEnsureInternetMetadata": "Hãy đảm bảo rằng việc tải xuống dữ liệu mô tả trên internet đã được bật.", "LabelSeriesRecordingPath": "Đường dẫn Ghi lại Phim Bộ:", From 75734a2a591b77ca10cb9d426febd30554e005d9 Mon Sep 17 00:00:00 2001 From: Tim Gels Date: Sat, 10 Oct 2020 16:05:05 +0000 Subject: [PATCH 274/281] 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 4369f26f56..73af67d3b3 100644 --- a/src/strings/nl.json +++ b/src/strings/nl.json @@ -904,7 +904,7 @@ "PlaceFavoriteChannelsAtBeginning": "Plaats favoriete kanalen aan het begin", "Play": "Afspelen", "PlayAllFromHere": "Speel allemaal vanaf hier", - "PlayCount": "Aantal keer afsgespeeld", + "PlayCount": "Aantal keer afgespeeld", "PlayFromBeginning": "Afspelen vanaf begin", "PlayNext": "Volgende afspelen", "PlayNextEpisodeAutomatically": "Speel volgende aflevering automatisch", @@ -1238,7 +1238,7 @@ "AskAdminToCreateLibrary": "Vraag een beheerder om een bibliotheek te maken.", "Artist": "Artiest", "AllowFfmpegThrottlingHelp": "Wanneer een transcode of remux ver genoeg voorloopt op de huidige afspeelpositie, pauzeer het proces, zodat het minder middelen verbruikt. Dit is vooral handig wanneer u kijkt zonder vaak te zoeken. Schakel dit uit als u afspeelproblemen ondervindt.", - "AllowFfmpegThrottling": "Throttle Transcodes", + "AllowFfmpegThrottling": "Beperk transcoderingen", "LabelPlayerDimensions": "Mediaspeler afmetingen:", "LabelLibraryPageSizeHelp": "Kies het aantal artikelen dat wordt weergegeven op een bibliotheekpagina. Kies 0 om dit te verbergen.", "LabelLibraryPageSize": "Bibliotheekpagina grootte:", From d1afe8263f11df2cd01dd1bfbe4348eb2b1c673f Mon Sep 17 00:00:00 2001 From: shakesac Date: Sat, 10 Oct 2020 18:33:56 +0000 Subject: [PATCH 275/281] Translated using Weblate (Portuguese (Portugal)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/pt_PT/ --- src/strings/pt-pt.json | 121 +++++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 54 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index ad2a45c381..855b010abb 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -45,7 +45,7 @@ "ButtonSubmit": "Enviar", "ButtonUninstall": "Desinstalar", "ChannelAccessHelp": "Selecione os canais para partilhar com este utilizador. Os administradores poderão editar todos os canais utilizando o gestor de metadados.", - "CinemaModeConfigurationHelp": "O modo cinema traz a experiência do cinema para a sua sala, possibilitando reproduzir trailers e introduções personalizadas antes da longa-metragem.", + "CinemaModeConfigurationHelp": "O modo cinema traz a experiência do cinema para a sua sala, possibilitando a reprodução de trailers e introduções personalizadas antes da longa-metragem.", "Composer": "Compositor", "ConfirmDeleteItem": "Apagar este item irá removê-lo da biblioteca e do sistema de ficheiros. Tem a certeza de que deseja continuar?", "ConfirmDeleteItems": "Apagar estes itens irá removê-los da biblioteca e do sistema de ficheiros. Tem a certeza de que deseja continuar?", @@ -62,13 +62,13 @@ "DeleteUserConfirmation": "Tem a certeza de que deseja apagar este utilizador?", "DeviceAccessHelp": "Apenas se aplica a dispositivos que podem ser identificados como únicos e que não impedem o acesso ao navegador. Filtrar o acesso a dispositivos do utilizador, impede-o de utilizar novos dispositivos, até estes serem aprovados aqui.", "Director": "Realizador", - "EasyPasswordHelp": "O código PIN é utilizado para acesso off-line em clientes suportados e pode ser usado para um acesso fácil dentro da rede.", + "EasyPasswordHelp": "O código PIN é utilizado para acesso offline em clientes suportados e pode ser usado para um acesso fácil dentro da rede.", "Edit": "Editar", "EnableCinemaMode": "Modo cinema", "Ended": "Terminado", - "ErrorAddingMediaPathToVirtualFolder": "Ocorreu um erro ao adicionar o caminho dos ficheiros. Por favor, assegure-se que o caminho é valido e que o Jellyfin tem acesso a ele.", + "ErrorAddingMediaPathToVirtualFolder": "Ocorreu um erro ao adicionar a localização dos ficheiros. Por favor, assegure-se que o caminho é valido e que o Jellyfin tem acesso ao mesmo.", "ErrorGettingTvLineups": "Ocorreu um erro ao transferir a programação de TV. Por favor, certifique-se que a sua informação está correta e tente novamente.", - "ErrorPleaseSelectLineup": "Por favor selecione a programação e tente novamente. Se não houver programações disponíveis, verifique se o seu nome de utilizador, senha e código postal estão corretos.", + "ErrorPleaseSelectLineup": "Por favor selecione a programação e tente novamente. Se não houver programações disponíveis, verifique se o seu nome de utilizador, palavra-passe e código postal estão corretos.", "ExitFullscreen": "Sair do ecrã inteiro", "FastForward": "Avanço rápido", "FileNotFound": "Ficheiro não encontrado.", @@ -144,7 +144,7 @@ "HeaderNewApiKey": "Nova Chave da API", "HeaderParentalRatings": "Classificações Parentais", "HeaderPassword": "Palavra-passe", - "HeaderPasswordReset": "Redefinição de Palavra-Passe", + "HeaderPasswordReset": "Repor Palavra-Passe", "HeaderPaths": "Localizações", "HeaderPinCodeReset": "Redefinir Código PIN", "HeaderPlayAll": "Reproduzir Todos", @@ -168,7 +168,7 @@ "HeaderSelectMetadataPathHelp": "Procure ou introduza a localização da pasta para guardar os metadados. A pasta deve ter permissões de escrita.", "HeaderSelectPath": "Selecione o Local", "HeaderSelectServerCachePath": "Selecione a Localização da Cache do Servidor", - "HeaderSelectServerCachePathHelp": "Procure ou introduza a localização da pasta para guardar a cache do servidor. O Servidor Jellyfin deve ter acesso de escrita a essa pasta.", + "HeaderSelectServerCachePathHelp": "Procure ou introduza a localização da pasta para guardar a cache do servidor. A pasta deve ter permissões de escrita.", "HeaderSelectTranscodingPath": "Selecione o Local Temporário da Transcodificação", "HeaderSelectTranscodingPathHelp": "Procure ou introduza a localização da pasta para guardar os ficheiros temporários de transcodificação. A pasta deve ter permissões de escrita.", "HeaderSendMessage": "Enviar mensagem", @@ -242,7 +242,7 @@ "LabelDateAddedBehavior": "Comportamento da data de adição para conteúdo novo:", "LabelDateAddedBehaviorHelp": "Caso os metadados tenham um valor presente, este terá prioridade sobre estas opções.", "LabelDay": "Dia:", - "LabelDefaultUser": "Utilizador por defeito:", + "LabelDefaultUser": "Utilizador padrão:", "LabelDefaultUserHelp": "Determina que biblioteca será apresentada aos dispositivos ligados. Pode ser redefinido para cada dispositivo utilizando perfis.", "LabelDeviceDescription": "Descrição do dispositivo", "LabelDidlMode": "Modo DIDL:", @@ -256,7 +256,7 @@ "LabelEmbedAlbumArtDidl": "Incorporar a capa do álbum no DIDL", "LabelEmbedAlbumArtDidlHelp": "Alguns dispositivos preferem este método para obter a capa do álbum. Noutros pode falhar a reprodução com esta opção ativada.", "LabelEnableAutomaticPortMap": "Ativar mapeamento automático de portas", - "LabelEnableAutomaticPortMapHelp": "Automaticamente encaminha o porto público para o porto local através de UPnP. Isto poderá não funcionar em alguns modelos de routers ou devido às configurações da rede. As alterações só serão aplicadas após o reiniciar do servidor", + "LabelEnableAutomaticPortMapHelp": "Encaminha automaticamente o porto público para o porto local através de UPnP. Isto poderá não funcionar em alguns modelos de routers ou configurações da rede. As alterações só serão aplicadas após o reiniciar do servidor.", "LabelEnableBlastAliveMessages": "Enviar mensagens de reconhecimento", "LabelEnableBlastAliveMessagesHelp": "Ativar esta opção se o servidor não for convenientemente detetado por outros dispositivos UPnP na rede.", "LabelEnableDlnaClientDiscoveryInterval": "Intervalo para descoberta de clientes", @@ -280,7 +280,7 @@ "LabelExtractChaptersDuringLibraryScanHelp": "Gerar imagens dos capítulos quando os vídeos forem importados durante a atualização da biblioteca. Caso contrário, serão geradas durante a tarefa agendada de extração de imagens dos capítulos, permitindo que a atualização da biblioteca seja mais rápida.", "LabelFailed": "Falhou", "LabelFinish": "Terminar", - "LabelForgotPasswordUsernameHelp": "Introduza o seu nome de utilizador, se se recordar.", + "LabelForgotPasswordUsernameHelp": "Introduza o seu nome de utilizador, caso se recorde.", "LabelFormat": "Formato:", "LabelFriendlyName": "Nome amigável:", "LabelServerNameHelp": "Este nome será utilizado para identificar o servidor. Hostname do servidor usado por defeito.", @@ -401,7 +401,7 @@ "LabelTagline": "Slogan:", "LabelTime": "Tempo:", "LabelTimeLimitHours": "Limite de tempo (horas):", - "LabelTranscodingTempPathHelp": "Indique uma localização personalizada para os ficheiros de transcodificação em utilização, ou deixe em branco para utilizar o caminho por defeito.", + "LabelTranscodingTempPathHelp": "Indique uma localização personalizada para os ficheiros de transcodificação em utilização, ou deixe em branco para utilizar o caminho padrão.", "LabelTranscodingThreadCount": "Número de threads de transcodificação:", "LabelTranscodingThreadCountHelp": "Indique o número máximo de threads a ser utilizado para transcodificação. Reduzir o número de threads diminuirá a utilização do CPU, mas pode não converter rápido o suficiente para uma experiência de reprodução suave.", "LabelTriggerType": "Tipo do Acionador:", @@ -437,13 +437,13 @@ "MessageInvalidUser": "Nome de utilizador ou palavra-passe inválidos. Por favor, tente novamente.", "MessageItemSaved": "Item guardado.", "MessageItemsAdded": "Itens adicionados.", - "MessageLeaveEmptyToInherit": "Deixar em branco para herdar as configurações do item pai, ou o valor global por defeito.", + "MessageLeaveEmptyToInherit": "Deixar em branco para herdar as configurações do item pai, ou o valor global predefinido.", "MessageNoAvailablePlugins": "Não existem extensões disponíveis.", "MessageNoMovieSuggestionsAvailable": "De momento, não existem sugestões de filmes disponíveis. Veja filmes e avalie-os, e regresse para ver as recomendações.", "MessageNoPluginsInstalled": "Não existe nenhuma extensão instalada.", "MessageNoTrailersFound": "Instale o canal de trailers para melhorar a sua experiência, adicionando uma biblioteca de trailers da internet.", "MessageNothingHere": "Nada aqui.", - "MessagePasswordResetForUsers": "As palavras-passe dos utilizadores seguintes foram repostas. Deverão utilizar o PIN de reposição de palavra-passe para fazer login.", + "MessagePasswordResetForUsers": "As palavras-passe dos seguintes utilizadores foram repostas. Deverão utilizar o PIN de reposição de palavra-passe para iniciar sessão.", "MessagePleaseEnsureInternetMetadata": "Certifique-se que a transferência de metadados da Internet está ativa.", "MessageReenableUser": "Veja abaixo para reativar", "MessageTheFollowingLocationWillBeRemovedFromLibrary": "As seguintes pastas multimédia serão removidas da Biblioteca:", @@ -513,7 +513,7 @@ "OptionPlayCount": "N.º de Visualizações", "OptionPremiereDate": "Data de Estreia", "OptionReleaseDate": "Data de Lançamento", - "OptionReportByteRangeSeekingWhenTranscoding": "Reportar que o servidor suporta busca de byte quando transcodificar", + "OptionReportByteRangeSeekingWhenTranscoding": "Reportar que o servidor suporta procura de byte durante transcodificação", "OptionReportByteRangeSeekingWhenTranscodingHelp": "Isto é necessário para alguns dispositivos que não procuram o tempo muito bem.", "OptionResElement": "elemento res", "OptionResumable": "Retomável", @@ -552,7 +552,7 @@ "Saturday": "Sábado", "Save": "Guardar", "ScanLibrary": "Analisar biblioteca", - "Search": "Busca", + "Search": "Procurar", "SearchForCollectionInternetMetadata": "Procurar na Internet por capas de álbum e metadados", "SearchForSubtitles": "Procurar Legendas", "SendMessage": "Enviar mensagem", @@ -638,7 +638,7 @@ "BirthPlaceValue": "Local de nascimento: {0}", "Blacklist": "Lista Negra", "Books": "Livros", - "BurnSubtitlesHelp": "Determina se o servidor deve integrar as legendas durante a conversão de vídeo. Evitar a integração de legendas melhora o desempenho do servidor. Selecione Auto para que legendas baseadas em imagem (VOBSUB, PGS, SUB/IDX), e certos formatos ASS/SSA sejam integrados.", + "BurnSubtitlesHelp": "Determina se o servidor deve integrar as legendas durante a conversão de vídeo. Evitar a integração de legendas melhora o desempenho do servidor. Selecione Auto para que legendas baseadas em imagem (VOBSUB, PGS, SUB/IDX) e certos formatos ASS/SSA sejam integrados.", "Channels": "Canais", "Collections": "Coleções", "Favorites": "Favoritos", @@ -691,7 +691,7 @@ "HeaderDetectMyDevices": "Detetar os Meus Dispositivos", "HeaderDeleteProvider": "Apagar Provedor", "HeaderDeleteDevice": "Apagar Dispositivo", - "HeaderDefaultRecordingSettings": "Definições de Gravação por Defeito", + "HeaderDefaultRecordingSettings": "Definições Padrão de Gravação", "HeaderContinueListening": "Continuar a Ouvir", "HeaderConnectionFailure": "Falha de Ligação", "HeaderConfirmPluginInstallation": "Confirmar Instalação de Extensão", @@ -715,7 +715,7 @@ "Filters": "Filtros", "File": "Ficheiro", "Favorite": "Favoritos", - "FFmpegSavePathNotFound": "Não foi possível encontrar o binário FFmpeg na localização que introduziu. O binário FFprobe também é necessário, e deve estar na mesma pasta. Estes componentes são, por norma, instalados em conjunto. Por favor, verifique o caminho da localização e tente de novo.", + "FFmpegSavePathNotFound": "Não foi possível encontrar o binário FFmpeg na localização que introduziu. O binário FFprobe também é necessário, e deve estar na mesma pasta. Estes componentes são, por norma, instalados em conjunto. Por favor, verifique o caminho da localização e tente novamente.", "Extras": "Extras", "ExtraLarge": "Extra Grande", "EveryNDays": "A cada {0} dias", @@ -750,14 +750,14 @@ "Disconnect": "Desligar", "DirectStreaming": "Reprodução direta", "DirectStreamHelp2": "Reprodução direta de um ficheiro requer pouco processamento e implica uma perda de qualidade mínima.", - "DefaultSubtitlesHelp": "As legendas são carregadas com base nas definições por defeito ou forçado nos metadados. As preferências de idioma são consideradas quando existem múltiplas opções disponíveis.", - "DefaultMetadataLangaugeDescription": "Estes são os valores por defeito que podem ser customizados para cada uma das bibliotecas.", + "DefaultSubtitlesHelp": "As legendas são carregadas com base nas definições padrão ou forçado nos metadados. As preferências de idioma são consideradas quando existem múltiplas opções disponíveis.", + "DefaultMetadataLangaugeDescription": "Estes são os valores padrão que podem ser personalizados para cada uma das bibliotecas.", "ErrorDefault": "Ocorreu um erro a processar o pedido. Por favor, tente novamente mais tarde.", - "Default": "Por defeito", + "Default": "Padrão", "DeathDateValue": "Faleceu: {0}", "DatePlayed": "Reproduzido a", "DateAdded": "Adicionado a", - "MessageContactAdminToResetPassword": "Por favor, contacte o Administrador de sistema para repôr a sua password.", + "MessageContactAdminToResetPassword": "Por favor, contacte o Administrador de sistema para repor a sua palavra-passe.", "MessageConfirmRemoveMediaLocation": "Tem a certeza de que deseja remover esta localização?", "MessageConfirmDeleteTunerDevice": "Tem a certeza de que deseja remover este dispositivo?", "UserAgentHelp": "Forneça um user-agent HTTP personalizado.", @@ -805,7 +805,7 @@ "MediaInfoChannels": "Canais", "MapChannels": "Mapear Canais", "LabelChannels": "Canais:", - "XmlTvPathHelp": "Caminho para um ficheiro XMLTV. O Servidor Jellyfin vai ler o ficheiro periodicamente para atualizar a programação de TV. O utilizador é responsável pela crição e atualização do ficheiro.", + "XmlTvPathHelp": "Caminho para um ficheiro XMLTV. O Jellyfin vai ler o ficheiro periodicamente para atualizar a programação da TV. O utilizador é responsável pela criação e atualização do ficheiro.", "TV": "TV", "LiveTV": "TV em Direto", "LabelSelectFolderGroups": "Agrupar automaticamente o conteúdo das seguintes pastas em vistas como Filmes, Música e TV:", @@ -845,7 +845,7 @@ "PlayAllFromHere": "Reproduzir todos a partir daqui", "PerfectMatch": "Correspondência perfeita", "People": "Pessoas", - "PasswordResetProviderHelp": "Selecione um fornecedor de reposição de senha a ser usado quando um utilizador solicitar a reposição da sua senha.", + "PasswordResetProviderHelp": "Selecione um fornecedor de reposição de palavra-passe a ser usado quando um utilizador solicitar a reposição da sua palavra-passe.", "PackageInstallFailed": "Instalação de {0} (version {1}) falhou.", "PackageInstallCompleted": "Instalação de {0} (version {1}) terminada.", "PackageInstallCancelled": "Instalação de {0} (version {1}) cancelada.", @@ -859,7 +859,7 @@ "HeaderOnNow": "No Ar", "Unplayed": "Por reproduzir", "RemoveFromPlaylist": "Remover da lista de reprodução", - "LabelUserRemoteClientBitrateLimitHelp": "Esta opção irá sobrepor-se ao valor global por defeito nas definições de reprodução do servidor.", + "LabelUserRemoteClientBitrateLimitHelp": "Esta opção irá sobrepor-se ao valor global predefinido nas definições de reprodução do servidor.", "MarkUnplayed": "Marcar como Não Visto", "MarkPlayed": "Marcar como Visto", "LabelSelectFolderGroupsHelp": "Pastas não selecionadas serão apresentadas sozinhas, na sua própria vista.", @@ -888,7 +888,7 @@ "Raised": "Alto relevo", "Depressed": "Baixo relevo", "OptionEnableExternalContentInSuggestionsHelp": "Permitir que trailers da Internet e programas de TV em Direto sejam incluídos no conteúdo sugerido.", - "H264CrfHelp": "O parâmetro \\\"Constant Rate Factor (CRF)\\\" é o que define por defeito o nível de qualidade para o codificador x264. Os valores aceites são entre 0 e 51, em que valores mais baixos resultam em maior qualidade (com o custo de ficheiros maiores). Os valores considerados aceitáveis estão entre 18 e 28. O valor por defeito é 23, podendo ser considerado um ponto de partida para ajustes.", + "H264CrfHelp": "O parâmetro \\\"Constant Rate Factor (CRF)\\\" é o que define o nível de qualidade padrão para o codificador x264. Os valores aceites são entre 0 e 51, em que valores mais baixos resultam numa maior qualidade (a custo de ficheiros de maior dimensão). Os valores considerados aceitáveis estão entre 18 e 28. O valor padrão é 23, podendo ser considerado um ponto de partida para ajustes.", "TabStreaming": "Transmissão", "SimultaneousConnectionLimitHelp": "Número máximo de transmissões permitido. Zero equivale a sem limite.", "LabelSimultaneousConnectionLimit": "Limite de transmissões simultâneas:", @@ -903,7 +903,7 @@ "Directors": "Realização", "ButtonAddImage": "Adicionar Imagem", "LabelOriginalTitle": "Título original:", - "LabelPostProcessorArgumentsHelp": "Utilizar o caminho {path} como caminho para o ficheiro de gravação.", + "LabelPostProcessorArgumentsHelp": "Utilizar {path} como caminho para o ficheiro de gravação.", "Hide": "Esconder", "LabelBaseUrl": "URL Base:", "LabelNewName": "Novo nome:", @@ -926,14 +926,14 @@ "LabelBaseUrlHelp": "Adiciona uma sub-pasta personalizada ao URL do servidor. Por exemplo: http://exemplo.com/<baseurl>", "LabelMoviePrefixHelp": "Se aplicar um prefixo aos títulos dos filmes, introduza-o aqui para que o servidor consiga tratá-los corretamente.", "LabelPleaseRestart": "As alterações produzirão efeito depois de recarregar a página web.", - "LabelRecordingPathHelp": "Especifique a localização por defeito para guardar as gravações. Se for deixado em branco, será utilizada a pasta base do servidor.", + "LabelRecordingPathHelp": "Especifique a localização predefinida para guardar as gravações. Se for deixado em branco, será utilizada a pasta base do servidor.", "ColorTransfer": "Transferência de cores", "ExtractChapterImagesHelp": "Extrair imagens do capítulo permite aos clientes apresentar menus de seleção de cenas com gráficos. O processo poderá ser lento e exigente em recursos, bem como ocupar múltiplos gigabytes em disco. Este processo é corrido quando novos vídeos são encontrados e também através de uma tarefa agendada noturna. É possível configurar a hora de execução para que, idealmente, não coincida com horas de maior utilização.", "Features": "Funcionalidades", "HeaderMusicQuality": "Qualidade da Música", "HeaderMyDevice": "O Meu Dispositivo", "HeaderSortBy": "Ordenar Por", - "LabelOptionalNetworkPathHelp": "Caso a pasta esteja partilhada, fornecer o caminho de rede pode permitir aos clientes aceder diretamente aos ficheiros multimédia. For example, {0} or {1}.", + "LabelOptionalNetworkPathHelp": "Caso a pasta esteja partilhada, fornecer o caminho de rede pode permitir aos clientes aceder diretamente aos ficheiros multimédia. Por exemplo, {0} ou {1}.", "LabelPersonRoleHelp": "Exemplo: motorista da carrinha de gelados", "LabelPlayer": "Reprodutor:", "LabelServerName": "Nome do servidor:", @@ -959,7 +959,7 @@ "LabelKidsCategories": "Categorias para crianças:", "LabelMovieCategories": "Categorias para filmes:", "LabelMoviePrefix": "Prefixo para filmes:", - "LabelMovieRecordingPath": "Caminho para gravação de filmes:", + "LabelMovieRecordingPath": "Localização para gravação de filmes:", "LabelNewsCategories": "Categorias para notícias:", "LabelNumber": "Número:", "LabelPlayMethod": "Método de reprodução:", @@ -969,9 +969,9 @@ "LabelProfileCodecs": "Codecs:", "LabelReasonForTranscoding": "Razão para transcodificação:", "LabelScreensaver": "Proteção de Ecrã:", - "LabelSeriesRecordingPath": "Caminho para gravação de séries:", + "LabelSeriesRecordingPath": "Localização para gravação de séries:", "ColorPrimaries": "Cores primárias", - "MessageInvalidForgotPasswordPin": "Foi inserido um código PIN inválido ou expirado. Por favor, tente de novo.", + "MessageInvalidForgotPasswordPin": "Foi inserido um código PIN inválido ou expirado. Por favor, tente novamente.", "MessageImageTypeNotSelected": "Por favor, selecione um tipo de imagem da lista.", "MessageImageFileTypeAllowed": "Apenas são suportados ficheiros JPEG ou PNG.", "MessageForgotPasswordInNetworkRequired": "Por favor, volte a tentar o processo de recuperação de palavra-passe quando se encontrar dentro da sua rede local.", @@ -1098,8 +1098,8 @@ "LearnHowYouCanContribute": "Veja como pode contribuir.", "Large": "Grande", "LanNetworksHelp": "Lista separada por vírgulas de endereços IP ou IP/máscara que serão considerados como locais quando se aplicam restrições de largura de banda. Se preenchido, todos os outros endereços serão considerados externos e estarão sujeitos às restrições de largura de banda para dispositivos externos. Se deixado em branco, apenas serão consideradas locais as sub-redes do servidor.", - "LabelffmpegPathHelp": "Caminho para a aplicação ou pasta que contém o ffmgeg.", - "LabelffmpegPath": "Caminho FFmpeg:", + "LabelffmpegPathHelp": "Localização da aplicação ou pasta que contém o ffmgeg.", + "LabelffmpegPath": "Localização FFmpeg:", "LabelYear": "Ano:", "LabelWeb": "Web:", "LabelVideoCodec": "Codec de vídeo:", @@ -1112,7 +1112,7 @@ "LabelUserLoginAttemptsBeforeLockout": "Tentativas de início de sessão falhadas até o utilizador ser bloqueado:", "LabelTranscodingProgress": "Progresso de transcodificação:", "LabelTranscodingFramerate": "Taxa de fotogramas de transcodificação:", - "LabelTranscodePath": "Caminho de transcodificação:", + "LabelTranscodePath": "Localização de transcodificação:", "LabelTrackNumber": "Número da faixa:", "LabelTextColor": "Côr do texto:", "LabelTextBackgroundColor": "Côr de fundo do texto:", @@ -1135,7 +1135,7 @@ "MusicArtist": "Artista de Música", "MusicAlbum": "Álbum de Música", "MoreMediaInfo": "Informações", - "MediaInfoBitrate": "Taxa de Bits", + "MediaInfoBitrate": "Fluxo de bits", "LabelUserAgent": "User-Agent:", "MediaInfoAnamorphic": "Anamórfico", "LabelTranscodes": "Transcodificação:", @@ -1199,25 +1199,25 @@ "MusicLibraryHelp": "Consulte o {0}guia de nomenclatura de música{1}.", "MovieLibraryHelp": "Consulte o {0}guia de nomenclatura de filmes{1}.", "MessageConfirmAppExit": "Quer sair?", - "MediaInfoRefFrames": "Ref quadros", + "MediaInfoRefFrames": "Ref frames", "MediaInfoLayout": "Disposição", "MediaInfoDefault": "Padrão", - "MediaInfoBitDepth": "Bit profundidade", - "Logo": "Logotipo", - "LabelXDlnaDoc": "X-DLNA doc:", - "LabelXDlnaCap": "X-DLNA cap:", + "MediaInfoBitDepth": "Profundidade de bit", + "Logo": "Logótipo", + "LabelXDlnaDoc": "Documentação X-DLNA:", + "LabelXDlnaCap": "Limite X-DLNA:", "LabelVaapiDeviceHelp": "Este é o nó de renderização usado para aceleração de hardware.", "LabelVaapiDevice": "Dispositivo VAAPI:", - "LabelTypeMetadataDownloaders": "{0} transferências de metadados:", + "LabelTypeMetadataDownloaders": "Fornecedores de metadados para {0}:", "LabelTheme": "Tema:", - "LabelTVHomeScreen": "TV modo ecrã de casa:", - "LabelSubtitleDownloaders": "Transferência de legendas:", - "LabelParentNumber": "Número fonte:", - "LabelMetadataSavers": "Formatos de Gravação de Metadados:", - "LabelAudioBitDepth": "Áudio bit quantidade:", + "LabelTVHomeScreen": "Modo TV ecrã inicial:", + "LabelSubtitleDownloaders": "Fornecedores de legendas:", + "LabelParentNumber": "Número da fonte:", + "LabelMetadataSavers": "Formatos de Gravação dos Metadados:", + "LabelAudioBitDepth": "Profundidade do bit de áudio:", "HeaderNavigation": "Navegação", - "EnableStreamLooping": "Auto-cíclico de streams ao vivo", - "Down": "Baixo", + "EnableStreamLooping": "Transmissão direta em auto loop", + "Down": "para baixo", "ButtonSplit": "Dividir", "NoCreatedLibraries": "Parece que ainda não foi criada nenhuma biblioteca. {0} Deseja criar uma biblioteca agora? {1}", "AskAdminToCreateLibrary": "Pergunte a um administrador para criar uma biblioteca.", @@ -1289,9 +1289,9 @@ "LabelSubtitleVerticalPosition": "Posição vertical:", "ClearQueue": "Limpar fila", "StopPlayback": "Parar reprodução", - "LabelTonemappingAlgorithm": "Selecione o algoritmo de mapeamento de tonalidade a usar:", - "EnableTonemapping": "Ativar mapeamento de tonalidade", - "LabelOpenclDeviceHelp": "Este é o dispositivo OpenCL usado para o mapeamento de tonalidades. O lado esquerdo do ponto representa o número da plataforma e no lado direito é representado o número do dispositivo na plataforma. O valor padrão é 0.0. É necessário o ficheiro da aplicação ffmpeg que contêm o método de aceleração por hardware OpenCL.", + "LabelTonemappingAlgorithm": "Selecione o algoritmo de Tone mapping a usar:", + "EnableTonemapping": "Ativar Tone mapping", + "LabelOpenclDeviceHelp": "Este é o dispositivo OpenCL usado para o Tone Mapping. O lado esquerdo do ponto representa o número da plataforma e no lado direito é representado o número do dispositivo na plataforma. O valor padrão é 0.0. É necessário o ficheiro da aplicação ffmpeg que contem o método de aceleração por hardware OpenCL.", "LabelOpenclDevice": "Dispositivo OpenCL:", "LabelColorPrimaries": "Cor primária:", "LabelColorTransfer": "Transferência de cor:", @@ -1316,7 +1316,7 @@ "PersonRole": "como {0}", "ListPaging": "{0}-{1} de {2}", "WriteAccessRequired": "O Jellyfin necessita de acesso de escrita a esta pasta. Garanta acesso de escrita e tente novamente.", - "PathNotFound": "O caminho não foi encontrado. Verifique se o caminho é válido e tente novamente.", + "PathNotFound": "A localização não foi encontrada. Verifique se o caminho é válido e tente novamente.", "Writers": "Argumentistas", "ViewAlbumArtist": "Ver artista do álbum", "Video": "Vídeo", @@ -1341,7 +1341,7 @@ "Season": "Temporada", "SaveChanges": "Guardar alterações", "Restart": "Reiniciar", - "ResetPassword": "Repor Senha", + "ResetPassword": "Repor Palavra-passe", "RefreshDialogHelp": "Os metadados são atualizados consoante as configurações e serviços de internet ativos no Painel Principal.", "QuickConnectNotActive": "O Quick Connect não está ativo neste servidor", "QuickConnectNotAvailable": "Solicite a ativação do Quick Connect ao administrador do servidor", @@ -1401,5 +1401,18 @@ "LabelIconMaxResHelp": "Resolução máxima dos ícones expostos através da propriedade upnp:icon.", "LabelCurrentStatus": "Ponto da situação:", "KnownProxiesHelp": "Lista de endereços IP, separada por virgulas, de proxies conhecidas que são usadas ao ligar à sua instância Jellyfin. É necessário para usar adequadamente o cabeçalho X-Forwarded-For. Requer reinicio após alterar.", - "Image": "Imagem" + "Image": "Imagem", + "LabelTonemappingParamHelp": "Afine o algoritmo do Tone mapping. Os valores recomendado e padrão são NaN. Geralmente este campo é deixado em branco.", + "LabelTonemappingParam": "Parâmetros do Tonemapping:", + "LabelTonemappingPeakHelp": "Sobrepor este valor ao pico de sinal/nominal/referência. Útil quando a informação de pico embutida nos metadados de visualização não é fiável ou quando o Tone mapping alterna de um intervalo mais pequeno para um maior.", + "LabelTonemappingPeak": "Pico do Tonemapping:", + "LabelTonemappingThresholdHelp": "Os parâmetros do algoritmo de Tonemapping são afinados a cada cena. E é aplicado um limite para detetar se a cena mudou ou não. Caso a distancia entre o brilho médio atual do frame e a média atual de execução excedam o valor do limite, o brilho médio e o pico de brilho da cena serão recalculados. Os valores recomendado e padrão são 0.8 e 0.2 respetivamente.", + "LabelTonemappingThreshold": "Limite do Tonemapping:", + "LabelTonemappingDesatHelp": "Aplicar dessaturação em partes claras da imagem que excedam este nível de brilho. Quanto maior o parâmetro, mais informação de cor será preservada. Esta definição ajuda a prevenir cores excessivamente claras tornando-as (suavemente) em branco. Produz imagens mais naturais devido à redução de informação sobre cores fora do espectro. Os valores recomendado e padrão são 0 e 0.5 respetivamente.", + "TonemappingRangeHelp": "Selecione o intervalo de cores de saída. A opção Auto mantém o intervalo de cores de entrada.", + "SmallCaps": "Maiúsculas reduzidas", + "LabelTonemappingRange": "Alcance do Tone mapping :", + "TonemappingAlgorithmHelp": "O Tone mapping pode ser afinado. Se não está familiarizado com estas opções mantenha os valores padrão. O valor recomendado é Reinhard.", + "AllowTonemappingHelp": "O Tone mapping permite transformar o alcance dinâmico de um vídeo de HDR para SDR mantendo as cores e detalhes da imagem, que é informação importante para representar a cena original. Atualmente apenas funciona durante a transcodificação de vídeos com metadados HDR10 ou HLG embutidos. Caso a reprodução não seja suave ou falhe, considere desligar o descodificador de hardware correspondente.", + "LabelMaxMuxingQueueSizeHelp": "Número máximo de pacotes armazenados em buffer enquanto aguardam que todas a transmissões iniciem. Tente aumentá-lo caso se depare com o seguinte erro nos logs do ffmpeg \"Too many packets buffered for output stream\". O valor recomendado é 2048." } From 97fc71ea7abe20848dee8e150cd0784f82e27db2 Mon Sep 17 00:00:00 2001 From: Lucas Ono Date: Sun, 11 Oct 2020 11:30:16 +0000 Subject: [PATCH 276/281] Translated using Weblate (Portuguese (Brazil)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/pt_BR/ --- src/strings/pt-br.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/strings/pt-br.json b/src/strings/pt-br.json index 6947772ba2..0fc5e3a6ff 100644 --- a/src/strings/pt-br.json +++ b/src/strings/pt-br.json @@ -1399,5 +1399,7 @@ "LabelQuickConnectCode": "Código de conexão rápida:", "LabelKnownProxies": "Proxies conhecidos:", "KnownProxiesHelp": "Lista de endereços IPs, separados por vírgula, de proxies conhecidos usados para conectar na sua instância do Jellyfin. Isso é necessário para usar de forma adequada os cabeçalhos X-Forwarded-for. Essa alteração necessita que o sistema seja reiniciado após salvar.", - "EnableAutoCast": "Definir como padrão" + "EnableAutoCast": "Definir como padrão", + "ThumbCard": "Card da miniatura", + "OptionMaxActiveSessionsHelp": "O valor 0 desativa esta funcão." } From 59325b68a026259aea67404c1e1104679a0de634 Mon Sep 17 00:00:00 2001 From: CutterXYZ Date: Mon, 12 Oct 2020 12:55:20 +0000 Subject: [PATCH 277/281] Translated using Weblate (French) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fr/ --- src/strings/fr.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/strings/fr.json b/src/strings/fr.json index cdab1cb32c..3e2720e006 100644 --- a/src/strings/fr.json +++ b/src/strings/fr.json @@ -810,7 +810,7 @@ "MetadataSettingChangeHelp": "Les modifications des paramètres des métadonnées auront une incidence sur le nouveau contenu ajouté. Pour actualiser le contenu existant, ouvrez l'écran des détails et cliquez sur le bouton Actualiser, ou effectuez des actualisations en masse en utilisant le gestionnaire de métadonnées.", "MinutesAfter": "minutes après", "MinutesBefore": "minutes avant", - "Mobile": "Pour appareil Mobile", + "Mobile": "Mobile", "Monday": "Lundi", "MoreFromValue": "Plus de {0}", "MoreUsersCanBeAddedLater": "D'autres utilisateurs pourront être ajoutés ultérieurement à partir du tableau de bord.", @@ -1322,8 +1322,8 @@ "MessageSyncPlayErrorAccessingGroups": "Une erreur s'est produite pendant l'accès à la liste de groupes.", "ShowMore": "Voir plus", "ShowLess": "Voir moins", - "EnableBlurHashHelp": "Les images qui sont encore en cours de chargement seront remplacées par une image générique floue.", - "EnableBlurHash": "Utilise des images génériques floues à la place des images", + "EnableBlurHashHelp": "Les images en cours de chargement seront remplacées par une image générique floue.", + "EnableBlurHash": "Images floues de substitution", "ButtonCast": "Diffuser", "ButtonSyncPlay": "SyncPlay", "TabRepositories": "Dépôts", @@ -1342,7 +1342,7 @@ "ClearQueue": "Vider la file d'attente", "StopPlayback": "Arrêter", "ButtonPlayer": "Démarrer", - "Writers": "Écrivains", + "Writers": "Scénaristes", "ViewAlbumArtist": "Voir l'album de l'artiste", "PreviousTrack": "Revenir au précédent", "NextTrack": "Passer au prochain", From db160c3ecce0bff0cb32aaf198f7674d5d35f586 Mon Sep 17 00:00:00 2001 From: RiddleDude Date: Mon, 12 Oct 2020 18:25:11 +0000 Subject: [PATCH 278/281] Translated using Weblate (Latvian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/lv/ --- src/strings/lv.json | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/strings/lv.json b/src/strings/lv.json index 7ff61f2498..563acbab71 100644 --- a/src/strings/lv.json +++ b/src/strings/lv.json @@ -173,7 +173,7 @@ "LabelEnableDlnaServer": "Iespējot DLNA serveri", "LabelEnableDlnaPlayTo": "Iespējot DLNA atskaņošanu uz", "LabelEnableDlnaDebugLogging": "Iespējot DLNA atkļūdošanas logošanu", - "LabelEnableDlnaClientDiscoveryInterval": "Klientu meklēšanas intervāls (sekundes)", + "LabelEnableDlnaClientDiscoveryInterval": "Klientu meklēšanas intervāls", "LabelEasyPinCode": "Vieglais pin kods:", "LabelDownloadLanguages": "Lejupielādēt valodas:", "LabelDisplayOrder": "Displeja kārtojums:", @@ -202,7 +202,7 @@ "LabelBirthYear": "Dzimšanas gads:", "LabelBirthDate": "Dzimšanas datums:", "LabelAudioLanguagePreference": "Ieteicamā audio valoda:", - "LabelArtistsHelp": "Atdali vairākus izmantojot ;", + "LabelArtistsHelp": "Atdali vairākus izpildītājus izmantojot semikolu", "LabelArtists": "Izpildītājs:", "LabelAppNameExample": "Piemēram: Sickbeard, Sonarr", "LabelAppName": "Lietotnes nosaukums", @@ -510,7 +510,7 @@ "AlwaysPlaySubtitles": "Vienmēr Rādīt", "AllowedRemoteAddressesHelp": "Ar komatiem atdalīts IP adrešu vai IP/tīkla masku saraksts, kas norāda uz tīkliem, kas var pieslēgties attālināti. Ja atstāts tukšs, visas attālinātās adreses tiks atļautas.", "AllowRemoteAccessHelp": "Ja atķeksēts, visi attālinātie savienojumi tiks bloķēti.", - "AllowRemoteAccess": "Atļaut attālinātus savienojumus šim Jellyfin Serverim.", + "AllowRemoteAccess": "Atļaut attālinātus savienojumus ar šo serveri", "AllowOnTheFlySubtitleExtraction": "Atļaut subtitru izvilkšanu atskaņošanas laikā", "AllowMediaConversion": "Atļaut multimēdiju pārveidošanu", "AllLibraries": "Visas bibliotēkas", @@ -723,7 +723,7 @@ "ErrorSavingTvProvider": "Kļūda saglabājot TV sniedzēju. Pārliecinies ka tas ir pieejams un mēģini vēlreiz.", "ErrorStartHourGreaterThanEnd": "Beigu laikam jābūt vēlākam par sākuma laiku.", "ErrorAddingXmlTvFile": "Kļūda atverot XMLTV datni. Lūdzu pārliecinies ka datne eksistē un mēģini vēlreiz.", - "LabelCustomCssHelp": "Izmanto pats savu pielāgoto silu web interfeisam.", + "LabelCustomCssHelp": "Izmanto pats savu pielāgoto stilu tīmekļa saskarnei.", "LabelCustomCss": "Pielāgots CSS:", "LabelCustomCertificatePath": "Pielāgotā SSL sertifikāta ceļš:", "LabelCorruptedFrames": "Bojātie kadri:", @@ -741,11 +741,11 @@ "LabelAlbumArtMaxWidth": "Albumu vāku maksimālais platums:", "LabelAlbumArtMaxHeight": "Albumu vāku maksimālais augstums:", "LabelAbortedByServerShutdown": "(Atcelts dēļ servera izslēgšanas)", - "ImportFavoriteChannelsHelp": "Ja iespējots, tikai kanāli, kas atzīmēti kā favorīti uztvērēja ierīcē tiks importēti.", + "ImportFavoriteChannelsHelp": "Tikai kanāli, kas atzīmēti kā favorīti uztvērēja ierīcē tiks importēti.", "HttpsRequiresCert": "Lai iespējotu drošos savienojumus, tev ir jānodrošina uzticams SSL sertifikāts, kā Let's Encrypt. Lūdzu nodrošini sertifikātu, vai atspējo drošos savienojumus.", "HeaderTranscodingProfileHelp": "Pievieno tiešās atskaņošanas profilus, lai norādītu kurus formātus izmantot kad ir vajadzīga trans-kodēšana.", "HeaderTaskTriggers": "Uzdevumu Trigeri", - "HeaderSelectTranscodingPathHelp": "Pārlūko vai ievadi ceļu, kurā tiks glabātas īslaicīgās trans-kodēšanas datnes. Šai mapei jābūt rakstāmai.", + "HeaderSelectTranscodingPathHelp": "Pārlūko vai ievadi ceļu, kurā tiks glabātas trans-kodēšanas datnes. Šai mapei jābūt rakstāmai.", "HeaderSelectTranscodingPath": "Izvēlies Trans-kodēšanas Īslaicīgo Ceļu", "HeaderSelectServerCachePathHelp": "Pārlūko vai ievadi ceļu, kurā vēlies saglabāt servera keša datnes. Šai mapei jābūt rakstāmai.", "HeaderSelectPath": "Izvēlies Ceļu", @@ -799,7 +799,7 @@ "DropShadow": "Fona Ēnojums", "DisplayMissingEpisodesWithinSeasons": "Rādīt trūkstošās epizodes sezonās", "Disconnect": "Atvienot", - "DirectStreamHelp2": "Tieši Straumējot datni tiek izmantots ļoti maz procesora jaudas, bez video vai audio kvalitātes zudumiem.", + "DirectStreamHelp2": "Tieši Straumējot datni, tiek izmantots ļoti maz procesora jaudas un rodas minimāli video kvalitātes zudumi.", "DirectStreamHelp1": "Šis medijs ir saderīgs ar ierīci pēc izšķirtspējas un medija veida (H.264, AC3, utt.), bet atrodas nesaderīgā datnes konteinerī (mkv, avi, wmv, utt.). Video tiks pārpakots uz saderīgu formātu pirms tas tiks straumēts uz ierīci.", "Descending": "Disltošs", "Depressed": "Atspiests", @@ -813,7 +813,7 @@ "ConfirmEndPlayerSession": "Vai jūs gribat izslēgt Jellyfin uz {0}?", "ConfirmDeleteItems": "Dzēšot šos vienumus, tie tiks izdzēsti gan no jūsu failu sistēmas, gan mediju bibliotēkas. Vai tiešām turpināt?", "ConfirmDeleteItem": "Dzēšot šo vienumu, tas tiks izdzēsts gan no jūsu failu sistēmas, gan mediju bibliotēkas. Vai tiešām turpināt?", - "ConfigureDateAdded": "Iestati kā pievienošanas datums tiek noteikts iekš Jellyfin Server pārvaldes paneļa zem Bibliotēkas iestatījumiem", + "ConfigureDateAdded": "Konfigurēt kā pievienošanas datums tiek noteikts iekš pārvaldes paneļa zem Bibliotēkas iestatījumiem", "Composer": "Komponists", "ColorSpace": "Krāsu telpa", "ColorPrimaries": "Primārās krāsas", @@ -829,7 +829,7 @@ "ButtonAddScheduledTaskTrigger": "Pievienot Trigeru", "BookLibraryHelp": "Audio un teksta grāmatas tiek atbalstītas. Pārskati {0} grāmatu nosaukumu instrukciju {1}.", "Blacklist": "Melnais saraksts", - "AuthProviderHelp": "Izvēlies Autentifikācijas Nodrošinājumu, kas tiks izmantots lai autentificētu šī lietotāja paroli.", + "AuthProviderHelp": "Izvēlies autentifikācijas nodrošinājumu, kas tiks izmantots lai autentificētu šī lietotāja paroli.", "AspectRatio": "Attēla Proporcijas", "AskAdminToCreateLibrary": "Vaicājiet administratoram, lai izveidotu bibliotēku.", "Ascending": "Augoši", @@ -916,7 +916,7 @@ "LabelBaseUrl": "Pamata URL:", "LabelEnableSingleImageInDidlLimitHelp": "Dažas ierīces pareizi neatskaņos ja vairāki attēli ir iegulti iekš Didl.", "LabelEnableSingleImageInDidlLimit": "Ierobežot uz vienu iegulto attēlu", - "LabelEnableDlnaClientDiscoveryIntervalHelp": "Nosaka laiku sekundēs starp Jellyfin veiktajiem SSDP meklējumiem.", + "LabelEnableDlnaClientDiscoveryIntervalHelp": "Nosaka laiku sekundēs veiktajiem SSDP meklējumiem.", "LabelEmbedAlbumArtDidlHelp": "Dažas ierīces labprātāk izmanto šo metodi lai saņemtu albumu vākus. Citas var neatskaņot ar šo opciju ieslēgtu.", "LabelDroppedFrames": "Nomestie kadri:", "LabelDownMixAudioScaleHelp": "Pastiprināt audio lejupmiksēšanas laikā. Vērtība viens paturēs oriģinālo skaļumu.", @@ -935,7 +935,7 @@ "ApiKeysCaption": "Saraksts ar pašlaik iespējotajām API atslēgām", "EncoderPresetHelp": "Izvēlies ātrāku vērtību lai uzlabotu veiktspēju, vai lēnāku vērtību lai uzlabotu kvalitāti.", "FetchingData": "Iegūst papildu datus", - "ErrorDeletingItem": "Notika kļūda dzēšot vienumu no Jellyfin Servera. Lūdzu pārliecinies vai Jellyfin Server ir rakstoša piekļuve pie satura mapes un mēģini vēlreiz.", + "ErrorDeletingItem": "Notika kļūda dzēšot vienumu no servera. Lūdzu pārliecinies vai Jellyfin ir rakstoša piekļuve pie satura mapes un mēģini vēlreiz.", "ErrorAddingTunerDevice": "Kļūda pievienojot tūnera ierīci. Lūdzu pārliecinies ka tā ir pieejama un mēģini vēlreiz.", "ErrorAddingMediaPathToVirtualFolder": "Notika kļūda pievienojot satura ceļu. Lūdzu pārliecinies ka ceļš ir derīgs un ka Jellyfin Servera procesam ir piekļuve tai vietai.", "Episode": "Epizode", @@ -1028,5 +1028,25 @@ "LabelEmbedAlbumArtDidl": "Ievietot albumu vākus iekš Didl", "LabelSelectFolderGroups": "Automātiski grupēt saturu no sekojošām datnēm skatos kā Filmas, Mūzika un TV:", "AllowFfmpegThrottlingHelp": "Kad trans-kodējums vai remux tiek pietiekami tālu priekšā pašreizējai atskaņošanas vietai, process tiks pauzēts lai patērētu mazāk resursu. Tas ir noderīgākais skatoties bez biežas pārlēkšanas. Atspējo šo ja saskaries ar atskaņošanas problēmām.", - "ButtonSyncPlay": "SyncPlay" + "ButtonSyncPlay": "SyncPlay", + "LabelCustomRating": "Pielāgotais vērtējums:", + "LabelCurrentStatus": "Pašreizējais status:", + "LabelAudioBitDepth": "Audio bitu dziļums:", + "LabelAlbumArtMaxResHelp": "Maksimālā albuma vāka izšķirtspēja, kas padota izmantojot upnp:albumArtURI rekvizītu.", + "InstantMix": "Tūlītēja jaukšana", + "Image": "Attēls", + "HeaderSyncPlayEnabled": "SyncPlay ieslēgts", + "HeaderSyncPlaySelectGroup": "Pievienoties grupai", + "HeaderServerAddressSettings": "Servera adresācijas iestatījumi", + "EnableQuickConnect": "Ieslēgt šim serverim Quick Connect", + "EnableDecodingColorDepth10Vp9": "Ieslēgt 10 bitu aparatūras dekodēšānu priekš VP9", + "EnableDecodingColorDepth10Hevc": "Ieslēgt 10 bitu aparatūras dekodēšānu priekš HEVC", + "EnableAutoCast": "Iestatīt kā noklusējumu", + "Down": "Uz leju", + "DefaultSubtitlesHelp": "Subtitri tiek izvēlēti atkarībā no iestrādāto metadatu noklusējuma un piespiedu karodziņiem. Valodas preference tiek ņemta vērā, kad pieejamas vairākas iespējas.", + "Data": "Dati", + "ButtonUseQuickConnect": "Izmantot Quick Connect", + "ButtonActivate": "Aktivizēt", + "BoxSet": "Komplekts", + "Authorize": "Atļaut" } From b77ef51899ba4bd976102a54f2ed835acdcf3dbb Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 21:27:30 +0000 Subject: [PATCH 279/281] Bump hls.js from 0.14.13 to 0.14.15 Bumps [hls.js](https://github.com/video-dev/hls.js) from 0.14.13 to 0.14.15. - [Release notes](https://github.com/video-dev/hls.js/releases) - [Changelog](https://github.com/video-dev/hls.js/blob/master/docs/release-process.md) - [Commits](https://github.com/video-dev/hls.js/compare/v0.14.13...v0.14.15) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 42bdc9dfcf..82f7a86afd 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "fast-text-encoding": "^1.0.3", "flv.js": "^1.5.0", "headroom.js": "^0.11.0", - "hls.js": "^0.14.13", + "hls.js": "^0.14.15", "howler": "^2.2.0", "intersection-observer": "^0.11.0", "jellyfin-apiclient": "^1.4.2", diff --git a/yarn.lock b/yarn.lock index fa4ef0b676..9eeed0850f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5499,10 +5499,10 @@ hex-color-regex@^1.1.0: resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== -hls.js@^0.14.13: - version "0.14.13" - resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-0.14.13.tgz#824395a0631c8e32bf0e8de06873f1d89774bada" - integrity sha512-0u61R0t6DcgJ7Ofr0RUlfrNrkP2gn5pHL+5clKmITY1P7pztyj5aoVw2/9SbeoM6k4shg5iPyuZb+7I32ZzqFQ== +hls.js@^0.14.15: + version "0.14.15" + resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-0.14.15.tgz#3d41c6a51cef31d2629df2d9ad4333215770febe" + integrity sha512-zKOY9PZVeDBu3iXL6Dg8DfUPDEf71lTyy7JFgCOJXkqV48HeDfNoMhcN1trMrYRtMyFnpA7YBiI8c1DzSdLAFA== dependencies: eventemitter3 "^4.0.3" url-toolkit "^2.1.6" From d73b7b9cb2af6b0bbff693c0b82989a8fef2efd1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 21:28:35 +0000 Subject: [PATCH 280/281] Bump swiper from 6.3.2 to 6.3.3 Bumps [swiper](https://github.com/nolimits4web/Swiper) from 6.3.2 to 6.3.3. - [Release notes](https://github.com/nolimits4web/Swiper/releases) - [Changelog](https://github.com/nolimits4web/swiper/blob/master/CHANGELOG.md) - [Commits](https://github.com/nolimits4web/Swiper/compare/v6.3.2...v6.3.3) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 42bdc9dfcf..d19d1d05f6 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "resize-observer-polyfill": "^1.5.1", "screenfull": "^5.0.2", "sortablejs": "^1.12.0", - "swiper": "^6.3.2", + "swiper": "^6.3.3", "webcomponents.js": "^0.7.24", "whatwg-fetch": "^3.4.1" }, diff --git a/yarn.lock b/yarn.lock index fa4ef0b676..8d60cd9b19 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11024,10 +11024,10 @@ svgo@^1.0.0, svgo@^1.3.2: unquote "~1.1.1" util.promisify "~1.0.0" -swiper@^6.3.2: - version "6.3.2" - resolved "https://registry.yarnpkg.com/swiper/-/swiper-6.3.2.tgz#3eb337ff58f425841a27400a7b0215234d94f3c1" - integrity sha512-mseVNXAsNNSfp3fHuZlMnsToc3ulM3X3on2EC8GMi4+/DwD9SSieSSIQroUbxkIMmCCIvpDN1Ese7o0Ls9I4lw== +swiper@^6.3.3: + version "6.3.3" + resolved "https://registry.yarnpkg.com/swiper/-/swiper-6.3.3.tgz#e0b2e27621c07e789bfa91569b5676e896d18001" + integrity sha512-SnG1weu2GhqKxuG4NTIA1A6OE9x3P/+d2DW6APLUgYNHm0ZgkAOxL/tEDubiHvgwqtaVaz6QWqkSbCaDYffSNg== dependencies: dom7 "^3.0.0-alpha.7" ssr-window "^3.0.0-alpha.4" From 74baf782fa5f4d8078f0a6f684a0744f9d1a2e64 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 21:29:55 +0000 Subject: [PATCH 281/281] Bump file-loader from 6.1.0 to 6.1.1 Bumps [file-loader](https://github.com/webpack-contrib/file-loader) from 6.1.0 to 6.1.1. - [Release notes](https://github.com/webpack-contrib/file-loader/releases) - [Changelog](https://github.com/webpack-contrib/file-loader/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack-contrib/file-loader/compare/v6.1.0...v6.1.1) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- yarn.lock | 34 +++++++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 42bdc9dfcf..aab80fdb73 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.22.1", "eslint-plugin-promise": "^4.2.1", - "file-loader": "^6.1.0", + "file-loader": "^6.1.1", "gulp": "^4.0.2", "gulp-babel": "^8.0.0", "gulp-cli": "^2.3.0", diff --git a/yarn.lock b/yarn.lock index fa4ef0b676..05972380bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -990,6 +990,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== +"@types/json-schema@^7.0.6": + version "7.0.6" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" + integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -1312,6 +1317,16 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.4, ajv@^6.5.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + alameda@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/alameda/-/alameda-1.4.0.tgz#ca53cad0feb5e24994a9be859e0593e8c2d8f58c" @@ -4433,13 +4448,13 @@ file-entry-cache@^5.0.1: dependencies: flat-cache "^2.0.1" -file-loader@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.1.0.tgz#65b9fcfb0ea7f65a234a1f10cdd7f1ab9a33f253" - integrity sha512-26qPdHyTsArQ6gU4P1HJbAbnFTyT2r0pG7czh1GFAd9TZbj0n94wWbupgixZH/ET/meqi2/5+F7DhW4OAXD+Lg== +file-loader@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.1.1.tgz#a6f29dfb3f5933a1c350b2dbaa20ac5be0539baa" + integrity sha512-Klt8C4BjWSXYQAfhpYYkG4qHNTna4toMHEbWrI5IuVoxbU6uiDKeKAP99R8mmbJi3lvewn/jQBOgU4+NS3tDQw== dependencies: loader-utils "^2.0.0" - schema-utils "^2.7.1" + schema-utils "^3.0.0" file-type@5.2.0, file-type@^5.2.0: version "5.2.0" @@ -9954,6 +9969,15 @@ schema-utils@^2.6.5, schema-utils@^2.7.0, schema-utils@^2.7.1: ajv "^6.12.4" ajv-keywords "^3.5.2" +schema-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.0.0.tgz#67502f6aa2b66a2d4032b4279a2944978a0913ef" + integrity sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA== + dependencies: + "@types/json-schema" "^7.0.6" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + screenfull@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.0.2.tgz#b9acdcf1ec676a948674df5cd0ff66b902b0bed7"