From 437729d3f32404c55bf12c15feeff0a59f5a232e Mon Sep 17 00:00:00 2001 From: ckcr4lyf Date: Tue, 27 Aug 2019 17:32:35 +0800 Subject: [PATCH 01/80] Added option, if file is downloadable, copy the URL to clipboard --- src/components/itemcontextmenu.js | 21 +++++++++++++++++++++ src/strings/en-gb.json | 3 ++- src/strings/en-us.json | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/components/itemcontextmenu.js b/src/components/itemcontextmenu.js index 5f649a2b02..dbc73f2da4 100644 --- a/src/components/itemcontextmenu.js +++ b/src/components/itemcontextmenu.js @@ -134,6 +134,11 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter', name: globalize.translate('Download'), id: 'download' }); + + commands.push({ + name: globalize.translate('CopyStreamURL'), + id: 'copy-stream' + }); } var canEdit = itemHelper.canEdit(user, item); @@ -305,6 +310,22 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter', getResolveFunction(getResolveFunction(resolve, id), id)(); }); break; + case 'copy-stream': + var downloadHref = apiClient.getItemDownloadUrl(itemId); + var textArea = document.createElement("textarea"); + textArea.value = downloadHref; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + try { + document.execCommand('copy'); + } catch (err) { + + } + + document.body.removeChild(textArea); + getResolveFunction(resolve, id)(); + break; case 'editsubtitles': require(['subtitleEditor'], function (subtitleEditor) { subtitleEditor.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); diff --git a/src/strings/en-gb.json b/src/strings/en-gb.json index 5873d8ae70..96d5f1851c 100644 --- a/src/strings/en-gb.json +++ b/src/strings/en-gb.json @@ -452,5 +452,6 @@ "HeaderPassword": "Password", "HeaderPasswordReset": "Password Reset", "HeaderPaths": "Paths", - "HeaderPendingInvitations": "Pending Invitations" + "HeaderPendingInvitations": "Pending Invitations", + "CopyStreamURL": "Copy Stream URL" } diff --git a/src/strings/en-us.json b/src/strings/en-us.json index ae8226b4fd..b701cd1f5f 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -160,6 +160,7 @@ "Connect": "Connect", "ContinueWatching": "Continue watching", "Continuing": "Continuing", + "CopyStreamURL": "Copy Stream URL", "CriticRating": "Critic rating", "CustomDlnaProfilesHelp": "Create a custom profile to target a new device or override a system profile.", "DateAdded": "Date added", From 0ea9faee08c4abd654e83cc3520ce28009b4a7d0 Mon Sep 17 00:00:00 2001 From: ckcr4lyf Date: Tue, 27 Aug 2019 17:37:49 +0800 Subject: [PATCH 02/80] Updated contributors.md --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 9ca9b10598..8cc2811d74 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -25,6 +25,7 @@ - [DrPandemic](https://github.com/drpandemic) - [Oddstr13](https://github.com/oddstr13) - [petermcneil](https://github.com/petermcneil) + - [Raghu Saxena](https://github.com/ckcr4lyf) # Emby Contributors From 7d585fde1b0f425c0a07a9615395f232bd431a61 Mon Sep 17 00:00:00 2001 From: ckcr4lyf Date: Tue, 27 Aug 2019 19:20:39 +0800 Subject: [PATCH 03/80] Logging error if copy failed --- src/components/itemcontextmenu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/itemcontextmenu.js b/src/components/itemcontextmenu.js index dbc73f2da4..7348eeef30 100644 --- a/src/components/itemcontextmenu.js +++ b/src/components/itemcontextmenu.js @@ -320,7 +320,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter', try { document.execCommand('copy'); } catch (err) { - + console.error("Failed to copy to clipboard"); } document.body.removeChild(textArea); From 101d0b11395a24d0a9a36c7202e4e78fb55559a6 Mon Sep 17 00:00:00 2001 From: dkanada Date: Sat, 31 Aug 2019 03:12:10 -0700 Subject: [PATCH 04/80] fix layout issues for device cards on dashboard --- src/components/indicators/indicators.js | 1 + src/controllers/dashboardpage.js | 26 +++--- src/css/dashboard.css | 110 +++++++----------------- 3 files changed, 46 insertions(+), 91 deletions(-) diff --git a/src/components/indicators/indicators.js b/src/components/indicators/indicators.js index d9c7af1ab0..2e8d28523e 100644 --- a/src/components/indicators/indicators.js +++ b/src/components/indicators/indicators.js @@ -221,6 +221,7 @@ define(['datetime', 'itemHelper', 'css!./indicators.css', 'material-icons'], fun }); return { + getProgressHtml: getProgressHtml, getProgressBarHtml: getProgressBarHtml, getPlayedIndicatorHtml: getPlayedIndicator, getChildCountIndicatorHtml: getChildCountIndicatorHtml, diff --git a/src/controllers/dashboardpage.js b/src/controllers/dashboardpage.js index 7c443e3087..be3ee9e081 100644 --- a/src/controllers/dashboardpage.js +++ b/src/controllers/dashboardpage.js @@ -1,4 +1,4 @@ -define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globalize", "loading", "connectionManager", "playMethodHelper", "cardBuilder", "imageLoader", "components/activitylog", "scripts/imagehelper", "humanedate", "listViewStyle", "emby-button", "flexStyles", "emby-button", "emby-itemscontainer"], function (datetime, events, itemHelper, serverNotifications, dom, globalize, loading, connectionManager, playMethodHelper, cardBuilder, imageLoader, ActivityLog, imageHelper) { +define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globalize", "loading", "connectionManager", "playMethodHelper", "cardBuilder", "imageLoader", "components/activitylog", "scripts/imagehelper", "indicators", "humanedate", "listViewStyle", "emby-button", "flexStyles", "emby-button", "emby-itemscontainer"], function (datetime, events, itemHelper, serverNotifications, dom, globalize, loading, connectionManager, playMethodHelper, cardBuilder, imageLoader, ActivityLog, imageHelper, indicators) { "use strict"; function buttonEnabled(elem, enabled) { @@ -249,20 +249,19 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa html += '
'; html += '
'; html += '
'; - var imgUrl = DashboardPage.getNowPlayingImageUrl(nowPlayingItem); + var imgUrl = DashboardPage.getNowPlayingImageUrl(nowPlayingItem); if (imgUrl) { html += '
"; } else { - html += '
"; html += "
"; html += "
"; - html += '
' + DashboardPage.getSessionNowPlayingTime(session) + "
"; if (session.TranscodingInfo && session.TranscodingInfo.Framerate) { html += '
' + session.TranscodingInfo.Framerate + " fps
"; @@ -280,20 +278,22 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa html += '
'; } + html += '
' var nowPlayingName = DashboardPage.getNowPlayingName(session); html += '
'; html += nowPlayingName.html; html += "
"; + html += '
' + DashboardPage.getSessionNowPlayingTime(session) + "
"; + html += '
' + if (nowPlayingItem && nowPlayingItem.RunTimeTicks) { - html += ''; - } else { - html += ''; + var percent = 100 * (session.PlayState.PositionTicks || 0) / nowPlayingItem.RunTimeTicks; + html += indicators.getProgressHtml(percent, { containerClass: "playbackProgress" }); } if (session.TranscodingInfo && session.TranscodingInfo.CompletionPercentage) { - html += ''; - } else { - html += ''; + var percent = session.TranscodingInfo.CompletionPercentage.toFixed(1); + html += indicators.getProgressHtml(percent, { containerClass: "transcodingProgress" }); } html += "
"; diff --git a/src/css/dashboard.css b/src/css/dashboard.css index 8ee6c69c8d..b07adc96ef 100644 --- a/src/css/dashboard.css +++ b/src/css/dashboard.css @@ -272,10 +272,9 @@ div[data-role=controlgroup] a.ui-btn-active { position: relative } -.sessionAppInfo, -.sessionNowPlayingInfo { - padding: .5em; - overflow: hidden +.sessionAppInfo { + padding: 0.5em; + overflow: hidden; } .sessionCardButtons { @@ -317,105 +316,60 @@ div[data-role=controlgroup] a.ui-btn-active { max-width: 200px } -.sessionNowPlayingInfo { +.sessionNowPlayingDetails { + display: flex; position: absolute; - left: 0; - bottom: 11px; - max-width: 50%; - -o-text-overflow: ellipsis; - text-overflow: ellipsis + bottom: 0px; + width: 100%; +} + +.sessionNowPlayingInfo { + flex-grow: 1; + text-overflow: ellipsis; + padding: 0.8em 0.5em; } .sessionAppInfo img { - max-width: 32px; - max-height: 32px; - margin-right: 5px -} - -.activeSession .playbackProgress { - position: absolute; - right: 0; - bottom: 0; - left: 0; - height: 7px; - width: 100%; - opacity: .95 -} - -.activeSession:not(.playingSession) .sessionNowPlayingInfo { - bottom: 0 + max-width: 40px; + max-height: 40px; + margin-right: 8px; } .sessionNowPlayingTime { - position: absolute; - right: 10px; - bottom: 19px + flex-shrink: 0; + align-self: flex-end; + text-overflow: ellipsis; + padding: 0.8em 0.5em; } .sessionNowPlayingStreamInfo { - white-space: nowrap + white-space: nowrap; } +.activeSession .playbackProgress, .activeSession .transcodingProgress { + position: absolute; right: 0; bottom: 0; left: 0; - height: 5px; + height: 6px; width: 100%; - opacity: .9; - position: absolute } .playbackProgress, .transcodingProgress { - appearance: none; - -moz-appearance: none; - -webkit-appearance: none; - margin: 0 5px 0 0; - height: 14px; - border: 0 solid #222; - -webkit-border-radius: 0; - border-radius: 0; - width: 50px; - background: #000 !important + margin: 0px; + width: 100%; + background: transparent !important; } -.playbackProgress::-webkit-progress-bar, -.transcodingProgress::-webkit-progress-bar { - background: #000 +.playbackProgress > div { + z-index: 1000; + background-color: #00a4dc; } -.transcodingSession .playbackProgress { - bottom: 5px -} - -.transcodingProgress::-moz-progress-bar { - border-radius: .3em; - background-color: #dd4919 -} - -.transcodingProgress::-webkit-progress-value { - -webkit-border-radius: .3em; - border-radius: .3em; - background-color: #dd4919 -} - -.transcodingProgress[aria-valuenow]:before { - -webkit-border-radius: .3em; - border-radius: .3em; - background-color: #dd4919 -} - -.playbackProgress::-moz-progress-bar { - background-color: #00a4dc -} - -.playbackProgress::-webkit-progress-value { - background-color: #00a4dc -} - -.playbackProgress[aria-valuenow]:before { - background-color: #00a4dc +.transcodingProgress > div { + background-color: #dd4919; } @media all and (max-width:34.375em) { From 2ffbc14cd7170cb7757954f10dbceb69c930759e Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Sat, 31 Aug 2019 17:41:56 +0300 Subject: [PATCH 05/80] add icon to metadata side bar --- src/css/metadataeditor.css | 6 +- src/scripts/editorsidebar.js | 347 +++++++++++++++++++++++------------ 2 files changed, 235 insertions(+), 118 deletions(-) diff --git a/src/css/metadataeditor.css b/src/css/metadataeditor.css index abc5668b24..542c7c8f2b 100644 --- a/src/css/metadataeditor.css +++ b/src/css/metadataeditor.css @@ -47,6 +47,10 @@ background: #00a4dc !important } +.metadataSidebarIcon { + margin-right: .4em +} + @media all and (min-width:50em) { .editPageSidebar { position: fixed; @@ -72,4 +76,4 @@ .editPageInnerContent { width: 73.5% } -} \ No newline at end of file +} diff --git a/src/scripts/editorsidebar.js b/src/scripts/editorsidebar.js index e39fc23a21..0477dedcfc 100644 --- a/src/scripts/editorsidebar.js +++ b/src/scripts/editorsidebar.js @@ -1,4 +1,4 @@ -define(["datetime", "jQuery", "material-icons"], function(datetime, $) { +define(["datetime", "jQuery", "material-icons"], function (datetime, $) { "use strict"; function getNode(item, folderState, selected) { @@ -7,7 +7,7 @@ define(["datetime", "jQuery", "material-icons"], function(datetime, $) { id: item.Id, text: htmlName, state: { - opened: item.IsFolder && "open" == folderState, + opened: item.IsFolder && folderState == "open", selected: selected }, li_attr: { @@ -15,211 +15,324 @@ define(["datetime", "jQuery", "material-icons"], function(datetime, $) { collectiontype: item.CollectionType } }; - return item.IsFolder ? (node.children = [{ - text: "Loading...", - icon: !1 - }], node.icon = !1) : node.icon = !1, node.state.opened && (node.li_attr.loadedFromServer = !0), selected && (selectedNodeId = item.Id), node + if (item.IsFolder) { + node.children = [{ + text: "Loading...", + icon: false + }]; + node.icon = false; + } else { + node.icon = false; + } + if (node.state.opened) { + node.li_attr.loadedFromServer = true; + } + if (selected) { + selectedNodeId = item.Id; + } + return node; } function getNodeInnerHtml(item) { var name = item.Name; - item.Number && (name = item.Number + " - " + name), null != item.IndexNumber && "Season" != item.Type && (name = item.IndexNumber + " - " + name); + if (item.Number) { + name = item.Number + " - " + name; + } + if (item.IndexNumber != null && item.Type != "Season") { + name = item.IndexNumber + " - " + name; + } var htmlName = "
"; - return item.LockData && (htmlName += 'lock'), htmlName += name, htmlName += "
" + if (item.IsFolder) { + htmlName += 'folder'; + } + else if (item.MediaType === "Video") { + htmlName += 'movie'; + } + else if (item.MediaType === "Audio") { + htmlName += 'audiotrack'; + } + else if (item.Type === "TvChannel") { + htmlName += 'live_tv'; + } + else if (item.MediaType === "Photo") { + htmlName += 'photo'; + } + else if (item.MediaType === "Book") { + htmlName += 'book'; + } + if (item.LockData) { + htmlName += 'lock'; + } + htmlName += name; + htmlName += ""; + return htmlName; } function loadChildrenOfRootNode(page, scope, callback) { ApiClient.getLiveTvChannels({ limit: 0 - }).then(function(result) { + }).then(function (result) { var nodes = []; nodes.push({ id: "MediaFolders", text: Globalize.translate("HeaderMediaFolders"), state: { - opened: !0 + opened: true }, li_attr: { itemtype: "mediafolders", - loadedFromServer: !0 + loadedFromServer: true }, - icon: !1 - }), result.TotalRecordCount && nodes.push({ - id: "livetv", - text: Globalize.translate("HeaderLiveTV"), - state: { - opened: !1 - }, - li_attr: { - itemtype: "livetv" - }, - children: [{ - text: "Loading...", - icon: !1 - }], - icon: !1 - }), callback.call(scope, nodes), nodesToLoad.push("MediaFolders") - }) + icon: false + }); + if (result.TotalRecordCount) { + nodes.push({ + id: "livetv", + text: Globalize.translate("HeaderLiveTV"), + state: { + opened: false + }, + li_attr: { + itemtype: "livetv" + }, + children: [{ + text: "Loading...", + icon: false + }], + icon: false + }); + } + callback.call(scope, nodes); + nodesToLoad.push("MediaFolders"); + }); } function loadLiveTvChannels(openItems, callback) { ApiClient.getLiveTvChannels({ - AddCurrentProgram: !1 - }).then(function(result) { - var nodes = result.Items.map(function(i) { - return getNode(i, -1 == openItems.indexOf(i.Id) ? "closed" : "open", !1) + AddCurrentProgram: false + }).then(function (result) { + var nodes = result.Items.map(function (i) { + var state = openItems.indexOf(i.Id) == -1 ? "closed" : "open"; + return getNode(i, state, false); }); - callback(nodes) - }) + callback(nodes); + }); } function loadMediaFolders(page, scope, openItems, callback) { - ApiClient.getJSON(ApiClient.getUrl("Library/MediaFolders")).then(function(result) { - var nodes = result.Items.map(function(n) { - return getNode(n, -1 == openItems.indexOf(n.Id) ? "closed" : "open", !1) + 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"; + return getNode(n, state, false); }); callback.call(scope, nodes); - for (var i = 0, length = nodes.length; i < length; i++) nodes[i].state.opened && nodesToLoad.push(nodes[i].id) - }) + for (var i = 0, length = nodes.length; i < length; i++) { + if (nodes[i].state.opened) { + nodesToLoad.push(nodes[i].id); + } + } + }); } function loadNode(page, scope, node, openItems, selectedId, currentUser, callback) { var id = node.id; - if ("#" == id) return void loadChildrenOfRootNode(page, scope, callback); - if ("livetv" == id) return void loadLiveTvChannels(openItems, callback); - if ("MediaFolders" == id) return void loadMediaFolders(page, scope, openItems, callback); + if (id == "#") { + loadChildrenOfRootNode(page, scope, callback); + return; + } + if (id == "livetv") { + loadLiveTvChannels(id, openItems, callback); + return; + } + if (id == "MediaFolders") { + loadMediaFolders(page, scope, openItems, callback); + return; + } var query = { - ParentId: id, - Fields: "Settings", - IsVirtualUnaired: !1, - IsMissing: !1, - EnableTotalRecordCount: !1, - EnableImages: !1, - EnableUserData: !1 - }, - itemtype = node.li_attr.itemtype; - "Season" != itemtype && "Series" != itemtype && (query.SortBy = "SortName"), ApiClient.getItems(Dashboard.getCurrentUserId(), query).then(function(result) { - var nodes = result.Items.map(function(n) { - return getNode(n, -1 == openItems.indexOf(n.Id) ? "closed" : "open", n.Id == selectedId) + ParentId: id, + Fields: "Settings", + IsVirtualUnaired: false, + IsMissing: false, + EnableTotalRecordCount: false, + EnableImages: false, + EnableUserData: false + }; + var 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"; + return getNode(n, state, n.Id == selectedId); }); callback.call(scope, nodes); - for (var i = 0, length = nodes.length; i < length; i++) nodes[i].state.opened && nodesToLoad.push(nodes[i].id) - }) + for (var i = 0, length = nodes.length; i < length; i++) { + if (nodes[i].state.opened) { + nodesToLoad.push(nodes[i].id); + } + } + }); } function scrollToNode(id) { var elem = $("#" + id)[0]; - elem && elem.scrollIntoView() + if (elem) { + elem.scrollIntoView(); + } } function initializeTree(page, currentUser, openItems, selectedId) { - require(["jstree"], function() { - initializeTreeInternal(page, currentUser, openItems, selectedId) - }) + require(["jstree"], function () { + initializeTreeInternal(page, currentUser, openItems, selectedId); + }); } function onNodeSelect(event, data) { - var node = data.node, - eventData = { - id: node.id, - itemType: node.li_attr.itemtype, - serverItemType: node.li_attr.serveritemtype, - collectionType: node.li_attr.collectiontype - }; - "livetv" != eventData.itemType && "mediafolders" != eventData.itemType ? (this.dispatchEvent(new CustomEvent("itemclicked", { - detail: eventData, - bubbles: !0, - cancelable: !1 - })), document.querySelector(".editPageSidebar").classList.add("editPageSidebar-withcontent")) : document.querySelector(".editPageSidebar").classList.remove("editPageSidebar-withcontent") + var node = data.node; + var eventData = { + id: node.id, + itemType: node.li_attr.itemtype, + serverItemType: node.li_attr.serveritemtype, + collectionType: node.li_attr.collectiontype + }; + if (eventData.itemType != "livetv" && eventData.itemType != "mediafolders") { + { + this.dispatchEvent(new CustomEvent("itemclicked", { + detail: eventData, + bubbles: true, + cancelable: false + })); + } + document.querySelector(".editPageSidebar").classList.add("editPageSidebar-withcontent"); + } else { + document.querySelector(".editPageSidebar").classList.remove("editPageSidebar-withcontent"); + } } function onNodeOpen(event, data) { - var page = $(this).parents(".page")[0], - node = data.node; - node.children && node.children && loadNodesToLoad(page, node), node.li_attr && "#" != node.id && !node.li_attr.loadedFromServer && (node.li_attr.loadedFromServer = !0, $.jstree.reference(".libraryTree", page).load_node(node.id, loadNodeCallback)) + var page = $(this).parents(".page")[0]; + var node = data.node; + if (node.children && node.children) { + loadNodesToLoad(page, node); + } + if (node.li_attr && node.id != "#" && !node.li_attr.loadedFromServer) { + node.li_attr.loadedFromServer = true; + $.jstree.reference(".libraryTree", page).load_node(node.id, loadNodeCallback); + } } function onNodeLoad(event, data) { - var page = $(this).parents(".page")[0], - node = data.node; - node.children && node.children && loadNodesToLoad(page, node), node.li_attr && "#" != node.id && !node.li_attr.loadedFromServer && (node.li_attr.loadedFromServer = !0, $.jstree.reference(".libraryTree", page).load_node(node.id, loadNodeCallback)) + var page = $(this).parents(".page")[0]; + var node = data.node; + if (node.children && node.children) { + loadNodesToLoad(page, node); + } + if (node.li_attr && node.id != "#" && !node.li_attr.loadedFromServer) { + node.li_attr.loadedFromServer = true; + $.jstree.reference(".libraryTree", page).load_node(node.id, loadNodeCallback); + } } function initializeTreeInternal(page, currentUser, openItems, selectedId) { - nodesToLoad = [], selectedNodeId = null, $.jstree.destroy(), $(".libraryTree", page).jstree({ - plugins: ["wholerow"], + nodesToLoad = []; + selectedNodeId = null; + $.jstree.destroy(); + $(".libraryTree", page).jstree({ + "plugins": ["wholerow"], core: { - // Disable animations because jQuery slim does not support them - animation: false, check_callback: true, - data: function(node, callback) { - loadNode(page, this, node, openItems, selectedId, currentUser, callback) + data: function (node, callback) { + loadNode(page, this, node, openItems, selectedId, currentUser, callback); }, themes: { variant: "large" } } - }).off("select_node.jstree", onNodeSelect).on("select_node.jstree", onNodeSelect).off("open_node.jstree", onNodeOpen).on("open_node.jstree", onNodeOpen).off("load_node.jstree", onNodeLoad).on("load_node.jstree", onNodeLoad) + }).off("select_node.jstree", onNodeSelect).on("select_node.jstree", onNodeSelect).off("open_node.jstree", onNodeOpen).on("open_node.jstree", onNodeOpen).off("load_node.jstree", onNodeLoad).on("load_node.jstree", onNodeLoad); } function loadNodesToLoad(page, node) { - for (var children = node.children, i = 0, length = children.length; i < length; i++) { - var child = children[i]; - 1 != nodesToLoad.indexOf(child) && (nodesToLoad = nodesToLoad.filter(function(n) { - return n != child - }), $.jstree.reference(".libraryTree", page).load_node(child, loadNodeCallback)) + var children = node.children; + for (var i = 0, length = children.length; i < length; i++) { + var child = children[i]; + if (nodesToLoad.indexOf(child) != -1) { + nodesToLoad = nodesToLoad.filter(function (n) { + return n != child; + }); + $.jstree.reference(".libraryTree", page).load_node(child, loadNodeCallback); + } } } function loadNodeCallback(node) { - selectedNodeId && node.children && -1 != node.children.indexOf(selectedNodeId) && setTimeout(function() { - scrollToNode(selectedNodeId) - }, 500) + if (selectedNodeId && node.children && node.children.indexOf(selectedNodeId) != -1) { + setTimeout(function () { + scrollToNode(selectedNodeId); + }, 500); + } } function updateEditorNode(page, item) { var elem = $("#" + item.Id + ">a", page)[0]; - if (null != elem && ($(".editorNode", elem).remove(), $(elem).append(getNodeInnerHtml(item)), item.IsFolder)) { - var tree = jQuery.jstree._reference(".libraryTree"), - currentNode = tree._get_node(null, !1); - tree.refresh(currentNode) + 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); + tree.refresh(currentNode); } } function setCurrentItemId(id) { - itemId = id + itemId = id; } function getCurrentItemId() { - if (itemId) return itemId; + if (itemId) { + return itemId; + } var url = window.location.hash || window.location.href; - return getParameterByName("id", url) + return getParameterByName("id", url); } - var selectedNodeId, nodesToLoad = []; - $(document).on("itemsaved", ".metadataEditorPage", function(e, item) { - updateEditorNode(this, item) - }).on("pagebeforeshow", ".metadataEditorPage", function() { - require(["css!css/metadataeditor.css"]) - }).on("pagebeforeshow", ".metadataEditorPage", function() { + var nodesToLoad = []; + var selectedNodeId; + $(document).on("itemsaved", ".metadataEditorPage", function (e, item) { + updateEditorNode(this, item); + }).on("pagebeforeshow", ".metadataEditorPage", function () { + require(["css!css/metadataeditor.css"]); + }).on("pagebeforeshow", ".metadataEditorPage", function () { var page = this; - Dashboard.getCurrentUser().then(function(user) { + Dashboard.getCurrentUser().then(function (user) { var id = getCurrentItemId(); - id ? ApiClient.getAncestorItems(id, user.Id).then(function(ancestors) { - var ids = ancestors.map(function(i) { - return i.Id + if (id) { + ApiClient.getAncestorItems(id, user.Id).then(function (ancestors) { + var ids = ancestors.map(function (i) { + return i.Id; + }); + initializeTree(page, user, ids, id); }); - initializeTree(page, user, ids, id) - }) : initializeTree(page, user, []) - }) - }).on("pagebeforehide", ".metadataEditorPage", function() { - $(".libraryTree", this).off("select_node.jstree", onNodeSelect).off("open_node.jstree", onNodeOpen).off("load_node.jstree", onNodeLoad) + } else { + initializeTree(page, user, []); + } + }); + }).on("pagebeforehide", ".metadataEditorPage", function () { + var page = this; + $(".libraryTree", page).off("select_node.jstree", onNodeSelect).off("open_node.jstree", onNodeOpen).off("load_node.jstree", onNodeLoad); }); var itemId; window.MetadataEditor = { - getItemPromise: function() { + getItemPromise: function () { var currentItemId = getCurrentItemId(); - return currentItemId ? ApiClient.getItem(Dashboard.getCurrentUserId(), currentItemId) : ApiClient.getRootFolder(Dashboard.getCurrentUserId()) + if (currentItemId) { + return ApiClient.getItem(Dashboard.getCurrentUserId(), currentItemId); + } + return ApiClient.getRootFolder(Dashboard.getCurrentUserId()); }, getCurrentItemId: getCurrentItemId, setCurrentItemId: setCurrentItemId - } + }; }); From 63cc1e0860649253bf162206f5605b9e95c08e2c Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Sat, 31 Aug 2019 19:03:19 +0300 Subject: [PATCH 06/80] add style --- src/components/themes/purple-haze/theme.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/themes/purple-haze/theme.css b/src/components/themes/purple-haze/theme.css index 843b573059..cdd58e83ef 100644 --- a/src/components/themes/purple-haze/theme.css +++ b/src/components/themes/purple-haze/theme.css @@ -569,3 +569,7 @@ a[data-role=button] { background-color: #dbe6ff; color: #0e0f2d; } + +.metadataSidebarIcon { + color: #dbe6ff +} From a8f904dc42f7d46e76557a533f9566e5fd6fc93f Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Sat, 31 Aug 2019 21:42:40 +0300 Subject: [PATCH 07/80] change primary action for delete confirmation dialog --- src/components/deletehelper.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/deletehelper.js b/src/components/deletehelper.js index ae0fdbdf52..baea618042 100644 --- a/src/components/deletehelper.js +++ b/src/components/deletehelper.js @@ -27,7 +27,7 @@ define(['connectionManager', 'confirm', 'appRouter', 'globalize'], function (con title: title, text: msg, confirmText: globalize.translate('Delete'), - primary: 'cancel' + primary: 'ok' }).then(function () { @@ -54,4 +54,4 @@ define(['connectionManager', 'confirm', 'appRouter', 'globalize'], function (con return { deleteItem: deleteItem }; -}); \ No newline at end of file +}); From 8a0c268973ab2b7c009c8b58851df7c879ab5694 Mon Sep 17 00:00:00 2001 From: Frank Riley Date: Sat, 31 Aug 2019 15:09:41 -0700 Subject: [PATCH 08/80] Always have last sort of movies be by production year. Implement https://features.jellyfin.org/posts/151/movies-should-always-have-a-second-sort-of-release-date --- src/controllers/movies/movies.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/controllers/movies/movies.js b/src/controllers/movies/movies.js index 1ee558e6e3..e0a5947ca6 100644 --- a/src/controllers/movies/movies.js +++ b/src/controllers/movies/movies.js @@ -140,31 +140,31 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", libraryBrowser.showSortMenu({ items: [{ name: Globalize.translate("OptionNameSort"), - id: "SortName" + id: "SortName,ProductionYear" }, { name: Globalize.translate("OptionImdbRating"), - id: "CommunityRating,SortName" + id: "CommunityRating,SortName,ProductionYear" }, { name: Globalize.translate("OptionCriticRating"), - id: "CriticRating,SortName" + id: "CriticRating,SortName,ProductionYear" }, { name: Globalize.translate("OptionDateAdded"), - id: "DateCreated,SortName" + id: "DateCreated,SortName,ProductionYear" }, { name: Globalize.translate("OptionDatePlayed"), - id: "DatePlayed,SortName" + id: "DatePlayed,SortName,ProductionYear" }, { name: Globalize.translate("OptionParentalRating"), - id: "OfficialRating,SortName" + id: "OfficialRating,SortName,ProductionYear" }, { name: Globalize.translate("OptionPlayCount"), - id: "PlayCount,SortName" + id: "PlayCount,SortName,ProductionYear" }, { name: Globalize.translate("OptionReleaseDate"), - id: "PremiereDate,SortName" + id: "PremiereDate,SortName,ProductionYear" }, { name: Globalize.translate("OptionRuntime"), - id: "Runtime,SortName" + id: "Runtime,SortName,ProductionYear" }], callback: function() { query.StartIndex = 0, userSettings.saveQuerySettings(savedQueryKey, query), itemsContainer.refreshItems() @@ -189,7 +189,7 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", savedQueryKey = params.topParentId + "-" + options.mode, savedViewKey = savedQueryKey + "-view", query = { - SortBy: "SortName", + SortBy: "SortName,ProductionYear", SortOrder: "Ascending", IncludeItemTypes: "Movie", Recursive: !0, From a7dfb236d08fe41db5f0af85bca1a7ee880d8775 Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Sun, 1 Sep 2019 17:06:28 +0300 Subject: [PATCH 09/80] add style --- src/components/themes/appletv/theme.css | 4 ++++ src/components/themes/blueradiance/theme.css | 4 ++++ src/components/themes/dark/theme.css | 4 ++++ src/components/themes/emby/theme.css | 4 ++++ src/components/themes/light/theme.css | 4 ++++ src/components/themes/wmc/theme.css | 4 ++++ 6 files changed, 24 insertions(+) diff --git a/src/components/themes/appletv/theme.css b/src/components/themes/appletv/theme.css index 43f1034ade..fa0617a655 100644 --- a/src/components/themes/appletv/theme.css +++ b/src/components/themes/appletv/theme.css @@ -453,3 +453,7 @@ html { .card:focus .card-focuscontent { border-color: #00a4dc } + +.metadataSidebarIcon { + color: #00a4dc +} diff --git a/src/components/themes/blueradiance/theme.css b/src/components/themes/blueradiance/theme.css index 840c0e23e0..7f581454a8 100644 --- a/src/components/themes/blueradiance/theme.css +++ b/src/components/themes/blueradiance/theme.css @@ -464,3 +464,7 @@ html { .timeslotHeaders-desktop::-webkit-scrollbar { height: .7em } + +.metadataSidebarIcon { + color: #00a4dc +} diff --git a/src/components/themes/dark/theme.css b/src/components/themes/dark/theme.css index da4c056023..4670b57459 100644 --- a/src/components/themes/dark/theme.css +++ b/src/components/themes/dark/theme.css @@ -442,3 +442,7 @@ html { .timeslotHeaders-desktop::-webkit-scrollbar { height: .7em } + +.metadataSidebarIcon { + color: #00a4dc +} diff --git a/src/components/themes/emby/theme.css b/src/components/themes/emby/theme.css index d948c3ae6f..542aa5f8d6 100644 --- a/src/components/themes/emby/theme.css +++ b/src/components/themes/emby/theme.css @@ -441,3 +441,7 @@ html { .timeslotHeaders-desktop::-webkit-scrollbar { height: .7em } + +.metadataSidebarIcon { + color: #00a4dc +} diff --git a/src/components/themes/light/theme.css b/src/components/themes/light/theme.css index 65ceefb52c..c2f01bab93 100644 --- a/src/components/themes/light/theme.css +++ b/src/components/themes/light/theme.css @@ -437,3 +437,7 @@ html { .card:focus .card-focuscontent { border-color: #00a4dc } + +.metadataSidebarIcon { + color: #00a4dc +} diff --git a/src/components/themes/wmc/theme.css b/src/components/themes/wmc/theme.css index 081345c77c..0685adfb0b 100644 --- a/src/components/themes/wmc/theme.css +++ b/src/components/themes/wmc/theme.css @@ -456,3 +456,7 @@ html { -webkit-border-radius: 2px; background: center no-repeat rgba(255, 255, 255, .7) } + +.metadataSidebarIcon { + color: #00a4dc +} From d53a0957289fa395503894fa3a15221c43c96915 Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Sun, 1 Sep 2019 18:24:56 +0300 Subject: [PATCH 10/80] change class name --- src/components/confirm/confirm.js | 4 ++-- src/components/themes/appletv/theme.css | 5 +++++ src/components/themes/blueradiance/theme.css | 5 +++++ src/components/themes/dark/theme.css | 5 +++++ src/components/themes/emby/theme.css | 5 +++++ src/components/themes/light/theme.css | 5 +++++ src/components/themes/purple-haze/theme.css | 5 +++++ src/components/themes/wmc/theme.css | 5 +++++ 8 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/components/confirm/confirm.js b/src/components/confirm/confirm.js index 730ca3cd73..a09adcbcf5 100644 --- a/src/components/confirm/confirm.js +++ b/src/components/confirm/confirm.js @@ -24,7 +24,7 @@ define(['dialog', 'globalize'], function (dialog, globalize) { items.push({ name: options.confirmText || globalize.translate('ButtonOk'), id: 'ok', - type: options.primary === 'cancel' ? 'cancel' : 'submit' + type: options.primary === 'cancel' ? 'cancel' : 'delete' }); options.buttons = items; @@ -37,4 +37,4 @@ define(['dialog', 'globalize'], function (dialog, globalize) { return Promise.reject(); }); }; -}); \ No newline at end of file +}); diff --git a/src/components/themes/appletv/theme.css b/src/components/themes/appletv/theme.css index 43f1034ade..bdb8229eb2 100644 --- a/src/components/themes/appletv/theme.css +++ b/src/components/themes/appletv/theme.css @@ -102,6 +102,11 @@ html { background: #0cb0e8 } +.button-delete { + background: rgb(247, 0, 0); + color: rgba(255, 255, 255, .87) +} + .checkboxLabel { color: inherit } diff --git a/src/components/themes/blueradiance/theme.css b/src/components/themes/blueradiance/theme.css index 840c0e23e0..9299dcdf84 100644 --- a/src/components/themes/blueradiance/theme.css +++ b/src/components/themes/blueradiance/theme.css @@ -89,6 +89,11 @@ html { color: #fff } +.button-delete { + background: rgb(247, 0, 0); + color: rgba(255, 255, 255, .87) +} + .checkboxLabel { color: inherit } diff --git a/src/components/themes/dark/theme.css b/src/components/themes/dark/theme.css index da4c056023..1b9370be54 100644 --- a/src/components/themes/dark/theme.css +++ b/src/components/themes/dark/theme.css @@ -70,6 +70,11 @@ html { color: #fff } +.button-delete { + background: rgb(247, 0, 0); + color: rgba(255, 255, 255, .87) +} + .checkboxLabel { color: inherit } diff --git a/src/components/themes/emby/theme.css b/src/components/themes/emby/theme.css index d948c3ae6f..88c098acf2 100644 --- a/src/components/themes/emby/theme.css +++ b/src/components/themes/emby/theme.css @@ -70,6 +70,11 @@ html { color: #fff } +.button-delete { + background: rgb(247, 0, 0); + color: rgba(255, 255, 255, .87) +} + .checkboxLabel { color: inherit } diff --git a/src/components/themes/light/theme.css b/src/components/themes/light/theme.css index 65ceefb52c..7dac5dbc01 100644 --- a/src/components/themes/light/theme.css +++ b/src/components/themes/light/theme.css @@ -85,6 +85,11 @@ html { background: #0cb0e8 } +.button-delete { + background: rgb(247, 0, 0); + color: rgba(255, 255, 255, .87) +} + .checkboxLabel { color: inherit } diff --git a/src/components/themes/purple-haze/theme.css b/src/components/themes/purple-haze/theme.css index 843b573059..2754e8db26 100644 --- a/src/components/themes/purple-haze/theme.css +++ b/src/components/themes/purple-haze/theme.css @@ -144,6 +144,11 @@ a[data-role=button] { background: #ff77f1 } +.button-delete { + background: rgb(247, 0, 0); + color: rgba(255, 255, 255, .87) +} + #btnResetPassword, .btnForgotPassword, .btnCancel, diff --git a/src/components/themes/wmc/theme.css b/src/components/themes/wmc/theme.css index 081345c77c..9c48450794 100644 --- a/src/components/themes/wmc/theme.css +++ b/src/components/themes/wmc/theme.css @@ -95,6 +95,11 @@ html { color: #fff } +.button-delete { + background: rgb(247, 0, 0); + color: rgba(255, 255, 255, .87) +} + .checkboxLabel { color: inherit } From babb4f1028966d8899d46ab0f8a4dc6b22fca5f4 Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Sun, 1 Sep 2019 18:38:23 +0300 Subject: [PATCH 11/80] some for devices --- src/controllers/devices.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/devices.js b/src/controllers/devices.js index ef24f19172..7b0896d575 100644 --- a/src/controllers/devices.js +++ b/src/controllers/devices.js @@ -12,7 +12,7 @@ define(["loading", "dom", "libraryMenu", "globalize", "scripts/imagehelper", "hu text: msg, title: globalize.translate("HeaderDeleteDevice"), confirmText: globalize.translate("ButtonDelete"), - primary: "cancel" + primary: "ok" }).then(function() { loading.show(), ApiClient.ajax({ type: "DELETE", @@ -112,4 +112,4 @@ define(["loading", "dom", "libraryMenu", "globalize", "scripts/imagehelper", "hu loadData(this) }) } -}); \ No newline at end of file +}); From 6d3c617c28f8754180d882762bb36304b17543cb Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Sun, 1 Sep 2019 18:52:36 +0300 Subject: [PATCH 12/80] change primary id that have delete, uninstall --- src/components/imageeditor/imageeditor.js | 6 +++--- src/components/medialibraryeditor/medialibraryeditor.js | 4 ++-- src/components/subtitleeditor/subtitleeditor.js | 4 ++-- src/controllers/installedplugins.js | 2 +- src/controllers/userprofilespage.js | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/imageeditor/imageeditor.js b/src/components/imageeditor/imageeditor.js index a0dfcd8499..8cd01b8dbb 100644 --- a/src/components/imageeditor/imageeditor.js +++ b/src/components/imageeditor/imageeditor.js @@ -203,7 +203,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager', text: globalize.translate('ConfirmDeleteImage'), confirmText: globalize.translate('Delete'), - primary: 'cancel' + primary: 'ok' }).then(afterConfirm); }); @@ -471,7 +471,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager', initEditor(dlg, options); - // Has to be assigned a z-index after the call to .open() + // Has to be assigned a z-index after the call to .open() dlg.addEventListener('close', function () { if (layoutManager.tv) { @@ -510,4 +510,4 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager', }); } }; -}); \ No newline at end of file +}); diff --git a/src/components/medialibraryeditor/medialibraryeditor.js b/src/components/medialibraryeditor/medialibraryeditor.js index ef3a3d5b19..be5c83f838 100644 --- a/src/components/medialibraryeditor/medialibraryeditor.js +++ b/src/components/medialibraryeditor/medialibraryeditor.js @@ -59,7 +59,7 @@ define(["loading", "dialogHelper", "dom", "components/libraryoptionseditor/libra title: Globalize.translate("HeaderRemoveMediaLocation"), text: Globalize.translate("MessageConfirmRemoveMediaLocation"), confirmText: Globalize.translate("ButtonDelete"), - primary: "cancel" + primary: "ok" }).then(function() { var refreshAfterChange = currentOptions.refresh; ApiClient.removeMediaPath(virtualFolder.Name, location, refreshAfterChange).then(function() { @@ -212,4 +212,4 @@ define(["loading", "dialogHelper", "dom", "components/libraryoptionseditor/libra var isCreating = false; return editor; -}); \ No newline at end of file +}); diff --git a/src/components/subtitleeditor/subtitleeditor.js b/src/components/subtitleeditor/subtitleeditor.js index e4742a8948..3ff7ac14c2 100644 --- a/src/components/subtitleeditor/subtitleeditor.js +++ b/src/components/subtitleeditor/subtitleeditor.js @@ -74,7 +74,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', title: globalize.translate('ConfirmDeletion'), text: msg, confirmText: globalize.translate('Delete'), - primary: 'cancel' + primary: 'ok' }).then(function () { @@ -523,4 +523,4 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', return { show: showEditor }; -}); \ No newline at end of file +}); diff --git a/src/controllers/installedplugins.js b/src/controllers/installedplugins.js index 40de0cc191..d02fdc0e59 100644 --- a/src/controllers/installedplugins.js +++ b/src/controllers/installedplugins.js @@ -7,7 +7,7 @@ define(["loading", "libraryMenu", "dom", "globalize", "cardStyle", "emby-button" confirm({ title: globalize.translate("UninstallPluginHeader"), text: msg, - primary: "cancel", + primary: "ok", confirmText: globalize.translate("UninstallPluginHeader") }).then(function() { loading.show(); diff --git a/src/controllers/userprofilespage.js b/src/controllers/userprofilespage.js index c0d1d0d87b..8505580904 100644 --- a/src/controllers/userprofilespage.js +++ b/src/controllers/userprofilespage.js @@ -9,7 +9,7 @@ define(["loading", "dom", "globalize", "humanedate", "paper-icon-button-light", title: globalize.translate("DeleteUser"), text: msg, confirmText: globalize.translate("ButtonDelete"), - primary: "cancel" + primary: "ok" }).then(function () { loading.show(); ApiClient.deleteUser(id).then(function () { @@ -207,7 +207,7 @@ define(["loading", "dom", "globalize", "humanedate", "paper-icon-button-light", page.querySelector(".pending").innerHTML = users.map(getPendingUserHtml).join(""); } - + // TODO cvium: maybe reuse for invitation system function cancelAuthorization(page, id) { loading.show(); @@ -230,7 +230,7 @@ define(["loading", "dom", "globalize", "humanedate", "paper-icon-button-light", // TODO cvium renderPendingGuests(page, []); // ApiClient.getJSON(ApiClient.getUrl("Connect/Pending")).then(function (pending) { - // + // // }); } From 295d6e32a38d17b2d0924b302fc1c6a5ac06a003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20F=C3=A4th?= Date: Tue, 3 Sep 2019 15:42:20 +0200 Subject: [PATCH 13/80] Improve image quality on detail page --- src/controllers/itemdetailpage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/itemdetailpage.js b/src/controllers/itemdetailpage.js index 9149d78391..e46a1d226e 100644 --- a/src/controllers/itemdetailpage.js +++ b/src/controllers/itemdetailpage.js @@ -361,7 +361,7 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuild function renderLogo(page, item, apiClient) { var url = logoImageUrl(item, apiClient, { - maxWidth: 300 + maxWidth: 400 }), detailLogo = page.querySelector(".detailLogo"); url ? (detailLogo.classList.remove("hide"), detailLogo.classList.add("lazy"), detailLogo.setAttribute("data-src", url), imageLoader.lazyImage(detailLogo)) : detailLogo.classList.add("hide") @@ -404,7 +404,7 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuild detectRatio = !1; imageTags.Primary ? (url = apiClient.getScaledImageUrl(item.Id, { type: "Primary", - maxHeight: 360, + maxHeight: 460, tag: item.ImageTags.Primary }), detectRatio = !0) : item.BackdropImageTags && item.BackdropImageTags.length ? (url = apiClient.getScaledImageUrl(item.Id, { type: "Backdrop", From baa87d2dfba2be198ee6e53f95150a7adf95e4f2 Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Wed, 4 Sep 2019 21:53:31 +0300 Subject: [PATCH 14/80] remove user policy --- src/components/itemMediaInfo/itemMediaInfo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/itemMediaInfo/itemMediaInfo.js b/src/components/itemMediaInfo/itemMediaInfo.js index 90a13d9cc8..da3708714d 100644 --- a/src/components/itemMediaInfo/itemMediaInfo.js +++ b/src/components/itemMediaInfo/itemMediaInfo.js @@ -26,7 +26,7 @@ define(["dialogHelper", "require", "layoutManager", "globalize", "userSettings", if (version.Path && user && user.Policy.IsAdministrator) { html += createAttribute(globalize.translate("MediaInfoPath"), version.Path) + "
"; } - if (version.Size && user && user.Policy.IsAdministrator) { + if (version.Size) { var size = (version.Size / (1024 * 1024)).toFixed(0) + " MB"; html += createAttribute(globalize.translate("MediaInfoSize"), size) + "
"; } From b4a5794573b1d677b10025b4f4b88cc081a2fb36 Mon Sep 17 00:00:00 2001 From: dkanada Date: Thu, 5 Sep 2019 11:42:38 -0700 Subject: [PATCH 15/80] minor changes to dashboard controller --- src/controllers/dashboardpage.js | 45 ++++++++++++-------------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/src/controllers/dashboardpage.js b/src/controllers/dashboardpage.js index be3ee9e081..1f6893ff67 100644 --- a/src/controllers/dashboardpage.js +++ b/src/controllers/dashboardpage.js @@ -12,27 +12,23 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa function showPlaybackInfo(btn, session) { require(["alert"], function (alert) { - var showTranscodeReasons; var title; var text = []; - var displayPlayMethod = playMethodHelper.getDisplayPlayMethod(session); - var isDirectStream = "DirectStream" === displayPlayMethod; - var isTranscode = "Transcode" === displayPlayMethod; - if (isDirectStream) { + var displayPlayMethod = playMethodHelper.getDisplayPlayMethod(session); + if (displayPlayMethod === "DirectStream") { title = globalize.translate("DirectStreaming"); text.push(globalize.translate("DirectStreamHelp1")); text.push("
"); text.push(globalize.translate("DirectStreamHelp2")); - } else if (isTranscode) { + } else if (displayPlayMethod === "Transcode") { title = globalize.translate("Transcoding"); text.push(globalize.translate("MediaIsBeingConverted")); - if (session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo.TranscodeReasons.length) { text.push("
"); text.push(globalize.translate("LabelReasonForTranscoding")); session.TranscodingInfo.TranscodeReasons.forEach(function (transcodeReason) { - text.push(globalize.translate("" + transcodeReason)); + text.push(globalize.translate(transcodeReason)); }); } } @@ -316,8 +312,8 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa html += '
'; var userImage = DashboardPage.getUserImage(session); html += userImage ? '' : '
'; - html += '
'; - html += DashboardPage.getUsersHtml(session) || " "; + html += '
'; + html += DashboardPage.getUsersHtml(session); html += "
"; html += "
"; html += "
"; @@ -398,13 +394,12 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } if (showTranscodingInfo) { var line = []; - if (session.TranscodingInfo) { if (session.TranscodingInfo.Bitrate) { if (session.TranscodingInfo.Bitrate > 1e6) { line.push((session.TranscodingInfo.Bitrate / 1e6).toFixed(1) + " Mbps"); } else { - line.push(Math.floor(session.TranscodingInfo.Bitrate / 1e3) + " kbps"); + line.push(Math.floor(session.TranscodingInfo.Bitrate / 1e3) + " Kbps"); } } @@ -426,7 +421,7 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } } - return html || " "; + return html; }, getSessionNowPlayingTime: function (session) { var nowPlayingItem = session.NowPlayingItem; @@ -436,7 +431,7 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa if (session.PlayState.PositionTicks) { html += datetime.getDisplayRunningTime(session.PlayState.PositionTicks); } else { - html += "--:--:--"; + html += "0:00"; } html += " / "; @@ -444,10 +439,8 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa if (nowPlayingItem && nowPlayingItem.RunTimeTicks) { html += datetime.getDisplayRunningTime(nowPlayingItem.RunTimeTicks); } else { - html += "--:--:--"; + html += "0:00"; } - - return html; } return html; @@ -488,15 +481,13 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa maxWidth: 130, type: "Logo" }); - } else { - if (nowPlayingItem.ParentLogoImageTag) { - imgUrl = ApiClient.getScaledImageUrl(nowPlayingItem.ParentLogoItemId, { - tag: nowPlayingItem.ParentLogoImageTag, - maxHeight: 24, - maxWidth: 130, - type: "Logo" - }); - } + } else if (nowPlayingItem.ParentLogoImageTag) { + imgUrl = ApiClient.getScaledImageUrl(nowPlayingItem.ParentLogoItemId, { + tag: nowPlayingItem.ParentLogoImageTag, + maxHeight: 24, + maxWidth: 130, + type: "Logo" + }); } if (imgUrl) { @@ -510,7 +501,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa }, getUsersHtml: function (session) { var html = []; - if (session.UserId) { html.push(session.UserName); } @@ -787,7 +777,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa loading.show(); pollForInfo(page, apiClient); DashboardPage.startInterval(apiClient); - // TODO we currently don't support packages and thus these events are useless events.on(serverNotifications, "RestartRequired", onRestartRequired); events.on(serverNotifications, "ServerShuttingDown", onServerShuttingDown); events.on(serverNotifications, "ServerRestarting", onServerRestarting); From 20923d5ab84823c247d2887bccd88ef35fefe343 Mon Sep 17 00:00:00 2001 From: dkanada Date: Thu, 5 Sep 2019 11:43:32 -0700 Subject: [PATCH 16/80] show transcode path on encoding configuration page --- src/controllers/encodingsettings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/encodingsettings.js b/src/controllers/encodingsettings.js index a66c5a49a4..0319d59a79 100644 --- a/src/controllers/encodingsettings.js +++ b/src/controllers/encodingsettings.js @@ -10,7 +10,7 @@ define(["jQuery", "loading", "globalize", "dom", "libraryMenu"], function($, loa $("#selectThreadCount", page).val(config.EncodingThreadCount); $("#txtDownMixAudioBoost", page).val(config.DownMixAudioBoost); page.querySelector(".txtEncoderPath").value = config.EncoderAppPathDisplay || ""; - $("#txtTranscodingTempPath", page).val(config.TranscodingTempPath || ""); + $("#txtTranscodingTempPath", page).val(systemInfo.TranscodingTempPath || ""); $("#txtVaapiDevice", page).val(config.VaapiDevice || ""); page.querySelector("#selectH264Preset").value = config.H264Preset || ""; page.querySelector("#txtH264Crf").value = config.H264Crf || ""; From cfb82dd16137e52ae55b74bafefbd2c1da9d280e Mon Sep 17 00:00:00 2001 From: dkanada Date: Thu, 5 Sep 2019 11:48:18 -0700 Subject: [PATCH 17/80] move experimental tag to select description --- src/encodingsettings.html | 14 +++++++------- src/strings/en-us.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/encodingsettings.html b/src/encodingsettings.html index ade2d41715..e57ba600c0 100644 --- a/src/encodingsettings.html +++ b/src/encodingsettings.html @@ -12,13 +12,13 @@
${LabelHardwareAccelerationTypeHelp}
diff --git a/src/strings/en-us.json b/src/strings/en-us.json index 1f8c931a8b..81a0470975 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -651,7 +651,7 @@ "LabelH264Crf": "H264 encoding CRF:", "LabelH264EncodingPreset": "H264 encoding preset:", "LabelHardwareAccelerationType": "Hardware acceleration:", - "LabelHardwareAccelerationTypeHelp": "Only available on supported systems.", + "LabelHardwareAccelerationTypeHelp": "This is an experimental feature only available on supported systems.", "LabelHomeNetworkQuality": "Home network quality:", "LabelHomeScreenSectionValue": "Home screen section {0}:", "LabelHttpsPort": "Local HTTPS port number:", From 86df74ad52b75cce57ea3ccd9364cf0b2194157e Mon Sep 17 00:00:00 2001 From: dkanada Date: Thu, 5 Sep 2019 12:01:30 -0700 Subject: [PATCH 18/80] lots of string changes --- src/strings/en-us.json | 96 +++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/src/strings/en-us.json b/src/strings/en-us.json index 81a0470975..a4c5a17872 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -19,7 +19,7 @@ "AllEpisodes": "All episodes", "AllLanguages": "All languages", "AllLibraries": "All libraries", - "AllowHWTranscodingHelp": "If enabled, allow the tuner to transcode streams on the fly. This may help reduce transcoding required by Jellyfin Server.", + "AllowHWTranscodingHelp": "Allow the tuner to transcode streams on the fly. This may help reduce transcoding required by the server.", "AllowMediaConversion": "Allow media conversion", "AllowMediaConversionHelp": "Grant or deny access to the convert media feature.", "AllowOnTheFlySubtitleExtraction": "Allow subtitle extraction on the fly", @@ -55,7 +55,7 @@ "BoxRear": "Box (rear)", "Browse": "Browse", "BrowsePluginCatalogMessage": "Browse our plugin catalog to view available plugins.", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitles format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (e.g. VOBSUB, PGS, SUB/IDX, etc.) as well as certain ASS/SSA subtitles.", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitle format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (VOBSUB, PGS, SUB/IDX, etc) and certain ASS/SSA subtitles.", "ButtonAdd": "Add", "ButtonAddMediaLibrary": "Add Media Library", "ButtonAddScheduledTaskTrigger": "Add Trigger", @@ -183,7 +183,7 @@ "DetectingDevices": "Detecting devices", "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.", "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc.), but is in an incompatible file container (.mkv, .avi, .wmv, etc.). The video will be re-packaged on the fly before streaming it to the device.", + "DirectStreamHelp1": "The media is compatible with the device regarding resolution and media type (H.264, AC3, etc), but is in an incompatible file container (mkv, avi, wmv, etc). The video will be re-packaged on the fly before streaming it to the device.", "DirectStreamHelp2": "Direct Streaming a file uses very little processing power without any loss in video quality.", "DirectStreaming": "Direct streaming", "Director": "Director", @@ -197,7 +197,7 @@ "DisplayInMyMedia": "Display on home screen", "DisplayInOtherHomeScreenSections": "Display in home screen sections such as latest media and continue watching", "DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons", - "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in Jellyfin Server setup.", + "DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in the server configuration.", "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", "DoNotRecord": "Do not record", "Down": "Down", @@ -210,24 +210,24 @@ "EditImages": "Edit images", "EditMetadata": "Edit metadata", "EditSubtitles": "Edit subtitles", - "EnableBackdrops": "Enable backdrops", - "EnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.", - "EnableCinemaMode": "Enable cinema mode", - "EnableColorCodedBackgrounds": "Enable color coded backgrounds", - "EnableDisplayMirroring": "Enable display mirroring", - "EnableExternalVideoPlayers": "Enable external video players", + "EnableBackdrops": "Backdrops", + "EnableBackdropsHelp": "Display backdrops in the background of some pages while browsing the library.", + "EnableCinemaMode": "Cinema mode", + "EnableColorCodedBackgrounds": "Color coded backgrounds", + "EnableDisplayMirroring": "Display mirroring", + "EnableExternalVideoPlayers": "External video players", "EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.", "EnableHardwareEncoding": "Enable hardware encoding", - "EnableNextVideoInfoOverlay": "Enable next video info during playback", + "EnableNextVideoInfoOverlay": "Show next video info during playback", "EnableNextVideoInfoOverlayHelp": "At the end of a video, display info about the next video coming up in the current playlist.", - "EnablePhotos": "Enable photos", - "EnablePhotosHelp": "Photos will be detected and displayed alongside other media files.", + "EnablePhotos": "Display photos", + "EnablePhotosHelp": "Images will be detected and displayed alongside other media files.", "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": "Enable theme songs", - "EnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.", - "EnableThemeVideos": "Enable theme videos", - "EnableThemeVideosHelp": "If enabled, theme videos will be played in the background while browsing the library.", + "EnableThemeSongs": "Theme songs", + "EnableThemeSongsHelp": "Play theme songs in the background while browsing the library.", + "EnableThemeVideos": "Theme videos", + "EnableThemeVideosHelp": "Play theme videos in the background while browsing the library.", "Ended": "Ended", "EndsAtValue": "Ends at {0}", "Episodes": "Episodes", @@ -243,7 +243,7 @@ "EveryNDays": "Every {0} days", "ExitFullscreen": "Exit full screen", "ExtraLarge": "Extra large", - "ExtractChapterImagesHelp": "Extracting chapter images will allow clients to display graphical scene selection menus. The process can be slow, cpu-intensive and may require several gigabytes of space. It runs when videos are discovered, and also as a nightly scheduled task. The schedule is configurable in the scheduled tasks area. It is not recommended to run this task during peak usage hours.", + "ExtractChapterImagesHelp": "Extracting chapter images will allow clients to display graphical scene selection menus. The process can be slow, resource intensive, and may require several gigabytes of space. It runs when videos are discovered, and also as a nightly scheduled task. The schedule is configurable in the scheduled tasks area. It is not recommended to run this task during peak usage hours.", "Extras": "Extras", "FFmpegSavePathNotFound": "We're unable to locate FFmpeg using the path you've entered. FFprobe is also required and must exist in the same folder. These components are normally bundled together in the same download. Please check the path and try again.", "FastForward": "Fast-forward", @@ -258,9 +258,9 @@ "FolderTypeBooks": "Books", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", - "FolderTypeMusicVideos": "Music videos", - "FolderTypeTvShows": "TV Shows", - "FolderTypeUnset": "Mixed content", + "FolderTypeMusicVideos": "Music Videos", + "FolderTypeTvShows": "Shows", + "FolderTypeUnset": "Mixed Content", "Folders": "Folders", "ForAdditionalLiveTvOptions": "For additional Live TV providers, click on the Services tab to see the available options.", "FormatValue": "Format: {0}", @@ -542,7 +542,7 @@ "LabelAll": "All", "LabelAllowHWTranscoding": "Allow hardware transcoding", "LabelAllowServerAutoRestart": "Allow the server to restart automatically to apply updates", - "LabelAllowServerAutoRestartHelp": "The server will only restart during idle periods, when no users are active.", + "LabelAllowServerAutoRestartHelp": "The server will only restart during idle periods when no users are active.", "LabelAllowedRemoteAddresses": "Remote IP address filter:", "LabelAllowedRemoteAddressesMode": "Remote IP address filter mode:", "LabelAppName": "App name", @@ -558,7 +558,7 @@ "LabelBirthDate": "Birth date:", "LabelBirthYear": "Birth year:", "LabelBlastMessageInterval": "Alive message interval (seconds)", - "LabelBlastMessageIntervalHelp": "Determines the duration in seconds between server alive messages.", + "LabelBlastMessageIntervalHelp": "Determines the duration in seconds between blast alive messages.", "LabelBlockContentWithTags": "Block items with tags:", "LabelBurnSubtitles": "Burn subtitles:", "LabelCache": "Cache:", @@ -602,7 +602,7 @@ "LabelDisplayOrder": "Display order:", "LabelDisplaySpecialsWithinSeasons": "Display specials within seasons they aired in", "LabelDownMixAudioScale": "Audio boost when downmixing:", - "LabelDownMixAudioScaleHelp": "Boost audio when downmixing. Set to 1 to preserve original volume value.", + "LabelDownMixAudioScaleHelp": "Boost audio when downmixing. A value of one will preserve the original volume.", "LabelDownloadLanguages": "Download languages:", "LabelDropImageHere": "Drop image here, or click to browse.", "LabelDropShadow": "Drop shadow:", @@ -620,7 +620,7 @@ "LabelEnableDlnaDebugLoggingHelp": "Create large log files and should only be used as needed for troubleshooting purposes.", "LabelEnableDlnaPlayTo": "Enable DLNA Play To", "LabelEnableDlnaPlayToHelp": "Detect devices within your network and offer the ability to remote control them.", - "LabelEnableDlnaServer": "Enable Dlna server", + "LabelEnableDlnaServer": "Enable DLNA server", "LabelEnableDlnaServerHelp": "Allows UPnP devices on your network to browse and play content.", "LabelEnableHardwareDecodingFor": "Enable hardware decoding for:", "LabelEnableRealtimeMonitor": "Enable real time monitoring", @@ -636,16 +636,16 @@ "LabelBaseUrl": "Base URL:", "LabelBaseUrlHelp": "You can add a custom subdirectory here to access the server from a more unique URL.", "LabelExtractChaptersDuringLibraryScan": "Extract chapter images during the library scan", - "LabelExtractChaptersDuringLibraryScanHelp": "If enabled, chapter images will be extracted when videos are imported during the library scan. If disabled they will be extracted during the chapter images scheduled task, allowing the regular library scan to complete faster.", + "LabelExtractChaptersDuringLibraryScanHelp": "Generate chapter images when videos are imported during the library scan. Otherwise, they will be extracted during the chapter images scheduled task, allowing the regular library scan to complete faster.", "LabelFailed": "Failed", - "LabelFileOrUrl": "File or url:", + "LabelFileOrUrl": "File or URL:", "LabelFinish": "Finish", "LabelFolder": "Folder:", "LabelFont": "Font:", "LabelForgotPasswordUsernameHelp": "Enter your username, if you remember it.", "LabelFormat": "Format:", "LabelFriendlyName": "Friendly name:", - "LabelServerNameHelp": "This name will be used to identify this server. If left blank, the computer name will be used.", + "LabelServerNameHelp": "This name will be used to identify the server and will default to the server's computer name.", "LabelGroupMoviesIntoCollections": "Group movies into collections", "LabelGroupMoviesIntoCollectionsHelp": "When displaying movie lists, movies belonging to a collection will be displayed as one grouped item.", "LabelH264Crf": "H264 encoding CRF:", @@ -665,20 +665,20 @@ "LabelImageType": "Image type:", "LabelImportOnlyFavoriteChannels": "Restrict to channels marked as favorite", "LabelInNetworkSignInWithEasyPassword": "Enable in-network sign in with my easy pin code", - "LabelInNetworkSignInWithEasyPasswordHelp": "If enabled, you'll be able to use your easy pin code to sign in to Jellyfin apps from inside your home network. Your regular password will only be needed away from home. If the pin code is left blank, you won't need a password within your home network.", + "LabelInNetworkSignInWithEasyPasswordHelp": "Use the easy pin code to sign in to clients within your local network. Your regular password will only be needed away from home. If the pin code is left blank, you won't need a password within your home network.", "LabelInternetQuality": "Internet quality:", "LabelKeepUpTo": "Keep up to:", "LabelKidsCategories": "Children's categories:", "LabelKodiMetadataDateFormat": "Release date format:", - "LabelKodiMetadataDateFormatHelp": "All dates within nfo's will be read and written to using this format.", - "LabelKodiMetadataEnableExtraThumbs": "Copy extrafanart into extrathumbs", + "LabelKodiMetadataDateFormatHelp": "All dates within NFO files will be parsed using this format.", + "LabelKodiMetadataEnableExtraThumbs": "Copy extrafanart to extrathumbs field", "LabelKodiMetadataEnableExtraThumbsHelp": "When downloading images they can be saved into both extrafanart and extrathumbs for maximum Kodi skin compatibility.", "LabelKodiMetadataEnablePathSubstitution": "Enable path substitution", "LabelKodiMetadataEnablePathSubstitutionHelp": "Enables path substitution of image paths using the server's path substitution settings.", "LabelKodiMetadataSaveImagePaths": "Save image paths within nfo files", "LabelKodiMetadataSaveImagePathsHelp": "This is recommended if you have image file names that don't conform to Kodi guidelines.", - "LabelKodiMetadataUser": "Save user watch data to nfo's for:", - "LabelKodiMetadataUserHelp": "Enable this to save watch data to NFO files for other applications to utilize.", + "LabelKodiMetadataUser": "Save user watch data to NFO files for:", + "LabelKodiMetadataUserHelp": "Save watch data to NFO files for other applications to utilize.", "LabelLanNetworks": "LAN networks:", "LabelLanguage": "Language:", "LabelLineup": "Lineup:", @@ -689,7 +689,7 @@ "LabelLoginDisclaimerHelp": "A message that will be displayed at the bottom of the login page.", "LabelLogs": "Logs:", "LabelManufacturer": "Manufacturer", - "LabelManufacturerUrl": "Manufacturer url", + "LabelManufacturerUrl": "Manufacturer URL", "LabelMatchType": "Match type:", "LabelMaxBackdropsPerItem": "Maximum number of backdrops per item:", "LabelMaxChromecastBitrate": "Chromecast streaming quality:", @@ -720,11 +720,11 @@ "LabelModelDescription": "Model description", "LabelModelName": "Model name", "LabelModelNumber": "Model number", - "LabelModelUrl": "Model url", + "LabelModelUrl": "Model URL", "LabelMonitorUsers": "Monitor activity from:", "LabelMovieCategories": "Movie categories:", "LabelMoviePrefix": "Movie prefix:", - "LabelMoviePrefixHelp": "If a prefix is applied to movie titles, enter it here so that Jellyfin can handle it properly.", + "LabelMoviePrefixHelp": "If a prefix is applied to movie titles, enter it here so the server can handle it properly.", "LabelMovieRecordingPath": "Movie recording path (optional):", "LabelMusicStreamingTranscodingBitrate": "Music transcoding bitrate:", "LabelMusicStreamingTranscodingBitrateHelp": "Specify a max bitrate when streaming music", @@ -842,10 +842,10 @@ "LabelTranscodingAudioCodec": "Audio codec:", "LabelTranscodingContainer": "Container:", "LabelTranscodePath": "Transcode path:", - "LabelTranscodingTempPathHelp": "This folder contains working files used by the transcoder. Specify a custom path, or leave empty to use the default within the server's data folder.", + "LabelTranscodingTempPathHelp": "Specify a custom path for the transcode files served to clients. Leave blank to use the server default.", "LabelTranscodes": "Transcodes:", "LabelTranscodingThreadCount": "Transcoding thread count:", - "LabelTranscodingThreadCountHelp": "Select the maximum number of threads to use when transcoding. Reducing the thread count will lower cpu usage but may not convert fast enough for a smooth playback experience.", + "LabelTranscodingThreadCountHelp": "Select the maximum number of threads to use when transcoding. Reducing the thread count will lower CPU usage but may not convert fast enough for a smooth playback experience.", "LabelTranscodingVideoCodec": "Video codec:", "LabelTriggerType": "Trigger Type:", "LabelTunerIpAddress": "Tuner IP Address:", @@ -872,9 +872,9 @@ "DashboardArchitecture": "Architecture: {0}", "LabelVideo": "Video:", "LabelWeb": "Web: ", - "LabelXDlnaCap": "X-Dlna cap:", + "LabelXDlnaCap": "X-DLNA cap:", "LabelXDlnaCapHelp": "Determines the content of the X_DLNACAP element in the urn:schemas-dlna-org:device-1-0 namespace.", - "LabelXDlnaDoc": "X-Dlna doc:", + "LabelXDlnaDoc": "X-DLNA doc:", "LabelXDlnaDocHelp": "Determines the content of the X_DLNADOC element in the urn:schemas-dlna-org:device-1-0 namespace.", "LabelYear": "Year:", "LabelYourFirstName": "Your first name:", @@ -989,7 +989,7 @@ "MetadataSettingChangeHelp": "Changing metadata settings will affect new content that is added going forward. To refresh existing content, open the detail screen and click the refresh button, or perform bulk refreshes using the metadata manager.", "MinutesAfter": "minutes after", "MinutesBefore": "minutes before", - "Mobile": "Mobile / Tablet", + "Mobile": "Mobile", "Monday": "Monday", "MoreFromValue": "More from {0}", "MoreUsersCanBeAddedLater": "More users can be added later from within the dashboard.", @@ -1027,7 +1027,7 @@ "OneChannel": "One channel", "OnlyForcedSubtitles": "Only forced subtitles", "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB, etc.)", + "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB, etc)", "Option3D": "3D", "OptionAdminUsers": "Administrators", "OptionAlbum": "Album", @@ -1078,7 +1078,7 @@ "OptionDisableUserHelp": "If disabled the server will not allow any connections from this user. Existing connections will be abruptly terminated.", "OptionDislikes": "Dislikes", "OptionDisplayFolderView": "Display a folder view to show plain media folders", - "OptionDisplayFolderViewHelp": "If enabled, Jellyfin apps will display a Folders category alongside your media library. This is useful if you'd like to have plain folder views.", + "OptionDisplayFolderViewHelp": "Display folders alongside your other media libraries. This can be useful if you'd like to have a plain folder view.", "OptionDownloadArtImage": "Art", "OptionDownloadBackImage": "Back", "OptionDownloadBannerImage": "Banner", @@ -1097,7 +1097,7 @@ "OptionEnableAccessToAllLibraries": "Enable access to all libraries", "OptionEnableAutomaticServerUpdates": "Enable automatic server updates", "OptionEnableExternalContentInSuggestions": "Enable external content in suggestions", - "OptionEnableExternalContentInSuggestionsHelp": "Allow internet trailers and live tv programs to be included within suggested content.", + "OptionEnableExternalContentInSuggestionsHelp": "Allow internet trailers and live TV programs to be included within suggested content.", "OptionEnableForAllTuners": "Enable for all tuner devices", "OptionEnableM2tsMode": "Enable M2ts mode", "OptionEnableM2tsModeHelp": "Enable m2ts mode when encoding to mpegts.", @@ -1116,8 +1116,8 @@ "OptionHasTrailer": "Trailer", "OptionHideUser": "Hide this user from login screens", "OptionHideUserFromLoginHelp": "Useful for private or hidden administrator accounts. The user will need to sign in manually by entering their username and password.", - "OptionHlsSegmentedSubtitles": "Hls segmented subtitles", - "OptionHomeVideos": "Home videos & photos", + "OptionHlsSegmentedSubtitles": "HLS segmented subtitles", + "OptionHomeVideos": "Photos", "OptionIgnoreTranscodeByteRangeRequests": "Ignore transcode byte range requests", "OptionIgnoreTranscodeByteRangeRequestsHelp": "If enabled, these requests will be honored but will ignore the byte range header.", "OptionImdbRating": "IMDb Rating", @@ -1126,7 +1126,7 @@ "OptionLikes": "Likes", "OptionList": "List", "OptionLoginAttemptsBeforeLockout": "Determines how many incorrect login attempts can be made before lockout occurs.", - "OptionLoginAttemptsBeforeLockoutHelp": "A value of zero means inheriting the default of three attempts for normal users and five for admin. Setting this to -1 will disable the feature.", + "OptionLoginAttemptsBeforeLockoutHelp": "A value of zero means inheriting the default of three attempts for normal users and five for administrators. Setting this to -1 will disable the feature.", "OptionMax": "Max", "OptionMissingEpisode": "Missing Episodes", "OptionMonday": "Monday", @@ -1311,7 +1311,7 @@ "StopRecording": "Stop recording", "Studios": "Studios", "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Chromecast playback started by this device.", - "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc), or subtitles that have their own styles embedded (ASS/SSA).", + "SubtitleAppearanceSettingsDisclaimer": "These settings will not apply to graphical subtitles (PGS, DVD, etc) or ASS/SSA subtitles that embed their own styles.", "SubtitleDownloadersHelp": "Enable and rank your preferred subtitle downloaders in order of priority.", "SubtitleOffset": "Subtitle Offset", "Subtitles": "Subtitles", From 1be3a7f205a786a6152e24e72ba10c1448157558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20F=C3=A4th?= Date: Thu, 5 Sep 2019 21:04:35 +0200 Subject: [PATCH 19/80] Fixed blurred My Media images (#443) * Fixed blurred My Media images * Update CONTRIBUTORS.md --- CONTRIBUTORS.md | 1 + src/components/homesections/homesections.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 71f53d260f..c7c8a07162 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -27,6 +27,7 @@ - [petermcneil](https://github.com/petermcneil) - [lewazo](https://github.com/lewazo) - [Raghu Saxena](https://github.com/ckcr4lyf) + - [Nickbert7](https://github.com/Nickbert7) # Emby Contributors diff --git a/src/components/homesections/homesections.js b/src/components/homesections/homesections.js index 9e809fc3f7..d2106c93bd 100644 --- a/src/components/homesections/homesections.js +++ b/src/components/homesections/homesections.js @@ -328,7 +328,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la html += cardBuilder.getCardsHtml({ items: userViews, - shape: enableScrollX() ? 'overflowSmallBackdrop' : shape, + shape: getThumbShape(), showTitle: true, centerText: true, overlayText: false, From f8628384582028c2ca1408944b2c12d8147fa519 Mon Sep 17 00:00:00 2001 From: dkanada Date: Thu, 5 Sep 2019 12:41:39 -0700 Subject: [PATCH 20/80] always keep confirm in the same location --- src/components/confirm/confirm.js | 4 ++-- src/components/deletehelper.js | 2 +- src/components/imageeditor/imageeditor.js | 2 +- src/components/medialibraryeditor/medialibraryeditor.js | 2 +- src/components/subtitleeditor/subtitleeditor.js | 2 +- src/controllers/devices.js | 2 +- src/controllers/installedplugins.js | 2 +- src/controllers/userprofilespage.js | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/confirm/confirm.js b/src/components/confirm/confirm.js index a09adcbcf5..f104350c87 100644 --- a/src/components/confirm/confirm.js +++ b/src/components/confirm/confirm.js @@ -18,13 +18,13 @@ define(['dialog', 'globalize'], function (dialog, globalize) { items.push({ name: options.cancelText || globalize.translate('ButtonCancel'), id: 'cancel', - type: options.primary === 'cancel' ? 'submit' : 'cancel' + type: 'cancel' }); items.push({ name: options.confirmText || globalize.translate('ButtonOk'), id: 'ok', - type: options.primary === 'cancel' ? 'cancel' : 'delete' + type: options.primary === 'delete' ? 'delete' : 'submit' }); options.buttons = items; diff --git a/src/components/deletehelper.js b/src/components/deletehelper.js index baea618042..2212fd4437 100644 --- a/src/components/deletehelper.js +++ b/src/components/deletehelper.js @@ -27,7 +27,7 @@ define(['connectionManager', 'confirm', 'appRouter', 'globalize'], function (con title: title, text: msg, confirmText: globalize.translate('Delete'), - primary: 'ok' + primary: 'delete' }).then(function () { diff --git a/src/components/imageeditor/imageeditor.js b/src/components/imageeditor/imageeditor.js index 8cd01b8dbb..15c58ad8d9 100644 --- a/src/components/imageeditor/imageeditor.js +++ b/src/components/imageeditor/imageeditor.js @@ -203,7 +203,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager', text: globalize.translate('ConfirmDeleteImage'), confirmText: globalize.translate('Delete'), - primary: 'ok' + primary: 'delete' }).then(afterConfirm); }); diff --git a/src/components/medialibraryeditor/medialibraryeditor.js b/src/components/medialibraryeditor/medialibraryeditor.js index be5c83f838..77a5f8f459 100644 --- a/src/components/medialibraryeditor/medialibraryeditor.js +++ b/src/components/medialibraryeditor/medialibraryeditor.js @@ -59,7 +59,7 @@ define(["loading", "dialogHelper", "dom", "components/libraryoptionseditor/libra title: Globalize.translate("HeaderRemoveMediaLocation"), text: Globalize.translate("MessageConfirmRemoveMediaLocation"), confirmText: Globalize.translate("ButtonDelete"), - primary: "ok" + primary: "delete" }).then(function() { var refreshAfterChange = currentOptions.refresh; ApiClient.removeMediaPath(virtualFolder.Name, location, refreshAfterChange).then(function() { diff --git a/src/components/subtitleeditor/subtitleeditor.js b/src/components/subtitleeditor/subtitleeditor.js index 3ff7ac14c2..27055f5976 100644 --- a/src/components/subtitleeditor/subtitleeditor.js +++ b/src/components/subtitleeditor/subtitleeditor.js @@ -74,7 +74,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', title: globalize.translate('ConfirmDeletion'), text: msg, confirmText: globalize.translate('Delete'), - primary: 'ok' + primary: 'delete' }).then(function () { diff --git a/src/controllers/devices.js b/src/controllers/devices.js index 7b0896d575..d50f9ce7e5 100644 --- a/src/controllers/devices.js +++ b/src/controllers/devices.js @@ -12,7 +12,7 @@ define(["loading", "dom", "libraryMenu", "globalize", "scripts/imagehelper", "hu text: msg, title: globalize.translate("HeaderDeleteDevice"), confirmText: globalize.translate("ButtonDelete"), - primary: "ok" + primary: "delete" }).then(function() { loading.show(), ApiClient.ajax({ type: "DELETE", diff --git a/src/controllers/installedplugins.js b/src/controllers/installedplugins.js index d02fdc0e59..f9653fe260 100644 --- a/src/controllers/installedplugins.js +++ b/src/controllers/installedplugins.js @@ -7,7 +7,7 @@ define(["loading", "libraryMenu", "dom", "globalize", "cardStyle", "emby-button" confirm({ title: globalize.translate("UninstallPluginHeader"), text: msg, - primary: "ok", + primary: "delete", confirmText: globalize.translate("UninstallPluginHeader") }).then(function() { loading.show(); diff --git a/src/controllers/userprofilespage.js b/src/controllers/userprofilespage.js index 8505580904..f76bb35e6a 100644 --- a/src/controllers/userprofilespage.js +++ b/src/controllers/userprofilespage.js @@ -9,7 +9,7 @@ define(["loading", "dom", "globalize", "humanedate", "paper-icon-button-light", title: globalize.translate("DeleteUser"), text: msg, confirmText: globalize.translate("ButtonDelete"), - primary: "ok" + primary: "delete" }).then(function () { loading.show(); ApiClient.deleteUser(id).then(function () { From e8ae9b3605af515145369c7adb454145f2843b15 Mon Sep 17 00:00:00 2001 From: dkanada Date: Fri, 6 Sep 2019 02:02:58 -0700 Subject: [PATCH 21/80] use new style for all warning dialogs --- src/components/recordingcreator/recordinghelper.js | 4 ++-- src/controllers/dashboardpage.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/recordingcreator/recordinghelper.js b/src/components/recordingcreator/recordinghelper.js index a8359b4d4f..8c56b578c9 100644 --- a/src/components/recordingcreator/recordinghelper.js +++ b/src/components/recordingcreator/recordinghelper.js @@ -37,7 +37,7 @@ define(['globalize', 'loading', 'connectionManager'], function (globalize, loadi confirm({ text: globalize.translate('MessageConfirmRecordingCancellation'), - primary: 'cancel', + primary: 'delete', confirmText: globalize.translate('HeaderCancelRecording'), cancelText: globalize.translate('HeaderKeepRecording') @@ -62,7 +62,7 @@ define(['globalize', 'loading', 'connectionManager'], function (globalize, loadi confirm({ text: globalize.translate('MessageConfirmRecordingCancellation'), - primary: 'cancel', + primary: 'delete', confirmText: globalize.translate('HeaderCancelSeries'), cancelText: globalize.translate('HeaderKeepSeries') diff --git a/src/controllers/dashboardpage.js b/src/controllers/dashboardpage.js index 7c443e3087..28d384f13b 100644 --- a/src/controllers/dashboardpage.js +++ b/src/controllers/dashboardpage.js @@ -707,7 +707,7 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa title: globalize.translate("HeaderRestart"), text: globalize.translate("MessageConfirmRestart"), confirmText: globalize.translate("ButtonRestart"), - primary: "cancel" + primary: "delete" }).then(function () { var page = dom.parentWithClass(btn, "page"); buttonEnabled(page.querySelector("#btnRestartServer"), false); @@ -722,7 +722,7 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa title: globalize.translate("HeaderShutdown"), text: globalize.translate("MessageConfirmShutdown"), confirmText: globalize.translate("ButtonShutdown"), - primary: "cancel" + primary: "delete" }).then(function () { var page = dom.parentWithClass(btn, "page"); buttonEnabled(page.querySelector("#btnRestartServer"), false); From 3b0a2f4caa46bcc3107f2977e1e0d37c09caa83b Mon Sep 17 00:00:00 2001 From: PrplHaz4 Date: Fri, 6 Sep 2019 14:58:31 -0400 Subject: [PATCH 22/80] fix AutoRunWebApp checkbox on dashboardgeneral --- src/controllers/dashboardgeneral.js | 6 ++++-- src/dashboardgeneral.html | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/controllers/dashboardgeneral.js b/src/controllers/dashboardgeneral.js index 09aa1ec08e..c37e5e9a46 100644 --- a/src/controllers/dashboardgeneral.js +++ b/src/controllers/dashboardgeneral.js @@ -3,10 +3,11 @@ define(["jQuery", "loading", "fnchecked", "emby-checkbox", "emby-textarea", "emb function loadPage(page, config, languageOptions, systemInfo) { page.querySelector("#txtServerName").value = systemInfo.ServerName; + $("#chkAutoRunWebApp", page).checked(config.AutoRunWebApp); if (systemInfo.CanLaunchWebBrowser) { - page.querySelector("#fldRunWebAppAtStartup").classList.remove("hide"); + page.querySelector("#fldAutoRunWebApp").classList.remove("hide"); } else { - page.querySelector("#fldRunWebAppAtStartup").classList.add("hide"); + page.querySelector("#fldAutoRunWebApp").classList.add("hide"); } page.querySelector("#txtCachePath").value = systemInfo.CachePath || ""; $("#txtMetadataPath", page).val(systemInfo.InternalMetadataPath || ""); @@ -46,6 +47,7 @@ define(["jQuery", "loading", "fnchecked", "emby-checkbox", "emby-textarea", "emb config.MetadataPath = $("#txtMetadataPath", form).val(); config.MetadataNetworkPath = $("#txtMetadataNetworkPath", form).val(); var requiresReload = (config.UICulture !== currentLanguage); + config.AutoRunWebApp = $("#chkAutoRunWebApp", form).checked(); config.EnableAutomaticRestart = $("#chkEnableAutomaticRestart", form).checked(); config.EnableAutoUpdate = $("#chkEnableAutomaticServerUpdates", form).checked(); ApiClient.updateServerConfiguration(config).then(function() { diff --git a/src/dashboardgeneral.html b/src/dashboardgeneral.html index a285b0e55f..af46f34903 100644 --- a/src/dashboardgeneral.html +++ b/src/dashboardgeneral.html @@ -26,9 +26,9 @@ -
+
From e4e315b1e0701016adf43f02c2c9cf6e4f4ad3c1 Mon Sep 17 00:00:00 2001 From: dkanada Date: Thu, 5 Sep 2019 22:30:16 -0700 Subject: [PATCH 23/80] fix issues with playback progress --- src/controllers/dashboardpage.js | 40 +++++++++++++------------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/controllers/dashboardpage.js b/src/controllers/dashboardpage.js index 1f6893ff67..6279f2d3df 100644 --- a/src/controllers/dashboardpage.js +++ b/src/controllers/dashboardpage.js @@ -236,10 +236,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa var nowPlayingItem = session.NowPlayingItem; var className = "scalableCard card activeSession backdropCard backdropCard-scalable"; - if (session.TranscodingInfo && session.TranscodingInfo.CompletionPercentage) { - className += " transcodingSession"; - } - html += '
'; html += '
'; html += '
'; @@ -285,11 +281,17 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa if (nowPlayingItem && nowPlayingItem.RunTimeTicks) { var percent = 100 * (session.PlayState.PositionTicks || 0) / nowPlayingItem.RunTimeTicks; html += indicators.getProgressHtml(percent, { containerClass: "playbackProgress" }); + } else { + // need to leave the element in just in case the device starts playback + html += indicators.getProgressHtml(0, { containerClass: "playbackProgress hide" }); } if (session.TranscodingInfo && session.TranscodingInfo.CompletionPercentage) { var percent = session.TranscodingInfo.CompletionPercentage.toFixed(1); html += indicators.getProgressHtml(percent, { containerClass: "transcodingProgress" }); + } else { + // same issue as playbackProgress element above + html += indicators.getProgressHtml(0, { containerClass: "transcodingProgress hide" }); } html += "
"; @@ -324,7 +326,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa parentElement.insertAdjacentHTML("beforeend", html); var deadSessionElem = parentElement.querySelector(".deadSession"); - if (deadSessionElem) { deadSessionElem.parentNode.removeChild(deadSessionElem); } @@ -524,8 +525,8 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa }, updateSession: function (row, session) { row.classList.remove("deadSession"); - var nowPlayingItem = session.NowPlayingItem; + var nowPlayingItem = session.NowPlayingItem; if (nowPlayingItem) { row.classList.add("playingSession"); } else { @@ -545,7 +546,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } var btnSessionPlayPause = row.querySelector(".btnSessionPlayPause"); - if (session.ServerId && nowPlayingItem && session.SupportsRemoteControl && session.DeviceId !== connectionManager.deviceId()) { btnSessionPlayPause.classList.remove("hide"); row.querySelector(".btnSessionStop").classList.remove("hide"); @@ -562,7 +562,7 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa row.querySelector(".sessionNowPlayingStreamInfo").innerHTML = DashboardPage.getSessionNowPlayingStreamInfo(session); row.querySelector(".sessionNowPlayingTime").innerHTML = DashboardPage.getSessionNowPlayingTime(session); - row.querySelector(".sessionUserName").innerHTML = DashboardPage.getUsersHtml(session) || " "; + row.querySelector(".sessionUserName").innerHTML = DashboardPage.getUsersHtml(session); row.querySelector(".sessionAppSecondaryText").innerHTML = DashboardPage.getAppSecondaryText(session); row.querySelector(".sessionTranscodingFramerate").innerHTML = session.TranscodingInfo && session.TranscodingInfo.Framerate ? session.TranscodingInfo.Framerate + " fps" : ""; var nowPlayingName = DashboardPage.getNowPlayingName(session); @@ -574,27 +574,19 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } var playbackProgressElem = row.querySelector(".playbackProgress"); - - if (playbackProgressElem) { - if (nowPlayingItem && nowPlayingItem.RunTimeTicks) { - var position = session.PlayState.PositionTicks || 0; - var value = 100 * position / nowPlayingItem.RunTimeTicks; - playbackProgressElem.classList.remove("hide"); - playbackProgressElem.value = value; - } else { - playbackProgressElem.classList.add("hide"); - } + if (nowPlayingItem && nowPlayingItem.RunTimeTicks) { + var percent = 100 * (session.PlayState.PositionTicks || 0) / nowPlayingItem.RunTimeTicks; + html += indicators.getProgressHtml(percent, { containerClass: "playbackProgress" }); + } else { + html += indicators.getProgressHtml(0, { containerClass: "playbackProgress hide" }); } var transcodingProgress = row.querySelector(".transcodingProgress"); - if (session.TranscodingInfo && session.TranscodingInfo.CompletionPercentage) { - row.classList.add("transcodingSession"); - transcodingProgress.value = session.TranscodingInfo.CompletionPercentage; - transcodingProgress.classList.remove("hide"); + var percent = session.TranscodingInfo.CompletionPercentage.toFixed(1); + html += indicators.getProgressHtml(percent, { containerClass: "transcodingProgress" }); } else { - transcodingProgress.classList.add("hide"); - row.classList.remove("transcodingSession"); + html += indicators.getProgressHtml(0, { containerClass: "transcodingProgress hide" }); } var imgUrl = DashboardPage.getNowPlayingImageUrl(nowPlayingItem) || ""; From 742354baee21d9c42dc3fc26db095642558a6c12 Mon Sep 17 00:00:00 2001 From: dkanada Date: Thu, 5 Sep 2019 23:20:16 -0700 Subject: [PATCH 24/80] use album cover as alternate image for active devices --- src/controllers/dashboardpage.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/controllers/dashboardpage.js b/src/controllers/dashboardpage.js index 6279f2d3df..510f6d1b60 100644 --- a/src/controllers/dashboardpage.js +++ b/src/controllers/dashboardpage.js @@ -674,6 +674,14 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa }); } + if (item && item.AlbumPrimaryImageTag) { + return ApiClient.getScaledImageUrl(item.AlbumId, { + type: "Primary", + width: 275, + tag: item.AlbumPrimaryImageTag + }); + } + return null; }, systemUpdateTaskKey: "SystemUpdateTask", From a61ef5bf3097a26b136c6f5697cc958c2a3e9f18 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Sat, 7 Sep 2019 00:24:51 -0400 Subject: [PATCH 25/80] Disable animations in editor sidebar --- src/scripts/editorsidebar.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/scripts/editorsidebar.js b/src/scripts/editorsidebar.js index 0477dedcfc..796ad96310 100644 --- a/src/scripts/editorsidebar.js +++ b/src/scripts/editorsidebar.js @@ -241,6 +241,8 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { $(".libraryTree", page).jstree({ "plugins": ["wholerow"], core: { + // Disable animations because jQuery slim does not support them + animation: false, check_callback: true, data: function (node, callback) { loadNode(page, this, node, openItems, selectedId, currentUser, callback); From e9d2c73c5e1350cce3c5590b9d10fe0f1f65b0ca Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Sun, 8 Sep 2019 01:11:27 +0300 Subject: [PATCH 26/80] degligy medialibrarypage --- src/controllers/medialibrarypage.js | 149 ++++++++++++++++++---------- 1 file changed, 97 insertions(+), 52 deletions(-) diff --git a/src/controllers/medialibrarypage.js b/src/controllers/medialibrarypage.js index 405d38bfa7..d8be309720 100644 --- a/src/controllers/medialibrarypage.js +++ b/src/controllers/medialibrarypage.js @@ -1,48 +1,54 @@ -define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "globalize", "dom", "indicators", "scripts/imagehelper", "cardStyle", "emby-itemrefreshindicator"], function($, appHost, taskButton, loading, libraryMenu, globalize, dom, indicators, imageHelper) { +define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "globalize", "dom", "indicators", "scripts/imagehelper", "cardStyle", "emby-itemrefreshindicator"], function ($, appHost, taskButton, loading, libraryMenu, globalize, dom, indicators, imageHelper) { "use strict"; function addVirtualFolder(page) { - require(["medialibrarycreator"], function(medialibrarycreator) { - (new medialibrarycreator).show({ - collectionTypeOptions: getCollectionTypeOptions().filter(function(f) { + require(["medialibrarycreator"], function (medialibrarycreator) { + new medialibrarycreator().show({ + collectionTypeOptions: getCollectionTypeOptions().filter(function (f) { return !f.hidden; }), refresh: shouldRefreshLibraryAfterChanges(page) - }).then(function(hasChanges) { - hasChanges && reloadLibrary(page); - }) - }) + }).then(function (hasChanges) { + if (hasChanges) { + reloadLibrary(page); + } + }); + }); } function editVirtualFolder(page, virtualFolder) { - require(["medialibraryeditor"], function(medialibraryeditor) { - (new medialibraryeditor).show({ + require(["medialibraryeditor"], function (medialibraryeditor) { + new medialibraryeditor().show({ refresh: shouldRefreshLibraryAfterChanges(page), library: virtualFolder - }).then(function(hasChanges) { - hasChanges && reloadLibrary(page); - }) - }) + }).then(function (hasChanges) { + if (hasChanges) { + reloadLibrary(page); + } + }); + }); } function deleteVirtualFolder(page, virtualFolder) { var msg = globalize.translate("MessageAreYouSureYouWishToRemoveMediaFolder"); + if (virtualFolder.Locations.length) { msg += "

" + globalize.translate("MessageTheFollowingLocationWillBeRemovedFromLibrary") + "

"; msg += virtualFolder.Locations.join("
"); } - require(["confirm"], function(confirm) { - confirm(msg, globalize.translate("HeaderRemoveMediaFolder")).then(function() { + + require(["confirm"], function (confirm) { + confirm(msg, globalize.translate("HeaderRemoveMediaFolder")).then(function () { var refreshAfterChange = shouldRefreshLibraryAfterChanges(page); - ApiClient.removeVirtualFolder(virtualFolder.Name, refreshAfterChange).then(function() { + ApiClient.removeVirtualFolder(virtualFolder.Name, refreshAfterChange).then(function () { reloadLibrary(page); - }) - }) - }) + }); + }); + }); } function refreshVirtualFolder(page, virtualFolder) { - require(["refreshDialog"], function(refreshDialog) { + require(["refreshDialog"], function (refreshDialog) { new refreshDialog({ itemIds: [virtualFolder.ItemId], serverId: ApiClient.serverId(), @@ -52,14 +58,14 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl } function renameVirtualFolder(page, virtualFolder) { - require(["prompt"], function(prompt) { + require(["prompt"], function (prompt) { prompt({ label: globalize.translate("LabelNewName"), confirmText: globalize.translate("ButtonRename") - }).then(function(newName) { + }).then(function (newName) { if (newName && newName != virtualFolder.Name) { var refreshAfterChange = shouldRefreshLibraryAfterChanges(page); - ApiClient.renameVirtualFolder(virtualFolder.Name, newName, refreshAfterChange).then(function() { + ApiClient.renameVirtualFolder(virtualFolder.Name, newName, refreshAfterChange).then(function () { reloadLibrary(page); }); } @@ -97,24 +103,29 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl id: "refresh", ironIcon: "refresh" }); - require(["actionsheet"], function(actionsheet) { + + require(["actionsheet"], function (actionsheet) { actionsheet.show({ items: menuItems, positionTo: elem, - callback: function(resultId) { + callback: function (resultId) { switch (resultId) { case "edit": editVirtualFolder(page, virtualFolder); break; + case "editimages": editImages(page, virtualFolder); break; + case "rename": renameVirtualFolder(page, virtualFolder); break; + case "delete": deleteVirtualFolder(page, virtualFolder); break; + case "refresh": refreshVirtualFolder(page, virtualFolder); } @@ -125,7 +136,7 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl function reloadLibrary(page) { loading.show(); - ApiClient.getVirtualFolders().then(function(result) { + ApiClient.getVirtualFolders().then(function (result) { reloadVirtualFolders(page, result); }); } @@ -148,36 +159,40 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl for (var i = 0; i < virtualFolders.length; i++) { var virtualFolder = virtualFolders[i]; - html += getVirtualFolderHtml(page, virtualFolder, i) + html += getVirtualFolderHtml(page, virtualFolder, i); } + var divVirtualFolders = page.querySelector("#divVirtualFolders"); divVirtualFolders.innerHTML = html; divVirtualFolders.classList.add("itemsContainer"); divVirtualFolders.classList.add("vertical-wrap"); - $(".btnCardMenu", divVirtualFolders).on("click", function() { + $(".btnCardMenu", divVirtualFolders).on("click", function () { showCardMenu(page, this, virtualFolders); }); - divVirtualFolders.querySelector(".addLibrary").addEventListener("click", function() { + divVirtualFolders.querySelector(".addLibrary").addEventListener("click", function () { addVirtualFolder(page); }); - $(".editLibrary", divVirtualFolders).on("click", function() { + $(".editLibrary", divVirtualFolders).on("click", function () { var card = $(this).parents(".card")[0]; var index = parseInt(card.getAttribute("data-index")); var virtualFolder = virtualFolders[index]; - virtualFolder.ItemId && editVirtualFolder(page, virtualFolder); + + if (virtualFolder.ItemId) { + editVirtualFolder(page, virtualFolder); + } }); loading.hide(); } function editImages(page, virtualFolder) { - require(["imageEditor"], function(imageEditor) { + require(["imageEditor"], function (imageEditor) { imageEditor.show({ itemId: virtualFolder.ItemId, serverId: ApiClient.serverId() - }).then(function() { + }).then(function () { reloadLibrary(page); }); - }) + }); } function getLink(text, url) { @@ -214,25 +229,32 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl name: globalize.translate("FolderTypeUnset"), value: "mixed", message: globalize.translate("MessageUnsetContentHelp") - }] + }]; } function getVirtualFolderHtml(page, virtualFolder, index) { var html = ""; var style = ""; - page.classList.contains("wizardPage") && (style += "min-width:33.3%;"); + + if (page.classList.contains("wizardPage")) { + style += "min-width:33.3%;"; + } + html += '
'; html += '
'; html += '
'; html += '
'; html += '
'; var imgUrl = ""; + if (virtualFolder.PrimaryImageItemId) { imgUrl = ApiClient.getScaledImageUrl(virtualFolder.PrimaryImageItemId, { type: "Primary" }); } + var hasCardImageContainer; + if (imgUrl) { html += '
"; hasCardImageContainer = true; @@ -241,38 +263,60 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl html += '' + (virtualFolder.icon || imageHelper.getLibraryIcon(virtualFolder.CollectionType)) + ""; hasCardImageContainer = true; } + if (hasCardImageContainer) { html += '
'; html += '
'; html += "
"; html += "
"; } + if (!imgUrl && virtualFolder.showNameWithIcon) { html += '

'; html += '' + (virtualFolder.icon || imageHelper.getLibraryIcon(virtualFolder.CollectionType)) + ""; - virtualFolder.showNameWithIcon && (html += '
', html += virtualFolder.Name, html += "
"); + + if (virtualFolder.showNameWithIcon) { + html += '
'; + html += virtualFolder.Name; + html += "
"; + } + html += "

"; } - html += "
"; - html += "
"; - html += '
'; - // always show menu unless explicitly hidden + html += "
"; + html += "
"; + html += '
'; // always show menu unless explicitly hidden + if (virtualFolder.showMenu !== false) { html += '
'; html += ''; html += "
"; } + html += "
"; - virtualFolder.showNameWithIcon ? html += " " : html += virtualFolder.Name; + + if (virtualFolder.showNameWithIcon) { + html += " "; + } else { + html += virtualFolder.Name; + } + html += "
"; - var typeName = getCollectionTypeOptions().filter(function(t) { - return t.value == virtualFolder.CollectionType + var typeName = getCollectionTypeOptions().filter(function (t) { + return t.value == virtualFolder.CollectionType; })[0]; typeName = typeName ? typeName.name : globalize.translate("FolderTypeUnset"); html += "
"; - virtualFolder.showType === false ? html += " " : html += typeName; + + if (virtualFolder.showType === false) { + html += " "; + } else { + html += typeName; + } + html += "
"; + if (virtualFolder.showLocations === false) { html += "
"; html += " "; @@ -286,6 +330,7 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl html += globalize.translate("NumLocationsValue", virtualFolder.Locations.length); html += "
"; } + html += "
"; html += "
"; html += "
"; @@ -305,18 +350,18 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl }, { href: "metadatanfo.html", name: globalize.translate("TabNfoSettings") - }] + }]; } window.WizardLibraryPage = { - next: function() { - Dashboard.navigate("wizardsettings.html") + next: function () { + Dashboard.navigate("wizardsettings.html"); } }; - pageClassOn("pageshow", "mediaLibraryPage", function() { + pageClassOn("pageshow", "mediaLibraryPage", function () { reloadLibrary(this); }); - pageIdOn("pageshow", "mediaLibraryPage", function() { + pageIdOn("pageshow", "mediaLibraryPage", function () { libraryMenu.setTabs("librarysetup", 0, getTabs); var page = this; taskButton({ @@ -326,7 +371,7 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl button: page.querySelector(".btnRefresh") }); }); - pageIdOn("pagebeforehide", "mediaLibraryPage", function() { + pageIdOn("pagebeforehide", "mediaLibraryPage", function () { var page = this; taskButton({ mode: "off", From 5f9a499c980e72c4e70958c7a376e95ca13d80e0 Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Sun, 8 Sep 2019 01:13:53 +0300 Subject: [PATCH 27/80] use the new style for medialibrarypage --- src/controllers/medialibrarypage.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/controllers/medialibrarypage.js b/src/controllers/medialibrarypage.js index d8be309720..6ce5f7fac7 100644 --- a/src/controllers/medialibrarypage.js +++ b/src/controllers/medialibrarypage.js @@ -38,7 +38,14 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl } require(["confirm"], function (confirm) { - confirm(msg, globalize.translate("HeaderRemoveMediaFolder")).then(function () { + confirm({ + + text: msg, + title: globalize.translate('HeaderRemoveMediaFolder'), + confirmText: globalize.translate('Delete'), + primary: 'delete' + + }).then(function () { var refreshAfterChange = shouldRefreshLibraryAfterChanges(page); ApiClient.removeVirtualFolder(virtualFolder.Name, refreshAfterChange).then(function () { reloadLibrary(page); From ea86b3f9e789332bb019a63515c4880e77df9195 Mon Sep 17 00:00:00 2001 From: dkanada Date: Sun, 8 Sep 2019 01:51:25 -0700 Subject: [PATCH 28/80] remove unused component --- .../homescreensettingsdialog.js | 88 ------------------- .../homescreensettingsdialog.template.html | 22 ----- src/scripts/site.js | 1 - 3 files changed, 111 deletions(-) delete mode 100644 src/components/homescreensettings/homescreensettingsdialog.js delete mode 100644 src/components/homescreensettings/homescreensettingsdialog.template.html diff --git a/src/components/homescreensettings/homescreensettingsdialog.js b/src/components/homescreensettings/homescreensettingsdialog.js deleted file mode 100644 index 9813e0163e..0000000000 --- a/src/components/homescreensettings/homescreensettingsdialog.js +++ /dev/null @@ -1,88 +0,0 @@ -define(['dialogHelper', 'layoutManager', 'globalize', 'require', 'events', 'homescreenSettings', 'paper-icon-button-light', 'css!./../formdialog'], function (dialogHelper, layoutManager, globalize, require, events, HomescreenSettings) { - 'use strict'; - - function centerFocus(elem, horiz, on) { - require(['scrollHelper'], function (scrollHelper) { - var fn = on ? 'on' : 'off'; - scrollHelper.centerFocus[fn](elem, horiz); - }); - } - - function show(options) { - return new Promise(function (resolve, reject) { - - require(['text!./homescreensettingsdialog.template.html'], function (template) { - - var dialogOptions = { - removeOnClose: true, - scrollY: false - }; - - if (layoutManager.tv) { - dialogOptions.size = 'fullscreen'; - } else { - dialogOptions.size = 'medium-tall'; - } - - var dlg = dialogHelper.createDialog(dialogOptions); - - dlg.classList.add('formDialog'); - - var html = ''; - var submitted = false; - - html += globalize.translateDocument(template, 'core'); - - dlg.innerHTML = html; - - if (layoutManager.tv) { - centerFocus(dlg.querySelector('.formDialogContent'), false, true); - } - - var homescreenSettingsInstance = new HomescreenSettings({ - serverId: options.serverId, - userId: options.userId, - element: dlg.querySelector('.settingsContent'), - userSettings: options.userSettings, - enableSaveButton: false, - enableSaveConfirmation: false - }); - - dialogHelper.open(dlg); - - dlg.addEventListener('close', function () { - - if (layoutManager.tv) { - centerFocus(dlg.querySelector('.formDialogContent'), false, false); - } - - if (submitted) { - resolve(); - } else { - reject(); - } - }); - - dlg.querySelector('.btnCancel').addEventListener('click', function (e) { - - dialogHelper.close(dlg); - }); - - dlg.querySelector('.btnSave').addEventListener('click', function (e) { - - submitted = true; - homescreenSettingsInstance.submit(); - }); - - events.on(homescreenSettingsInstance, 'saved', function () { - submitted = true; - dialogHelper.close(dlg); - }); - }); - }); - } - - return { - show: show - }; -}); \ No newline at end of file diff --git a/src/components/homescreensettings/homescreensettingsdialog.template.html b/src/components/homescreensettings/homescreensettingsdialog.template.html deleted file mode 100644 index d707fcdfb4..0000000000 --- a/src/components/homescreensettings/homescreensettingsdialog.template.html +++ /dev/null @@ -1,22 +0,0 @@ -
- -

- ${HeaderDisplaySettings} -

-
- -
-
- -
- -
- -
- -
- -
-
\ No newline at end of file diff --git a/src/scripts/site.js b/src/scripts/site.js index 838608c661..deea1be286 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -783,7 +783,6 @@ var AppInfo = {}; define("displaySettings", [componentsPath + "/displaysettings/displaysettings"], returnFirstDependency); define("playbackSettings", [componentsPath + "/playbacksettings/playbacksettings"], returnFirstDependency); define("homescreenSettings", [componentsPath + "/homescreensettings/homescreensettings"], returnFirstDependency); - define("homescreenSettingsDialog", [componentsPath + "/homescreensettings/homescreensettingsdialog"], returnFirstDependency); define("playbackManager", [componentsPath + "/playback/playbackmanager"], getPlaybackManager); define("layoutManager", [componentsPath + "/layoutManager", "apphost"], getLayoutManager); define("homeSections", [componentsPath + "/homesections/homesections"], returnFirstDependency); From 8c2f56394f1a0c3274aef0f1d0952fb8aba9501f Mon Sep 17 00:00:00 2001 From: Albin Larsson Date: Thu, 22 Aug 2019 13:14:05 +0200 Subject: [PATCH 29/80] add favorite books section to favorite tab tmp --- src/controllers/favorites.js | 9 +++++++++ src/strings/de.json | 1 + src/strings/en-gb.json | 1 + src/strings/en-us.json | 1 + 4 files changed, 12 insertions(+) diff --git a/src/controllers/favorites.js b/src/controllers/favorites.js index 4412ec6e9b..6c521f7bfe 100644 --- a/src/controllers/favorites.js +++ b/src/controllers/favorites.js @@ -108,6 +108,15 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap overlayMoreButton: !0, action: "instantmix", coverImage: !0 + }, { + name: "HeaderFavoriteBooks", + types: "Book", + shape: getPosterShape(), + showTitle: true, + showYear: true, + overlayPlayButton: true, + overlayText: false, + centerText: true }] } diff --git a/src/strings/de.json b/src/strings/de.json index 424eb49cb7..d144818b0e 100644 --- a/src/strings/de.json +++ b/src/strings/de.json @@ -1412,6 +1412,7 @@ "Whitelist": "Erlaubt", "AuthProviderHelp": "Auswählen eines Authentifizierungsanbieter, der zur Authentifizierung des Passworts dieses Benutzes verwendet werden soll", "Features": "Features", + "HeaderFavoriteBooks": "Lieblingsbücher", "HeaderFavoriteMovies": "Lieblingsfilme", "HeaderFavoriteShows": "Lieblingsserien", "HeaderFavoriteEpisodes": "Lieblingsepisoden", diff --git a/src/strings/en-gb.json b/src/strings/en-gb.json index 5873d8ae70..4407164e1f 100644 --- a/src/strings/en-gb.json +++ b/src/strings/en-gb.json @@ -385,6 +385,7 @@ "HeaderEpisodes": "Episodes", "HeaderError": "Error", "HeaderExternalIds": "External IDs:", + "HeaderFavoriteBooks": "Favourite Books", "HeaderFavoriteMovies": "Favourite Movies", "HeaderFavoriteShows": "Favourite Shows", "HeaderFavoriteEpisodes": "Favourite Episodes", diff --git a/src/strings/en-us.json b/src/strings/en-us.json index 2c7b98167f..db07c756c4 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -351,6 +351,7 @@ "HeaderEpisodes": "Episodes", "HeaderError": "Error", "HeaderExternalIds": "External IDs:", + "HeaderFavoriteBooks": "Favorite Books", "HeaderFavoriteMovies": "Favorite Movies", "HeaderFavoriteShows": "Favorite Shows", "HeaderFavoriteEpisodes": "Favorite Episodes", From 137947772336f8d15724856b8aba96d9906f083b Mon Sep 17 00:00:00 2001 From: WWWesten Date: Fri, 30 Aug 2019 13:34:05 +0000 Subject: [PATCH 30/80] Translated using Weblate (Russian) Currently translated at 100.0% (1443 of 1443 strings) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/ru/ --- src/strings/ru.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/ru.json b/src/strings/ru.json index 83b67d58ee..67f6333d16 100644 --- a/src/strings/ru.json +++ b/src/strings/ru.json @@ -54,7 +54,7 @@ "BoxRear": "Спинка коробки", "Browse": "Навигация", "BrowsePluginCatalogMessage": "Просмотрите каталог плагинов, чтобы ознакомиться с имеющимися плагинами.", - "BurnSubtitlesHelp": "Определяется, должен ли сервер внедрять субтитры при преобразовании видео в зависимости от формата субтитров. Избегание внедрения субтитров улучшит производительность сервера. Выберите «Авто» для записи основанных на графике форматов (например, VOBSUB, PGS, SUB/IDX и т.п.), а также некоторых субтитров ASS/SSA", + "BurnSubtitlesHelp": "Определяется, должен ли сервер внедрять субтитры при преобразовании видео в зависимости от формата субтитров. Избегание внедрения субтитров улучшит производительность сервера. Выберите «Авто» для записи основанных на графике форматов (например, VOBSUB, PGS, SUB/IDX и т.п.), а также некоторых субтитров ASS/SSA.", "ButtonAdd": "Добавить", "ButtonAddMediaLibrary": "Добавить медиатеку", "ButtonAddScheduledTaskTrigger": "Добавить триггер", From 57d87caaeb53b60bfb24d51ce48602fb4b7fd8eb Mon Sep 17 00:00:00 2001 From: NunzioArdi Date: Thu, 29 Aug 2019 14:40:04 +0000 Subject: [PATCH 31/80] Translated using Weblate (French) Currently translated at 99.9% (1441 of 1443 strings) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fr/ --- src/strings/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/fr.json b/src/strings/fr.json index 346e83bfe7..5db2c9aa31 100644 --- a/src/strings/fr.json +++ b/src/strings/fr.json @@ -1411,7 +1411,7 @@ "MediaInfoStreamTypeData": "Données", "MediaInfoStreamTypeSubtitle": "Sous-titres", "MediaInfoStreamTypeVideo": "Video", - "AuthProviderHelp": "Sélectionnez le fournisseur d'authentification à utiliser pour identifier cet utilisateur par mot de passe", + "AuthProviderHelp": "Sélectionner un fournisseur d'authentification pour authentifier le mot de passe de cet utilisateur", "PasswordResetProviderHelp": "Choisissez un Fournisseur de réinitialisation de mot de passe à utiliser lorsqu'un utilisateur demande la réinitialisation de son mot de passe", "HeaderHome": "Accueil", "HeaderHomeSettings": "Paramètre d'Accueil", From 2f0683f82667be871c7c7c2a347116d407dee21a Mon Sep 17 00:00:00 2001 From: qqq-qqqq Date: Sat, 31 Aug 2019 15:52:44 +0000 Subject: [PATCH 32/80] Translated using Weblate (Chinese (Simplified)) Currently translated at 97.4% (1405 of 1443 strings) 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, 2 insertions(+), 2 deletions(-) diff --git a/src/strings/zh-cn.json b/src/strings/zh-cn.json index b3fbe4a16a..536887372e 100644 --- a/src/strings/zh-cn.json +++ b/src/strings/zh-cn.json @@ -1351,8 +1351,8 @@ "DirectStreamHelp1": "该媒体文件的分辨率和编码(H.264、AC3 等)与您的设备兼容,但容器格式(.mkv、.avi、.wmv 等)不受支持。因此,视频在串流至您的设备之前将会被即时封装为另一种格式。", "HeaderAppearsOn": "出现于", "HeaderCancelSeries": "取消系列", - "HeaderFavoriteEpisodes": "最喜欢的剧集", - "HeaderFavoriteArtists": "最喜欢的演员", + "HeaderFavoriteEpisodes": "最爱的剧集", + "HeaderFavoriteArtists": "最爱的艺术家", "HeaderKeepRecording": "继续录制", "HeaderKeepSeries": "保持系列", "HeaderMusicQuality": "音质", From 96584b5786e84b823afc0eea9d8b705547cdff56 Mon Sep 17 00:00:00 2001 From: tluciomiranda Date: Fri, 6 Sep 2019 20:36:02 +0000 Subject: [PATCH 33/80] Translated using Weblate (Portuguese (Portugal)) Currently translated at 58.7% (847 of 1443 strings) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/pt_PT/ --- src/strings/pt-pt.json | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index 05e6173a99..0b7836d388 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -795,7 +795,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, dependendo do formato da legenda. Evitar integração de legendas melhora o desempenho do servidor. Selecione Auto para que legendas baseadas em imagem (VOBSUB, PGS, SUB/IDX, etc.), assim como alguns formatos ASS/SSA sejam integrados", + "BurnSubtitlesHelp": "Determina se o servidor deve integrar as legendas durante a conversão de vídeo, dependendo do formato da legenda. Evitar integração de legendas melhora o desempenho do servidor. Selecione Auto para que legendas baseadas em imagem (VOBSUB, PGS, SUB/IDX, etc.), assim como alguns formatos ASS/SSA sejam integrados.", "Channels": "Canais", "Collections": "Coleções", "Favorites": "Favoritos", @@ -813,5 +813,39 @@ "Shows": "Séries", "Songs": "Músicas", "Sync": "Sincronização", - "Absolute": "Absoluta" + "Absolute": "Absoluto", + "CriticRating": "Avaliação dos críticos", + "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", + "CommunityRating": "Avaliação da comunidade", + "ChannelNumber": "Número do canal", + "ChannelNameOnly": "Apenas canal {0}", + "ChangingMetadataImageSettingsNewContent": "Alterações às definições de transferência de metadados ou capas apenas serão aplicadas a conteúdo novo adicionado à biblioteca. Para aplicar as alterações aos itens já existentes, necessitará de atualizar manualmente os metadados.", + "Categories": "Categorias", + "CancelSeries": "Cancelar série", + "CancelRecording": "Cancelar gravação", + "ButtonWebsite": "Website", + "ButtonTrailer": "Trailer", + "ButtonSelectServer": "Selecionar Servidor", + "ButtonRename": "Alterar o nome", + "ButtonParentalControl": "Controlo parental", + "ButtonOther": "Outro", + "ButtonOk": "OK", + "ButtonLibraryAccess": "Acesso à biblioteca", + "ButtonGuide": "Guia", + "ButtonGotIt": "Entendido", + "ButtonEditImages": "Editar imagens", + "ButtonDownload": "Transferir", + "ButtonAudioTracks": "Faixas de Áudio", + "Browse": "Procurar", + "BoxRear": "Caixa (verso)", + "Box": "Caixa", + "BookLibraryHelp": "Livros de texto e áudio são suportados. Consulte o Guia de Nomenclatura de Livros Jellyfin {1}.", + "BirthLocation": "Local de nascimento", + "AsManyAsPossible": "Tantos quanto possível", + "Art": "Capa", + "Anytime": "Qualquer altura", + "Aired": "Estreou" } From 9e0d13ebaf1b0c00c683d3dfda9674d6a43f35d0 Mon Sep 17 00:00:00 2001 From: ZsiGiT Date: Wed, 28 Aug 2019 13:12:00 +0000 Subject: [PATCH 34/80] Translated using Weblate (Hungarian) Currently translated at 95.1% (1373 of 1443 strings) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/hu/ --- src/strings/hu.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/strings/hu.json b/src/strings/hu.json index ce05bd5b4f..0c3c56e3de 100644 --- a/src/strings/hu.json +++ b/src/strings/hu.json @@ -1372,5 +1372,7 @@ "LabelLocalHttpServerPortNumberHelp": "A TCP port száma, melyen a Jellyfin HTTP szerver figyel.", "UserAgentHelp": "Adj meg egy egyedi http user-agent fejlécet, amennyiben szükséges.", "XmlDocumentAttributeListHelp": "Ezek a tulajdonságok minden xml válaszüzenet gyökér elemére alkalmazásra kerülnek.", - "Thumb": "Thumb" + "Thumb": "Thumb", + "MediaInfoStreamTypeData": "Adat", + "MediaInfoStreamTypeEmbeddedImage": "Beágyazott kép" } From a28270bdd35606b04ca27e55d025a7784d6d814f Mon Sep 17 00:00:00 2001 From: Matteo Zannini Date: Thu, 29 Aug 2019 22:46:23 +0000 Subject: [PATCH 35/80] Translated using Weblate (Italian) Currently translated at 90.8% (1310 of 1443 strings) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/it/ --- src/strings/it.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strings/it.json b/src/strings/it.json index 6b521b33ee..8ee2b6fb78 100644 --- a/src/strings/it.json +++ b/src/strings/it.json @@ -4,7 +4,7 @@ "Actor": "Attore", "Add": "Aggiungi", "AddItemToCollectionHelp": "Aggiungi elementi alle collezioni ricercandoli e utilizzando il pulsante destro del mouse o toccare i menu per aggiungerli a una raccolta.", - "AddToCollection": "Aggiungi ad una collezione", + "AddToCollection": "Aggiunto alla collezione", "AddToPlayQueue": "Aggiungi alla coda di riproduzione", "AddToPlaylist": "Aggiungi alla playlist", "AddedOnValue": "Aggiunto {0}", @@ -1322,8 +1322,8 @@ "AuthProviderHelp": "Selezionare un Authentication Provider da utilizzare per autenticare la password dell'utente", "HeaderFavoriteMovies": "Film Preferiti", "HeaderFavoriteShows": "Serie TV Preferite", - "HeaderFavoriteEpisodes": "Episodi Favoriti", - "HeaderFavoriteAlbums": "Album Favoriti", + "HeaderFavoriteEpisodes": "Episodi Preferiti", + "HeaderFavoriteAlbums": "Album preferiti", "HeaderFavoriteArtists": "Artisti Preferiti", "HeaderFavoriteSongs": "Brani Preferiti", "HeaderFavoriteVideos": "Video Preferiti", From 476eaff384bbdcd8a0653a20a9ea8f49745f69ea Mon Sep 17 00:00:00 2001 From: WWWesten Date: Fri, 30 Aug 2019 13:38:15 +0000 Subject: [PATCH 36/80] Translated using Weblate (Kazakh) Currently translated at 100.0% (1443 of 1443 strings) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/kk/ --- src/strings/kk.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/kk.json b/src/strings/kk.json index 814aa28d99..d5d899d509 100644 --- a/src/strings/kk.json +++ b/src/strings/kk.json @@ -56,7 +56,7 @@ "BoxRear": "Qorap arty", "Browse": "Sharlaý", "BrowsePluginCatalogMessage": "Qoljetimdi plagındermen tanysý úshin plagın tizimdemesin sholyńyz.", - "BurnSubtitlesHelp": "Sýbtıtrler pishimine baılanysty beıneni túrlendirgen kezde server sýbtıtrlerdi jazyýyn anyqtaıdy. Sýbtıtrler jazýdy qashqaqtaý serverdiń ónimdiligin jaqsartady. Sýretke negizdelgen pishimderdi (mysaly, VOBSUB, PGS, SUB/IDX j.t.b.), sondaı-aq keıbir ASS/SSA sýbtıtrlerin jazý úshin Avtomattyny tańdańyz", + "BurnSubtitlesHelp": "Sýbtıtrler pishimine baılanysty beıneni túrlendirgen kezde server sýbtıtrlerdi jazyýyn anyqtaıdy. Sýbtıtrler jazýdy qashqaqtaý serverdiń ónimdiligin jaqsartady. Sýretke negizdelgen pishimderdi (mysaly, VOBSUB, PGS, SUB/IDX j.t.b.), sondaı-aq keıbir ASS/SSA sýbtıtrlerin jazý úshin Avtomattyny tańdańyz.", "ButtonAdd": "Ústeý", "ButtonAddMediaLibrary": "Tasyǵyshhanany ústeý", "ButtonAddScheduledTaskTrigger": "Trıggerdi ústeý", From 0c22b76035c2096d32e605468eeb8f068fee51f9 Mon Sep 17 00:00:00 2001 From: tluciomiranda Date: Fri, 6 Sep 2019 20:57:37 +0000 Subject: [PATCH 37/80] Translated using Weblate (Portuguese (Portugal)) Currently translated at 64.9% (936 of 1443 strings) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/pt_PT/ --- src/strings/pt-pt.json | 101 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 6 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index 0b7836d388..92626f5091 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -181,7 +181,7 @@ "HeaderLibraryFolders": "Pastas multimédia", "HeaderLibrarySettings": "Definições da Biblioteca", "HeaderLiveTV": "TV em Direto", - "HeaderLiveTv": "TV ao Vivo", + "HeaderLiveTv": "TV em Direto", "HeaderLoginFailure": "Falha no Login", "HeaderMedia": "Multimédia", "HeaderMediaFolders": "Pastas Multimédia", @@ -545,10 +545,10 @@ "OptionAlbumArtist": "Artista do Álbum", "OptionAllUsers": "Todos os utilizadores", "OptionAllowAudioPlaybackTranscoding": "Permitir reprodução de áudio que necessite de transcodificação", - "OptionAllowBrowsingLiveTv": "Permitir acesso a TV ao Vivo", + "OptionAllowBrowsingLiveTv": "Permitir acesso a TV em Direto", "OptionAllowContentDownloading": "Permitir download dos ficheiros multimédia", "OptionAllowLinkSharing": "Permitir partilha nas redes sociais", - "OptionAllowManageLiveTv": "Permitir gerir gravações de TV ao Vivo", + "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.", "OptionAllowRemoteControlOthers": "Permitir controlo remoto de outros utilizadores", @@ -561,7 +561,7 @@ "OptionAutomatic": "Automático", "OptionBlockBooks": "Livros", "OptionBlockChannelContent": "Conteúdo do Canal de Internet", - "OptionBlockLiveTvChannels": "Canais de TV ao vivo", + "OptionBlockLiveTvChannels": "Canais de TV em Direto", "OptionBlockMovies": "Filmes", "OptionBlockMusic": "Música", "OptionBlockTvShows": "Séries de TV", @@ -710,7 +710,7 @@ "TabGenres": "Géneros", "TabGuide": "Guia", "TabLatest": "Mais recente", - "TabLiveTV": "TV ao Vivo", + "TabLiveTV": "TV em Direto", "TabMetadata": "Metadados", "TabMovies": "Filmes", "TabMusic": "Música", @@ -847,5 +847,94 @@ "AsManyAsPossible": "Tantos quanto possível", "Art": "Capa", "Anytime": "Qualquer altura", - "Aired": "Estreou" + "Aired": "Estreou", + "HeaderKeepRecording": "Manter Gravação", + "HeaderKeepSeries": "Manter Série", + "HeaderItems": "Itens", + "HeaderImageOptions": "Opções de Imagem", + "HeaderHome": "Início", + "HeaderForKids": "Para Crianças", + "HeaderFavoriteVideos": "Vídeos Favoritos", + "HeaderFavoriteMovies": "Filmes Favoritos", + "HeaderExternalIds": "IDs Externos:", + "HeaderEpisodes": "Episódios", + "HeaderEditImages": "Editar Imagens", + "HeaderDownloadSync": "Transferência & Sincronização", + "HeaderDetectMyDevices": "Detetar os Meus Dispositivos", + "HeaderDeleteProvider": "Apagar Provedor", + "HeaderDeleteDevice": "Apagar Dispositivo", + "HeaderDefaultRecordingSettings": "Definições de Gravação por Defeito", + "HeaderContinueListening": "Continuar a Ouvir", + "HeaderConnectionFailure": "Falha de ligação", + "HeaderConfirmPluginInstallation": "Confirmar instalação de Plug-In", + "HeaderConfigureRemoteAccess": "Configurar Acesso Remoto", + "HeaderChapterImages": "Imagens do Capítulo", + "HeaderCancelSeries": "Cancelar Série", + "HeaderCancelRecording": "Cancelar Gravação", + "HeaderBooks": "Livros", + "HeaderAudioBooks": "Livros de Áudio", + "HeaderAllowMediaDeletionFrom": "Permitir remoção de multimédia a partir de", + "HeaderAlert": "Alerta", + "HeaderAlbums": "Álbuns", + "HeaderAddToPlaylist": "Adicionar à Lista de Reprodução", + "HandledByProxy": "Gerido pelo proxy inverso", + "HDPrograms": "Programas HD", + "H264EncodingPresetHelp": "Escolha um valor mais rápido para melhorar o desempenho, ou um valor mais lento para melhorar a qualidade.", + "Guide": "Guia", + "GuestStar": "Estrela convidada", + "GroupVersions": "Agrupar versões", + "GroupBySeries": "Agrupar por série", + "GenresValue": "Géneros: {0}", + "GenreValue": "Género: {0}", + "General": "Geral", + "FormatValue": "Formato: {0}", + "ForAdditionalLiveTvOptions": "Para encontrar provedores de serviços de TV, clique no separador Serviços para ver os provedores disponíveis.", + "FolderTypeUnset": "Conteúdo misto", + "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 encontrar-se na mesma pasta. Estes componentes são, por norma, instalados em conjunto. Por favor, verifique o caminho da localização e tente de novo.", + "Extras": "Extras", + "ExtraLarge": "Extra grande", + "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.", + "ErrorMessageStartHourGreaterThanEnd": "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.", + "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, garanta que o ficheiro está acessível e tente de novo.", + "Episodes": "Episódios", + "EndsAtValue": "Termina às {0}", + "EnablePhotosHelp": "Fotografias serão detectadas e mostradas em conjunto com outros ficheiros multimédia.", + "EnablePhotos": "Ativar fotografias", + "EnableNextVideoInfoOverlayHelp": "No final de um vídeo, mostrar informação sobre o próximo vídeo da lista de reprodução.", + "EnableNextVideoInfoOverlay": "Ativar informação sobre o próximo vídeo durante a reprodução", + "EnableHardwareEncoding": "Ativar codificação por hardware", + "EnableExternalVideoPlayersHelp": "O menu de um reprodutor externo será mostrado no início da reprodução de vídeo.", + "EnableExternalVideoPlayers": "Ativar reprodutores de vídeo externos", + "EnableDisplayMirroring": "Ativar espelho de ecrã", + "EnableColorCodedBackgrounds": "Ativar código de cores para o fundo", + "EditSubtitles": "Editar legendas", + "EditMetadata": "Editar metadados", + "EditImages": "Editar imagens", + "DrmChannelsNotImported": "Canais com proteção DRM não serão importados.", + "DownloadsValue": "{0} transferências", + "Download": "Transferir", + "DoNotRecord": "Não gravar", + "DisplayModeHelp": "Selecione o tipo de ecrã onde o Jellyfin será utilizado.", + "DisplayMissingEpisodesWithinSeasonsHelp": "Deve também ser ativado para as bibliotecas de TV no painel de controlo do Servidor Jellyfin.", + "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", + "Dislike": "Não gosto", + "Disconnect": "Desligar", + "Disabled": "Desativado", + "DirectStreaming": "Reprodução direta", + "DirectStreamHelp2": "Reprodução direta de um ficheiro requer pouco processamento e não implica perda de qualidade num vídeo.", + "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.", + "DefaultErrorMessage": "Ocorreu um erro a processar o pedido. Por favor, tente novamente mais tarde.", + "Default": "Por defeito", + "DeathDateValue": "Faleceu: {0}", + "DatePlayed": "Reproduzido a", + "DateAdded": "Adicionado a" } From 266aac4364eec56710582ec306eb3b3022530a88 Mon Sep 17 00:00:00 2001 From: tluciomiranda Date: Mon, 9 Sep 2019 14:19:33 +0000 Subject: [PATCH 38/80] 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 | 45 ++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index 92626f5091..5e6baa3cb8 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -75,19 +75,19 @@ "ChannelAccessHelp": "Selecione os canais a compartilhar com este utilizador. Administradores poderão editar todos os canais usando 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.", "Composer": "Compositor", - "ConfirmDeleteItem": "Excluir este item o excluirá do sistema de arquivos e também da biblioteca multimédia. Deseja realmente continuar?", - "ConfirmDeleteItems": "Ao excluir estes itens você os excluirá do sistema de arquivos e de sua biblioteca multimédia. Deseja realmente continuar?", + "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?", "ConfirmDeletion": "Confirmar Exclusão", "Connect": "Conectar", "Continuing": "A Continuar", "CustomDlnaProfilesHelp": "Crie um perfil personalizado para um novo dispositivo ou para sobrepor um perfil de sistema.", "Delete": "Remover", - "DeleteDeviceConfirmation": "Deseja realmente excluir este dispositivo? Ele reaparecerá da próxima vez que um utilizador o utilize.", + "DeleteDeviceConfirmation": "Tem a certeza de que deseja apagar este dispositivo? Irá reaparecer da próxima vez que o utilizador inicie sessão a partir dele.", "DeleteImage": "Apagar Imagem", - "DeleteImageConfirmation": "Tem a certeza que deseja apagar a imagem?", + "DeleteImageConfirmation": "Tem a certeza de que deseja apagar a imagem?", "DeleteMedia": "Remover multimédia", "DeleteUser": "Apagar Utilizador", - "DeleteUserConfirmation": "Tem a certeza que deseja apagar este utilizador?", + "DeleteUserConfirmation": "Tem a certeza de que deseja apagar este utilizador?", "DeviceAccessHelp": "Isto apenas se aplica para dispositivos que podem ser identificados como únicos e não evitarão o acesso do navegador. Filtrar o acesso ao dispositivo do utilizador evita que sejam usados novos dispositivos até que sejam aprovados aqui.", "Director": "Diretor", "EasyPasswordHelp": "Seu código pin fácil é usado para acesso off-line com apps suportados pelo Jellyfin e pode ser usado para acesso fácil dentro da rede.", @@ -506,14 +506,14 @@ "LabelZipCode": "CEP:", "LibraryAccessHelp": "Escolha as pastas multimédia a partilhar com este utilizador. Os Administradores poderão editar todas as pastas, usando o Gestor de Metadados.", "MaxParentalRatingHelp": "Conteúdo com classificação mais elevada será escondida deste utilizador.", - "MessageAreYouSureDeleteSubtitles": "Deseja realmente remover este arquivo de legendas?", - "MessageAreYouSureYouWishToRemoveMediaFolder": "Deseja realmente excluir esta pasta multimédia?", - "MessageConfirmProfileDeletion": "Deseja realmente remover este perfil?", - "MessageConfirmRecordingCancellation": "Deseja realmente cancelar esta gravação?", - "MessageConfirmRestart": "Deseja realmente reiniciar o Servidor Jellyfin?", - "MessageConfirmRevokeApiKey": "Deseja realmente revogar esta chave de api? A conexão da aplicação com o Servidor Jellyfin será abruptamente encerrada.", - "MessageConfirmShutdown": "Deseja realmente desligar o Servidor Jellyfin?", - "MessageDeleteTaskTrigger": "Deseja realmente excluir este disparador de tarefa?", + "MessageAreYouSureDeleteSubtitles": "Tem a certeza de que deseja remover este ficheiro de legendas?", + "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 abruptamente.", + "MessageConfirmShutdown": "Tem a certeza de que deseja encerrar o Servidor Jellyfin?", + "MessageDeleteTaskTrigger": "Tem a certeza de que deseja remover o agendamento desta tarefa?", "MessageDirectoryPickerBSDInstruction": "Para BSD, você precisará configurar o disco dentro de seu Jail do FreeNAS para permitir que o Jellyfin tenha acesso a ele.", "MessageDirectoryPickerInstruction": "Os locais de rede podem ser digitados manualmente caso o botão de Rede não consiga localizar seus dispositivos. Por exemplo, {0} ou {1}.", "MessageDirectoryPickerLinuxInstruction": "Para Linux no Arch Linux, CentOS, Debian, Fedora, OpenSuse ou Ubuntu, você deve permitir que o utilizador Jellyfin tenha ao menos acesso de leitura no seu disco.", @@ -652,14 +652,14 @@ "OptionWeekdays": "Dias da semana", "OptionWeekends": "Fins-de-semana", "OptionWeekly": "Semanalmente", - "ParentalRating": "Parental Rating", - "PasswordMatchError": "A senha e a confirmação da senha devem coincidir.", - "PasswordResetComplete": "A senha foi redefinida.", - "PasswordResetConfirmation": "Tem a certeza que deseja redefinir a senha?", - "PasswordResetHeader": "Redefinir Senha", + "ParentalRating": "Classificação parental", + "PasswordMatchError": "A password e a confirmação da password devem coincidir.", + "PasswordResetComplete": "A password foi redefinida.", + "PasswordResetConfirmation": "Tem a certeza de que deseja redefinir a password?", + "PasswordResetHeader": "Redefinir Password", "PasswordSaved": "Senha guardada.", "PinCodeResetComplete": "O código pin foi redefinido.", - "PinCodeResetConfirmation": "Deseja realmente redefinir o código pin?", + "PinCodeResetConfirmation": "Tem a certeza de que devia repôr o código PIN?", "Play": "Reproduzir", "PlayNextEpisodeAutomatically": "Reproduzir próximo episódio automaticamente", "PleaseEnterNameOrId": "Por favor, digite um nome ou Id externo.", @@ -746,7 +746,7 @@ "TitlePlayback": "Reprodução", "TrackCount": "{0} faixas", "Tuesday": "Terça", - "UninstallPluginConfirmation": "Tem a certeza que deseja desinstalar {0}?", + "UninstallPluginConfirmation": "Tem a certeza de que deseja desinstalar {0}?", "UninstallPluginHeader": "Desinstalar extensão", "Unmute": "Ativar Som", "UserProfilesIntro": "O Jellyfin inclui suporte nativo de perfis de utilizadores, permitindo que cada utilizador tenha as suas configurações de visualização, estado da reprodução e controlos parentais.", @@ -936,5 +936,8 @@ "Default": "Por defeito", "DeathDateValue": "Faleceu: {0}", "DatePlayed": "Reproduzido a", - "DateAdded": "Adicionado a" + "DateAdded": "Adicionado a", + "MessageContactAdminToResetPassword": "Por favor, contacte o Administrador de sistema para repôr a sua password.", + "MessageConfirmRemoveMediaLocation": "Tem a certeza de que deseja remover esta localização?", + "MessageConfirmDeleteTunerDevice": "Tem a certeza de que deseja remover este dispositivo?" } From db7e016aa7030271e6023ff19439218767bfad76 Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Tue, 10 Sep 2019 00:02:59 -0400 Subject: [PATCH 39/80] Allow fldSelectLoginProvider for admins And the same for fldSelectPasswordResetProvider. Allows modification of the authentication provider and password reset provider for admins, if applicable. Further converts the reset provider to a trinary rather than single-line if/else statements. --- src/controllers/useredit.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/controllers/useredit.js b/src/controllers/useredit.js index 356a93c4e7..0709e8dae9 100644 --- a/src/controllers/useredit.js +++ b/src/controllers/useredit.js @@ -13,7 +13,7 @@ define(["jQuery", "loading", "libraryMenu", "fnchecked"], function($, loading, l } function loadAuthProviders(page, user, providers) { - providers.length > 1 && !user.Policy.IsAdministrator ? page.querySelector(".fldSelectLoginProvider").classList.remove("hide") : page.querySelector(".fldSelectLoginProvider").classList.add("hide"); + providers.length > 1 ? page.querySelector(".fldSelectLoginProvider").classList.remove("hide") : page.querySelector(".fldSelectLoginProvider").classList.add("hide"); var currentProviderId = user.Policy.AuthenticationProviderId; page.querySelector(".selectLoginProvider").innerHTML = providers.map(function(provider) { var selected = provider.Id === currentProviderId || providers.length < 2 ? " selected" : ""; @@ -22,11 +22,7 @@ define(["jQuery", "loading", "libraryMenu", "fnchecked"], function($, loading, l } function loadPasswordResetProviders(page, user, providers) { - if (providers.length > 1 && !user.Policy.IsAdministrator) { - page.querySelector(".fldSelectPasswordResetProvider").classList.remove("hide"); - } else { - page.querySelector(".fldSelectPasswordResetProvider").classList.add("hide"); - } + providers.length > 1 ? page.querySelector(".fldSelectPasswordResetProvider").classList.remove("hide") : page.querySelector(".fldSelectPasswordResetProvider").classList.add("hide"); var currentProviderId = user.Policy.PasswordResetProviderId; page.querySelector(".selectPasswordResetProvider").innerHTML = providers.map(function(provider) { var selected = (provider.Id === currentProviderId || providers.length < 2) ? " selected" : ""; From e46ddedf0c31802628fec7900f01b1936bc93ce7 Mon Sep 17 00:00:00 2001 From: tluciomiranda Date: Mon, 9 Sep 2019 14:33:58 +0000 Subject: [PATCH 40/80] 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 | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index 5e6baa3cb8..7477b51d87 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -26,7 +26,7 @@ "ButtonEdit": "Editar", "ButtonEditOtherUserPreferences": "Editar este perfil de utilizador, imagem e preferências pessoais.", "ButtonFilter": "Filtro", - "ButtonForgotPassword": "Esqueci a senha", + "ButtonForgotPassword": "Esqueci-me da palavra-passe", "ButtonFullscreen": "Ecrã Inteiro", "ButtonHelp": "Ajuda", "ButtonHome": "Início", @@ -48,7 +48,7 @@ "ButtonRemove": "Remover", "ButtonRepeat": "Repetir", "ButtonResetEasyPassword": "Redefinir código pin fácil", - "ButtonResetPassword": "Redefinir Senha", + "ButtonResetPassword": "Redefinir palavra-passe", "ButtonRestart": "Reiniciar", "ButtonResume": "Retomar", "ButtonRevoke": "Revogar", @@ -159,7 +159,7 @@ "HeaderFeatures": "Recursos", "HeaderFetchImages": "Buscar Imagens:", "HeaderFilters": "Filtros", - "HeaderForgotPassword": "Esqueci a Senha", + "HeaderForgotPassword": "Esqueci-me da palavra-passe", "HeaderFrequentlyPlayed": "Reproduzido frequentemente", "HeaderGenres": "Gêneros", "HeaderGuideProviders": "Provedores de Guia", @@ -192,8 +192,8 @@ "HeaderNewApiKey": "Nova Chave da API", "HeaderNextUp": "A Seguir", "HeaderParentalRatings": "Classificações Parentais", - "HeaderPassword": "Senha", - "HeaderPasswordReset": "Redefinição de Senha", + "HeaderPassword": "Palavra-passe", + "HeaderPasswordReset": "Redefinição de Palavra-Passe", "HeaderPaths": "Localizações", "HeaderPendingInvitations": "Convites pendentes", "HeaderPeople": "Pessoas", @@ -299,7 +299,7 @@ "LabelContentType": "Tipo de conteúdo:", "LabelCountry": "País:", "LabelCriticRating": "Avaliação da crítica:", - "LabelCurrentPassword": "Senha actual:", + "LabelCurrentPassword": "Palavra-Passe atual:", "LabelCustomCertificatePath": "Localização do certificado SSL personalizado:", "LabelCustomCertificatePathHelp": "Forneça o seu próprio ficheiro .pfx do certificado ssl.", "LabelCustomCss": "CSS personalizado:", @@ -403,7 +403,7 @@ "LabelMetadataPathHelp": "Define um local para artwork e metadados baixados da internet.", "LabelMethod": "Método:", "LabelMinBackdropDownloadWidth": "Transferir Imagens de fundo com o tamanho mínimo:", - "LabelMinResumeDuration": "Duração mínima da retoma (segundos):", + "LabelMinResumeDuration": "Duração mínima da retoma:", "LabelMinResumeDurationHelp": "Conteúdos com duração inferior não permitirão parar e retomar a reprodução", "LabelMinResumePercentage": "Percentagem mínima para retomar:", "LabelMinResumePercentageHelp": "Os títulos são considerados não assistidos se parados antes deste tempo", @@ -416,8 +416,8 @@ "LabelMusicStreamingTranscodingBitrate": "Taxa de transcodificação das músicas:", "LabelMusicStreamingTranscodingBitrateHelp": "Defina a taxa máxima ao fazer streaming das músicas", "LabelName": "Nome:", - "LabelNewPassword": "Nova senha:", - "LabelNewPasswordConfirm": "Confirmar nova senha:", + "LabelNewPassword": "Nova palavra-passe:", + "LabelNewPasswordConfirm": "Confirmar nova palavra-passe:", "LabelNext": "Seguinte", "LabelNotificationEnabled": "Ativar esta notificação", "LabelNumberOfGuideDays": "Número de dias de informação do guia para transferir:", @@ -425,8 +425,8 @@ "LabelOriginalAspectRatio": "Proporção da imagem original:", "LabelOverview": "Sinopse:", "LabelParentalRating": "Classificação parental:", - "LabelPassword": "Senha:", - "LabelPasswordConfirm": "Senha (confirmar):", + "LabelPassword": "Palavra-Passe:", + "LabelPasswordConfirm": "Palavra-Passe (confirmar):", "LabelPasswordRecoveryPinCode": "Código pin:", "LabelPath": "Local:", "LabelPersonRole": "Personagem:", @@ -519,7 +519,7 @@ "MessageDirectoryPickerLinuxInstruction": "Para Linux no Arch Linux, CentOS, Debian, Fedora, OpenSuse ou Ubuntu, você deve permitir que o utilizador Jellyfin tenha ao menos acesso de leitura no seu disco.", "MessageEnablingOptionLongerScans": "Ativar esta opção pode aumentar significativamente a duração da análise da biblioteca.", "MessageFileReadError": "Ocorreu um erro ao ler este arquivo.", - "MessageInvalidUser": "Nome de utilizador ou senha inválidos. Por favor, tente novamente.", + "MessageInvalidUser": "Nome de utilizador ou palavra-passe inválidos. Por favor, tente novamente.", "MessageItemSaved": "Item salvo.", "MessageItemsAdded": "Itens adicionados.", "MessageLeaveEmptyToInherit": "Deixar em branco para herdar as configurações do item pai, ou o valor global por defeito.", @@ -605,7 +605,7 @@ "OptionHasThemeSong": "Música de Tema", "OptionHasThemeVideo": "Vídeo de Tema", "OptionHideUser": "Ocultar este utilizador dos formulários de início de sessão", - "OptionHideUserFromLoginHelp": "Útil para contas de administrador privadas ou ocultas. O utilizador necessita de entrar manualmente, introduzindo o seu nome de utilizador e senha.", + "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.", @@ -653,11 +653,11 @@ "OptionWeekends": "Fins-de-semana", "OptionWeekly": "Semanalmente", "ParentalRating": "Classificação parental", - "PasswordMatchError": "A password e a confirmação da password devem coincidir.", - "PasswordResetComplete": "A password foi redefinida.", - "PasswordResetConfirmation": "Tem a certeza de que deseja redefinir a password?", - "PasswordResetHeader": "Redefinir Password", - "PasswordSaved": "Senha guardada.", + "PasswordMatchError": "A palavra-passe e a confirmação devem coincidir.", + "PasswordResetComplete": "A palavra-passe foi redefinida.", + "PasswordResetConfirmation": "Tem a certeza de que deseja redefinir a palavra-passe?", + "PasswordResetHeader": "Redefinir Palavra-Passe", + "PasswordSaved": "Palavra-passe guardada.", "PinCodeResetComplete": "O código pin foi redefinido.", "PinCodeResetConfirmation": "Tem a certeza de que devia repôr o código PIN?", "Play": "Reproduzir", @@ -721,7 +721,7 @@ "TabNotifications": "Notificações", "TabOther": "Outro", "TabParentalControl": "Controlo Parental", - "TabPassword": "Senha", + "TabPassword": "Palavra-Passe", "TabPlayback": "Reprodução", "TabPlaylist": "Lista de Reprodução", "TabPlaylists": "Listas de Reprodução", From 120b3106aa681c5fd923767d86720f947581b253 Mon Sep 17 00:00:00 2001 From: tluciomiranda Date: Tue, 10 Sep 2019 09:10:54 +0000 Subject: [PATCH 41/80] 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 | 225 +++++++++++++++++++++++++---------------- 1 file changed, 139 insertions(+), 86 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index 7477b51d87..a740ce4c3e 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -42,9 +42,9 @@ "ButtonPlay": "Reproduzir", "ButtonPreviousTrack": "Faixa anterior", "ButtonProfile": "Perfil", - "ButtonQuickStartGuide": "Guia rápido", + "ButtonQuickStartGuide": "Guia de Início Rápido", "ButtonRefresh": "Atualizar", - "ButtonRefreshGuideData": "Atualizar Dados do Guia", + "ButtonRefreshGuideData": "Atualizar Programação da TV", "ButtonRemove": "Remover", "ButtonRepeat": "Repetir", "ButtonResetEasyPassword": "Redefinir código pin fácil", @@ -58,7 +58,7 @@ "ButtonSelectDirectory": "Selecione a diretoria", "ButtonSelectView": "Selecionar visualização", "ButtonSend": "Enviar", - "ButtonSettings": "Ajustes", + "ButtonSettings": "Configurações", "ButtonShuffle": "Aleatório", "ButtonShutdown": "Encerrar", "ButtonSignIn": "Iniciar Sessão", @@ -72,7 +72,7 @@ "ButtonUninstall": "Desinstalar", "ButtonUpload": "Carregar", "ButtonViewWebsite": "Ver website", - "ChannelAccessHelp": "Selecione os canais a compartilhar com este utilizador. Administradores poderão editar todos os canais usando o gestor de metadados.", + "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.", "Composer": "Compositor", "ConfirmDeleteItem": "Apagar este item irá removê-lo da biblioteca e do sistema de ficheiros. Tem a certeza de que deseja continuar?", @@ -88,14 +88,14 @@ "DeleteMedia": "Remover multimédia", "DeleteUser": "Apagar Utilizador", "DeleteUserConfirmation": "Tem a certeza de que deseja apagar este utilizador?", - "DeviceAccessHelp": "Isto apenas se aplica para dispositivos que podem ser identificados como únicos e não evitarão o acesso do navegador. Filtrar o acesso ao dispositivo do utilizador evita que sejam usados novos dispositivos até que sejam aprovados aqui.", + "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": "Diretor", "EasyPasswordHelp": "Seu código pin fácil é usado para acesso off-line com apps suportados pelo Jellyfin e pode ser usado para acesso fácil dentro da rede.", "Edit": "Editar", "EnableCinemaMode": "Ativar modo cinema", "Ended": "Terminado", "ErrorAddingMediaPathToVirtualFolder": "Ocorreu um erro ao adicionar o local dos seus ficheiros. Por favor, assegure-se que o local é valido e que o processo do Jellyfin Server tenha acesso a essa localização.", - "ErrorGettingTvLineups": "Ocorreu um erro ao fazer download da programação da tv. Por favor, certifique-se que a sua informação está correta e tente novamente.", + "ErrorGettingTvLineups": "Ocorreu um erro ao transferir a programação da 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", "FastForward": "Avanço rápido", @@ -106,7 +106,7 @@ "FolderTypeMovies": "Filmes", "FolderTypeMusic": "Música", "FolderTypeMusicVideos": "Vídeos musicais", - "FolderTypeTvShows": "TV", + "FolderTypeTvShows": "Programas TV", "Friday": "Sexta", "Fullscreen": "Ecrã inteiro", "GuideProviderSelectListings": "Selecionar Listas", @@ -124,7 +124,7 @@ "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.", "HeaderApp": "Aplicação", - "HeaderAudioSettings": "Ajustes de Áudio", + "HeaderAudioSettings": "Configurações de Áudio", "HeaderAutomaticUpdates": "Atualizações automáticas", "HeaderBlockItemsWithNoRating": "Bloquear conteúdo sem informação de classificação etária ou com informação desconhecida:", "HeaderBranding": "Marca", @@ -162,7 +162,7 @@ "HeaderForgotPassword": "Esqueci-me da palavra-passe", "HeaderFrequentlyPlayed": "Reproduzido frequentemente", "HeaderGenres": "Gêneros", - "HeaderGuideProviders": "Provedores de Guia", + "HeaderGuideProviders": "Provedores de Programação da TV", "HeaderHttpHeaders": "Cabeçalhos HTTP", "HeaderIdentification": "Identificação", "HeaderIdentificationCriteriaHelp": "Digite, pelo menos, um critério de identificação.", @@ -186,7 +186,7 @@ "HeaderMedia": "Multimédia", "HeaderMediaFolders": "Pastas Multimédia", "HeaderMediaInfo": "Informações Multimédia", - "HeaderMetadataSettings": "Ajustes dos Metadados", + "HeaderMetadataSettings": "Configurações de Metadados", "HeaderMusicVideos": "Vídeos de Música", "HeaderMyMedia": "A Minha Multimédia", "HeaderNewApiKey": "Nova Chave da API", @@ -202,7 +202,7 @@ "HeaderPlayback": "Reprodução de Mídia", "HeaderPlaybackError": "Erro na Reprodução", "HeaderPlaybackSettings": "Opções de Reprodução", - "HeaderPleaseSignIn": "Por favor inicie a sessão", + "HeaderPleaseSignIn": "Iniciar Sessão", "HeaderPreferredMetadataLanguage": "Idioma Preferencial dos Metadados", "HeaderProfile": "Perfil", "HeaderProfileInformation": "Informação do Perfil", @@ -230,7 +230,7 @@ "HeaderSendMessage": "Enviar mensagem", "HeaderSeries": "Série", "HeaderServerSettings": "Opções do Servidor", - "HeaderSettings": "Ajustes", + "HeaderSettings": "Configurações", "HeaderSetupLibrary": "Configurar as suas bibliotecas multimédia", "HeaderShutdown": "Encerrar", "HeaderSpecialEpisodeInfo": "Informação do Episódio Especial", @@ -239,7 +239,7 @@ "HeaderSubtitleProfile": "Perfil da Legenda", "HeaderSubtitleProfiles": "Perfis da Legenda", "HeaderSubtitleProfilesHelp": "Perfis da legenda descrevem os formatos da legenda suportados pelo dispositivo.", - "HeaderSubtitleSettings": "Ajustes de Legenda", + "HeaderSubtitleSettings": "Configurações de Legendas", "HeaderSystemDlnaProfiles": "Perfis de Sistema", "HeaderTaskTriggers": "Disparadores de Tarefa", "HeaderThisUserIsCurrentlyDisabled": "Este utilizador está desativado atualmente", @@ -252,116 +252,116 @@ "HeaderUsers": "Utilizadores", "HeaderVideoTypes": "Tipos de Vídeo", "HeaderVideos": "Vídeos", - "HeaderXmlDocumentAttribute": "Atributo do Documento Xml", - "HeaderXmlDocumentAttributes": "Atributos do Documento Xml", - "HeaderXmlSettings": "Ajustes do Xml", + "HeaderXmlDocumentAttribute": "Atributo do Documento XML", + "HeaderXmlDocumentAttributes": "Atributos do Documento XML", + "HeaderXmlSettings": "Configurações de XML", "HeaderYears": "Anos", "HeadersFolders": "Pastas", "Help": "Ajuda", "Identify": "Identificar", "Images": "Imagens", "ImportFavoriteChannelsHelp": "Se ativado, apenas canais que estão marcados como favoritos no sintonizador serão importados.", - "ImportMissingEpisodesHelp": "Se ativo, a informação acerca dos episódios em falta, serão importados para a sua base de dados do Jellyfin e exibida dentro das temporadas e séries. Isto pode aumentar significativamente a duração da análise da biblioteca.", + "ImportMissingEpisodesHelp": "Se ativado, a informação acerca dos episódios em falta será importada para a base de dados do Servidor Jellyfin e exibida dentro das temporadas e séries. Isto pode aumentar significativamente a duração da análise da biblioteca.", "InstantMix": "Mix instântaneo", "ItemCount": "{0} itens", "Label3DFormat": "Formato 3D:", "LabelAccessDay": "Dia da semana:", - "LabelAccessEnd": "Hora final:", - "LabelAccessStart": "Hora inicial:", - "LabelAirDays": "Dias da exibição:", + "LabelAccessEnd": "Hora de Fim:", + "LabelAccessStart": "Hora de Início:", + "LabelAirDays": "Dias da Exibição:", "LabelAirTime": "Horário:", "LabelAirsAfterSeason": "Exibido depois da temporada:", "LabelAirsBeforeEpisode": "Exibido antes do episódio:", "LabelAirsBeforeSeason": "Exibido antes da temporada:", "LabelAlbum": "Álbum:", "LabelAlbumArtMaxHeight": "Altura máxima da capa do álbum:", - "LabelAlbumArtMaxHeightHelp": "Resolução máxima da capa do álbum que é exposta via upnp:albumArtURI.", + "LabelAlbumArtMaxHeightHelp": "Resolução máxima da capa do álbum exposta via upnp:albumArtURI.", "LabelAlbumArtMaxWidth": "Largura máxima da capa do álbum:", - "LabelAlbumArtMaxWidthHelp": "Resolução máxima da capa do álbum que é exposta via upnp:albumArtURI.", + "LabelAlbumArtMaxWidthHelp": "Resolução máxima da capa do álbum exposta via upnp:albumArtURI.", "LabelAlbumArtPN": "PN da capa do álbum:", "LabelAlbumArtists": "Artistas do Álbum:", "LabelAll": "Todos", - "LabelAllowServerAutoRestart": "Permitir ao servidor reiniciar automaticamente para aplicar as atualizações", + "LabelAllowServerAutoRestart": "Permitir ao servidor reiniciar automaticamente para aplicar atualizações", "LabelAllowServerAutoRestartHelp": "O servidor irá reiniciar apenas durante períodos em que não esteja a ser usado, quando nenhum utilizador estiver ativo.", - "LabelAppName": "Nome do app", + "LabelAppName": "Nome da aplicação", "LabelAppNameExample": "Exemplo: Sickbeard, NzbDrone", "LabelArtists": "Artistas:", - "LabelArtistsHelp": "Separa múltiplas com ;", - "LabelAudioLanguagePreference": "Preferências de Idioma de Audio:", - "LabelBlastMessageInterval": "Intervalo das mensagens de reconhecimento (segundos)", + "LabelArtistsHelp": "Separe múltiplos com ;", + "LabelAudioLanguagePreference": "Idioma de áudio preferido:", + "LabelBlastMessageInterval": "Intervalo para envio de mensagens de reconhecimento (segundos)", "LabelBlastMessageIntervalHelp": "Determina a duração em segundos entre as mensagens de exploração enviadas pelo servidor.", - "LabelBlockContentWithTags": "Bloquear conteúdo com tags:", + "LabelBlockContentWithTags": "Bloquear conteúdo com as tags:", "LabelCachePath": "Localização da cache:", - "LabelCachePathHelp": "Defina uma localização para os arquivos de cache como, por exemplo, imagens. Por favor, deixe em branco para usar o padrão do servidor.", + "LabelCachePathHelp": "Defina uma localização para os ficheiros de cache como, por exemplo, imagens. Deixe em branco para utilizar o padrão do servidor.", "LabelCancelled": "Cancelado", "LabelCollection": "Coleção:", "LabelCommunityRating": "Avaliação da comunidade:", "LabelContentType": "Tipo de conteúdo:", "LabelCountry": "País:", "LabelCriticRating": "Avaliação da crítica:", - "LabelCurrentPassword": "Palavra-Passe atual:", + "LabelCurrentPassword": "Palavra-passe atual:", "LabelCustomCertificatePath": "Localização do certificado SSL personalizado:", - "LabelCustomCertificatePathHelp": "Forneça o seu próprio ficheiro .pfx do certificado ssl.", + "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": "Adiciona o teu css personalizado à interface web.", - "LabelCustomDeviceDisplayName": "Nome para exibição:", - "LabelCustomDeviceDisplayNameHelp": "Forneça um nome para exibição ou deixe em branco para usar o nome informado pelo dispositivo.", + "LabelCustomCssHelp": "Aplica um ficheiro de estilos CSS customizado à interface web.", + "LabelCustomDeviceDisplayName": "Nome a ser mostrado:", + "LabelCustomDeviceDisplayNameHelp": "Forneça um nome a ser mostrado, ou deixe em branco para utilizar o nome reportado pelo dispositivo.", "LabelCustomRating": "Classificação personalizada:", - "LabelDateAdded": "Data adicionado:", - "LabelDateAddedBehavior": "Data de adição de comportamento para o novo conteúdo:", - "LabelDateAddedBehaviorHelp": "Se um valor de metadados estiver presente, ele sempre será utilizado antes destas opções.", + "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.", "LabelDay": "Dia:", - "LabelDefaultUser": "Utilizador padrão:", - "LabelDefaultUserHelp": "Determina qual utilizador será exibido nos dispositivos conectados. Isto pode ser ignorado para cada dispositivo usando perfis.", + "LabelDefaultUser": "Utilizador por defeito:", + "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:", "LabelDisplayMissingEpisodesWithinSeasons": "Mostrar episódios em falta dentro das temporadas", - "LabelDisplayName": "Nome para exibição:", - "LabelDisplayOrder": "Ordem de exibição:", + "LabelDisplayName": "Nome para apresentação:", + "LabelDisplayOrder": "Ordem de apresentação:", "LabelDisplaySpecialsWithinSeasons": "Exibir especiais dentro das temporadas em que são exibidos", - "LabelDownMixAudioScale": "Escala do aumento de áudio ao fazer downmix:", - "LabelDownMixAudioScaleHelp": "Aumentar o áudio ao fazer downmix. Defina como 1 para preservar o volume original.", - "LabelDownloadLanguages": "Idiomas para download:", - "LabelEasyPinCode": "Código pin fácil:", - "LabelEmbedAlbumArtDidl": "Inserir a capa do álbum no Didl", - "LabelEmbedAlbumArtDidlHelp": "Alguns dispositivos preferem este método para obter a capa do álbum. Outros podem falhar a reprodução com esta opção ativada.", + "LabelDownMixAudioScale": "Reforço de áudio durante o downmix:", + "LabelDownMixAudioScaleHelp": "Aumentar o volume de áudio durante o downmix. O valor 1 preserva o volume original.", + "LabelDownloadLanguages": "Transferir os idiomas:", + "LabelEasyPinCode": "Código PIN:", + "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": "Tentativa de mapear automaticamente a porta pública para a porta local através de UPnP. Isto poderá não funcionar em alguns modelos de roteadores.", - "LabelEnableBlastAliveMessages": "Propagar mensagens de reconhecimento", - "LabelEnableBlastAliveMessagesHelp": "Ativar isto se o servidor não é detetado convenientemente por outros dispositivos UPnP na sua rede.", - "LabelEnableDlnaClientDiscoveryInterval": "Intervalo para a descoberta do cliente (segundos)", - "LabelEnableDlnaClientDiscoveryIntervalHelp": "Determina a duração em segundos entre buscas SSDP executadas pelo Jellyfin.", + "LabelEnableAutomaticPortMapHelp": "Tenta mapear automaticamente o porto público para o porto local através de UPnP. Isto poderá não funcionar em alguns modelos de routers.", + "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.", "LabelEnableDlnaDebugLogging": "Ativar log de depuração do DLNA", - "LabelEnableDlnaDebugLoggingHelp": "Isto irá criar ficheiros de log grandes e deve ser usado apenas quando é necessário para depurar problemas.", - "LabelEnableDlnaPlayTo": "Ativar DLNA Play To", - "LabelEnableDlnaPlayToHelp": "Jellyfin pode detectar dispositivos dentro de sua rede e oferece a possibilidade de controlá-los.", + "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": "O Servidor Jellyfin pode detectar dispositivos na rede e oferecer a possibilidade de os controlar.", "LabelEnableDlnaServer": "Ativar servidor DLNA", - "LabelEnableDlnaServerHelp": "Permite que dispositivos UPnP em sua rede naveguem e reproduzam conteúdo do Jellyfin.", + "LabelEnableDlnaServerHelp": "Permite que dispositivos UPnP na rede naveguem e reproduzam conteúdo do Servidor Jellyfin.", "LabelEnableHardwareDecodingFor": "Ativar descodificação por hardware para:", "LabelEnableRealtimeMonitor": "Ativar monitorização em tempo real", - "LabelEnableRealtimeMonitorHelp": "As alterações irão ser processadas imediatamente em sistemas de ficheiros suportados.", + "LabelEnableRealtimeMonitorHelp": "As alterações 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 dentro do Didl.", - "LabelEndDate": "Data final:", + "LabelEnableSingleImageInDidlLimitHelp": "Alguns dispositivos não interpretarão apropriadamente se múltiplas imagens estiverem incorporadas no DIDL.", + "LabelEndDate": "Data de fim:", "LabelEpisodeNumber": "Número do episódio:", "LabelEvent": "Evento:", "LabelEveryXMinutes": "A cada:", "LabelExternalDDNS": "Domínio externo:", "LabelExternalDDNSHelp": "Se tem um servidor DNS dinâmico insira-o aqui. As aplicações do Jellyfin irão usá-lo ao ligar-se remotamente. Este campo é obrigatório quando usado com um certificado SSL personalizado. Exemplo: omeudominio.com.", - "LabelExtractChaptersDuringLibraryScan": "Extrair imagens dos capítulos durante o rastreamento da biblioteca", - "LabelExtractChaptersDuringLibraryScanHelp": "Se ativado, as imagens dos capítulos serão extraídas quando os vídeos forem importados durante a pesquisa na biblioteca. Se desativado, elas serão extraídas durante a tarefa agendada de imagens dos capítulos, permitindo que a pesquisa na biblioteca seja mais rápida.", + "LabelExtractChaptersDuringLibraryScan": "Extrair imagens dos capítulos durante a atualização da biblioteca", + "LabelExtractChaptersDuringLibraryScanHelp": "Se ativado, as imagens dos capítulos serão extraídas quando os vídeos forem importados durante a atualização da biblioteca. Se desativado, serão extraídas 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": "Digite o nome de seu utilizador, se lembrar.", + "LabelForgotPasswordUsernameHelp": "Introduza o seu nome de utilizador, se se recordar.", "LabelFormat": "Formato:", "LabelFriendlyName": "Nome amigável:", - "LabelServerNameHelp": "Será usado este nome para identificar o servidor. Se não for preenchido, será usado o nome do computador.", - "LabelGroupMoviesIntoCollections": "Agrupar filmes nas coleções", - "LabelGroupMoviesIntoCollectionsHelp": "Ao exibir listas de filmes, filmes que pertençam a uma coleção serão exibidos como um único item agrupado.", - "LabelHardwareAccelerationType": "Aceleração de hardware:", + "LabelServerNameHelp": "Este nome será utilizado para identificar o servidor. Se não for preenchido, será usado o nome do computador.", + "LabelGroupMoviesIntoCollections": "Agrupar filmes em coleções", + "LabelGroupMoviesIntoCollectionsHelp": "Ao mostrar listas de filmes, filmes que pertençam a uma coleção serão exibidos como um único item agrupado.", + "LabelHardwareAccelerationType": "Aceleração por hardware:", "LabelHardwareAccelerationTypeHelp": "Disponível apenas em sistemas suportados.", - "LabelHttpsPort": "Número da porta https local:", - "LabelHttpsPortHelp": "O número da porta tcp que o servidor https do Jellyfin deveria se conectar.", + "LabelHttpsPort": "Número do porto HTTPS local:", + "LabelHttpsPortHelp": "Número do porto TCP em que o servidor HTTPS do Jellyfin ficará à escuta.", "LabelIconMaxHeight": "Altura máxima do ícone:", "LabelIconMaxHeightHelp": "Resolução máxima do ícone que é exposto via upnp:icon.", "LabelIconMaxWidth": "Largura máxima do ícone:", @@ -374,15 +374,15 @@ "LabelKodiMetadataDateFormat": "Formato da data de lançamento:", "LabelKodiMetadataDateFormatHelp": "Todas as datas dentro dos nfo's serão lidas e gravadas usando este formato.", "LabelKodiMetadataEnableExtraThumbs": "Copiar extrafanart para extrathumbs", - "LabelKodiMetadataEnableExtraThumbsHelp": "Ao fazer download das imagens, elas podem ser salvas em ambas extrafanart e extrathumbs para uma maior compatibilidade com as skins do Kodi.", + "LabelKodiMetadataEnableExtraThumbsHelp": "Ao transferir imagens, estas podem ser guardadas como extrafanart e extrathumbs para uma maior compatibilidade com os temas Kodi.", "LabelKodiMetadataEnablePathSubstitution": "Ativar substituição de local", "LabelKodiMetadataEnablePathSubstitutionHelp": "Ativa a substituição do local das imagens usando as opções de substituição de caminho no servidor.", - "LabelKodiMetadataSaveImagePaths": "Salvar o local das imagens dentro dos arquivos nfo's", + "LabelKodiMetadataSaveImagePaths": "Guardar a localização de imagens em ficheiros nfo", "LabelKodiMetadataSaveImagePathsHelp": "Esta opção é recomendada se você tiver nomes de arquivos de imagem que não estão de acordo às recomendações do Kodi.", "LabelLanguage": "Idioma:", "LabelLineup": "Programação:", - "LabelLocalHttpServerPortNumber": "Número da porta http local:", - "LabelLocalHttpServerPortNumberHelp": "O número da porta tcp que o servidor http do Jellyfin deveria se conectar.", + "LabelLocalHttpServerPortNumber": "Número do porto HTTP local:", + "LabelLocalHttpServerPortNumberHelp": "Número do porto TCP em que o servidor HTTP do Jellyfin ficará à escuta.", "LabelLockItemToPreventChanges": "Bloquear este item para evitar alterações futuras", "LabelLoginDisclaimer": "Aviso legal no login:", "LabelLoginDisclaimerHelp": "Este aviso será exibido na parte inferior da página de login.", @@ -420,8 +420,8 @@ "LabelNewPasswordConfirm": "Confirmar nova palavra-passe:", "LabelNext": "Seguinte", "LabelNotificationEnabled": "Ativar esta notificação", - "LabelNumberOfGuideDays": "Número de dias de informação do guia para transferir:", - "LabelNumberOfGuideDaysHelp": "Transferir mais dias de informação do guia permite agendar com maior antecedência e ver mais listagens, no entanto irá levar mais tempo a transferir. Se optar que seja Automático, será escolhido baseado no número de canais.", + "LabelNumberOfGuideDays": "Número de dias de programação da TV para transferir:", + "LabelNumberOfGuideDaysHelp": "Transferir mais dias de programação da TV permite agendar com maior antecedência e ver mais listagens, no entanto, irá levar mais tempo a transferir. Se selecionar Automático, será escolhido o período baseado no número de canais.", "LabelOriginalAspectRatio": "Proporção da imagem original:", "LabelOverview": "Sinopse:", "LabelParentalRating": "Classificação parental:", @@ -443,10 +443,10 @@ "LabelProtocol": "Protocolo:", "LabelProtocolInfo": "Informação do protocolo:", "LabelProtocolInfoHelp": "O valor que será usado ao responder os pedidos GetProtocolInfo do dispositivo.", - "LabelPublicHttpPort": "Número da porta pública de http:", - "LabelPublicHttpPortHelp": "O número da porta pública que deverá ser mapeada para a porta local de http.", - "LabelPublicHttpsPort": "Número da porta pública de https:", - "LabelPublicHttpsPortHelp": "O número da porta pública que deverá ser mapeada para a porta local de https.", + "LabelPublicHttpPort": "Número do porto público HTTP:", + "LabelPublicHttpPortHelp": "Número do porto público que deverá ser mapeado para o porto HTTP local.", + "LabelPublicHttpsPort": "Número do porto público HTTPS:", + "LabelPublicHttpsPortHelp": "Número do porto público que deverá ser mapeado para o porto HTTPS local.", "LabelReadHowYouCanContribute": "Aprenda como pode contribuir.", "LabelRecordingPath": "Localização predefinida das gravações:", "LabelReleaseDate": "Data do lançamento:", @@ -462,7 +462,7 @@ "LabelSerialNumber": "Número de série", "LabelServerHost": "Servidor:", "LabelServerHostHelp": "192.168.1.100 ou https://meuservidor.com", - "LabelServerPort": "Porta:", + "LabelServerPort": "Porto:", "LabelSkipIfAudioTrackPresent": "Ignorar se a faixa de áudio padrão coincidir com o idioma de download", "LabelSkipIfAudioTrackPresentHelp": "Desmarque esta opção para garantir que todos os vídeos têm legendas, independentemente do idioma do áudio.", "LabelSkipIfGraphicalSubsPresent": "Ignorar se o vídeo já possuir legendas embutidas", @@ -520,7 +520,7 @@ "MessageEnablingOptionLongerScans": "Ativar esta opção pode aumentar significativamente a duração da análise da biblioteca.", "MessageFileReadError": "Ocorreu um erro ao ler este arquivo.", "MessageInvalidUser": "Nome de utilizador ou palavra-passe inválidos. Por favor, tente novamente.", - "MessageItemSaved": "Item salvo.", + "MessageItemSaved": "Item guardado.", "MessageItemsAdded": "Itens adicionados.", "MessageLeaveEmptyToInherit": "Deixar em branco para herdar as configurações do item pai, ou o valor global por defeito.", "MessageNoAvailablePlugins": "Sem extensões disponíveis.", @@ -564,7 +564,7 @@ "OptionBlockLiveTvChannels": "Canais de TV em Direto", "OptionBlockMovies": "Filmes", "OptionBlockMusic": "Música", - "OptionBlockTvShows": "Séries de TV", + "OptionBlockTvShows": "Programas de TV", "OptionCommunityRating": "Classificação da Comunidade", "OptionContinuing": "A Continuar", "OptionCriticRating": "Classificação dos críticos", @@ -604,7 +604,7 @@ "OptionHasSubtitles": "Legendas", "OptionHasThemeSong": "Música de Tema", "OptionHasThemeVideo": "Vídeo de Tema", - "OptionHideUser": "Ocultar este utilizador dos formulários de início de sessão", + "OptionHideUser": "Ocultar este utilizador nos formulários de início de sessão", "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", @@ -638,7 +638,7 @@ "OptionResumable": "Retomável", "OptionRuntime": "Duração", "OptionSaturday": "Sábado", - "OptionSaveMetadataAsHidden": "Salvar metadados e imagens como arquivos ocultos", + "OptionSaveMetadataAsHidden": "Guardar metadados e imagens como ficheiros ocultos", "OptionSpecialEpisode": "Especiais", "OptionSunday": "Domingo", "OptionThursday": "Quinta", @@ -685,7 +685,7 @@ "SendMessage": "Enviar mensagem", "Series": "Séries", "ServerUpdateNeeded": "Este Servidor Jellyfin precisa ser atualizado. Para fazer download da versão mais recente, por favor visite {0}", - "Settings": "Ajustes", + "Settings": "Configurações", "SettingsSaved": "Configurações guardadas.", "Share": "Partilhar", "Shuffle": "Aleatório", @@ -708,7 +708,7 @@ "TabEpisodes": "Episódios", "TabFavorites": "Favoritos", "TabGenres": "Géneros", - "TabGuide": "Guia", + "TabGuide": "Programação", "TabLatest": "Mais recente", "TabLiveTV": "TV em Direto", "TabMetadata": "Metadados", @@ -939,5 +939,58 @@ "DateAdded": "Adicionado a", "MessageContactAdminToResetPassword": "Por favor, contacte o Administrador de sistema para repôr a sua password.", "MessageConfirmRemoveMediaLocation": "Tem a certeza de que deseja remover esta localização?", - "MessageConfirmDeleteTunerDevice": "Tem a certeza de que deseja remover este dispositivo?" + "MessageConfirmDeleteTunerDevice": "Tem a certeza de que deseja remover este dispositivo?", + "UserAgentHelp": "Forneça um user-agent HTTP personalizado, se necessário.", + "OptionProtocolHttp": "HTTP", + "OptionProtocolHls": "Emissão HTTP em direto", + "LabelHomeScreenSectionValue": "Secção {0} do painel principal:", + "LabelHomeNetworkQuality": "Qualidade da rede interna:", + "LabelH264EncodingPreset": "Preset para codificação H264:", + "LabelH264Crf": "CRF para codificação H264:", + "LabelFont": "Tipo de Letra:", + "LabelFileOrUrl": "Ficheiro ou URL:", + "LabelDynamicExternalId": "{0} ID:", + "LabelDropShadow": "Sombra:", + "LabelDropImageHere": "Arraste a imagem para aqui, ou clique para procurar.", + "LabelDisplayMode": "Modo de apresentação:", + "LabelDisplayLanguageHelp": "A tradução do Jellyfin é um projeto em desenvolvimento contínuo.", + "LabelDisplayLanguage": "Idioma:", + "LabelDefaultScreen": "Ecrã por defeito:", + "LabelDeathDate": "Data de falecimento:", + "LabelDateTimeLocale": "Localização da data/hora:", + "LabelDashboardTheme": "Tema do Painel Principal:", + "LabelCertificatePasswordHelp": "Se o certificado requer uma palavra-passe, escreva-a aqui.", + "LabelCertificatePassword": "Palavra-passe do certificado:", + "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.", + "LabelBindToLocalNetworkAddress": "Endereço local para colocar o servidor à escuta:", + "LabelAutomaticallyRefreshInternetMetadataEvery": "Atualizar metadados automaticamente a partir da Internet:", + "LabelAuthProvider": "Provedor de autenticação:", + "LabelAudio": "Áudio:", + "LabelAllowedRemoteAddressesMode": "Tipo de filtro de IP remoto:", + "LabelAllowedRemoteAddresses": "Filtro de IP remoto:", + "LabelAllowHWTranscoding": "Permitir transcodificação por hardware", + "LabelAlbumArtHelp": "PN utilizado para a capa do álbum no atributo dlna:profileID/upnp:albumArtURI. Alguns dispositivos requerem um valor específico, independentemente to tamanho da imagem.", + "LabelAbortedByServerShutdown": "(Abortado - Servidor encerrado)", + "Kids": "Crianças", + "Items": "Itens", + "InstallingPackage": "A instalar {0}", + "HttpsRequiresCert": "Para ativar ligações seguras, é necessário fornecer um certificado SSL confiável. Forneça um certificado SSL ou desative 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.", + "DirectPlaying": "Reprodução direta", + "Backdrop": "Imagem de Fundo", + "SortChannelsBy": "Ordenar canais por:", + "PlaceFavoriteChannelsAtBeginning": "Mover canais favoritos para o início", + "OneChannel": "Um canal", + "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 da TV. O utilizador é responsável por criar e manter o ficheiro atualizado.", + "TV": "TV", + "LiveTV": "TV em Direto", + "LabelSelectFolderGroups": "Agrupar automaticamente o conteúdo das seguintes pastas em vistas como Filmes, Música e TV:", + "HeaderUpcomingOnTV": "A Seguir", + "HeaderLiveTvTunerSetup": "Configurar Sintonizador de TV" } From ed34530b1e5a857e3339c581471d223f9379af57 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 11 Sep 2019 05:35:41 -0400 Subject: [PATCH 42/80] Require hls.js from npm (#456) * hlsjs * Fix webpack libraryTarget config --- package.json | 3 +- src/bower_components/hlsjs/dist/hls.min.js | 8745 ----------------- .../hlsjs/hls.js.sublime-project | 19 - src/bundle.js | 5 + src/scripts/site.js | 3 +- webpack.config.js | 2 +- yarn.lock | 18 + 7 files changed, 27 insertions(+), 8768 deletions(-) delete mode 100644 src/bower_components/hlsjs/dist/hls.min.js delete mode 100644 src/bower_components/hlsjs/hls.js.sublime-project diff --git a/package.json b/package.json index 10e599b7d8..0e1922a7e1 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "webpack-cli": "^3.2.3" }, "dependencies": { - "jstree": "^3.3.7" + "jstree": "^3.3.7", + "hls.js": "^0.12.4" }, "scripts": { "dev": "webpack --mode development", diff --git a/src/bower_components/hlsjs/dist/hls.min.js b/src/bower_components/hlsjs/dist/hls.min.js deleted file mode 100644 index 9c48ae7403..0000000000 --- a/src/bower_components/hlsjs/dist/hls.min.js +++ /dev/null @@ -1,8745 +0,0 @@ -! function(t, e) { - "object" == typeof exports && "object" == typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define([], e) : "object" == typeof exports ? exports.Hls = e() : t.Hls = e() -}(this, function() { - return function(t) { - function e(i) { - if (r[i]) return r[i].exports; - var a = r[i] = { - i: i, - l: !1, - exports: {} - }; - return t[i].call(a.exports, a, a.exports, e), a.l = !0, a.exports - } - var r = {}; - return e.m = t, e.c = r, e.d = function(t, r, i) { - e.o(t, r) || Object.defineProperty(t, r, { - configurable: !1, - enumerable: !0, - get: i - }) - }, e.n = function(t) { - var r = t && t.__esModule ? function() { - return t.default - } : function() { - return t - }; - return e.d(r, "a", r), r - }, e.o = function(t, e) { - return Object.prototype.hasOwnProperty.call(t, e) - }, e.p = "/dist/", e(e.s = 28) - }([function(t, e, r) { - "use strict"; - - function i() {} - - function a(t, e) { - return e = "[" + t + "] > " + e - } - - function n(t) { - var e = c.console[t]; - return e ? function() { - for (var r = arguments.length, i = Array(r), n = 0; n < r; n++) i[n] = arguments[n]; - i[0] && (i[0] = a(t, i[0])), e.apply(c.console, i) - } : i - } - - function o(t) { - for (var e = arguments.length, r = Array(e > 1 ? e - 1 : 0), i = 1; i < e; i++) r[i - 1] = arguments[i]; - r.forEach(function(e) { - d[e] = t[e] ? t[e].bind(t) : n(e) - }) - } - r.d(e, "a", function() { - return h - }), r.d(e, "b", function() { - return f - }); - var s = r(4), - l = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(t) { - return typeof t - } : function(t) { - return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t - }, - u = { - trace: i, - debug: i, - log: i, - warn: i, - info: i, - error: i - }, - d = u, - c = Object(s.a)(), - h = function(t) { - if (!0 === t || "object" === (void 0 === t ? "undefined" : l(t))) { - o(t, "debug", "log", "info", "warn", "error"); - try { - d.log() - } catch (t) { - d = u - } - } else d = u - }, - f = d - }, function(t, e, r) { - "use strict"; - var i = { - MEDIA_ATTACHING: "hlsMediaAttaching", - MEDIA_ATTACHED: "hlsMediaAttached", - MEDIA_DETACHING: "hlsMediaDetaching", - MEDIA_DETACHED: "hlsMediaDetached", - BUFFER_RESET: "hlsBufferReset", - BUFFER_CODECS: "hlsBufferCodecs", - BUFFER_CREATED: "hlsBufferCreated", - BUFFER_APPENDING: "hlsBufferAppending", - BUFFER_APPENDED: "hlsBufferAppended", - BUFFER_EOS: "hlsBufferEos", - BUFFER_FLUSHING: "hlsBufferFlushing", - BUFFER_FLUSHED: "hlsBufferFlushed", - MANIFEST_LOADING: "hlsManifestLoading", - MANIFEST_LOADED: "hlsManifestLoaded", - MANIFEST_PARSED: "hlsManifestParsed", - LEVEL_SWITCHING: "hlsLevelSwitching", - LEVEL_SWITCHED: "hlsLevelSwitched", - LEVEL_LOADING: "hlsLevelLoading", - LEVEL_LOADED: "hlsLevelLoaded", - LEVEL_UPDATED: "hlsLevelUpdated", - LEVEL_PTS_UPDATED: "hlsLevelPtsUpdated", - AUDIO_TRACKS_UPDATED: "hlsAudioTracksUpdated", - AUDIO_TRACK_SWITCHING: "hlsAudioTrackSwitching", - AUDIO_TRACK_SWITCHED: "hlsAudioTrackSwitched", - AUDIO_TRACK_LOADING: "hlsAudioTrackLoading", - AUDIO_TRACK_LOADED: "hlsAudioTrackLoaded", - SUBTITLE_TRACKS_UPDATED: "hlsSubtitleTracksUpdated", - SUBTITLE_TRACK_SWITCH: "hlsSubtitleTrackSwitch", - SUBTITLE_TRACK_LOADING: "hlsSubtitleTrackLoading", - SUBTITLE_TRACK_LOADED: "hlsSubtitleTrackLoaded", - SUBTITLE_FRAG_PROCESSED: "hlsSubtitleFragProcessed", - INIT_PTS_FOUND: "hlsInitPtsFound", - FRAG_LOADING: "hlsFragLoading", - FRAG_LOAD_PROGRESS: "hlsFragLoadProgress", - FRAG_LOAD_EMERGENCY_ABORTED: "hlsFragLoadEmergencyAborted", - FRAG_LOADED: "hlsFragLoaded", - FRAG_DECRYPTED: "hlsFragDecrypted", - FRAG_PARSING_INIT_SEGMENT: "hlsFragParsingInitSegment", - FRAG_PARSING_USERDATA: "hlsFragParsingUserdata", - FRAG_PARSING_METADATA: "hlsFragParsingMetadata", - FRAG_PARSING_DATA: "hlsFragParsingData", - FRAG_PARSED: "hlsFragParsed", - FRAG_BUFFERED: "hlsFragBuffered", - FRAG_CHANGED: "hlsFragChanged", - FPS_DROP: "hlsFpsDrop", - FPS_DROP_LEVEL_CAPPING: "hlsFpsDropLevelCapping", - ERROR: "hlsError", - DESTROYING: "hlsDestroying", - KEY_LOADING: "hlsKeyLoading", - KEY_LOADED: "hlsKeyLoaded", - STREAM_STATE_TRANSITION: "hlsStreamStateTransition" - }; - e.a = i - }, function(t, e, r) { - "use strict"; - r.d(e, "b", function() { - return i - }), r.d(e, "a", function() { - return a - }); - var i = { - NETWORK_ERROR: "networkError", - MEDIA_ERROR: "mediaError", - KEY_SYSTEM_ERROR: "keySystemError", - MUX_ERROR: "muxError", - OTHER_ERROR: "otherError" - }, - a = { - KEY_SYSTEM_NO_KEYS: "keySystemNoKeys", - KEY_SYSTEM_NO_ACCESS: "keySystemNoAccess", - KEY_SYSTEM_NO_SESSION: "keySystemNoSession", - KEY_SYSTEM_LICENSE_REQUEST_FAILED: "keySystemLicenseRequestFailed", - MANIFEST_LOAD_ERROR: "manifestLoadError", - MANIFEST_LOAD_TIMEOUT: "manifestLoadTimeOut", - MANIFEST_PARSING_ERROR: "manifestParsingError", - MANIFEST_INCOMPATIBLE_CODECS_ERROR: "manifestIncompatibleCodecsError", - LEVEL_LOAD_ERROR: "levelLoadError", - LEVEL_LOAD_TIMEOUT: "levelLoadTimeOut", - LEVEL_SWITCH_ERROR: "levelSwitchError", - AUDIO_TRACK_LOAD_ERROR: "audioTrackLoadError", - AUDIO_TRACK_LOAD_TIMEOUT: "audioTrackLoadTimeOut", - FRAG_LOAD_ERROR: "fragLoadError", - FRAG_LOAD_TIMEOUT: "fragLoadTimeOut", - FRAG_DECRYPT_ERROR: "fragDecryptError", - FRAG_PARSING_ERROR: "fragParsingError", - REMUX_ALLOC_ERROR: "remuxAllocError", - KEY_LOAD_ERROR: "keyLoadError", - KEY_LOAD_TIMEOUT: "keyLoadTimeOut", - BUFFER_ADD_CODEC_ERROR: "bufferAddCodecError", - BUFFER_APPEND_ERROR: "bufferAppendError", - BUFFER_APPENDING_ERROR: "bufferAppendingError", - BUFFER_STALLED_ERROR: "bufferStalledError", - BUFFER_FULL_ERROR: "bufferFullError", - BUFFER_SEEK_OVER_HOLE: "bufferSeekOverHole", - BUFFER_NUDGE_ON_STALL: "bufferNudgeOnStall", - INTERNAL_EXCEPTION: "internalException" - } - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(0), - n = r(2), - o = r(1), - s = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(t) { - return typeof t - } : function(t) { - return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t - }, - l = new Set(["hlsEventGeneric", "hlsHandlerDestroying", "hlsHandlerDestroyed"]), - u = function() { - function t(e) { - i(this, t), this.hls = e, this.onEvent = this.onEvent.bind(this); - for (var r = arguments.length, a = Array(r > 1 ? r - 1 : 0), n = 1; n < r; n++) a[n - 1] = arguments[n]; - this.handledEvents = a, this.useGenericHandler = !0, this.registerListeners() - } - return t.prototype.destroy = function() { - this.onHandlerDestroying(), this.unregisterListeners(), this.onHandlerDestroyed() - }, t.prototype.onHandlerDestroying = function() {}, t.prototype.onHandlerDestroyed = function() {}, t.prototype.isEventHandler = function() { - return "object" === s(this.handledEvents) && this.handledEvents.length && "function" == typeof this.onEvent - }, t.prototype.registerListeners = function() { - this.isEventHandler() && this.handledEvents.forEach(function(t) { - if (l.has(t)) throw new Error("Forbidden event-name: " + t); - this.hls.on(t, this.onEvent) - }, this) - }, t.prototype.unregisterListeners = function() { - this.isEventHandler() && this.handledEvents.forEach(function(t) { - this.hls.off(t, this.onEvent) - }, this) - }, t.prototype.onEvent = function(t, e) { - this.onEventGeneric(t, e) - }, t.prototype.onEventGeneric = function(t, e) { - var r = function(t, e) { - var r = "on" + t.replace("hls", ""); - if ("function" != typeof this[r]) throw new Error("Event " + t + " has no generic handler in this " + this.constructor.name + " class (tried " + r + ")"); - return this[r].bind(this, e) - }; - try { - r.call(this, t, e).call() - } catch (e) { - a.b.error("An internal error happened while handling event " + t + '. Error message: "' + e.message + '". Here is a stacktrace:', e), this.hls.trigger(o.a.ERROR, { - type: n.b.OTHER_ERROR, - details: n.a.INTERNAL_EXCEPTION, - fatal: !1, - event: t, - err: e - }) - } - }, t - }(); - e.a = u - }, function(t, e, r) { - "use strict"; - - function i() { - return "undefined" == typeof window ? self : window - } - e.a = i - }, function(t, e, r) { - ! function(e) { - var r = /^((?:[a-zA-Z0-9+\-.]+:)?)(\/\/[^\/\;?#]*)?(.*?)??(;.*?)?(\?.*?)?(#.*?)?$/, - i = /^([^\/;?#]*)(.*)$/, - a = /(?:\/|^)\.(?=\/)/g, - n = /(?:\/|^)\.\.\/(?!\.\.\/).*?(?=\/)/g, - o = { - buildAbsoluteURL: function(t, e, r) { - if (r = r || {}, t = t.trim(), !(e = e.trim())) { - if (!r.alwaysNormalize) return t; - var a = this.parseURL(t); - if (!s) throw new Error("Error trying to parse base URL."); - return a.path = o.normalizePath(a.path), o.buildURLFromParts(a) - } - var n = this.parseURL(e); - if (!n) throw new Error("Error trying to parse relative URL."); - if (n.scheme) return r.alwaysNormalize ? (n.path = o.normalizePath(n.path), o.buildURLFromParts(n)) : e; - var s = this.parseURL(t); - if (!s) throw new Error("Error trying to parse base URL."); - if (!s.netLoc && s.path && "/" !== s.path[0]) { - var l = i.exec(s.path); - s.netLoc = l[1], s.path = l[2] - } - s.netLoc && !s.path && (s.path = "/"); - var u = { - scheme: s.scheme, - netLoc: n.netLoc, - path: null, - params: n.params, - query: n.query, - fragment: n.fragment - }; - if (!n.netLoc && (u.netLoc = s.netLoc, "/" !== n.path[0])) - if (n.path) { - var d = s.path, - c = d.substring(0, d.lastIndexOf("/") + 1) + n.path; - u.path = o.normalizePath(c) - } else u.path = s.path, n.params || (u.params = s.params, n.query || (u.query = s.query)); - return null === u.path && (u.path = r.alwaysNormalize ? o.normalizePath(n.path) : n.path), o.buildURLFromParts(u) - }, - parseURL: function(t) { - var e = r.exec(t); - return e ? { - scheme: e[1] || "", - netLoc: e[2] || "", - path: e[3] || "", - params: e[4] || "", - query: e[5] || "", - fragment: e[6] || "" - } : null - }, - normalizePath: function(t) { - for (t = t.split("").reverse().join("").replace(a, ""); t.length !== (t = t.replace(n, "")).length;); - return t.split("").reverse().join("") - }, - buildURLFromParts: function(t) { - return t.scheme + t.netLoc + t.path + t.params + t.query + t.fragment - } - }; - t.exports = o - }() - }, function(t, e, r) { - "use strict"; - var i = { - search: function(t, e) { - for (var r = 0, i = t.length - 1, a = null, n = null; r <= i;) { - a = (r + i) / 2 | 0, n = t[a]; - var o = e(n); - if (o > 0) r = a + 1; - else { - if (!(o < 0)) return n; - i = a - 1 - } - } - return null - } - }; - e.a = i - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - r.d(e, "b", function() { - return n - }); - var a = function() { - function t() { - i(this, t) - } - return t.isHeader = function(t, e) { - return e + 10 <= t.length && 73 === t[e] && 68 === t[e + 1] && 51 === t[e + 2] && t[e + 3] < 255 && t[e + 4] < 255 && t[e + 6] < 128 && t[e + 7] < 128 && t[e + 8] < 128 && t[e + 9] < 128 - }, t.isFooter = function(t, e) { - return e + 10 <= t.length && 51 === t[e] && 68 === t[e + 1] && 73 === t[e + 2] && t[e + 3] < 255 && t[e + 4] < 255 && t[e + 6] < 128 && t[e + 7] < 128 && t[e + 8] < 128 && t[e + 9] < 128 - }, t.getID3Data = function(e, r) { - for (var i = r, a = 0; t.isHeader(e, r);) { - a += 10; - a += t._readSize(e, r + 6), t.isFooter(e, r + 10) && (a += 10), r += a - } - if (a > 0) return e.subarray(i, i + a) - }, t._readSize = function(t, e) { - var r = 0; - return r = (127 & t[e]) << 21, r |= (127 & t[e + 1]) << 14, r |= (127 & t[e + 2]) << 7, r |= 127 & t[e + 3] - }, t.getTimeStamp = function(e) { - for (var r = t.getID3Frames(e), i = 0; i < r.length; i++) { - var a = r[i]; - if (t.isTimeStampFrame(a)) return t._readTimeStamp(a) - } - }, t.isTimeStampFrame = function(t) { - return t && "PRIV" === t.key && "com.apple.streaming.transportStreamTimestamp" === t.info - }, t._getFrameData = function(e) { - var r = String.fromCharCode(e[0], e[1], e[2], e[3]), - i = t._readSize(e, 4); - return { - type: r, - size: i, - data: e.subarray(10, 10 + i) - } - }, t.getID3Frames = function(e) { - for (var r = 0, i = []; t.isHeader(e, r);) { - var a = t._readSize(e, r + 6); - r += 10; - for (var n = r + a; r + 8 < n;) { - var o = t._getFrameData(e.subarray(r)), - s = t._decodeFrame(o); - s && i.push(s), r += o.size + 10 - } - t.isFooter(e, r) && (r += 10) - } - return i - }, t._decodeFrame = function(e) { - return "PRIV" === e.type ? t._decodePrivFrame(e) : "T" === e.type[0] ? t._decodeTextFrame(e) : "W" === e.type[0] ? t._decodeURLFrame(e) : void 0 - }, t._readTimeStamp = function(t) { - if (8 === t.data.byteLength) { - var e = new Uint8Array(t.data), - r = 1 & e[3], - i = (e[4] << 23) + (e[5] << 15) + (e[6] << 7) + e[7]; - return i /= 45, r && (i += 47721858.84), Math.round(i) - } - }, t._decodePrivFrame = function(e) { - if (!(e.size < 2)) { - var r = t._utf8ArrayToStr(e.data, !0), - i = new Uint8Array(e.data.subarray(r.length + 1)); - return { - key: e.type, - info: r, - data: i.buffer - } - } - }, t._decodeTextFrame = function(e) { - if (!(e.size < 2)) { - if ("TXXX" === e.type) { - var r = 1, - i = t._utf8ArrayToStr(e.data.subarray(r)); - r += i.length + 1; - var a = t._utf8ArrayToStr(e.data.subarray(r)); - return { - key: e.type, - info: i, - data: a - } - } - var n = t._utf8ArrayToStr(e.data.subarray(1)); - return { - key: e.type, - data: n - } - } - }, t._decodeURLFrame = function(e) { - if ("WXXX" === e.type) { - if (e.size < 2) return; - var r = 1, - i = t._utf8ArrayToStr(e.data.subarray(r)); - r += i.length + 1; - var a = t._utf8ArrayToStr(e.data.subarray(r)); - return { - key: e.type, - info: i, - data: a - } - } - var n = t._utf8ArrayToStr(e.data); - return { - key: e.type, - data: n - } - }, t._utf8ArrayToStr = function(t) { - for (var e = arguments.length > 1 && void 0 !== arguments[1] && arguments[1], r = t.length, i = void 0, a = void 0, n = void 0, o = "", s = 0; s < r;) { - if (0 === (i = t[s++]) && e) return o; - if (0 !== i && 3 !== i) switch (i >> 4) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - o += String.fromCharCode(i); - break; - case 12: - case 13: - a = t[s++], o += String.fromCharCode((31 & i) << 6 | 63 & a); - break; - case 14: - a = t[s++], n = t[s++], o += String.fromCharCode((15 & i) << 12 | (63 & a) << 6 | (63 & n) << 0) - } - } - return o - }, t - }(), - n = a._utf8ArrayToStr; - e.a = a - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(3), - s = function(t) { - function e(r) { - i(this, e); - for (var n = arguments.length, o = Array(n > 1 ? n - 1 : 0), s = 1; s < n; s++) o[s - 1] = arguments[s]; - var l = a(this, t.call.apply(t, [this, r].concat(o))); - return l._tickInterval = null, l._tickTimer = null, l._tickCallCount = 0, l._boundTick = l.tick.bind(l), l - } - return n(e, t), e.prototype.onHandlerDestroying = function() { - this.clearNextTick(), this.clearInterval() - }, e.prototype.hasInterval = function() { - return !!this._tickInterval - }, e.prototype.hasNextTick = function() { - return !!this._tickTimer - }, e.prototype.setInterval = function(t) { - function e(e) { - return t.apply(this, arguments) - } - return e.toString = function() { - return t.toString() - }, e - }(function(t) { - return !this._tickInterval && (this._tickInterval = setInterval(this._boundTick, t), !0) - }), e.prototype.clearInterval = function(t) { - function e() { - return t.apply(this, arguments) - } - return e.toString = function() { - return t.toString() - }, e - }(function() { - return !!this._tickInterval && (clearInterval(this._tickInterval), this._tickInterval = null, !0) - }), e.prototype.clearNextTick = function() { - return !!this._tickTimer && (clearTimeout(this._tickTimer), this._tickTimer = null, !0) - }, e.prototype.tick = function() { - 1 === ++this._tickCallCount && (this.doTick(), this._tickCallCount > 1 && (this.clearNextTick(), this._tickTimer = setTimeout(this._boundTick, 0)), this._tickCallCount = 0) - }, e.prototype.doTick = function() {}, e - }(o.a); - e.a = s - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(5), - n = r.n(a), - o = r(18), - s = function() { - function t(t, e) { - for (var r = 0; r < e.length; r++) { - var i = e[r]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(t, i.key, i) - } - } - return function(e, r, i) { - return r && t(e.prototype, r), i && t(e, i), e - } - }(), - l = function() { - function t() { - var e; - i(this, t), this._url = null, this._byteRange = null, this._decryptdata = null, this.tagList = [], this._elementaryStreams = (e = {}, e[t.ElementaryStreamTypes.AUDIO] = !1, e[t.ElementaryStreamTypes.VIDEO] = !1, e) - } - return t.prototype.addElementaryStream = function(t) { - this._elementaryStreams[t] = !0 - }, t.prototype.hasElementaryStream = function(t) { - return !0 === this._elementaryStreams[t] - }, t.prototype.createInitializationVector = function(t) { - for (var e = new Uint8Array(16), r = 12; r < 16; r++) e[r] = t >> 8 * (15 - r) & 255; - return e - }, t.prototype.fragmentDecryptdataFromLevelkey = function(t, e) { - var r = t; - return t && t.method && t.uri && !t.iv && (r = new o.a, r.method = t.method, r.baseuri = t.baseuri, r.reluri = t.reluri, r.iv = this.createInitializationVector(e)), r - }, s(t, [{ - key: "url", - get: function() { - return !this._url && this.relurl && (this._url = n.a.buildAbsoluteURL(this.baseurl, this.relurl, { - alwaysNormalize: !0 - })), this._url - }, - set: function(t) { - this._url = t - } - }, { - key: "programDateTime", - get: function() { - return !this._programDateTime && this.rawProgramDateTime && (this._programDateTime = new Date(Date.parse(this.rawProgramDateTime))), this._programDateTime - } - }, { - key: "byteRange", - get: function() { - if (!this._byteRange && !this.rawByteRange) return []; - if (this._byteRange) return this._byteRange; - var t = []; - if (this.rawByteRange) { - var e = this.rawByteRange.split("@", 2); - if (1 === e.length) { - var r = this.lastByteRangeEndOffset; - t[0] = r || 0 - } else t[0] = parseInt(e[1]); - t[1] = parseInt(e[0]) + t[0], this._byteRange = t - } - return t - } - }, { - key: "byteRangeStartOffset", - get: function() { - return this.byteRange[0] - } - }, { - key: "byteRangeEndOffset", - get: function() { - return this.byteRange[1] - } - }, { - key: "decryptdata", - get: function() { - return this._decryptdata || (this._decryptdata = this.fragmentDecryptdataFromLevelkey(this.levelkey, this.sn)), this._decryptdata - } - }, { - key: "encrypted", - get: function() { - return !(!this.decryptdata || null === this.decryptdata.uri || null !== this.decryptdata.key) - } - }], [{ - key: "ElementaryStreamTypes", - get: function() { - return { - AUDIO: "audio", - VIDEO: "video" - } - } - }]), t - }(); - e.a = l - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - r.d(e, "a", function() { - return l - }), r.d(e, "b", function() { - return u - }); - var o = r(3), - s = r(1), - l = { - NOT_LOADED: "NOT_LOADED", - APPENDING: "APPENDING", - PARTIAL: "PARTIAL", - OK: "OK" - }, - u = function(t) { - function e(r) { - i(this, e); - var n = a(this, t.call(this, r, s.a.BUFFER_APPENDED, s.a.FRAG_BUFFERED, s.a.FRAG_LOADED)); - return n.bufferPadding = .2, n.fragments = Object.create(null), n.timeRanges = Object.create(null), n.config = r.config, n - } - return n(e, t), e.prototype.destroy = function() { - this.fragments = null, this.timeRanges = null, this.config = null, o.a.prototype.destroy.call(this), t.prototype.destroy.call(this) - }, e.prototype.getBufferedFrag = function(t, e) { - var r = this.fragments, - i = Object.keys(r).filter(function(i) { - var a = r[i]; - if (a.body.type !== e) return !1; - if (!a.buffered) return !1; - var n = a.body; - return n.startPTS <= t && t <= n.endPTS - }); - if (0 === i.length) return null; - var a = i.pop(); - return r[a].body - }, e.prototype.detectEvictedFragments = function(t, e) { - var r = this, - i = void 0, - a = void 0; - Object.keys(this.fragments).forEach(function(n) { - var o = r.fragments[n]; - if (!0 === o.buffered) { - var s = o.range[t]; - if (s) { - i = s.time; - for (var l = 0; l < i.length; l++) - if (a = i[l], !1 === r.isTimeBuffered(a.startPTS, a.endPTS, e)) { - r.removeFragment(o.body); - break - } - } - } - }) - }, e.prototype.detectPartialFragments = function(t) { - var e = this, - r = this.getFragmentKey(t), - i = this.fragments[r]; - i && (i.buffered = !0, Object.keys(this.timeRanges).forEach(function(r) { - if (!0 === t.hasElementaryStream(r)) { - var a = e.timeRanges[r]; - i.range[r] = e.getBufferedTimes(t.startPTS, t.endPTS, a) - } - })) - }, e.prototype.getBufferedTimes = function(t, e, r) { - for (var i = [], a = void 0, n = void 0, o = !1, s = 0; s < r.length; s++) { - if (a = r.start(s) - this.bufferPadding, n = r.end(s) + this.bufferPadding, t >= a && e <= n) { - i.push({ - startPTS: Math.max(t, r.start(s)), - endPTS: Math.min(e, r.end(s)) - }); - break - } - if (t < n && e > a) i.push({ - startPTS: Math.max(t, r.start(s)), - endPTS: Math.min(e, r.end(s)) - }), o = !0; - else if (e <= a) break - } - return { - time: i, - partial: o - } - }, e.prototype.getFragmentKey = function(t) { - return t.type + "_" + t.level + "_" + t.urlId + "_" + t.sn - }, e.prototype.getPartialFragment = function(t) { - var e = this, - r = void 0, - i = void 0, - a = void 0, - n = null, - o = 0; - return Object.keys(this.fragments).forEach(function(s) { - var l = e.fragments[s]; - e.isPartial(l) && (i = l.body.startPTS - e.bufferPadding, a = l.body.endPTS + e.bufferPadding, t >= i && t <= a && (r = Math.min(t - i, a - t), o <= r && (n = l.body, o = r))) - }), n - }, e.prototype.getState = function(t) { - var e = this.getFragmentKey(t), - r = this.fragments[e], - i = l.NOT_LOADED; - return void 0 !== r && (i = r.buffered ? !0 === this.isPartial(r) ? l.PARTIAL : l.OK : l.APPENDING), i - }, e.prototype.isPartial = function(t) { - return !0 === t.buffered && (void 0 !== t.range.video && !0 === t.range.video.partial || void 0 !== t.range.audio && !0 === t.range.audio.partial) - }, e.prototype.isTimeBuffered = function(t, e, r) { - for (var i = void 0, a = void 0, n = 0; n < r.length; n++) { - if (i = r.start(n) - this.bufferPadding, a = r.end(n) + this.bufferPadding, t >= i && e <= a) return !0; - if (e <= i) return !1 - } - return !1 - }, e.prototype.onFragLoaded = function(t) { - var e = t.frag; - if (!isNaN(e.sn) && !e.bitrateTest) { - var r = this.getFragmentKey(e), - i = { - body: e, - range: Object.create(null), - buffered: !1 - }; - this.fragments[r] = i - } - }, e.prototype.onBufferAppended = function(t) { - var e = this; - this.timeRanges = t.timeRanges, Object.keys(this.timeRanges).forEach(function(t) { - var r = e.timeRanges[t]; - e.detectEvictedFragments(t, r) - }) - }, e.prototype.onFragBuffered = function(t) { - this.detectPartialFragments(t.frag) - }, e.prototype.hasFragment = function(t) { - var e = this.getFragmentKey(t); - return void 0 !== this.fragments[e] - }, e.prototype.removeFragment = function(t) { - var e = this.getFragmentKey(t); - delete this.fragments[e] - }, e.prototype.removeAllFragments = function() { - this.fragments = Object.create(null) - }, e - }(o.a) - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - r.d(e, "a", function() { - return a - }); - var a = function() { - function t() { - i(this, t) - } - return t.isBuffered = function(t, e) { - try { - if (t) - for (var r = t.buffered, i = 0; i < r.length; i++) - if (e >= r.start(i) && e <= r.end(i)) return !0 - } catch (t) {} - return !1 - }, t.bufferInfo = function(t, e, r) { - try { - if (t) { - var i = t.buffered, - a = [], - n = void 0; - for (n = 0; n < i.length; n++) a.push({ - start: i.start(n), - end: i.end(n) - }); - return this.bufferedInfo(a, e, r) - } - } catch (t) {} - return { - len: 0, - start: e, - end: e, - nextStart: void 0 - } - }, t.bufferedInfo = function(t, e, r) { - var i = [], - a = void 0, - n = void 0, - o = void 0, - s = void 0, - l = void 0; - for (t.sort(function(t, e) { - var r = t.start - e.start; - return r || e.end - t.end - }), l = 0; l < t.length; l++) { - var u = i.length; - if (u) { - var d = i[u - 1].end; - t[l].start - d < r ? t[l].end > d && (i[u - 1].end = t[l].end) : i.push(t[l]) - } else i.push(t[l]) - } - for (l = 0, a = 0, n = o = e; l < i.length; l++) { - var c = i[l].start, - h = i[l].end; - if (e + r >= c && e < h) n = c, o = h, a = o - e; - else if (e + r < c) { - s = c; - break - } - } - return { - len: a, - start: n, - end: o, - nextStart: s - } - }, t - }() - }, function(t, e) { - function r() { - this._events = this._events || {}, this._maxListeners = this._maxListeners || void 0 - } - - function i(t) { - return "function" == typeof t - } - - function a(t) { - return "number" == typeof t - } - - function n(t) { - return "object" == typeof t && null !== t - } - - function o(t) { - return void 0 === t - } - t.exports = r, r.EventEmitter = r, r.prototype._events = void 0, r.prototype._maxListeners = void 0, r.defaultMaxListeners = 10, r.prototype.setMaxListeners = function(t) { - if (!a(t) || t < 0 || isNaN(t)) throw TypeError("n must be a positive number"); - return this._maxListeners = t, this - }, r.prototype.emit = function(t) { - var e, r, a, s, l, u; - if (this._events || (this._events = {}), "error" === t && (!this._events.error || n(this._events.error) && !this._events.error.length)) { - if ((e = arguments[1]) instanceof Error) throw e; - var d = new Error('Uncaught, unspecified "error" event. (' + e + ")"); - throw d.context = e, d - } - if (r = this._events[t], o(r)) return !1; - if (i(r)) switch (arguments.length) { - case 1: - r.call(this); - break; - case 2: - r.call(this, arguments[1]); - break; - case 3: - r.call(this, arguments[1], arguments[2]); - break; - default: - s = Array.prototype.slice.call(arguments, 1), r.apply(this, s) - } else if (n(r)) - for (s = Array.prototype.slice.call(arguments, 1), u = r.slice(), a = u.length, l = 0; l < a; l++) u[l].apply(this, s); - return !0 - }, r.prototype.addListener = function(t, e) { - var a; - if (!i(e)) throw TypeError("listener must be a function"); - return this._events || (this._events = {}), this._events.newListener && this.emit("newListener", t, i(e.listener) ? e.listener : e), this._events[t] ? n(this._events[t]) ? this._events[t].push(e) : this._events[t] = [this._events[t], e] : this._events[t] = e, n(this._events[t]) && !this._events[t].warned && (a = o(this._maxListeners) ? r.defaultMaxListeners : this._maxListeners) && a > 0 && this._events[t].length > a && (this._events[t].warned = !0, console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.", this._events[t].length), "function" == typeof console.trace && console.trace()), this - }, r.prototype.on = r.prototype.addListener, r.prototype.once = function(t, e) { - function r() { - this.removeListener(t, r), a || (a = !0, e.apply(this, arguments)) - } - if (!i(e)) throw TypeError("listener must be a function"); - var a = !1; - return r.listener = e, this.on(t, r), this - }, r.prototype.removeListener = function(t, e) { - var r, a, o, s; - if (!i(e)) throw TypeError("listener must be a function"); - if (!this._events || !this._events[t]) return this; - if (r = this._events[t], o = r.length, a = -1, r === e || i(r.listener) && r.listener === e) delete this._events[t], this._events.removeListener && this.emit("removeListener", t, e); - else if (n(r)) { - for (s = o; s-- > 0;) - if (r[s] === e || r[s].listener && r[s].listener === e) { - a = s; - break - } if (a < 0) return this; - 1 === r.length ? (r.length = 0, delete this._events[t]) : r.splice(a, 1), this._events.removeListener && this.emit("removeListener", t, e) - } - return this - }, r.prototype.removeAllListeners = function(t) { - var e, r; - if (!this._events) return this; - if (!this._events.removeListener) return 0 === arguments.length ? this._events = {} : this._events[t] && delete this._events[t], this; - if (0 === arguments.length) { - for (e in this._events) "removeListener" !== e && this.removeAllListeners(e); - return this.removeAllListeners("removeListener"), this._events = {}, this - } - if (r = this._events[t], i(r)) this.removeListener(t, r); - else if (r) - for (; r.length;) this.removeListener(t, r[r.length - 1]); - return delete this._events[t], this - }, r.prototype.listeners = function(t) { - return this._events && this._events[t] ? i(this._events[t]) ? [this._events[t]] : this._events[t].slice() : [] - }, r.prototype.listenerCount = function(t) { - if (this._events) { - var e = this._events[t]; - if (i(e)) return 1; - if (e) return e.length - } - return 0 - }, r.listenerCount = function(t, e) { - return t.listenerCount(e) - } - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(35), - n = r(36), - o = r(37), - s = r(2), - l = r(0), - u = r(1), - d = r(4), - c = Object(d.a)(), - h = function() { - function t(e, r) { - var a = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {}, - n = a.removePKCS7Padding, - o = void 0 === n || n; - if (i(this, t), this.logEnabled = !0, this.observer = e, this.config = r, this.removePKCS7Padding = o, o) try { - var s = c.crypto; - s && (this.subtle = s.subtle || s.webkitSubtle) - } catch (t) {} - this.disableWebCrypto = !this.subtle - } - return t.prototype.isSync = function() { - return this.disableWebCrypto && this.config.enableSoftwareAES - }, t.prototype.decrypt = function(t, e, r, i) { - var s = this; - if (this.disableWebCrypto && this.config.enableSoftwareAES) { - this.logEnabled && (l.b.log("JS AES decrypt"), this.logEnabled = !1); - var u = this.decryptor; - u || (this.decryptor = u = new o.a), u.expandKey(e), i(u.decrypt(t, 0, r, this.removePKCS7Padding)) - } else { - this.logEnabled && (l.b.log("WebCrypto AES decrypt"), this.logEnabled = !1); - var d = this.subtle; - this.key !== e && (this.key = e, this.fastAesKey = new n.a(d, e)), this.fastAesKey.expandKey().then(function(n) { - new a.a(d, r).decrypt(t, n).catch(function(a) { - s.onWebCryptoError(a, t, e, r, i) - }).then(function(t) { - i(t) - }) - }).catch(function(a) { - s.onWebCryptoError(a, t, e, r, i) - }) - } - }, t.prototype.onWebCryptoError = function(t, e, r, i, a) { - this.config.enableSoftwareAES ? (l.b.log("WebCrypto Error, disable WebCrypto API"), this.disableWebCrypto = !0, this.logEnabled = !0, this.decrypt(e, r, i, a)) : (l.b.error("decrypting error : " + t.message), this.observer.trigger(u.a.ERROR, { - type: s.b.MEDIA_ERROR, - details: s.a.FRAG_DECRYPT_ERROR, - fatal: !0, - reason: t.message - })) - }, t.prototype.destroy = function() { - var t = this.decryptor; - t && (t.destroy(), this.decryptor = void 0) - }, t - }(); - e.a = h - }, function(t, e, r) { - "use strict"; - - function i() { - if ("undefined" != typeof window) return window.MediaSource || window.WebKitMediaSource - } - e.a = i - }, function(t, e, r) { - "use strict"; - - function i(t, e, r) { - switch (e) { - case "audio": - t.audioGroupIds || (t.audioGroupIds = []), t.audioGroupIds.push(r); - break; - case "text": - t.textGroupIds || (t.textGroupIds = []), t.textGroupIds.push(r) - } - } - - function a(t, e, r) { - var i = t[e], - a = t[r], - n = a.startPTS; - isNaN(n) ? a.start = r > e ? i.start + i.duration : Math.max(i.start - a.duration, 0) : r > e ? (i.duration = n - i.start, i.duration < 0 && s.b.warn("negative duration computed for frag " + i.sn + ",level " + i.level + ", there should be some duration drift between playlist and fragment!")) : (a.duration = i.start - n, a.duration < 0 && s.b.warn("negative duration computed for frag " + a.sn + ",level " + a.level + ", there should be some duration drift between playlist and fragment!")) - } - - function n(t, e, r, i, n, o) { - var s = r; - if (!isNaN(e.startPTS)) { - var l = Math.abs(e.startPTS - r); - isNaN(e.deltaPTS) ? e.deltaPTS = l : e.deltaPTS = Math.max(l, e.deltaPTS), s = Math.max(r, e.startPTS), r = Math.min(r, e.startPTS), i = Math.max(i, e.endPTS), n = Math.min(n, e.startDTS), o = Math.max(o, e.endDTS) - } - var u = r - e.start; - e.start = e.startPTS = r, e.maxStartPTS = s, e.endPTS = i, e.startDTS = n, e.endDTS = o, e.duration = i - r; - var d = e.sn; - if (!t || d < t.startSN || d > t.endSN) return 0; - var c = void 0, - h = void 0, - f = void 0; - for (c = d - t.startSN, h = t.fragments, h[c] = e, f = c; f > 0; f--) a(h, f, f - 1); - for (f = c; f < h.length - 1; f++) a(h, f, f + 1); - return t.PTSKnown = !0, u - } - - function o(t, e) { - var r = Math.max(t.startSN, e.startSN) - e.startSN, - i = Math.min(t.endSN, e.endSN) - e.startSN, - a = e.startSN - t.startSN, - o = t.fragments, - l = e.fragments, - u = 0, - d = void 0; - if (e.initSegment && t.initSegment && (e.initSegment = t.initSegment), i < r) return void(e.PTSKnown = !1); - for (var c = r; c <= i; c++) { - var h = o[a + c], - f = l[c]; - f && h && (u = h.cc - f.cc, isNaN(h.startPTS) || (f.start = f.startPTS = h.startPTS, f.endPTS = h.endPTS, f.duration = h.duration, f.backtracked = h.backtracked, f.dropped = h.dropped, d = f)) - } - if (u) - for (s.b.log("discontinuity sliding from playlist, take drift into account"), c = 0; c < l.length; c++) l[c].cc += u; - if (d) n(e, d, d.startPTS, d.endPTS, d.startDTS, d.endDTS); - else if (a >= 0 && a < o.length) { - var p = o[a].start; - for (c = 0; c < l.length; c++) l[c].start += p - } - e.PTSKnown = t.PTSKnown - } - e.a = i, e.c = n, e.b = o; - var s = r(0) - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(1), - s = r(3), - l = r(2), - u = r(0), - d = r(17), - c = r(29), - h = function() { - function t(t, e) { - for (var r = 0; r < e.length; r++) { - var i = e[r]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(t, i.key, i) - } - } - return function(e, r, i) { - return r && t(e.prototype, r), i && t(e, i), e - } - }(), - f = window, - p = f.performance, - v = { - MANIFEST: "manifest", - LEVEL: "level", - AUDIO_TRACK: "audioTrack", - SUBTITLE_TRACK: "subtitleTrack" - }, - g = { - MAIN: "main", - AUDIO: "audio", - SUBTITLE: "subtitle" - }, - y = function(t) { - function e(r) { - i(this, e); - var n = a(this, t.call(this, r, o.a.MANIFEST_LOADING, o.a.LEVEL_LOADING, o.a.AUDIO_TRACK_LOADING, o.a.SUBTITLE_TRACK_LOADING)); - return n.loaders = {}, n - } - return n(e, t), e.canHaveQualityLevels = function(t) { - return t !== v.AUDIO_TRACK && t !== v.SUBTITLE_TRACK - }, e.mapContextToLevelType = function(t) { - switch (t.type) { - case v.AUDIO_TRACK: - return g.AUDIO; - case v.SUBTITLE_TRACK: - return g.SUBTITLE; - default: - return g.MAIN - } - }, e.getResponseUrl = function(t, e) { - var r = t.url; - return void 0 !== r && 0 !== r.indexOf("data:") || (r = e.url), r - }, e.prototype.createInternalLoader = function(t) { - var e = this.hls.config, - r = e.pLoader, - i = e.loader, - a = r || i, - n = new a(e); - return t.loader = n, this.loaders[t.type] = n, n - }, e.prototype.getInternalLoader = function(t) { - return this.loaders[t.type] - }, e.prototype.resetInternalLoader = function(t) { - this.loaders[t] && delete this.loaders[t] - }, e.prototype.destroyInternalLoaders = function() { - for (var t in this.loaders) { - var e = this.loaders[t]; - e && e.destroy(), this.resetInternalLoader(t) - } - }, e.prototype.destroy = function() { - this.destroyInternalLoaders(), t.prototype.destroy.call(this) - }, e.prototype.onManifestLoading = function(t) { - this.load(t.url, { - type: v.MANIFEST, - level: 0, - id: null - }) - }, e.prototype.onLevelLoading = function(t) { - this.load(t.url, { - type: v.LEVEL, - level: t.level, - id: t.id - }) - }, e.prototype.onAudioTrackLoading = function(t) { - this.load(t.url, { - type: v.AUDIO_TRACK, - level: 0, - id: t.id - }) - }, e.prototype.onSubtitleTrackLoading = function(t) { - this.load(t.url, { - type: v.SUBTITLE_TRACK, - level: 0, - id: t.id - }) - }, e.prototype.load = function(t, e) { - var r = this.hls.config; - u.b.debug("Loading playlist of type " + e.type + ", level: " + e.level + ", id: " + e.id); - var i = this.getInternalLoader(e); - if (i) { - var a = i.context; - if (a && a.url === t) return u.b.trace("playlist request ongoing"), !1; - u.b.warn("aborting previous loader for type: " + e.type), i.abort() - } - var n = void 0, - o = void 0, - s = void 0, - l = void 0; - switch (e.type) { - case v.MANIFEST: - n = r.manifestLoadingMaxRetry, o = r.manifestLoadingTimeOut, s = r.manifestLoadingRetryDelay, l = r.manifestLoadingMaxRetryTimeout; - break; - case v.LEVEL: - n = 0, o = r.levelLoadingTimeOut; - break; - default: - n = r.levelLoadingMaxRetry, o = r.levelLoadingTimeOut, s = r.levelLoadingRetryDelay, l = r.levelLoadingMaxRetryTimeout - } - i = this.createInternalLoader(e), e.url = t, e.responseType = e.responseType || ""; - var d = { - timeout: o, - maxRetry: n, - retryDelay: s, - maxRetryDelay: l - }, - c = { - onSuccess: this.loadsuccess.bind(this), - onError: this.loaderror.bind(this), - onTimeout: this.loadtimeout.bind(this) - }; - return u.b.debug("Calling internal loader delegate for URL: " + t), i.load(e, d, c), !0 - }, e.prototype.loadsuccess = function(t, e, r) { - var i = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : null; - if (r.isSidxRequest) return this._handleSidxRequest(t, r), void this._handlePlaylistLoaded(t, e, r, i); - this.resetInternalLoader(r.type); - var a = t.data; - if (e.tload = p.now(), 0 !== a.indexOf("#EXTM3U")) return void this._handleManifestParsingError(t, r, "no EXTM3U delimiter", i); - a.indexOf("#EXTINF:") > 0 || a.indexOf("#EXT-X-TARGETDURATION:") > 0 ? this._handleTrackOrLevelPlaylist(t, e, r, i) : this._handleMasterPlaylist(t, e, r, i) - }, e.prototype.loaderror = function(t, e) { - var r = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : null; - this._handleNetworkError(e, r) - }, e.prototype.loadtimeout = function(t, e) { - var r = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : null; - this._handleNetworkError(e, r, !0) - }, e.prototype._handleMasterPlaylist = function(t, r, i, a) { - var n = this.hls, - s = t.data, - l = e.getResponseUrl(t, i), - d = c.a.parseMasterPlaylist(s, l); - if (!d.length) return void this._handleManifestParsingError(t, i, "no level found in manifest", a); - var h = d.map(function(t) { - return { - id: t.attrs.AUDIO, - codec: t.audioCodec - } - }), - f = c.a.parseMasterPlaylistMedia(s, l, "AUDIO", h), - p = c.a.parseMasterPlaylistMedia(s, l, "SUBTITLES"); - if (f.length) { - var v = !1; - f.forEach(function(t) { - t.url || (v = !0) - }), !1 === v && d[0].audioCodec && !d[0].attrs.AUDIO && (u.b.log("audio codec signaled in quality level, but no embedded audio track signaled, create one"), f.unshift({ - type: "main", - name: "main" - })) - } - n.trigger(o.a.MANIFEST_LOADED, { - levels: d, - audioTracks: f, - subtitles: p, - url: l, - stats: r, - networkDetails: a - }) - }, e.prototype._handleTrackOrLevelPlaylist = function(t, r, i, a) { - var n = this.hls, - s = i.id, - l = i.level, - u = i.type, - d = e.getResponseUrl(t, i), - h = isNaN(s) ? 0 : s, - f = isNaN(l) ? h : l, - g = e.mapContextToLevelType(i), - y = c.a.parseLevelPlaylist(t.data, d, f, g, h); - if (y.tload = r.tload, u === v.MANIFEST) { - var m = { - url: d, - details: y - }; - n.trigger(o.a.MANIFEST_LOADED, { - levels: [m], - audioTracks: [], - url: d, - stats: r, - networkDetails: a - }) - } - if (r.tparsed = p.now(), y.needSidxRanges) { - var b = y.initSegment.url; - return void this.load(b, { - isSidxRequest: !0, - type: u, - level: l, - levelDetails: y, - id: s, - rangeStart: 0, - rangeEnd: 2048, - responseType: "arraybuffer" - }) - } - i.levelDetails = y, this._handlePlaylistLoaded(t, r, i, a) - }, e.prototype._handleSidxRequest = function(t, e) { - var r = d.a.parseSegmentIndex(new Uint8Array(t.data)); - r.references.forEach(function(t, r) { - var i = t.info, - a = e.levelDetails.fragments[r]; - 0 === a.byteRange.length && (a.rawByteRange = String(1 + i.end - i.start) + "@" + String(i.start)) - }), e.levelDetails.initSegment.rawByteRange = String(r.moovEndOffset) + "@0" - }, e.prototype._handleManifestParsingError = function(t, e, r, i) { - this.hls.trigger(o.a.ERROR, { - type: l.b.NETWORK_ERROR, - details: l.a.MANIFEST_PARSING_ERROR, - fatal: !0, - url: t.url, - reason: r, - networkDetails: i - }) - }, e.prototype._handleNetworkError = function(t, e) { - var r = arguments.length > 2 && void 0 !== arguments[2] && arguments[2]; - u.b.info("A network error occured while loading a " + t.type + "-type playlist"); - var i = void 0, - a = void 0, - n = this.getInternalLoader(t); - switch (t.type) { - case v.MANIFEST: - i = r ? l.a.MANIFEST_LOAD_TIMEOUT : l.a.MANIFEST_LOAD_ERROR, a = !0; - break; - case v.LEVEL: - i = r ? l.a.LEVEL_LOAD_TIMEOUT : l.a.LEVEL_LOAD_ERROR, a = !1; - break; - case v.AUDIO_TRACK: - i = r ? l.a.AUDIO_TRACK_LOAD_TIMEOUT : l.a.AUDIO_TRACK_LOAD_ERROR, a = !1; - break; - default: - a = !1 - } - n && (n.abort(), this.resetInternalLoader(t.type)), this.hls.trigger(o.a.ERROR, { - type: l.b.NETWORK_ERROR, - details: i, - fatal: a, - url: n.url, - loader: n, - context: t, - networkDetails: e - }) - }, e.prototype._handlePlaylistLoaded = function(t, r, i, a) { - var n = i.type, - s = i.level, - l = i.id, - u = i.levelDetails; - if (!u.targetduration) return void this._handleManifestParsingError(t, i, "invalid target duration", a); - if (e.canHaveQualityLevels(i.type)) this.hls.trigger(o.a.LEVEL_LOADED, { - details: u, - level: s || 0, - id: l || 0, - stats: r, - networkDetails: a - }); - else switch (n) { - case v.AUDIO_TRACK: - this.hls.trigger(o.a.AUDIO_TRACK_LOADED, { - details: u, - id: l, - stats: r, - networkDetails: a - }); - break; - case v.SUBTITLE_TRACK: - this.hls.trigger(o.a.SUBTITLE_TRACK_LOADED, { - details: u, - id: l, - stats: r, - networkDetails: a - }) - } - }, h(e, null, [{ - key: "ContextType", - get: function() { - return v - } - }, { - key: "LevelType", - get: function() { - return g - } - }]), e - }(s.a); - e.a = y - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(0), - n = r(1), - o = Math.pow(2, 32) - 1, - s = function() { - function t(e, r) { - i(this, t), this.observer = e, this.remuxer = r - } - return t.prototype.resetTimeStamp = function(t) { - this.initPTS = t - }, t.prototype.resetInitSegment = function(e, r, i, a) { - if (e && e.byteLength) { - var o = this.initData = t.parseInitSegment(e); - null == r && (r = "mp4a.40.5"), null == i && (i = "avc1.42e01e"); - var s = {}; - o.audio && o.video ? s.audiovideo = { - container: "video/mp4", - codec: r + "," + i, - initSegment: a ? e : null - } : (o.audio && (s.audio = { - container: "audio/mp4", - codec: r, - initSegment: a ? e : null - }), o.video && (s.video = { - container: "video/mp4", - codec: i, - initSegment: a ? e : null - })), this.observer.trigger(n.a.FRAG_PARSING_INIT_SEGMENT, { - tracks: s - }) - } else r && (this.audioCodec = r), i && (this.videoCodec = i) - }, t.probe = function(e) { - return t.findBox({ - data: e, - start: 0, - end: Math.min(e.length, 16384) - }, ["moof"]).length > 0 - }, t.bin2str = function(t) { - return String.fromCharCode.apply(null, t) - }, t.readUint16 = function(t, e) { - t.data && (e += t.start, t = t.data); - var r = t[e] << 8 | t[e + 1]; - return r < 0 ? 65536 + r : r - }, t.readUint32 = function(t, e) { - t.data && (e += t.start, t = t.data); - var r = t[e] << 24 | t[e + 1] << 16 | t[e + 2] << 8 | t[e + 3]; - return r < 0 ? 4294967296 + r : r - }, t.writeUint32 = function(t, e, r) { - t.data && (e += t.start, t = t.data), t[e] = r >> 24, t[e + 1] = r >> 16 & 255, t[e + 2] = r >> 8 & 255, t[e + 3] = 255 & r - }, t.findBox = function(e, r) { - var i = [], - a = void 0, - n = void 0, - o = void 0, - s = void 0, - l = void 0, - u = void 0, - d = void 0; - if (e.data ? (u = e.start, s = e.end, e = e.data) : (u = 0, s = e.byteLength), !r.length) return null; - for (a = u; a < s;) n = t.readUint32(e, a), o = t.bin2str(e.subarray(a + 4, a + 8)), d = n > 1 ? a + n : s, o === r[0] && (1 === r.length ? i.push({ - data: e, - start: a + 8, - end: d - }) : (l = t.findBox({ - data: e, - start: a + 8, - end: d - }, r.slice(1)), l.length && (i = i.concat(l)))), a = d; - return i - }, t.parseSegmentIndex = function(e) { - var r = t.findBox(e, ["moov"])[0], - i = r ? r.end : null, - a = 0, - n = t.findBox(e, ["sidx"]), - o = void 0; - if (!n || !n[0]) return null; - o = [], n = n[0]; - var s = n.data[0]; - a = 0 === s ? 8 : 16; - var l = t.readUint32(n, a); - a += 4; - a += 0 === s ? 8 : 16, a += 2; - var u = n.end + 0, - d = t.readUint16(n, a); - a += 2; - for (var c = 0; c < d; c++) { - var h = a, - f = t.readUint32(n, h); - h += 4; - var p = 2147483647 & f; - if (1 === (2147483648 & f) >>> 31) return void console.warn("SIDX has hierarchical references (not supported)"); - var v = t.readUint32(n, h); - h += 4, o.push({ - referenceSize: p, - subsegmentDuration: v, - info: { - duration: v / l, - start: u, - end: u + p - 1 - } - }), u += p, h += 4, a = h - } - return { - earliestPresentationTime: 0, - timescale: l, - version: s, - referencesCount: d, - references: o, - moovEndOffset: i - } - }, t.parseInitSegment = function(e) { - var r = []; - return t.findBox(e, ["moov", "trak"]).forEach(function(e) { - var i = t.findBox(e, ["tkhd"])[0]; - if (i) { - var n = i.data[i.start], - o = 0 === n ? 12 : 20, - s = t.readUint32(i, o), - l = t.findBox(e, ["mdia", "mdhd"])[0]; - if (l) { - n = l.data[l.start], o = 0 === n ? 12 : 20; - var u = t.readUint32(l, o), - d = t.findBox(e, ["mdia", "hdlr"])[0]; - if (d) { - var c = t.bin2str(d.data.subarray(d.start + 8, d.start + 12)), - h = { - soun: "audio", - vide: "video" - } [c]; - if (h) { - var f = t.findBox(e, ["mdia", "minf", "stbl", "stsd"]); - if (f.length) { - f = f[0]; - var p = t.bin2str(f.data.subarray(f.start + 12, f.start + 16)); - a.b.log("MP4Demuxer:" + h + ":" + p + " found") - } - r[s] = { - timescale: u, - type: h - }, r[h] = { - timescale: u, - id: s - } - } - } - } - } - }), r - }, t.getStartDTS = function(e, r) { - var i = void 0, - a = void 0, - n = void 0; - return i = t.findBox(r, ["moof", "traf"]), a = [].concat.apply([], i.map(function(r) { - return t.findBox(r, ["tfhd"]).map(function(i) { - var a = void 0, - n = void 0; - return a = t.readUint32(i, 4), n = e[a].timescale || 9e4, t.findBox(r, ["tfdt"]).map(function(e) { - var r = void 0, - i = void 0; - return r = e.data[e.start], i = t.readUint32(e, 4), 1 === r && (i *= Math.pow(2, 32), i += t.readUint32(e, 8)), i - })[0] / n - }) - })), n = Math.min.apply(null, a), isFinite(n) ? n : 0 - }, t.offsetStartDTS = function(e, r, i) { - t.findBox(r, ["moof", "traf"]).map(function(r) { - return t.findBox(r, ["tfhd"]).map(function(a) { - var n = t.readUint32(a, 4), - s = e[n].timescale || 9e4; - t.findBox(r, ["tfdt"]).map(function(e) { - var r = e.data[e.start], - a = t.readUint32(e, 4); - if (0 === r) t.writeUint32(e, 4, a - i * s); - else { - a *= Math.pow(2, 32), a += t.readUint32(e, 8), a -= i * s, a = Math.max(a, 0); - var n = Math.floor(a / (o + 1)), - l = Math.floor(a % (o + 1)); - t.writeUint32(e, 4, n), t.writeUint32(e, 8, l) - } - }) - }) - }) - }, t.prototype.append = function(e, r, i, a) { - var o = this.initData; - o || (this.resetInitSegment(e, this.audioCodec, this.videoCodec, !1), o = this.initData); - var s = void 0, - l = this.initPTS; - if (void 0 === l) { - var u = t.getStartDTS(o, e); - this.initPTS = l = u - r, this.observer.trigger(n.a.INIT_PTS_FOUND, { - initPTS: l - }) - } - t.offsetStartDTS(o, e, l), s = t.getStartDTS(o, e), this.remuxer.remux(o.audio, o.video, null, null, s, i, a, e) - }, t.prototype.destroy = function() {}, t - }(); - e.a = s - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(5), - n = r.n(a), - o = function() { - function t(t, e) { - for (var r = 0; r < e.length; r++) { - var i = e[r]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(t, i.key, i) - } - } - return function(e, r, i) { - return r && t(e.prototype, r), i && t(e, i), e - } - }(), - s = function() { - function t() { - i(this, t), this.method = null, this.key = null, this.iv = null, this._uri = null - } - return o(t, [{ - key: "uri", - get: function() { - return !this._uri && this.reluri && (this._uri = n.a.buildAbsoluteURL(this.baseuri, this.reluri, { - alwaysNormalize: !0 - })), this._uri - } - }]), t - }(); - e.a = s - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - var r = n[e]; - return !!r && !0 === r[t.slice(0, 4)] - } - - function a(t, e) { - return window.MediaSource.isTypeSupported((e || "video") + '/mp4;codecs="' + t + '"') - } - r.d(e, "b", function() { - return i - }), r.d(e, "a", function() { - return a - }); - var n = { - audio: { - a3ds: !0, - "ac-3": !0, - "ac-4": !0, - alac: !0, - alaw: !0, - dra1: !0, - "dts+": !0, - "dts-": !0, - dtsc: !0, - dtse: !0, - dtsh: !0, - "ec-3": !0, - enca: !0, - g719: !0, - g726: !0, - m4ae: !0, - mha1: !0, - mha2: !0, - mhm1: !0, - mhm2: !0, - mlpa: !0, - mp4a: !0, - "raw ": !0, - Opus: !0, - samr: !0, - sawb: !0, - sawp: !0, - sevc: !0, - sqcp: !0, - ssmv: !0, - twos: !0, - ulaw: !0 - }, - video: { - avc1: !0, - avc2: !0, - avc3: !0, - avc4: !0, - avcp: !0, - drac: !0, - dvav: !0, - dvhe: !0, - encv: !0, - hev1: !0, - hvc1: !0, - mjp2: !0, - mp4v: !0, - mvc1: !0, - mvc2: !0, - mvc3: !0, - mvc4: !0, - resv: !0, - rv60: !0, - s263: !0, - svc1: !0, - svc2: !0, - "vc-1": !0, - vp08: !0, - vp09: !0 - } - } - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(12), - n = r.n(a), - o = r(34), - s = r.n(o), - l = r(1), - u = r(21), - d = r(0), - c = r(2), - h = r(14), - f = r(4), - p = Object(f.a)(), - v = Object(h.a)(), - g = function() { - function t(e, r) { - i(this, t), this.hls = e, this.id = r; - var a = this.observer = new n.a, - o = e.config; - a.trigger = function(t) { - for (var e = arguments.length, r = Array(e > 1 ? e - 1 : 0), i = 1; i < e; i++) r[i - 1] = arguments[i]; - a.emit.apply(a, [t, t].concat(r)) - }, a.off = function(t) { - for (var e = arguments.length, r = Array(e > 1 ? e - 1 : 0), i = 1; i < e; i++) r[i - 1] = arguments[i]; - a.removeListener.apply(a, [t].concat(r)) - }; - var h = function(t, r) { - r = r || {}, r.frag = this.frag, r.id = this.id, e.trigger(t, r) - }.bind(this); - a.on(l.a.FRAG_DECRYPTED, h), a.on(l.a.FRAG_PARSING_INIT_SEGMENT, h), a.on(l.a.FRAG_PARSING_DATA, h), a.on(l.a.FRAG_PARSED, h), a.on(l.a.ERROR, h), a.on(l.a.FRAG_PARSING_METADATA, h), a.on(l.a.FRAG_PARSING_USERDATA, h), a.on(l.a.INIT_PTS_FOUND, h); - var f = { - mp4: v.isTypeSupported("video/mp4"), - mpeg: v.isTypeSupported("audio/mpeg"), - mp3: v.isTypeSupported('audio/mp4; codecs="mp3"') - }, - g = navigator.vendor; - if (o.enableWorker && "undefined" != typeof Worker) { - d.b.log("demuxing in webworker"); - var y = void 0; - try { - y = this.w = s()(47), this.onwmsg = this.onWorkerMessage.bind(this), y.addEventListener("message", this.onwmsg), y.onerror = function(t) { - e.trigger(l.a.ERROR, { - type: c.b.OTHER_ERROR, - details: c.a.INTERNAL_EXCEPTION, - fatal: !0, - event: "demuxerWorker", - err: { - message: t.message + " (" + t.filename + ":" + t.lineno + ")" - } - }) - }, y.postMessage({ - cmd: "init", - typeSupported: f, - vendor: g, - id: r, - config: JSON.stringify(o) - }) - } catch (t) { - d.b.error("error while initializing DemuxerWorker, fallback on DemuxerInline"), y && p.URL.revokeObjectURL(y.objectURL), this.demuxer = new u.a(a, f, o, g), this.w = void 0 - } - } else this.demuxer = new u.a(a, f, o, g) - } - return t.prototype.destroy = function() { - var t = this.w; - if (t) t.removeEventListener("message", this.onwmsg), t.terminate(), this.w = null; - else { - var e = this.demuxer; - e && (e.destroy(), this.demuxer = null) - } - var r = this.observer; - r && (r.removeAllListeners(), this.observer = null) - }, t.prototype.push = function(t, e, r, i, a, n, o, s) { - var l = this.w, - u = isNaN(a.startDTS) ? a.start : a.startDTS, - c = a.decryptdata, - h = this.frag, - f = !(h && a.cc === h.cc), - p = !(h && a.level === h.level), - v = h && a.sn === h.sn + 1, - g = !p && v; - if (f && d.b.log(this.id + ":discontinuity detected"), p && d.b.log(this.id + ":switch detected"), this.frag = a, l) l.postMessage({ - cmd: "demux", - data: t, - decryptdata: c, - initSegment: e, - audioCodec: r, - videoCodec: i, - timeOffset: u, - discontinuity: f, - trackSwitch: p, - contiguous: g, - duration: n, - accurateTimeOffset: o, - defaultInitPTS: s - }, t instanceof ArrayBuffer ? [t] : []); - else { - var y = this.demuxer; - y && y.push(t, c, e, r, i, u, f, p, g, n, o, s) - } - }, t.prototype.onWorkerMessage = function(t) { - var e = t.data, - r = this.hls; - switch (e.event) { - case "init": - p.URL.revokeObjectURL(this.w.objectURL); - break; - case l.a.FRAG_PARSING_DATA: - e.data.data1 = new Uint8Array(e.data1), e.data2 && (e.data.data2 = new Uint8Array(e.data2)); - default: - e.data = e.data || {}, e.data.frag = this.frag, e.data.id = this.id, r.trigger(e.event, e.data) - } - }, t - }(); - e.a = g - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(1), - n = r(2), - o = r(13), - s = r(38), - l = r(17), - u = r(39), - d = r(42), - c = r(43), - h = r(46), - f = r(4), - p = Object(f.a)(), - v = p, - g = function() { - function t(e, r, a, n) { - i(this, t), this.observer = e, this.typeSupported = r, this.config = a, this.vendor = n - } - return t.prototype.destroy = function() { - var t = this.demuxer; - t && t.destroy() - }, t.prototype.push = function(t, e, r, i, n, s, l, u, d, c, h, f) { - if (t.byteLength > 0 && null != e && null != e.key && "AES-128" === e.method) { - var p = this.decrypter; - null == p && (p = this.decrypter = new o.a(this.observer, this.config)); - var g = this, - y = void 0; - try { - y = v.now() - } catch (t) { - y = Date.now() - } - p.decrypt(t, e.key.buffer, e.iv.buffer, function(t) { - var o = void 0; - try { - o = v.now() - } catch (t) { - o = Date.now() - } - g.observer.trigger(a.a.FRAG_DECRYPTED, { - stats: { - tstart: y, - tdecrypt: o - } - }), g.pushDecrypted(new Uint8Array(t), e, new Uint8Array(r), i, n, s, l, u, d, c, h, f) - }) - } else this.pushDecrypted(new Uint8Array(t), e, new Uint8Array(r), i, n, s, l, u, d, c, h, f) - }, t.prototype.pushDecrypted = function(t, e, r, i, o, f, p, v, g, y, m, b) { - var E = this.demuxer; - if (!E || (p || v) && !this.probe(t)) { - for (var T = this.observer, S = this.typeSupported, R = this.config, A = [{ - demux: u.a, - remux: c.a - }, { - demux: l.a, - remux: h.a - }, { - demux: s.a, - remux: c.a - }, { - demux: d.a, - remux: c.a - }], _ = 0, w = A.length; _ < w; _++) { - var L = A[_], - D = L.demux.probe; - if (D(t)) { - var I = this.remuxer = new L.remux(T, R, S, this.vendor); - E = new L.demux(T, I, R, S), this.probe = D; - break - } - } - if (!E) return void T.trigger(a.a.ERROR, { - type: n.b.MEDIA_ERROR, - details: n.a.FRAG_PARSING_ERROR, - fatal: !0, - reason: "no demux matching with content found" - }); - this.demuxer = E - } - var k = this.remuxer; - (p || v) && (E.resetInitSegment(r, i, o, y), k.resetInitSegment()), p && (E.resetTimeStamp(b), k.resetTimeStamp(b)), "function" == typeof E.setDecryptData && E.setDecryptData(e), E.append(t, f, g, m) - }, t - }(); - e.a = g - }, function(t, e, r) { - "use strict"; - - function i(t, e, r, i) { - var a = void 0, - n = void 0, - o = void 0, - s = void 0, - l = void 0, - u = navigator.userAgent.toLowerCase(), - d = i, - c = [96e3, 88200, 64e3, 48e3, 44100, 32e3, 24e3, 22050, 16e3, 12e3, 11025, 8e3, 7350]; - return a = 1 + ((192 & e[r + 2]) >>> 6), (n = (60 & e[r + 2]) >>> 2) > c.length - 1 ? void t.trigger(v.a.ERROR, { - type: p.b.MEDIA_ERROR, - details: p.a.FRAG_PARSING_ERROR, - fatal: !0, - reason: "invalid ADTS sampling index:" + n - }) : (s = (1 & e[r + 2]) << 2, s |= (192 & e[r + 3]) >>> 6, f.b.log("manifest codec:" + i + ",ADTS data:type:" + a + ",sampleingIndex:" + n + "[" + c[n] + "Hz],channelConfig:" + s), /firefox/i.test(u) ? n >= 6 ? (a = 5, l = new Array(4), o = n - 3) : (a = 2, l = new Array(2), o = n) : -1 !== u.indexOf("android") ? (a = 2, l = new Array(2), o = n) : (a = 5, l = new Array(4), i && (-1 !== i.indexOf("mp4a.40.29") || -1 !== i.indexOf("mp4a.40.5")) || !i && n >= 6 ? o = n - 3 : ((i && -1 !== i.indexOf("mp4a.40.2") && (n >= 6 && 1 === s || /vivaldi/i.test(u)) || !i && 1 === s) && (a = 2, l = new Array(2)), o = n)), l[0] = a << 3, l[0] |= (14 & n) >> 1, l[1] |= (1 & n) << 7, l[1] |= s << 3, 5 === a && (l[1] |= (14 & o) >> 1, l[2] = (1 & o) << 7, l[2] |= 8, l[3] = 0), { - config: l, - samplerate: c[n], - channelCount: s, - codec: "mp4a.40." + a, - manifestCodec: d - }) - } - - function a(t, e) { - return 255 === t[e] && 240 == (246 & t[e + 1]) - } - - function n(t, e) { - return 1 & t[e + 1] ? 7 : 9 - } - - function o(t, e) { - return (3 & t[e + 3]) << 11 | t[e + 4] << 3 | (224 & t[e + 5]) >>> 5 - } - - function s(t, e) { - return !!(e + 1 < t.length && a(t, e)) - } - - function l(t, e) { - if (e + 1 < t.length && a(t, e)) { - var r = n(t, e), - i = r; - e + 5 < t.length && (i = o(t, e)); - var s = e + i; - if (s === t.length || s + 1 < t.length && a(t, s)) return !0 - } - return !1 - } - - function u(t, e, r, a, n) { - if (!t.samplerate) { - var o = i(e, r, a, n); - t.config = o.config, t.samplerate = o.samplerate, t.channelCount = o.channelCount, t.codec = o.codec, t.manifestCodec = o.manifestCodec, f.b.log("parsed codec:" + t.codec + ",rate:" + o.samplerate + ",nb channel:" + o.channelCount) - } - } - - function d(t) { - return 9216e4 / t - } - - function c(t, e, r, i, a) { - var s = void 0, - l = void 0, - u = void 0, - d = t.length; - if (s = n(t, e), l = o(t, e), (l -= s) > 0 && e + s + l <= d) return u = r + i * a, { - headerLength: s, - frameLength: l, - stamp: u - } - } - - function h(t, e, r, i, a) { - var n = d(t.samplerate), - o = c(e, r, i, a, n); - if (o) { - var s = o.stamp, - l = o.headerLength, - u = o.frameLength, - h = { - unit: e.subarray(r + l, r + l + u), - pts: s, - dts: s - }; - return t.samples.push(h), t.len += u, { - sample: h, - length: u + l - } - } - } - e.d = s, e.e = l, e.c = u, e.b = d, e.a = h; - var f = r(0), - p = r(2), - v = r(1); - r(4) - }, function(t, e, r) { - "use strict"; - var i = { - BitratesMap: [32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160], - SamplingRateMap: [44100, 48e3, 32e3, 22050, 24e3, 16e3, 11025, 12e3, 8e3], - SamplesCoefficients: [ - [0, 72, 144, 12], - [0, 0, 0, 0], - [0, 72, 144, 12], - [0, 144, 144, 12] - ], - BytesInSlot: [0, 1, 1, 4], - appendFrame: function(t, e, r, i, a) { - if (!(r + 24 > e.length)) { - var n = this.parseHeader(e, r); - if (n && r + n.frameLength <= e.length) { - var o = 9e4 * n.samplesPerFrame / n.sampleRate, - s = i + a * o, - l = { - unit: e.subarray(r, r + n.frameLength), - pts: s, - dts: s - }; - return t.config = [], t.channelCount = n.channelCount, t.samplerate = n.sampleRate, t.samples.push(l), t.len += n.frameLength, { - sample: l, - length: n.frameLength - } - } - } - }, - parseHeader: function(t, e) { - var r = t[e + 1] >> 3 & 3, - a = t[e + 1] >> 1 & 3, - n = t[e + 2] >> 4 & 15, - o = t[e + 2] >> 2 & 3, - s = t[e + 2] >> 1 & 1; - if (1 !== r && 0 !== n && 15 !== n && 3 !== o) { - var l = 3 === r ? 3 - a : 3 === a ? 3 : 4, - u = 1e3 * i.BitratesMap[14 * l + n - 1], - d = 3 === r ? 0 : 2 === r ? 1 : 2, - c = i.SamplingRateMap[3 * d + o], - h = t[e + 3] >> 6 == 3 ? 1 : 2, - f = i.SamplesCoefficients[r][a], - p = i.BytesInSlot[a], - v = 8 * f * p; - return { - sampleRate: c, - channelCount: h, - frameLength: parseInt(f * u / c + s, 10) * p, - samplesPerFrame: v - } - } - }, - isHeaderPattern: function(t, e) { - return 255 === t[e] && 224 == (224 & t[e + 1]) && 0 != (6 & t[e + 1]) - }, - isHeader: function(t, e) { - return !!(e + 1 < t.length && this.isHeaderPattern(t, e)) - }, - probe: function(t, e) { - if (e + 1 < t.length && this.isHeaderPattern(t, e)) { - var r = this.parseHeader(t, e), - i = 4; - r && r.frameLength && (i = r.frameLength); - var a = e + i; - if (a === t.length || a + 1 < t.length && this.isHeaderPattern(t, a)) return !0 - } - return !1 - } - }; - e.a = i - }, function(t, e, r) { - "use strict"; - var i = { - toString: function(t) { - for (var e = "", r = t.length, i = 0; i < r; i++) e += "[" + t.start(i).toFixed(3) + "," + t.end(i).toFixed(3) + "]"; - return e - } - }; - e.a = i - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - for (var r = null, i = 0; i < t.length; i += 1) { - var a = t[i]; - if (a && a.cc === e) { - r = a; - break - } - } - return r - } - - function a(t, e) { - return u.a.search(t, function(t) { - return t.cc < e ? 1 : t.cc > e ? -1 : 0 - }) - } - - function n(t, e, r) { - var i = !1; - return e && e.details && r && (r.endCC > r.startCC || t && t.cc < r.startCC) && (i = !0), i - } - - function o(t, e) { - var r = t.fragments, - a = e.fragments; - if (!a.length || !r.length) return void d.b.log("No fragments to align"); - var n = i(r, a[0].cc); - return !n || n && !n.startPTS ? void d.b.log("No frag in previous level to align on") : n - } - - function s(t, e) { - e.fragments.forEach(function(e) { - if (e) { - var r = e.start + t; - e.start = e.startPTS = r, e.endPTS = r + e.duration - } - }), e.PTSKnown = !0 - } - - function l(t, e, r) { - if (n(t, e, r)) { - var i = o(e.details, r); - i && (d.b.log("Adjusting PTS using last level due to CC increase within current level"), s(i.start, r)) - } - if (!1 === r.PTSKnown && e && e.details && e.details.fragments && e.details.fragments.length) { - var a = e.details.programDateTime, - l = r.programDateTime, - u = (l - a) / 1e3 + e.details.fragments[0].start; - isNaN(u) || (d.b.log("adjusting PTS using programDateTime delta, sliding:" + u.toFixed(3)), s(u, r)) - } - } - e.b = a, e.a = l; - var u = r(6), - d = r(0) - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - var r = null; - try { - r = new window.Event("addtrack") - } catch (t) { - r = document.createEvent("Event"), r.initEvent("addtrack", !1, !1) - } - r.track = t, e.dispatchEvent(r) - } - - function a(t) { - if (t && t.cues) - for (; t.cues.length > 0;) t.removeCue(t.cues[0]) - } - e.b = i, e.a = a - }, function(t, e, r) { - "use strict"; - - function i() { - this.window = window, this.state = "INITIAL", this.buffer = "", this.decoder = new d, this.regionList = [] - } - - function a(t) { - function e(t, e, r, i) { - return 3600 * (0 | t) + 60 * (0 | e) + (0 | r) + (0 | i) / 1e3 - } - var r = t.match(/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/); - return r ? r[3] ? e(r[1], r[2], r[3].replace(":", ""), r[4]) : r[1] > 59 ? e(r[1], r[2], 0, r[4]) : e(0, r[1], r[2], r[4]) : null - } - - function n() { - this.values = Object.create(null) - } - - function o(t, e, r, i) { - var a = i ? t.split(i) : [t]; - for (var n in a) - if ("string" == typeof a[n]) { - var o = a[n].split(r); - if (2 === o.length) { - var s = o[0], - l = o[1]; - e(s, l) - } - } - } - - function s(t, e, r) { - function i() { - var e = a(t); - if (null === e) throw new Error("Malformed timestamp: " + l); - return t = t.replace(/^[^\sa-zA-Z-]+/, ""), e - } - - function s() { - t = t.replace(/^\s+/, "") - } - var l = t; - if (s(), e.startTime = i(), s(), "--\x3e" !== t.substr(0, 3)) throw new Error("Malformed time stamp (time stamps must be separated by '--\x3e'): " + l); - t = t.substr(3), s(), e.endTime = i(), s(), - function(t, e) { - var i = new n; - o(t, function(t, e) { - switch (t) { - case "region": - for (var a = r.length - 1; a >= 0; a--) - if (r[a].id === e) { - i.set(t, r[a].region); - break - } break; - case "vertical": - i.alt(t, e, ["rl", "lr"]); - break; - case "line": - var n = e.split(","), - o = n[0]; - i.integer(t, o), i.percent(t, o) && i.set("snapToLines", !1), i.alt(t, o, ["auto"]), 2 === n.length && i.alt("lineAlign", n[1], ["start", h, "end"]); - break; - case "position": - n = e.split(","), i.percent(t, n[0]), 2 === n.length && i.alt("positionAlign", n[1], ["start", h, "end", "line-left", "line-right", "auto"]); - break; - case "size": - i.percent(t, e); - break; - case "align": - i.alt(t, e, ["start", h, "end", "left", "right"]) - } - }, /:/, /\s/), e.region = i.get("region", null), e.vertical = i.get("vertical", ""); - var a = i.get("line", "auto"); - "auto" === a && -1 === c.line && (a = -1), e.line = a, e.lineAlign = i.get("lineAlign", "start"), e.snapToLines = i.get("snapToLines", !0), e.size = i.get("size", 100), e.align = i.get("align", h); - var s = i.get("position", "auto"); - "auto" === s && 50 === c.position && (s = "start" === e.align || "left" === e.align ? 0 : "end" === e.align || "right" === e.align ? 100 : 50), e.position = s - }(t, e) - } - - function l(t) { - return t.replace(//gi, "\n") - } - r.d(e, "b", function() { - return l - }); - var u = r(63), - d = function() { - return { - decode: function(t) { - if (!t) return ""; - if ("string" != typeof t) throw new Error("Error - expected string data."); - return decodeURIComponent(encodeURIComponent(t)) - } - } - }; - n.prototype = { - set: function(t, e) { - this.get(t) || "" === e || (this.values[t] = e) - }, - get: function(t, e, r) { - return r ? this.has(t) ? this.values[t] : e[r] : this.has(t) ? this.values[t] : e - }, - has: function(t) { - return t in this.values - }, - alt: function(t, e, r) { - for (var i = 0; i < r.length; ++i) - if (e === r[i]) { - this.set(t, e); - break - } - }, - integer: function(t, e) { - /^-?\d+$/.test(e) && this.set(t, parseInt(e, 10)) - }, - percent: function(t, e) { - return !!(e.match(/^([\d]{1,3})(\.[\d]*)?%$/) && (e = parseFloat(e)) >= 0 && e <= 100) && (this.set(t, e), !0) - } - }; - var c = new u.a(0, 0, 0), - h = "middle" === c.align ? "middle" : "center"; - i.prototype = { - parse: function(t) { - function e() { - var t = r.buffer, - e = 0; - for (t = l(t); e < t.length && "\r" !== t[e] && "\n" !== t[e];) ++e; - var i = t.substr(0, e); - return "\r" === t[e] && ++e, "\n" === t[e] && ++e, r.buffer = t.substr(e), i - } - var r = this; - t && (r.buffer += r.decoder.decode(t, { - stream: !0 - })); - try { - var i = void 0; - if ("INITIAL" === r.state) { - if (!/\r\n|\n/.test(r.buffer)) return this; - i = e(); - var a = i.match(/^()?WEBVTT([ \t].*)?$/); - if (!a || !a[0]) throw new Error("Malformed WebVTT signature."); - r.state = "HEADER" - } - for (var n = !1; r.buffer;) { - if (!/\r\n|\n/.test(r.buffer)) return this; - switch (n ? n = !1 : i = e(), r.state) { - case "HEADER": - /:/.test(i) ? function(t) { - o(t, function(t, e) {}, /:/) - }(i) : i || (r.state = "ID"); - continue; - case "NOTE": - i || (r.state = "ID"); - continue; - case "ID": - if (/^NOTE($|[ \t])/.test(i)) { - r.state = "NOTE"; - break - } - if (!i) continue; - if (r.cue = new u.a(0, 0, ""), r.state = "CUE", -1 === i.indexOf("--\x3e")) { - r.cue.id = i; - continue - } - case "CUE": - try { - s(i, r.cue, r.regionList) - } catch (t) { - r.cue = null, r.state = "BADCUE"; - continue - } - r.state = "CUETEXT"; - continue; - case "CUETEXT": - var d = -1 !== i.indexOf("--\x3e"); - if (!i || d && (n = !0)) { - r.oncue && r.oncue(r.cue), r.cue = null, r.state = "ID"; - continue - } - r.cue.text && (r.cue.text += "\n"), r.cue.text += i; - continue; - case "BADCUE": - i || (r.state = "ID"); - continue - } - } - } catch (t) { - "CUETEXT" === r.state && r.cue && r.oncue && r.oncue(r.cue), r.cue = null, r.state = "INITIAL" === r.state ? "BADWEBVTT" : "BADCUE" - } - return this - }, - flush: function() { - var t = this; - try { - if (t.buffer += t.decoder.decode(), (t.cue || "HEADER" === t.state) && (t.buffer += "\n\n", t.parse()), "INITIAL" === t.state) throw new Error("Malformed WebVTT signature.") - } catch (t) { - throw t - } - return t.onflush && t.onflush(), this - } - }, e.a = i - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - Object.defineProperty(e, "__esModule", { - value: !0 - }); - var a = r(5), - n = r.n(a), - o = r(2), - s = r(16), - l = r(31), - u = r(32), - d = r(10), - c = r(33), - h = r(49), - f = r(50), - p = r(51), - v = r(0), - g = r(52), - y = r(1), - m = r(12), - b = r.n(m), - E = function() { - function t(t, e) { - for (var r = 0; r < e.length; r++) { - var i = e[r]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(t, i.key, i) - } - } - return function(e, r, i) { - return r && t(e.prototype, r), i && t(e, i), e - } - }(); - r(72); - var T = function() { - function t() { - var e = this, - r = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; - i(this, t); - var a = t.DefaultConfig; - if ((r.liveSyncDurationCount || r.liveMaxLatencyDurationCount) && (r.liveSyncDuration || r.liveMaxLatencyDuration)) throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration"); - for (var n in a) n in r || (r[n] = a[n]); - if (void 0 !== r.liveMaxLatencyDurationCount && r.liveMaxLatencyDurationCount <= r.liveSyncDurationCount) throw new Error('Illegal hls.js config: "liveMaxLatencyDurationCount" must be gt "liveSyncDurationCount"'); - if (void 0 !== r.liveMaxLatencyDuration && (r.liveMaxLatencyDuration <= r.liveSyncDuration || void 0 === r.liveSyncDuration)) throw new Error('Illegal hls.js config: "liveMaxLatencyDuration" must be gt "liveSyncDuration"'); - Object(v.a)(r.debug), this.config = r, this._autoLevelCapping = -1; - var o = this.observer = new b.a; - o.trigger = function(t) { - for (var e = arguments.length, r = Array(e > 1 ? e - 1 : 0), i = 1; i < e; i++) r[i - 1] = arguments[i]; - o.emit.apply(o, [t, t].concat(r)) - }, o.off = function(t) { - for (var e = arguments.length, r = Array(e > 1 ? e - 1 : 0), i = 1; i < e; i++) r[i - 1] = arguments[i]; - o.removeListener.apply(o, [t].concat(r)) - }, this.on = o.on.bind(o), this.off = o.off.bind(o), this.once = o.once.bind(o), this.trigger = o.trigger.bind(o); - var p = this.abrController = new r.abrController(this), - g = new r.bufferController(this), - y = new r.capLevelController(this), - m = new r.fpsController(this), - E = new s.a(this), - T = new l.a(this), - S = new u.a(this), - R = new f.a(this), - A = this.levelController = new h.a(this), - _ = new d.b(this), - w = this.streamController = new c.a(this, _), - L = [A, w], - D = r.audioStreamController; - D && L.push(new D(this, _)), this.networkControllers = L; - var I = [E, T, S, p, g, y, m, R, _]; - if (D = r.audioTrackController) { - var k = new D(this); - this.audioTrackController = k, I.push(k) - } - if (D = r.subtitleTrackController) { - var O = new D(this); - this.subtitleTrackController = O, I.push(O) - } - if (D = r.emeController) { - var C = new D(this); - this.emeController = C, I.push(C) - } [r.subtitleStreamController, r.timelineController].forEach(function(t) { - t && I.push(new t(e)) - }), this.coreComponents = I - } - return t.isSupported = function() { - return Object(p.a)() - }, E(t, null, [{ - key: "version", - get: function() { - return "0.10.0" - } - }, { - key: "Events", - get: function() { - return y.a - } - }, { - key: "ErrorTypes", - get: function() { - return o.b - } - }, { - key: "ErrorDetails", - get: function() { - return o.a - } - }, { - key: "DefaultConfig", - get: function() { - return t.defaultConfig ? t.defaultConfig : g.a - }, - set: function(e) { - t.defaultConfig = e - } - }]), t.prototype.destroy = function() { - v.b.log("destroy"), this.trigger(y.a.DESTROYING), this.detachMedia(), this.coreComponents.concat(this.networkControllers).forEach(function(t) { - t.destroy() - }), this.url = null, this.observer.removeAllListeners(), this._autoLevelCapping = -1 - }, t.prototype.attachMedia = function(t) { - v.b.log("attachMedia"), this.media = t, this.trigger(y.a.MEDIA_ATTACHING, { - media: t - }) - }, t.prototype.detachMedia = function() { - v.b.log("detachMedia"), this.trigger(y.a.MEDIA_DETACHING), this.media = null - }, t.prototype.loadSource = function(t) { - t = n.a.buildAbsoluteURL(window.location.href, t, { - alwaysNormalize: !0 - }), v.b.log("loadSource:" + t), this.url = t, this.trigger(y.a.MANIFEST_LOADING, { - url: t - }) - }, t.prototype.startLoad = function() { - var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : -1; - v.b.log("startLoad(" + t + ")"), this.networkControllers.forEach(function(e) { - e.startLoad(t) - }) - }, t.prototype.stopLoad = function() { - v.b.log("stopLoad"), this.networkControllers.forEach(function(t) { - t.stopLoad() - }) - }, t.prototype.swapAudioCodec = function() { - v.b.log("swapAudioCodec"), this.streamController.swapAudioCodec() - }, t.prototype.recoverMediaError = function() { - v.b.log("recoverMediaError"); - var t = this.media; - this.detachMedia(), this.attachMedia(t) - }, E(t, [{ - key: "levels", - get: function() { - return this.levelController.levels - } - }, { - key: "currentLevel", - get: function() { - return this.streamController.currentLevel - }, - set: function(t) { - v.b.log("set currentLevel:" + t), this.loadLevel = t, this.streamController.immediateLevelSwitch() - } - }, { - key: "nextLevel", - get: function() { - return this.streamController.nextLevel - }, - set: function(t) { - v.b.log("set nextLevel:" + t), this.levelController.manualLevel = t, this.streamController.nextLevelSwitch() - } - }, { - key: "loadLevel", - get: function() { - return this.levelController.level - }, - set: function(t) { - v.b.log("set loadLevel:" + t), this.levelController.manualLevel = t - } - }, { - key: "nextLoadLevel", - get: function() { - return this.levelController.nextLoadLevel - }, - set: function(t) { - this.levelController.nextLoadLevel = t - } - }, { - key: "firstLevel", - get: function() { - return Math.max(this.levelController.firstLevel, this.minAutoLevel) - }, - set: function(t) { - v.b.log("set firstLevel:" + t), this.levelController.firstLevel = t - } - }, { - key: "startLevel", - get: function() { - return this.levelController.startLevel - }, - set: function(t) { - v.b.log("set startLevel:" + t); - var e = this; - 1 !== t && (t = Math.max(t, e.minAutoLevel)), e.levelController.startLevel = t - } - }, { - key: "autoLevelCapping", - get: function() { - return this._autoLevelCapping - }, - set: function(t) { - v.b.log("set autoLevelCapping:" + t), this._autoLevelCapping = t - } - }, { - key: "autoLevelEnabled", - get: function() { - return -1 === this.levelController.manualLevel - } - }, { - key: "manualLevel", - get: function() { - return this.levelController.manualLevel - } - }, { - key: "minAutoLevel", - get: function() { - for (var t = this, e = t.levels, r = t.config.minAutoBitrate, i = e ? e.length : 0, a = 0; a < i; a++) { - if ((e[a].realBitrate ? Math.max(e[a].realBitrate, e[a].bitrate) : e[a].bitrate) > r) return a - } - return 0 - } - }, { - key: "maxAutoLevel", - get: function() { - var t = this, - e = t.levels, - r = t.autoLevelCapping; - return -1 === r && e && e.length ? e.length - 1 : r - } - }, { - key: "nextAutoLevel", - get: function() { - var t = this; - return Math.min(Math.max(t.abrController.nextAutoLevel, t.minAutoLevel), t.maxAutoLevel) - }, - set: function(t) { - var e = this; - e.abrController.nextAutoLevel = Math.max(e.minAutoLevel, t) - } - }, { - key: "audioTracks", - get: function() { - var t = this.audioTrackController; - return t ? t.audioTracks : [] - } - }, { - key: "audioTrack", - get: function() { - var t = this.audioTrackController; - return t ? t.audioTrack : -1 - }, - set: function(t) { - var e = this.audioTrackController; - e && (e.audioTrack = t) - } - }, { - key: "liveSyncPosition", - get: function() { - return this.streamController.liveSyncPosition - } - }, { - key: "subtitleTracks", - get: function() { - var t = this.subtitleTrackController; - return t ? t.subtitleTracks : [] - } - }, { - key: "subtitleTrack", - get: function() { - var t = this.subtitleTrackController; - return t ? t.subtitleTrack : -1 - }, - set: function(t) { - var e = this.subtitleTrackController; - e && (e.subtitleTrack = t) - } - }, { - key: "subtitleDisplay", - get: function() { - var t = this.subtitleTrackController; - return !!t && t.subtitleDisplay - }, - set: function(t) { - var e = this.subtitleTrackController; - e && (e.subtitleDisplay = t) - } - }]), t - }(); - e.default = T - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(5), - n = r.n(a), - o = r(9), - s = r(18), - l = r(30), - u = r(0), - d = r(19), - c = /#EXT-X-STREAM-INF:([^\n\r]*)[\r\n]+([^\r\n]+)/g, - h = /#EXT-X-MEDIA:(.*)/g, - f = new RegExp([/#EXTINF:\s*(\d*(?:\.\d+)?)(?:,(.*)\s+)?/.source, /|(?!#)(\S+)/.source, /|#EXT-X-BYTERANGE:*(.+)/.source, /|#EXT-X-PROGRAM-DATE-TIME:(.+)/.source, /|#.*/.source].join(""), "g"), - p = /(?:(?:#(EXTM3U))|(?:#EXT-X-(PLAYLIST-TYPE):(.+))|(?:#EXT-X-(MEDIA-SEQUENCE): *(\d+))|(?:#EXT-X-(TARGETDURATION): *(\d+))|(?:#EXT-X-(KEY):(.+))|(?:#EXT-X-(START):(.+))|(?:#EXT-X-(ENDLIST))|(?:#EXT-X-(DISCONTINUITY-SEQ)UENCE:(\d+))|(?:#EXT-X-(DIS)CONTINUITY))|(?:#EXT-X-(VERSION):(\d+))|(?:#EXT-X-(MAP):(.+))|(?:(#)(.*):(.*))|(?:(#)(.*))(?:.*)\r?\n?/, - v = /\.(mp4|m4s|m4v|m4a)$/i, - g = function() { - function t() { - i(this, t) - } - return t.findGroup = function(t, e) { - if (!t) return null; - for (var r = null, i = 0; i < t.length; i++) { - var a = t[i]; - a.id === e && (r = a) - } - return r - }, t.convertAVC1ToAVCOTI = function(t) { - var e = void 0, - r = t.split("."); - return r.length > 2 ? (e = r.shift() + ".", e += parseInt(r.shift()).toString(16), e += ("000" + parseInt(r.shift()).toString(16)).substr(-4)) : e = t, e - }, t.resolve = function(t, e) { - return n.a.buildAbsoluteURL(e, t, { - alwaysNormalize: !0 - }) - }, t.parseMasterPlaylist = function(e, r) { - var i = [], - a = void 0; - for (c.lastIndex = 0; null != (a = c.exec(e));) { - var n = {}, - o = n.attrs = new l.a(a[1]); - n.url = t.resolve(a[2], r); - var s = o.decimalResolution("RESOLUTION"); - s && (n.width = s.width, n.height = s.height), n.bitrate = o.decimalInteger("AVERAGE-BANDWIDTH") || o.decimalInteger("BANDWIDTH"), n.name = o.NAME, - function(t, e) { - ["video", "audio"].forEach(function(r) { - var i = t.filter(function(t) { - return Object(d.b)(t, r) - }); - if (i.length) { - var a = i.filter(function(t) { - return 0 === t.lastIndexOf("avc1", 0) || 0 === t.lastIndexOf("mp4a", 0) - }); - e[r + "Codec"] = a.length > 0 ? a[0] : i[0], t = t.filter(function(t) { - return -1 === i.indexOf(t) - }) - } - }), e.unknownCodecs = t - }([].concat((o.CODECS || "").split(/[ ,]+/)), n), n.videoCodec && -1 !== n.videoCodec.indexOf("avc1") && (n.videoCodec = t.convertAVC1ToAVCOTI(n.videoCodec)), i.push(n) - } - return i - }, t.parseMasterPlaylistMedia = function(e, r, i) { - var a = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : [], - n = void 0, - o = [], - s = 0; - for (h.lastIndex = 0; null !== (n = h.exec(e));) { - var u = {}, - d = new l.a(n[1]); - if (d.TYPE === i) { - if (u.groupId = d["GROUP-ID"], u.name = d.NAME, u.type = i, u.default = "YES" === d.DEFAULT, u.autoselect = "YES" === d.AUTOSELECT, u.forced = "YES" === d.FORCED, d.URI && (u.url = t.resolve(d.URI, r)), u.lang = d.LANGUAGE, u.name || (u.name = u.lang), a.length) { - var c = t.findGroup(a, u.groupId); - u.audioCodec = c ? c.codec : a[0].codec - } - u.id = s++, o.push(u) - } - } - return o - }, t.parseLevelPlaylist = function(t, e, r, i, a) { - var n = 0, - d = 0, - c = { - type: null, - version: null, - url: e, - fragments: [], - live: !0, - startSN: 0 - }, - h = new s.a, - g = 0, - y = null, - m = new o.a, - b = void 0, - E = void 0; - for (f.lastIndex = 0; null !== (b = f.exec(t));) { - var T = b[1]; - if (T) { - m.duration = parseFloat(T); - var S = (" " + b[2]).slice(1); - m.title = S || null, m.tagList.push(S ? ["INF", T, S] : ["INF", T]) - } else if (b[3]) { - if (!isNaN(m.duration)) { - var R = n++; - m.type = i, m.start = d, m.levelkey = h, m.sn = R, m.level = r, m.cc = g, m.urlId = a, m.baseurl = e, m.relurl = (" " + b[3]).slice(1), c.programDateTime && (y ? m.rawProgramDateTime ? m.pdt = Date.parse(m.rawProgramDateTime) : m.pdt = y.pdt + 1e3 * y.duration : m.pdt = Date.parse(c.programDateTime), m.endPdt = m.pdt + 1e3 * m.duration), c.fragments.push(m), y = m, d += m.duration, m = new o.a - } - } else if (b[4]) { - if (m.rawByteRange = (" " + b[4]).slice(1), y) { - var A = y.byteRangeEndOffset; - A && (m.lastByteRangeEndOffset = A) - } - } else if (b[5]) m.rawProgramDateTime = (" " + b[5]).slice(1), m.tagList.push(["PROGRAM-DATE-TIME", m.rawProgramDateTime]), void 0 === c.programDateTime && (c.programDateTime = new Date(new Date(Date.parse(b[5])) - 1e3 * d)); - else { - for (b = b[0].match(p), E = 1; E < b.length && void 0 === b[E]; E++); - var _ = (" " + b[E + 1]).slice(1), - w = (" " + b[E + 2]).slice(1); - switch (b[E]) { - case "#": - m.tagList.push(w ? [_, w] : [_]); - break; - case "PLAYLIST-TYPE": - c.type = _.toUpperCase(); - break; - case "MEDIA-SEQUENCE": - n = c.startSN = parseInt(_); - break; - case "TARGETDURATION": - c.targetduration = parseFloat(_); - break; - case "VERSION": - c.version = parseInt(_); - break; - case "EXTM3U": - break; - case "ENDLIST": - c.live = !1; - break; - case "DIS": - g++, m.tagList.push(["DIS"]); - break; - case "DISCONTINUITY-SEQ": - g = parseInt(_); - break; - case "KEY": - var L = _, - D = new l.a(L), - I = D.enumeratedString("METHOD"), - k = D.URI, - O = D.hexadecimalInteger("IV"); - I && (h = new s.a, k && ["AES-128", "SAMPLE-AES", "SAMPLE-AES-CENC"].indexOf(I) >= 0 && (h.method = I, h.baseuri = e, h.reluri = k, h.key = null, h.iv = O)); - break; - case "START": - var C = _, - P = new l.a(C), - x = P.decimalFloatingPoint("TIME-OFFSET"); - isNaN(x) || (c.startTimeOffset = x); - break; - case "MAP": - var F = new l.a(_); - m.relurl = F.URI, m.rawByteRange = F.BYTERANGE, m.baseurl = e, m.level = r, m.type = i, m.sn = "initSegment", c.initSegment = m, m = new o.a; - break; - default: - u.b.warn("line parsed but not handled: " + b) - } - } - } - return m = y, m && !m.relurl && (c.fragments.pop(), d -= m.duration), c.totalduration = d, c.averagetargetduration = d / c.fragments.length, c.endSN = n - 1, c.startCC = c.fragments[0] ? c.fragments[0].cc : 0, c.endCC = g, !c.initSegment && c.fragments.length && c.fragments.every(function(t) { - return v.test(t.relurl) - }) && (u.b.warn("MP4 fragments found but no init segment (probably no MAP, incomplete M3U8), trying to fetch SIDX"), m = new o.a, m.relurl = c.fragments[0].relurl, m.baseurl = e, m.level = r, m.type = i, m.sn = "initSegment", c.initSegment = m, c.needSidxRanges = !0), c - }, t - }(); - e.a = g - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = /^(\d+)x(\d+)$/, - n = /\s*(.+?)\s*=((?:\".*?\")|.*?)(?:,|$)/g, - o = function() { - function t(e) { - i(this, t), "string" == typeof e && (e = t.parseAttrList(e)); - for (var r in e) e.hasOwnProperty(r) && (this[r] = e[r]) - } - return t.prototype.decimalInteger = function(t) { - var e = parseInt(this[t], 10); - return e > Number.MAX_SAFE_INTEGER ? 1 / 0 : e - }, t.prototype.hexadecimalInteger = function(t) { - if (this[t]) { - var e = (this[t] || "0x").slice(2); - e = (1 & e.length ? "0" : "") + e; - for (var r = new Uint8Array(e.length / 2), i = 0; i < e.length / 2; i++) r[i] = parseInt(e.slice(2 * i, 2 * i + 2), 16); - return r - } - return null - }, t.prototype.hexadecimalIntegerAsNumber = function(t) { - var e = parseInt(this[t], 16); - return e > Number.MAX_SAFE_INTEGER ? 1 / 0 : e - }, t.prototype.decimalFloatingPoint = function(t) { - return parseFloat(this[t]) - }, t.prototype.enumeratedString = function(t) { - return this[t] - }, t.prototype.decimalResolution = function(t) { - var e = a.exec(this[t]); - if (null !== e) return { - width: parseInt(e[1], 10), - height: parseInt(e[2], 10) - } - }, t.parseAttrList = function(t) { - var e = void 0, - r = {}; - for (n.lastIndex = 0; null !== (e = n.exec(t));) { - var i = e[2]; - 0 === i.indexOf('"') && i.lastIndexOf('"') === i.length - 1 && (i = i.slice(1, -1)), r[e[1]] = i - } - return r - }, t - }(); - e.a = o - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(1), - s = r(3), - l = r(2), - u = r(0), - d = function(t) { - function e(r) { - i(this, e); - var n = a(this, t.call(this, r, o.a.FRAG_LOADING)); - return n.loaders = {}, n - } - return n(e, t), e.prototype.destroy = function() { - var e = this.loaders; - for (var r in e) { - var i = e[r]; - i && i.destroy() - } - this.loaders = {}, t.prototype.destroy.call(this) - }, e.prototype.onFragLoading = function(t) { - var e = t.frag, - r = e.type, - i = this.loaders, - a = this.hls.config, - n = a.fLoader, - o = a.loader; - e.loaded = 0; - var s = i[r]; - s && (u.b.warn("abort previous fragment loader for type: " + r), s.abort()), s = i[r] = e.loader = a.fLoader ? new n(a) : new o(a); - var l = void 0, - d = void 0, - c = void 0; - l = { - url: e.url, - frag: e, - responseType: "arraybuffer", - progressData: !1 - }; - var h = e.byteRangeStartOffset, - f = e.byteRangeEndOffset; - isNaN(h) || isNaN(f) || (l.rangeStart = h, l.rangeEnd = f), d = { - timeout: a.fragLoadingTimeOut, - maxRetry: 0, - retryDelay: 0, - maxRetryDelay: a.fragLoadingMaxRetryTimeout - }, c = { - onSuccess: this.loadsuccess.bind(this), - onError: this.loaderror.bind(this), - onTimeout: this.loadtimeout.bind(this), - onProgress: this.loadprogress.bind(this) - }, s.load(l, d, c) - }, e.prototype.loadsuccess = function(t, e, r) { - var i = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : null, - a = t.data, - n = r.frag; - n.loader = void 0, this.loaders[n.type] = void 0, this.hls.trigger(o.a.FRAG_LOADED, { - payload: a, - frag: n, - stats: e, - networkDetails: i - }) - }, e.prototype.loaderror = function(t, e) { - var r = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : null, - i = e.loader; - i && i.abort(), this.loaders[e.type] = void 0, this.hls.trigger(o.a.ERROR, { - type: l.b.NETWORK_ERROR, - details: l.a.FRAG_LOAD_ERROR, - fatal: !1, - frag: e.frag, - response: t, - networkDetails: r - }) - }, e.prototype.loadtimeout = function(t, e) { - var r = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : null, - i = e.loader; - i && i.abort(), this.loaders[e.type] = void 0, this.hls.trigger(o.a.ERROR, { - type: l.b.NETWORK_ERROR, - details: l.a.FRAG_LOAD_TIMEOUT, - fatal: !1, - frag: e.frag, - networkDetails: r - }) - }, e.prototype.loadprogress = function(t, e, r) { - var i = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : null, - a = e.frag; - a.loaded = t.loaded, this.hls.trigger(o.a.FRAG_LOAD_PROGRESS, { - frag: a, - stats: t, - networkDetails: i - }) - }, e - }(s.a); - e.a = d - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(1), - s = r(3), - l = r(2), - u = r(0), - d = function(t) { - function e(r) { - i(this, e); - var n = a(this, t.call(this, r, o.a.KEY_LOADING)); - return n.loaders = {}, n.decryptkey = null, n.decrypturl = null, n - } - return n(e, t), e.prototype.destroy = function() { - for (var t in this.loaders) { - var e = this.loaders[t]; - e && e.destroy() - } - this.loaders = {}, s.a.prototype.destroy.call(this) - }, e.prototype.onKeyLoading = function(t) { - var e = t.frag, - r = e.type, - i = this.loaders[r], - a = e.decryptdata, - n = a.uri; - if (n !== this.decrypturl || null === this.decryptkey) { - var s = this.hls.config; - i && (u.b.warn("abort previous key loader for type:" + r), i.abort()), e.loader = this.loaders[r] = new s.loader(s), this.decrypturl = n, this.decryptkey = null; - var l = void 0, - d = void 0, - c = void 0; - l = { - url: n, - frag: e, - responseType: "arraybuffer" - }, d = { - timeout: s.fragLoadingTimeOut, - maxRetry: s.fragLoadingMaxRetry, - retryDelay: s.fragLoadingRetryDelay, - maxRetryDelay: s.fragLoadingMaxRetryTimeout - }, c = { - onSuccess: this.loadsuccess.bind(this), - onError: this.loaderror.bind(this), - onTimeout: this.loadtimeout.bind(this) - }, e.loader.load(l, d, c) - } else this.decryptkey && (a.key = this.decryptkey, this.hls.trigger(o.a.KEY_LOADED, { - frag: e - })) - }, e.prototype.loadsuccess = function(t, e, r) { - var i = r.frag; - this.decryptkey = i.decryptdata.key = new Uint8Array(t.data), i.loader = void 0, this.loaders[i.type] = void 0, this.hls.trigger(o.a.KEY_LOADED, { - frag: i - }) - }, e.prototype.loaderror = function(t, e) { - var r = e.frag, - i = r.loader; - i && i.abort(), this.loaders[e.type] = void 0, this.hls.trigger(o.a.ERROR, { - type: l.b.NETWORK_ERROR, - details: l.a.KEY_LOAD_ERROR, - fatal: !1, - frag: r, - response: t - }) - }, e.prototype.loadtimeout = function(t, e) { - var r = e.frag, - i = r.loader; - i && i.abort(), this.loaders[e.type] = void 0, this.hls.trigger(o.a.ERROR, { - type: l.b.NETWORK_ERROR, - details: l.a.KEY_LOAD_TIMEOUT, - fatal: !1, - frag: r - }) - }, e - }(s.a); - e.a = d - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(6), - s = r(11), - l = r(20), - u = r(1), - d = r(10), - c = r(9), - h = r(16), - f = r(15), - p = r(24), - v = r(2), - g = r(0), - y = r(25), - m = r(8), - b = r(48), - E = function() { - function t(t, e) { - for (var r = 0; r < e.length; r++) { - var i = e[r]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(t, i.key, i) - } - } - return function(e, r, i) { - return r && t(e.prototype, r), i && t(e, i), e - } - }(), - T = { - STOPPED: "STOPPED", - IDLE: "IDLE", - KEY_LOADING: "KEY_LOADING", - FRAG_LOADING: "FRAG_LOADING", - FRAG_LOADING_WAITING_RETRY: "FRAG_LOADING_WAITING_RETRY", - WAITING_LEVEL: "WAITING_LEVEL", - PARSING: "PARSING", - PARSED: "PARSED", - BUFFER_FLUSHING: "BUFFER_FLUSHING", - ENDED: "ENDED", - ERROR: "ERROR" - }, - S = function(t) { - function e(r, n) { - i(this, e); - var o = a(this, t.call(this, r, u.a.MEDIA_ATTACHED, u.a.MEDIA_DETACHING, u.a.MANIFEST_LOADING, u.a.MANIFEST_PARSED, u.a.LEVEL_LOADED, u.a.KEY_LOADED, u.a.FRAG_LOADED, u.a.FRAG_LOAD_EMERGENCY_ABORTED, u.a.FRAG_PARSING_INIT_SEGMENT, u.a.FRAG_PARSING_DATA, u.a.FRAG_PARSED, u.a.ERROR, u.a.AUDIO_TRACK_SWITCHING, u.a.AUDIO_TRACK_SWITCHED, u.a.BUFFER_CREATED, u.a.BUFFER_APPENDED, u.a.BUFFER_FLUSHED)); - return o.fragmentTracker = n, o.config = r.config, o.audioCodecSwap = !1, o._state = T.STOPPED, o.stallReported = !1, o - } - return n(e, t), e.prototype.onHandlerDestroying = function() { - this.stopLoad(), t.prototype.onHandlerDestroying.call(this) - }, e.prototype.onHandlerDestroyed = function() { - this.state = T.STOPPED, this.fragmentTracker = null, t.prototype.onHandlerDestroyed.call(this) - }, e.prototype.startLoad = function(t) { - if (this.levels) { - var e = this.lastCurrentTime, - r = this.hls; - if (this.stopLoad(), this.setInterval(100), this.level = -1, this.fragLoadError = 0, !this.startFragRequested) { - var i = r.startLevel; - 1 === i && (i = 0, this.bitrateTest = !0), this.level = r.nextLoadLevel = i, this.loadedmetadata = !1 - } - e > 0 && -1 === t && (g.b.log("override startPosition with lastCurrentTime @" + e.toFixed(3)), t = e), this.state = T.IDLE, this.nextLoadPosition = this.startPosition = this.lastCurrentTime = t, this.tick() - } else this.forceStartLoad = !0, this.state = T.STOPPED - }, e.prototype.stopLoad = function() { - var t = this.fragCurrent; - t && (t.loader && t.loader.abort(), this.fragmentTracker.removeFragment(t), this.fragCurrent = null), this.fragPrevious = null, this.demuxer && (this.demuxer.destroy(), this.demuxer = null), this.clearInterval(), this.state = T.STOPPED, this.forceStartLoad = !1 - }, e.prototype.doTick = function() { - switch (this.state) { - case T.BUFFER_FLUSHING: - this.fragLoadError = 0; - break; - case T.IDLE: - this._doTickIdle(); - break; - case T.WAITING_LEVEL: - var t = this.levels[this.level]; - t && t.details && (this.state = T.IDLE); - break; - case T.FRAG_LOADING_WAITING_RETRY: - var e = window.performance.now(), - r = this.retryDate; - (!r || e >= r || this.media && this.media.seeking) && (g.b.log("mediaController: retryDate reached, switch back to IDLE state"), this.state = T.IDLE); - break; - case T.ERROR: - case T.STOPPED: - case T.FRAG_LOADING: - case T.PARSING: - case T.PARSED: - case T.ENDED: - } - this._checkBuffer(), this._checkFragmentChanged() - }, e.prototype._doTickIdle = function() { - var t = this.hls, - e = t.config, - r = this.media; - if (void 0 !== this.levelLastLoaded && (r || !this.startFragRequested && e.startFragPrefetch)) { - var i = void 0; - i = this.loadedmetadata ? r.currentTime : this.nextLoadPosition; - var a = t.nextLoadLevel, - n = this.levels[a]; - if (n) { - var o = n.bitrate, - l = void 0; - l = o ? Math.max(8 * e.maxBufferSize / o, e.maxBufferLength) : e.maxBufferLength, l = Math.min(l, e.maxMaxBufferLength); - var d = s.a.bufferInfo(this.mediaBuffer ? this.mediaBuffer : r, i, e.maxBufferHole), - c = d.len; - if (!(c >= l)) { - g.b.trace("buffer length of " + c.toFixed(3) + " is below max of " + l.toFixed(3) + ". checking for more payload ..."), this.level = t.nextLoadLevel = a; - var h = n.details; - if (!h || h.live && this.levelLastLoaded !== a) return void(this.state = T.WAITING_LEVEL); - var f = this.fragPrevious; - if (!h.live && f && !f.backtracked && f.sn === h.endSN && !d.nextStart) { - if (Math.min(r.duration, f.start + f.duration) - Math.max(d.end, f.start) <= Math.max(.2, f.duration)) { - var p = {}; - return this.altAudio && (p.type = "video"), this.hls.trigger(u.a.BUFFER_EOS, p), void(this.state = T.ENDED) - } - } - this._fetchPayloadOrEos(i, d, h) - } - } - } - }, e.prototype._fetchPayloadOrEos = function(t, e, r) { - var i = this.fragPrevious, - a = this.level, - n = r.fragments, - o = n.length; - if (0 !== o) { - var s = n[0].start, - l = n[o - 1].start + n[o - 1].duration, - u = e.end, - d = void 0; - if (r.initSegment && !r.initSegment.data) d = r.initSegment; - else if (r.live) { - var c = this.config.initialLiveManifestSize; - if (o < c) return void g.b.warn("Can not start playback of a level, reason: not enough fragments " + o + " < " + c); - if (null === (d = this._ensureFragmentAtLivePoint(r, u, s, l, i, n, o))) return - } else u < s && (d = n[0]); - d || (d = this._findFragment(s, i, o, n, u, l, r)), d && (d.encrypted ? (g.b.log("Loading key for " + d.sn + " of [" + r.startSN + " ," + r.endSN + "],level " + a), this._loadKey(d)) : (g.b.log("Loading " + d.sn + " of [" + r.startSN + " ," + r.endSN + "],level " + a + ", currentTime:" + t.toFixed(3) + ",bufferEnd:" + u.toFixed(3)), this._loadFragment(d))) - } - }, e.prototype._ensureFragmentAtLivePoint = function(t, e, r, i, a, n, s) { - var l = this.hls.config, - u = this.media, - d = void 0, - c = void 0 !== l.liveMaxLatencyDuration ? l.liveMaxLatencyDuration : l.liveMaxLatencyDurationCount * t.targetduration; - if (e < Math.max(r - l.maxFragLookUpTolerance, i - c)) { - var h = this.liveSyncPosition = this.computeLivePosition(r, t); - g.b.log("buffer end: " + e.toFixed(3) + " is located too far from the end of live sliding playlist, reset currentTime to : " + h.toFixed(3)), e = h, u && u.readyState && u.duration > h && (u.currentTime = h), this.nextLoadPosition = h - } - if (t.PTSKnown && e > i && u && u.readyState) return null; - if (this.startFragRequested && !t.PTSKnown) { - if (a) - if (t.programDateTime) d = Object(b.b)(n, a.endPdt + 1); - else { - var f = a.sn + 1; - if (f >= t.startSN && f <= t.endSN) { - var p = n[f - t.startSN]; - a.cc === p.cc && (d = p, g.b.log("live playlist, switching playlist, load frag with next SN: " + d.sn)) - } - d || (d = o.a.search(n, function(t) { - return a.cc - t.cc - })) && g.b.log("live playlist, switching playlist, load frag with same CC: " + d.sn) - } d || (d = n[Math.min(s - 1, Math.round(s / 2))], g.b.log("live playlist, switching playlist, unknown, load middle frag : " + d.sn)) - } - return d - }, e.prototype._findFragment = function(t, e, r, i, a, n, o) { - var s = this.hls.config, - l = void 0, - u = void 0; - if (a < n ? o.programDateTime ? (u = Object(b.b)(i, Object(b.a)(t, a, o))) && !Object(b.d)(a, s.maxFragLookUpTolerance, u) || (g.b.warn("Frag found by PDT search did not fit within tolerance; falling back to finding by SN"), u = function() { - return Object(b.c)(e, i, a, n, s.maxFragLookUpTolerance) - }()) : u = Object(b.c)(e, i, a, n, s.maxFragLookUpTolerance) : u = i[r - 1], u) { - l = u; - var d = l.sn - o.startSN, - c = e && l.level === e.level, - h = i[d - 1], - f = i[d + 1]; - if (e && l.sn === e.sn) - if (c && !l.backtracked) - if (l.sn < o.endSN) { - var p = e.deltaPTS; - p && p > s.maxBufferHole && e.dropped && d ? (l = h, g.b.warn("SN just loaded, with large PTS gap between audio and video, maybe frag is not starting with a keyframe ? load previous one to try to overcome this")) : (l = f, g.b.log("SN just loaded, load next one: " + l.sn)) - } else l = null; - else l.backtracked && (f && f.backtracked ? (g.b.warn("Already backtracked from fragment " + f.sn + ", will not backtrack to fragment " + l.sn + ". Loading fragment " + f.sn), l = f) : (g.b.warn("Loaded fragment with dropped frames, backtracking 1 segment to find a keyframe"), l.dropped = 0, h ? (l = h, l.backtracked = !0) : d && (l = null))) - } - return l - }, e.prototype._loadKey = function(t) { - this.state = T.KEY_LOADING, this.hls.trigger(u.a.KEY_LOADING, { - frag: t - }) - }, e.prototype._loadFragment = function(t) { - var e = this.fragmentTracker.getState(t); - this.fragCurrent = t, this.startFragRequested = !0, isNaN(t.sn) || t.bitrateTest || (this.nextLoadPosition = t.start + t.duration), t.backtracked || e === d.a.NOT_LOADED || e === d.a.PARTIAL ? (t.autoLevel = this.hls.autoLevelEnabled, t.bitrateTest = this.bitrateTest, this.hls.trigger(u.a.FRAG_LOADING, { - frag: t - }), this.demuxer || (this.demuxer = new l.a(this.hls, "main")), this.state = T.FRAG_LOADING) : e === d.a.APPENDING && this._reduceMaxBufferLength(t.duration) && this.fragmentTracker.removeFragment(t) - }, e.prototype.getBufferedFrag = function(t) { - return this.fragmentTracker.getBufferedFrag(t, h.a.LevelType.MAIN) - }, e.prototype.followingBufferedFrag = function(t) { - return t ? this.getBufferedFrag(t.endPTS + .5) : null - }, e.prototype._checkFragmentChanged = function() { - var t = void 0, - e = void 0, - r = this.media; - if (r && r.readyState && !1 === r.seeking && (e = r.currentTime, e > this.lastCurrentTime && (this.lastCurrentTime = e), s.a.isBuffered(r, e) ? t = this.getBufferedFrag(e) : s.a.isBuffered(r, e + .1) && (t = this.getBufferedFrag(e + .1)), t)) { - var i = t; - if (i !== this.fragPlaying) { - this.hls.trigger(u.a.FRAG_CHANGED, { - frag: i - }); - var a = i.level; - this.fragPlaying && this.fragPlaying.level === a || this.hls.trigger(u.a.LEVEL_SWITCHED, { - level: a - }), this.fragPlaying = i - } - } - }, e.prototype.immediateLevelSwitch = function() { - if (g.b.log("immediateLevelSwitch"), !this.immediateSwitch) { - this.immediateSwitch = !0; - var t = this.media, - e = void 0; - t ? (e = t.paused, t.pause()) : e = !0, this.previouslyPaused = e - } - var r = this.fragCurrent; - r && r.loader && r.loader.abort(), this.fragCurrent = null, this.flushMainBuffer(0, Number.POSITIVE_INFINITY) - }, e.prototype.immediateLevelSwitchEnd = function() { - var t = this.media; - t && t.buffered.length && (this.immediateSwitch = !1, s.a.isBuffered(t, t.currentTime) && (t.currentTime -= 1e-4), this.previouslyPaused || t.play()) - }, e.prototype.nextLevelSwitch = function() { - var t = this.media; - if (t && t.readyState) { - var e = void 0, - r = void 0, - i = void 0; - if (r = this.getBufferedFrag(t.currentTime), r && r.startPTS > 1 && this.flushMainBuffer(0, r.startPTS - 1), t.paused) e = 0; - else { - var a = this.hls.nextLoadLevel, - n = this.levels[a], - o = this.fragLastKbps; - e = o && this.fragCurrent ? this.fragCurrent.duration * n.bitrate / (1e3 * o) + 1 : 0 - } - if ((i = this.getBufferedFrag(t.currentTime + e)) && (i = this.followingBufferedFrag(i))) { - var s = this.fragCurrent; - s && s.loader && s.loader.abort(), this.fragCurrent = null, this.flushMainBuffer(i.maxStartPTS, Number.POSITIVE_INFINITY) - } - } - }, e.prototype.flushMainBuffer = function(t, e) { - this.state = T.BUFFER_FLUSHING; - var r = { - startOffset: t, - endOffset: e - }; - this.altAudio && (r.type = "video"), this.hls.trigger(u.a.BUFFER_FLUSHING, r) - }, e.prototype.onMediaAttached = function(t) { - var e = this.media = this.mediaBuffer = t.media; - this.onvseeking = this.onMediaSeeking.bind(this), this.onvseeked = this.onMediaSeeked.bind(this), this.onvended = this.onMediaEnded.bind(this), e.addEventListener("seeking", this.onvseeking), e.addEventListener("seeked", this.onvseeked), e.addEventListener("ended", this.onvended); - var r = this.config; - this.levels && r.autoStartLoad && this.hls.startLoad(r.startPosition) - }, e.prototype.onMediaDetaching = function() { - var t = this.media; - t && t.ended && (g.b.log("MSE detaching and video ended, reset startPosition"), this.startPosition = this.lastCurrentTime = 0); - var e = this.levels; - e && e.forEach(function(t) { - t.details && t.details.fragments.forEach(function(t) { - t.backtracked = void 0 - }) - }), t && (t.removeEventListener("seeking", this.onvseeking), t.removeEventListener("seeked", this.onvseeked), t.removeEventListener("ended", this.onvended), this.onvseeking = this.onvseeked = this.onvended = null), this.media = this.mediaBuffer = null, this.loadedmetadata = !1, this.stopLoad() - }, e.prototype.onMediaSeeking = function() { - var t = this.media, - e = t ? t.currentTime : void 0, - r = this.config; - isNaN(e) || g.b.log("media seeking to " + e.toFixed(3)); - var i = this.mediaBuffer ? this.mediaBuffer : t, - a = s.a.bufferInfo(i, e, this.config.maxBufferHole); - if (this.state === T.FRAG_LOADING) { - var n = this.fragCurrent; - if (0 === a.len && n) { - var o = r.maxFragLookUpTolerance, - l = n.start - o, - u = n.start + n.duration + o; - e < l || e > u ? (n.loader && (g.b.log("seeking outside of buffer while fragment load in progress, cancel fragment load"), n.loader.abort()), this.fragCurrent = null, this.fragPrevious = null, this.state = T.IDLE) : g.b.log("seeking outside of buffer but within currently loaded fragment range") - } - } else this.state === T.ENDED && (0 === a.len && (this.fragPrevious = 0), this.state = T.IDLE); - t && (this.lastCurrentTime = e), this.loadedmetadata || (this.nextLoadPosition = this.startPosition = e), this.tick() - }, e.prototype.onMediaSeeked = function() { - var t = this.media, - e = t ? t.currentTime : void 0; - isNaN(e) || g.b.log("media seeked to " + e.toFixed(3)), this.tick() - }, e.prototype.onMediaEnded = function() { - g.b.log("media ended"), this.startPosition = this.lastCurrentTime = 0 - }, e.prototype.onManifestLoading = function() { - g.b.log("trigger BUFFER_RESET"), this.hls.trigger(u.a.BUFFER_RESET), this.fragmentTracker.removeAllFragments(), this.stalled = !1, this.startPosition = this.lastCurrentTime = 0 - }, e.prototype.onManifestParsed = function(t) { - var e = !1, - r = !1, - i = void 0; - t.levels.forEach(function(t) { - (i = t.audioCodec) && (-1 !== i.indexOf("mp4a.40.2") && (e = !0), -1 !== i.indexOf("mp4a.40.5") && (r = !0)) - }), this.audioCodecSwitch = e && r, this.audioCodecSwitch && g.b.log("both AAC/HE-AAC audio found in levels; declaring level codec as HE-AAC"), this.levels = t.levels, this.startFragRequested = !1; - var a = this.config; - (a.autoStartLoad || this.forceStartLoad) && this.hls.startLoad(a.startPosition) - }, e.prototype.onLevelLoaded = function(t) { - var e = t.details, - r = t.level, - i = this.levels[this.levelLastLoaded], - a = this.levels[r], - n = e.totalduration, - o = 0; - if (g.b.log("level " + r + " loaded [" + e.startSN + "," + e.endSN + "],duration:" + n), e.live) { - var s = a.details; - s && e.fragments.length > 0 ? (f.b(s, e), o = e.fragments[0].start, this.liveSyncPosition = this.computeLivePosition(o, s), e.PTSKnown && !isNaN(o) ? g.b.log("live playlist sliding:" + o.toFixed(3)) : (g.b.log("live playlist - outdated PTS, unknown sliding"), Object(y.a)(this.fragPrevious, i, e))) : (g.b.log("live playlist - first load, unknown sliding"), e.PTSKnown = !1, Object(y.a)(this.fragPrevious, i, e)) - } else e.PTSKnown = !1; - if (a.details = e, this.levelLastLoaded = r, this.hls.trigger(u.a.LEVEL_UPDATED, { - details: e, - level: r - }), !1 === this.startFragRequested) { - if (-1 === this.startPosition || -1 === this.lastCurrentTime) { - var l = e.startTimeOffset; - isNaN(l) ? e.live ? (this.startPosition = this.computeLivePosition(o, e), g.b.log("configure startPosition to " + this.startPosition)) : this.startPosition = 0 : (l < 0 && (g.b.log("negative start time offset " + l + ", count from end of last fragment"), l = o + n + l), g.b.log("start time offset found in playlist, adjust startPosition to " + l), this.startPosition = l), this.lastCurrentTime = this.startPosition - } - this.nextLoadPosition = this.startPosition - } - this.state === T.WAITING_LEVEL && (this.state = T.IDLE), this.tick() - }, e.prototype.onKeyLoaded = function() { - this.state === T.KEY_LOADING && (this.state = T.IDLE, this.tick()) - }, e.prototype.onFragLoaded = function(t) { - var e = this.fragCurrent, - r = t.frag; - if (this.state === T.FRAG_LOADING && e && "main" === r.type && r.level === e.level && r.sn === e.sn) { - var i = t.stats, - a = this.levels[e.level], - n = a.details; - if (g.b.log("Loaded " + e.sn + " of [" + n.startSN + " ," + n.endSN + "],level " + e.level), this.bitrateTest = !1, this.stats = i, !0 === r.bitrateTest && this.hls.nextLoadLevel) this.state = T.IDLE, this.startFragRequested = !1, i.tparsed = i.tbuffered = window.performance.now(), this.hls.trigger(u.a.FRAG_BUFFERED, { - stats: i, - frag: e, - id: "main" - }), this.tick(); - else if ("initSegment" === r.sn) this.state = T.IDLE, i.tparsed = i.tbuffered = window.performance.now(), n.initSegment.data = t.payload, this.hls.trigger(u.a.FRAG_BUFFERED, { - stats: i, - frag: e, - id: "main" - }), this.tick(); - else { - this.state = T.PARSING; - var o = n.totalduration, - s = e.level, - d = e.sn, - c = this.config.defaultAudioCodec || a.audioCodec; - this.audioCodecSwap && (g.b.log("swapping playlist audio codec"), void 0 === c && (c = this.lastAudioCodec), c && (c = -1 !== c.indexOf("mp4a.40.5") ? "mp4a.40.2" : "mp4a.40.5")), this.pendingBuffering = !0, this.appended = !1, g.b.log("Parsing " + d + " of [" + n.startSN + " ," + n.endSN + "],level " + s + ", cc " + e.cc); - var h = this.demuxer; - h || (h = this.demuxer = new l.a(this.hls, "main")); - var f = this.media, - p = f && f.seeking, - v = !p && (n.PTSKnown || !n.live), - y = n.initSegment ? n.initSegment.data : []; - h.push(t.payload, y, c, a.videoCodec, e, o, v, void 0) - } - } - this.fragLoadError = 0 - }, e.prototype.onFragParsingInitSegment = function(t) { - var e = this.fragCurrent, - r = t.frag; - if (e && "main" === t.id && r.sn === e.sn && r.level === e.level && this.state === T.PARSING) { - var i = t.tracks, - a = void 0, - n = void 0; - if (i.audio && this.altAudio && delete i.audio, n = i.audio) { - var o = this.levels[this.level].audioCodec, - s = navigator.userAgent.toLowerCase(); - o && this.audioCodecSwap && (g.b.log("swapping playlist audio codec"), o = -1 !== o.indexOf("mp4a.40.5") ? "mp4a.40.2" : "mp4a.40.5"), this.audioCodecSwitch && 1 !== n.metadata.channelCount && -1 === s.indexOf("firefox") && (o = "mp4a.40.5"), -1 !== s.indexOf("android") && "audio/mpeg" !== n.container && (o = "mp4a.40.2", g.b.log("Android: force audio codec to " + o)), n.levelCodec = o, n.id = t.id - } - n = i.video, n && (n.levelCodec = this.levels[this.level].videoCodec, n.id = t.id), this.hls.trigger(u.a.BUFFER_CODECS, i); - for (a in i) { - n = i[a], g.b.log("main track:" + a + ",container:" + n.container + ",codecs[level/parsed]=[" + n.levelCodec + "/" + n.codec + "]"); - var l = n.initSegment; - l && (this.appended = !0, this.pendingBuffering = !0, this.hls.trigger(u.a.BUFFER_APPENDING, { - type: a, - data: l, - parent: "main", - content: "initSegment" - })) - } - this.tick() - } - }, e.prototype.onFragParsingData = function(t) { - var e = this, - r = this.fragCurrent, - i = t.frag; - if (r && "main" === t.id && i.sn === r.sn && i.level === r.level && ("audio" !== t.type || !this.altAudio) && this.state === T.PARSING) { - var a = this.levels[this.level], - n = r; - if (isNaN(t.endPTS) && (t.endPTS = t.startPTS + r.duration, t.endDTS = t.startDTS + r.duration), !0 === t.hasAudio && n.addElementaryStream(c.a.ElementaryStreamTypes.AUDIO), !0 === t.hasVideo && n.addElementaryStream(c.a.ElementaryStreamTypes.VIDEO), g.b.log("Parsed " + t.type + ",PTS:[" + t.startPTS.toFixed(3) + "," + t.endPTS.toFixed(3) + "],DTS:[" + t.startDTS.toFixed(3) + "/" + t.endDTS.toFixed(3) + "],nb:" + t.nb + ",dropped:" + (t.dropped || 0)), "video" === t.type) - if (n.dropped = t.dropped, n.dropped) - if (n.backtracked) g.b.warn("Already backtracked on this fragment, appending with the gap", n.sn); - else { - var o = a.details; - if (!o || n.sn !== o.startSN) return g.b.warn("missing video frame(s), backtracking fragment", n.sn), this.fragmentTracker.removeFragment(n), n.backtracked = !0, this.nextLoadPosition = t.startPTS, this.state = T.IDLE, this.fragPrevious = n, void this.tick(); - g.b.warn("missing video frame(s) on first frag, appending with gap", n.sn) - } - else n.backtracked = !1; - var s = f.c(a.details, n, t.startPTS, t.endPTS, t.startDTS, t.endDTS), - l = this.hls; - l.trigger(u.a.LEVEL_PTS_UPDATED, { - details: a.details, - level: this.level, - drift: s, - type: t.type, - start: t.startPTS, - end: t.endPTS - }), [t.data1, t.data2].forEach(function(r) { - r && r.length && e.state === T.PARSING && (e.appended = !0, e.pendingBuffering = !0, l.trigger(u.a.BUFFER_APPENDING, { - type: t.type, - data: r, - parent: "main", - content: "data" - })) - }), this.tick() - } - }, e.prototype.onFragParsed = function(t) { - var e = this.fragCurrent, - r = t.frag; - e && "main" === t.id && r.sn === e.sn && r.level === e.level && this.state === T.PARSING && (this.stats.tparsed = window.performance.now(), this.state = T.PARSED, this._checkAppendedParsed()) - }, e.prototype.onAudioTrackSwitching = function(t) { - var e = !!t.url, - r = t.id; - if (!e) { - if (this.mediaBuffer !== this.media) { - g.b.log("switching on main audio, use media.buffered to schedule main fragment loading"), this.mediaBuffer = this.media; - var i = this.fragCurrent; - i.loader && (g.b.log("switching to main audio track, cancel main fragment load"), i.loader.abort()), this.fragCurrent = null, this.fragPrevious = null, this.demuxer && (this.demuxer.destroy(), this.demuxer = null), this.state = T.IDLE - } - var a = this.hls; - a.trigger(u.a.BUFFER_FLUSHING, { - startOffset: 0, - endOffset: Number.POSITIVE_INFINITY, - type: "audio" - }), a.trigger(u.a.AUDIO_TRACK_SWITCHED, { - id: r - }), this.altAudio = !1 - } - }, e.prototype.onAudioTrackSwitched = function(t) { - var e = t.id, - r = !!this.hls.audioTracks[e].url; - if (r) { - var i = this.videoBuffer; - i && this.mediaBuffer !== i && (g.b.log("switching on alternate audio, use video.buffered to schedule main fragment loading"), this.mediaBuffer = i) - } - this.altAudio = r, this.tick() - }, e.prototype.onBufferCreated = function(t) { - var e = t.tracks, - r = void 0, - i = void 0, - a = !1; - for (var n in e) { - var o = e[n]; - "main" === o.id ? (i = n, r = o, "video" === n && (this.videoBuffer = e[n].buffer)) : a = !0 - } - a && r ? (g.b.log("alternate track found, use " + i + ".buffered to schedule main fragment loading"), this.mediaBuffer = r.buffer) : this.mediaBuffer = this.media - }, e.prototype.onBufferAppended = function(t) { - if ("main" === t.parent) { - var e = this.state; - e !== T.PARSING && e !== T.PARSED || (this.pendingBuffering = t.pending > 0, this._checkAppendedParsed()) - } - }, e.prototype._checkAppendedParsed = function() { - if (!(this.state !== T.PARSED || this.appended && this.pendingBuffering)) { - var t = this.fragCurrent; - if (t) { - var e = this.mediaBuffer ? this.mediaBuffer : this.media; - g.b.log("main buffered : " + p.a.toString(e.buffered)), this.fragPrevious = t; - var r = this.stats; - r.tbuffered = window.performance.now(), this.fragLastKbps = Math.round(8 * r.total / (r.tbuffered - r.tfirst)), this.hls.trigger(u.a.FRAG_BUFFERED, { - stats: r, - frag: t, - id: "main" - }), this.state = T.IDLE - } - this.tick() - } - }, e.prototype.onError = function(t) { - var e = t.frag || this.fragCurrent; - if (!e || "main" === e.type) { - var r = !!this.media && s.a.isBuffered(this.media, this.media.currentTime) && s.a.isBuffered(this.media, this.media.currentTime + .5); - switch (t.details) { - case v.a.FRAG_LOAD_ERROR: - case v.a.FRAG_LOAD_TIMEOUT: - case v.a.KEY_LOAD_ERROR: - case v.a.KEY_LOAD_TIMEOUT: - if (!t.fatal) - if (this.fragLoadError + 1 <= this.config.fragLoadingMaxRetry) { - var i = Math.min(Math.pow(2, this.fragLoadError) * this.config.fragLoadingRetryDelay, this.config.fragLoadingMaxRetryTimeout); - g.b.warn("mediaController: frag loading failed, retry in " + i + " ms"), this.retryDate = window.performance.now() + i, this.loadedmetadata || (this.startFragRequested = !1, this.nextLoadPosition = this.startPosition), this.fragLoadError++, this.state = T.FRAG_LOADING_WAITING_RETRY - } else g.b.error("mediaController: " + t.details + " reaches max retry, redispatch as fatal ..."), t.fatal = !0, this.state = T.ERROR; - break; - case v.a.LEVEL_LOAD_ERROR: - case v.a.LEVEL_LOAD_TIMEOUT: - this.state !== T.ERROR && (t.fatal ? (this.state = T.ERROR, g.b.warn("streamController: " + t.details + ",switch to " + this.state + " state ...")) : t.levelRetry || this.state !== T.WAITING_LEVEL || (this.state = T.IDLE)); - break; - case v.a.BUFFER_FULL_ERROR: - "main" !== t.parent || this.state !== T.PARSING && this.state !== T.PARSED || (r ? (this._reduceMaxBufferLength(this.config.maxBufferLength), this.state = T.IDLE) : (g.b.warn("buffer full error also media.currentTime is not buffered, flush everything"), this.fragCurrent = null, this.flushMainBuffer(0, Number.POSITIVE_INFINITY))) - } - } - }, e.prototype._reduceMaxBufferLength = function(t) { - var e = this.config; - return e.maxMaxBufferLength >= t && (e.maxMaxBufferLength /= 2, g.b.warn("main:reduce max buffer length to " + e.maxMaxBufferLength + "s"), !0) - }, e.prototype._checkBuffer = function() { - var t = this.config, - e = this.media; - if (e && 0 !== e.readyState) { - var r = e.currentTime, - i = this.mediaBuffer ? this.mediaBuffer : e, - a = i.buffered; - if (!this.loadedmetadata && a.length) this.loadedmetadata = !0, this._seekToStartPos(); - else if (this.immediateSwitch) this.immediateLevelSwitchEnd(); - else { - var n = !(e.paused && e.readyState > 1 || e.ended || 0 === e.buffered.length), - o = window.performance.now(); - if (r !== this.lastCurrentTime) this.stallReported && (g.b.warn("playback not stuck anymore @" + r + ", after " + Math.round(o - this.stalled) + "ms"), this.stallReported = !1), this.stalled = null, this.nudgeRetry = 0; - else if (n) { - var l = o - this.stalled, - u = s.a.bufferInfo(e, r, t.maxBufferHole); - if (!this.stalled) return void(this.stalled = o); - l >= 1e3 && this._reportStall(u.len), this._tryFixBufferStall(u, l) - } - } - } - }, e.prototype.onFragLoadEmergencyAborted = function() { - this.state = T.IDLE, this.loadedmetadata || (this.startFragRequested = !1, this.nextLoadPosition = this.startPosition), this.tick() - }, e.prototype.onBufferFlushed = function() { - var t = this.mediaBuffer ? this.mediaBuffer : this.media; - t && this.fragmentTracker.detectEvictedFragments(c.a.ElementaryStreamTypes.VIDEO, t.buffered), this.state = T.IDLE, this.fragPrevious = null - }, e.prototype.swapAudioCodec = function() { - this.audioCodecSwap = !this.audioCodecSwap - }, e.prototype.computeLivePosition = function(t, e) { - var r = void 0 !== this.config.liveSyncDuration ? this.config.liveSyncDuration : this.config.liveSyncDurationCount * e.targetduration; - return t + Math.max(0, e.totalduration - r) - }, e.prototype._tryFixBufferStall = function(t, e) { - var r = this.config, - i = this.media, - a = i.currentTime, - n = this.fragmentTracker.getPartialFragment(a); - n && this._trySkipBufferHole(n), t.len > .5 && e > 1e3 * r.highBufferWatchdogPeriod && (this.stalled = null, this._tryNudgeBuffer()) - }, e.prototype._reportStall = function(t) { - var e = this.hls, - r = this.media; - this.stallReported || (this.stallReported = !0, g.b.warn("Playback stalling at @" + r.currentTime + " due to low buffer"), e.trigger(u.a.ERROR, { - type: v.b.MEDIA_ERROR, - details: v.a.BUFFER_STALLED_ERROR, - fatal: !1, - buffer: t - })) - }, e.prototype._trySkipBufferHole = function(t) { - for (var e = this.hls, r = this.media, i = r.currentTime, a = 0, n = 0; n < r.buffered.length; n++) { - var o = r.buffered.start(n); - if (i >= a && i < o) return r.currentTime = Math.max(o, r.currentTime + .1), g.b.warn("skipping hole, adjusting currentTime from " + i + " to " + r.currentTime), this.stalled = null, void e.trigger(u.a.ERROR, { - type: v.b.MEDIA_ERROR, - details: v.a.BUFFER_SEEK_OVER_HOLE, - fatal: !1, - reason: "fragment loaded with buffer holes, seeking from " + i + " to " + r.currentTime, - frag: t - }); - a = r.buffered.end(n) - } - }, e.prototype._tryNudgeBuffer = function() { - var t = this.config, - e = this.hls, - r = this.media, - i = r.currentTime, - a = (this.nudgeRetry || 0) + 1; - if (this.nudgeRetry = a, a < t.nudgeMaxRetry) { - var n = i + a * t.nudgeOffset; - g.b.log("adjust currentTime from " + i + " to " + n), r.currentTime = n, e.trigger(u.a.ERROR, { - type: v.b.MEDIA_ERROR, - details: v.a.BUFFER_NUDGE_ON_STALL, - fatal: !1 - }) - } else g.b.error("still stuck in high buffer @" + i + " after " + t.nudgeMaxRetry + ", raise fatal error"), e.trigger(u.a.ERROR, { - type: v.b.MEDIA_ERROR, - details: v.a.BUFFER_STALLED_ERROR, - fatal: !0 - }) - }, e.prototype._seekToStartPos = function() { - var t = this.media, - e = t.currentTime, - r = t.seeking ? e : this.startPosition; - e !== r && (g.b.log("target start position not buffered, seek to buffered.start(0) " + r + " from current time " + e + " "), t.currentTime = r) - }, E(e, [{ - key: "state", - set: function(t) { - if (this.state !== t) { - var e = this.state; - this._state = t, g.b.log("main stream:" + e + "->" + t), this.hls.trigger(u.a.STREAM_STATE_TRANSITION, { - previousState: e, - nextState: t - }) - } - }, - get: function() { - return this._state - } - }, { - key: "currentLevel", - get: function() { - var t = this.media; - if (t) { - var e = this.getBufferedFrag(t.currentTime); - if (e) return e.level - } - return -1 - } - }, { - key: "nextBufferedFrag", - get: function() { - var t = this.media; - return t ? this.followingBufferedFrag(this.getBufferedFrag(t.currentTime)) : null - } - }, { - key: "nextLevel", - get: function() { - var t = this.nextBufferedFrag; - return t ? t.level : -1 - } - }, { - key: "liveSyncPosition", - get: function() { - return this._liveSyncPosition - }, - set: function(t) { - this._liveSyncPosition = t - } - }]), e - }(m.a); - e.a = S - }, function(t, e, r) { - function i(t) { - function e(i) { - if (r[i]) return r[i].exports; - var a = r[i] = { - i: i, - l: !1, - exports: {} - }; - return t[i].call(a.exports, a, a.exports, e), a.l = !0, a.exports - } - var r = {}; - e.m = t, e.c = r, e.i = function(t) { - return t - }, e.d = function(t, r, i) { - e.o(t, r) || Object.defineProperty(t, r, { - configurable: !1, - enumerable: !0, - get: i - }) - }, e.n = function(t) { - var r = t && t.__esModule ? function() { - return t.default - } : function() { - return t - }; - return e.d(r, "a", r), r - }, e.o = function(t, e) { - return Object.prototype.hasOwnProperty.call(t, e) - }, e.p = "/", e.oe = function(t) { - throw console.error(t), t - }; - var i = e(e.s = ENTRY_MODULE); - return i.default || i - } - - function a(t) { - return (t + "").replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&") - } - - function n(t, e, i) { - var n = {}; - n[i] = []; - var o = e.toString(), - s = o.match(/^function\s?\(\w+,\s*\w+,\s*(\w+)\)/); - if (!s) return n; - for (var d, c = s[1], h = new RegExp("(\\\\n|\\W)" + a(c) + u, "g"); d = h.exec(o);) "dll-reference" !== d[3] && n[i].push(d[3]); - for (h = new RegExp("\\(" + a(c) + '\\("(dll-reference\\s(' + l + '))"\\)\\)' + u, "g"); d = h.exec(o);) t[d[2]] || (n[i].push(d[1]), t[d[2]] = r(d[1]).m), n[d[2]] = n[d[2]] || [], n[d[2]].push(d[4]); - return n - } - - function o(t) { - return Object.keys(t).reduce(function(e, r) { - return e || t[r].length > 0 - }, !1) - } - - function s(t, e) { - for (var r = { - main: [e] - }, i = { - main: [] - }, a = { - main: {} - }; o(r);) - for (var s = Object.keys(r), l = 0; l < s.length; l++) { - var u = s[l], - d = r[u], - c = d.pop(); - if (a[u] = a[u] || {}, !a[u][c] && t[u][c]) { - a[u][c] = !0, i[u] = i[u] || [], i[u].push(c); - for (var h = n(t, t[u][c], u), f = Object.keys(h), p = 0; p < f.length; p++) r[f[p]] = r[f[p]] || [], r[f[p]] = r[f[p]].concat(h[f[p]]) - } - } - return i - } - var l = "[\\.|\\-|\\+|\\w|/|@]+", - u = "\\((/\\*.*?\\*/)?s?.*?(" + l + ").*?\\)"; - t.exports = function(t, e) { - e = e || {}; - var a = { - main: r.m - }, - n = e.all ? { - main: Object.keys(a) - } : s(a, t), - o = ""; - Object.keys(n).filter(function(t) { - return "main" !== t - }).forEach(function(t) { - for (var e = 0; n[t][e];) e++; - n[t].push(e), a[t][e] = "(function(module, exports, __webpack_require__) { module.exports = __webpack_require__; })", o = o + "var " + t + " = (" + i.toString().replace("ENTRY_MODULE", JSON.stringify(e)) + ")({" + n[t].map(function(e) { - return JSON.stringify(e) + ": " + a[t][e].toString() - }).join(",") + "});\n" - }), o = o + "(" + i.toString().replace("ENTRY_MODULE", JSON.stringify(t)) + ")({" + n.main.map(function(t) { - return JSON.stringify(t) + ": " + a.main[t].toString() - }).join(",") + "})(self);"; - var l = new window.Blob([o], { - type: "text/javascript" - }); - if (e.bare) return l; - var u = window.URL || window.webkitURL || window.mozURL || window.msURL, - d = u.createObjectURL(l), - c = new window.Worker(d); - return c.objectURL = d, c - } - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = function() { - function t(e, r) { - i(this, t), this.subtle = e, this.aesIV = r - } - return t.prototype.decrypt = function(t, e) { - return this.subtle.decrypt({ - name: "AES-CBC", - iv: this.aesIV - }, e, t) - }, t - }(); - e.a = a - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = function() { - function t(e, r) { - i(this, t), this.subtle = e, this.key = r - } - return t.prototype.expandKey = function() { - return this.subtle.importKey("raw", this.key, { - name: "AES-CBC" - }, !1, ["encrypt", "decrypt"]) - }, t - }(); - e.a = a - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t) { - var e = t.byteLength, - r = e && new DataView(t).getUint8(e - 1); - return r ? t.slice(0, e - r) : t - } - var n = function() { - function t() { - i(this, t), this.rcon = [0, 1, 2, 4, 8, 16, 32, 64, 128, 27, 54], this.subMix = [new Uint32Array(256), new Uint32Array(256), new Uint32Array(256), new Uint32Array(256)], this.invSubMix = [new Uint32Array(256), new Uint32Array(256), new Uint32Array(256), new Uint32Array(256)], this.sBox = new Uint32Array(256), this.invSBox = new Uint32Array(256), this.key = new Uint32Array(0), this.initTable() - } - return t.prototype.uint8ArrayToUint32Array_ = function(t) { - for (var e = new DataView(t), r = new Uint32Array(4), i = 0; i < 4; i++) r[i] = e.getUint32(4 * i); - return r - }, t.prototype.initTable = function() { - var t = this.sBox, - e = this.invSBox, - r = this.subMix, - i = r[0], - a = r[1], - n = r[2], - o = r[3], - s = this.invSubMix, - l = s[0], - u = s[1], - d = s[2], - c = s[3], - h = new Uint32Array(256), - f = 0, - p = 0, - v = 0; - for (v = 0; v < 256; v++) h[v] = v < 128 ? v << 1 : v << 1 ^ 283; - for (v = 0; v < 256; v++) { - var g = p ^ p << 1 ^ p << 2 ^ p << 3 ^ p << 4; - g = g >>> 8 ^ 255 & g ^ 99, t[f] = g, e[g] = f; - var y = h[f], - m = h[y], - b = h[m], - E = 257 * h[g] ^ 16843008 * g; - i[f] = E << 24 | E >>> 8, a[f] = E << 16 | E >>> 16, n[f] = E << 8 | E >>> 24, o[f] = E, E = 16843009 * b ^ 65537 * m ^ 257 * y ^ 16843008 * f, l[g] = E << 24 | E >>> 8, u[g] = E << 16 | E >>> 16, d[g] = E << 8 | E >>> 24, c[g] = E, f ? (f = y ^ h[h[h[b ^ y]]], p ^= h[h[p]]) : f = p = 1 - } - }, t.prototype.expandKey = function(t) { - for (var e = this.uint8ArrayToUint32Array_(t), r = !0, i = 0; i < e.length && r;) r = e[i] === this.key[i], i++; - if (!r) { - this.key = e; - var a = this.keySize = e.length; - if (4 !== a && 6 !== a && 8 !== a) throw new Error("Invalid aes key size=" + a); - var n = this.ksRows = 4 * (a + 6 + 1), - o = void 0, - s = void 0, - l = this.keySchedule = new Uint32Array(n), - u = this.invKeySchedule = new Uint32Array(n), - d = this.sBox, - c = this.rcon, - h = this.invSubMix, - f = h[0], - p = h[1], - v = h[2], - g = h[3], - y = void 0, - m = void 0; - for (o = 0; o < n; o++) o < a ? y = l[o] = e[o] : (m = y, o % a == 0 ? (m = m << 8 | m >>> 24, m = d[m >>> 24] << 24 | d[m >>> 16 & 255] << 16 | d[m >>> 8 & 255] << 8 | d[255 & m], m ^= c[o / a | 0] << 24) : a > 6 && o % a == 4 && (m = d[m >>> 24] << 24 | d[m >>> 16 & 255] << 16 | d[m >>> 8 & 255] << 8 | d[255 & m]), l[o] = y = (l[o - a] ^ m) >>> 0); - for (s = 0; s < n; s++) o = n - s, m = 3 & s ? l[o] : l[o - 4], u[s] = s < 4 || o <= 4 ? m : f[d[m >>> 24]] ^ p[d[m >>> 16 & 255]] ^ v[d[m >>> 8 & 255]] ^ g[d[255 & m]], u[s] = u[s] >>> 0 - } - }, t.prototype.networkToHostOrderSwap = function(t) { - return t << 24 | (65280 & t) << 8 | (16711680 & t) >> 8 | t >>> 24 - }, t.prototype.decrypt = function(t, e, r, i) { - for (var n = this.keySize + 6, o = this.invKeySchedule, s = this.invSBox, l = this.invSubMix, u = l[0], d = l[1], c = l[2], h = l[3], f = this.uint8ArrayToUint32Array_(r), p = f[0], v = f[1], g = f[2], y = f[3], m = new Int32Array(t), b = new Int32Array(m.length), E = void 0, T = void 0, S = void 0, R = void 0, A = void 0, _ = void 0, w = void 0, L = void 0, D = void 0, I = void 0, k = void 0, O = void 0, C = void 0, P = void 0, x = this.networkToHostOrderSwap; e < m.length;) { - for (D = x(m[e]), I = x(m[e + 1]), k = x(m[e + 2]), O = x(m[e + 3]), A = D ^ o[0], _ = O ^ o[1], w = k ^ o[2], L = I ^ o[3], C = 4, P = 1; P < n; P++) E = u[A >>> 24] ^ d[_ >> 16 & 255] ^ c[w >> 8 & 255] ^ h[255 & L] ^ o[C], T = u[_ >>> 24] ^ d[w >> 16 & 255] ^ c[L >> 8 & 255] ^ h[255 & A] ^ o[C + 1], S = u[w >>> 24] ^ d[L >> 16 & 255] ^ c[A >> 8 & 255] ^ h[255 & _] ^ o[C + 2], R = u[L >>> 24] ^ d[A >> 16 & 255] ^ c[_ >> 8 & 255] ^ h[255 & w] ^ o[C + 3], A = E, _ = T, w = S, L = R, C += 4; - E = s[A >>> 24] << 24 ^ s[_ >> 16 & 255] << 16 ^ s[w >> 8 & 255] << 8 ^ s[255 & L] ^ o[C], T = s[_ >>> 24] << 24 ^ s[w >> 16 & 255] << 16 ^ s[L >> 8 & 255] << 8 ^ s[255 & A] ^ o[C + 1], S = s[w >>> 24] << 24 ^ s[L >> 16 & 255] << 16 ^ s[A >> 8 & 255] << 8 ^ s[255 & _] ^ o[C + 2], R = s[L >>> 24] << 24 ^ s[A >> 16 & 255] << 16 ^ s[_ >> 8 & 255] << 8 ^ s[255 & w] ^ o[C + 3], C += 3, b[e] = x(E ^ p), b[e + 1] = x(R ^ v), b[e + 2] = x(S ^ g), b[e + 3] = x(T ^ y), p = D, v = I, g = k, y = O, e += 4 - } - return i ? a(b.buffer) : b.buffer - }, t.prototype.destroy = function() { - this.key = void 0, this.keySize = void 0, this.ksRows = void 0, this.sBox = void 0, this.invSBox = void 0, this.subMix = void 0, this.invSubMix = void 0, this.keySchedule = void 0, this.invKeySchedule = void 0, this.rcon = void 0 - }, t - }(); - e.a = n - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(22), - n = r(0), - o = r(7), - s = function() { - function t(e, r, a) { - i(this, t), this.observer = e, this.config = a, this.remuxer = r - } - return t.prototype.resetInitSegment = function(t, e, r, i) { - this._audioTrack = { - container: "audio/adts", - type: "audio", - id: 0, - sequenceNumber: 0, - isAAC: !0, - samples: [], - len: 0, - manifestCodec: e, - duration: i, - inputTimeScale: 9e4 - } - }, t.prototype.resetTimeStamp = function() {}, t.probe = function(t) { - if (!t) return !1; - for (var e = o.a.getID3Data(t, 0) || [], r = e.length, i = t.length; r < i; r++) - if (a.e(t, r)) return n.b.log("ADTS sync word found !"), !0; - return !1 - }, t.prototype.append = function(t, e, r, i) { - for (var s = this._audioTrack, l = o.a.getID3Data(t, 0) || [], u = o.a.getTimeStamp(l), d = u ? 90 * u : 9e4 * e, c = 0, h = d, f = t.length, p = l.length, v = [{ - pts: h, - dts: h, - data: l - }]; p < f - 1;) - if (a.d(t, p) && p + 5 < f) { - a.c(s, this.observer, t, p, s.manifestCodec); - var g = a.a(s, t, p, d, c); - if (!g) { - n.b.log("Unable to parse AAC frame"); - break - } - p += g.length, h = g.sample.pts, c++ - } else o.a.isHeader(t, p) ? (l = o.a.getID3Data(t, p), v.push({ - pts: h, - dts: h, - data: l - }), p += l.length) : p++; - this.remuxer.remux(s, { - samples: [] - }, { - samples: v, - inputTimeScale: 9e4 - }, { - samples: [] - }, e, r, i) - }, t.prototype.destroy = function() {}, t - }(); - e.a = s - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(22), - n = r(23), - o = r(1), - s = r(40), - l = r(41), - u = r(0), - d = r(2), - c = { - video: 1, - audio: 2, - id3: 3, - text: 4 - }, - h = function() { - function t(e, r, a, n) { - i(this, t), this.observer = e, this.config = a, this.typeSupported = n, this.remuxer = r, this.sampleAes = null - } - return t.prototype.setDecryptData = function(t) { - null != t && null != t.key && "SAMPLE-AES" === t.method ? this.sampleAes = new l.a(this.observer, this.config, t, this.discardEPB) : this.sampleAes = null - }, t.probe = function(e) { - var r = t._syncOffset(e); - return !(r < 0) && (r && u.b.warn("MPEG2-TS detected but first sync word found @ offset " + r + ", junk ahead ?"), !0) - }, t._syncOffset = function(t) { - for (var e = Math.min(1e3, t.length - 564), r = 0; r < e;) { - if (71 === t[r] && 71 === t[r + 188] && 71 === t[r + 376]) return r; - r++ - } - return -1 - }, t.createTrack = function(t, e) { - return { - container: "video" === t || "audio" === t ? "video/mp2t" : void 0, - type: t, - id: c[t], - pid: -1, - inputTimeScale: 9e4, - sequenceNumber: 0, - samples: [], - len: 0, - dropped: "video" === t ? 0 : void 0, - isAAC: "audio" === t || void 0, - duration: "audio" === t ? e : void 0 - } - }, t.prototype.resetInitSegment = function(e, r, i, a) { - this.pmtParsed = !1, this._pmtId = -1, this._avcTrack = t.createTrack("video", a), this._audioTrack = t.createTrack("audio", a), this._id3Track = t.createTrack("id3", a), this._txtTrack = t.createTrack("text", a), this.aacOverFlow = null, this.aacLastPTS = null, this.avcSample = null, this.audioCodec = r, this.videoCodec = i, this._duration = a - }, t.prototype.resetTimeStamp = function() {}, t.prototype.append = function(e, r, i, a) { - var n = void 0, - s = e.length, - l = void 0, - c = void 0, - h = void 0, - f = void 0, - p = !1; - this.contiguous = i; - var v = this.pmtParsed, - g = this._avcTrack, - y = this._audioTrack, - m = this._id3Track, - b = g.pid, - E = y.pid, - T = m.pid, - S = this._pmtId, - R = g.pesData, - A = y.pesData, - _ = m.pesData, - w = this._parsePAT, - L = this._parsePMT, - D = this._parsePES, - I = this._parseAVCPES.bind(this), - k = this._parseAACPES.bind(this), - O = this._parseMPEGPES.bind(this), - C = this._parseID3PES.bind(this), - P = t._syncOffset(e); - for (s -= (s + P) % 188, n = P; n < s; n += 188) - if (71 === e[n]) { - if (l = !!(64 & e[n + 1]), c = ((31 & e[n + 1]) << 8) + e[n + 2], (48 & e[n + 3]) >> 4 > 1) { - if ((h = n + 5 + e[n + 4]) === n + 188) continue - } else h = n + 4; - switch (c) { - case b: - l && (R && (f = D(R)) && void 0 !== f.pts && I(f, !1), R = { - data: [], - size: 0 - }), R && (R.data.push(e.subarray(h, n + 188)), R.size += n + 188 - h); - break; - case E: - l && (A && (f = D(A)) && void 0 !== f.pts && (y.isAAC ? k(f) : O(f)), A = { - data: [], - size: 0 - }), A && (A.data.push(e.subarray(h, n + 188)), A.size += n + 188 - h); - break; - case T: - l && (_ && (f = D(_)) && void 0 !== f.pts && C(f), _ = { - data: [], - size: 0 - }), _ && (_.data.push(e.subarray(h, n + 188)), _.size += n + 188 - h); - break; - case 0: - l && (h += e[h] + 1), S = this._pmtId = w(e, h); - break; - case S: - l && (h += e[h] + 1); - var x = L(e, h, !0 === this.typeSupported.mpeg || !0 === this.typeSupported.mp3, null != this.sampleAes); - b = x.avc, b > 0 && (g.pid = b), E = x.audio, E > 0 && (y.pid = E, y.isAAC = x.isAAC), T = x.id3, T > 0 && (m.pid = T), p && !v && (u.b.log("reparse from beginning"), p = !1, n = P - 188), v = this.pmtParsed = !0; - break; - case 17: - case 8191: - break; - default: - p = !0 - } - } else this.observer.trigger(o.a.ERROR, { - type: d.b.MEDIA_ERROR, - details: d.a.FRAG_PARSING_ERROR, - fatal: !1, - reason: "TS packet did not start with 0x47" - }); - R && (f = D(R)) && void 0 !== f.pts ? (I(f, !0), g.pesData = null) : g.pesData = R, A && (f = D(A)) && void 0 !== f.pts ? (y.isAAC ? k(f) : O(f), y.pesData = null) : (A && A.size && u.b.log("last AAC PES packet truncated,might overlap between fragments"), y.pesData = A), _ && (f = D(_)) && void 0 !== f.pts ? (C(f), m.pesData = null) : m.pesData = _, null == this.sampleAes ? this.remuxer.remux(y, g, m, this._txtTrack, r, i, a) : this.decryptAndRemux(y, g, m, this._txtTrack, r, i, a) - }, t.prototype.decryptAndRemux = function(t, e, r, i, a, n, o) { - if (t.samples && t.isAAC) { - var s = this; - this.sampleAes.decryptAacSamples(t.samples, 0, function() { - s.decryptAndRemuxAvc(t, e, r, i, a, n, o) - }) - } else this.decryptAndRemuxAvc(t, e, r, i, a, n, o) - }, t.prototype.decryptAndRemuxAvc = function(t, e, r, i, a, n, o) { - if (e.samples) { - var s = this; - this.sampleAes.decryptAvcSamples(e.samples, 0, 0, function() { - s.remuxer.remux(t, e, r, i, a, n, o) - }) - } else this.remuxer.remux(t, e, r, i, a, n, o) - }, t.prototype.destroy = function() { - this._initPTS = this._initDTS = void 0, this._duration = 0 - }, t.prototype._parsePAT = function(t, e) { - return (31 & t[e + 10]) << 8 | t[e + 11] - }, t.prototype._parsePMT = function(t, e, r, i) { - var a = void 0, - n = void 0, - o = void 0, - s = void 0, - l = { - audio: -1, - avc: -1, - id3: -1, - isAAC: !0 - }; - for (a = (15 & t[e + 1]) << 8 | t[e + 2], n = e + 3 + a - 4, o = (15 & t[e + 10]) << 8 | t[e + 11], e += 12 + o; e < n;) { - switch (s = (31 & t[e + 1]) << 8 | t[e + 2], t[e]) { - case 207: - if (!i) { - u.b.log("unkown stream type:" + t[e]); - break - } - case 15: - -1 === l.audio && (l.audio = s); - break; - case 21: - -1 === l.id3 && (l.id3 = s); - break; - case 219: - if (!i) { - u.b.log("unkown stream type:" + t[e]); - break - } - case 27: - -1 === l.avc && (l.avc = s); - break; - case 3: - case 4: - r ? -1 === l.audio && (l.audio = s, l.isAAC = !1) : u.b.log("MPEG audio found, not supported in this browser for now"); - break; - case 36: - u.b.warn("HEVC stream type found, not supported for now"); - break; - default: - u.b.log("unkown stream type:" + t[e]) - } - e += 5 + ((15 & t[e + 3]) << 8 | t[e + 4]) - } - return l - }, t.prototype._parsePES = function(t) { - var e = 0, - r = void 0, - i = void 0, - a = void 0, - n = void 0, - o = void 0, - s = void 0, - l = void 0, - d = void 0, - c = t.data; - if (!t || 0 === t.size) return null; - for (; c[0].length < 19 && c.length > 1;) { - var h = new Uint8Array(c[0].length + c[1].length); - h.set(c[0]), h.set(c[1], c[0].length), c[0] = h, c.splice(1, 1) - } - if (r = c[0], 1 === (r[0] << 16) + (r[1] << 8) + r[2]) { - if ((a = (r[4] << 8) + r[5]) && a > t.size - 6) return null; - i = r[7], 192 & i && (s = 536870912 * (14 & r[9]) + 4194304 * (255 & r[10]) + 16384 * (254 & r[11]) + 128 * (255 & r[12]) + (254 & r[13]) / 2, s > 4294967295 && (s -= 8589934592), 64 & i ? (l = 536870912 * (14 & r[14]) + 4194304 * (255 & r[15]) + 16384 * (254 & r[16]) + 128 * (255 & r[17]) + (254 & r[18]) / 2, l > 4294967295 && (l -= 8589934592), s - l > 54e5 && (u.b.warn(Math.round((s - l) / 9e4) + "s delta between PTS and DTS, align them"), s = l)) : l = s), n = r[8], d = n + 9, t.size -= d, o = new Uint8Array(t.size); - for (var f = 0, p = c.length; f < p; f++) { - r = c[f]; - var v = r.byteLength; - if (d) { - if (d > v) { - d -= v; - continue - } - r = r.subarray(d), v -= d, d = 0 - } - o.set(r, e), e += v - } - return a && (a -= n + 3), { - data: o, - pts: s, - dts: l, - len: a - } - } - return null - }, t.prototype.pushAccesUnit = function(t, e) { - if (t.units.length && t.frame) { - var r = e.samples, - i = r.length; - !this.config.forceKeyFrameOnDiscontinuity || !0 === t.key || e.sps && (i || this.contiguous) ? (t.id = i, r.push(t)) : e.dropped++ - } - t.debug.length && u.b.log(t.pts + "/" + t.dts + ":" + t.debug) - }, t.prototype._parseAVCPES = function(t, e) { - var r = this, - i = this._avcTrack, - a = this._parseAVCNALu(t.data), - n = void 0, - o = this.avcSample, - l = void 0, - u = !1, - d = void 0, - c = this.pushAccesUnit.bind(this), - h = function(t, e, r, i) { - return { - key: t, - pts: e, - dts: r, - units: [], - debug: i - } - }; - t.data = null, o && a.length && !i.audFound && (c(o, i), o = this.avcSample = h(!1, t.pts, t.dts, "")), a.forEach(function(e) { - switch (e.type) { - case 1: - l = !0, o || (o = r.avcSample = h(!0, t.pts, t.dts, "")), o.frame = !0; - var a = e.data; - if (u && a.length > 4) { - var f = new s.a(a).readSliceType(); - 2 !== f && 4 !== f && 7 !== f && 9 !== f || (o.key = !0) - } - break; - case 5: - l = !0, o || (o = r.avcSample = h(!0, t.pts, t.dts, "")), o.key = !0, o.frame = !0; - break; - case 6: - l = !0, n = new s.a(r.discardEPB(e.data)), n.readUByte(); - for (var p = 0, v = 0, g = !1, y = 0; !g && n.bytesAvailable > 1;) { - p = 0; - do { - y = n.readUByte(), p += y - } while (255 === y); - v = 0; - do { - y = n.readUByte(), v += y - } while (255 === y); - if (4 === p && 0 !== n.bytesAvailable) { - g = !0; - if (181 === n.readUByte()) { - if (49 === n.readUShort()) { - if (1195456820 === n.readUInt()) { - if (3 === n.readUByte()) { - var m = n.readUByte(), - b = n.readUByte(), - E = 31 & m, - T = [m, b]; - for (d = 0; d < E; d++) T.push(n.readUByte()), T.push(n.readUByte()), T.push(n.readUByte()); - r._insertSampleInOrder(r._txtTrack.samples, { - type: 3, - pts: t.pts, - bytes: T - }) - } - } - } - } - } else if (v < n.bytesAvailable) - for (d = 0; d < v; d++) n.readUByte() - } - break; - case 7: - if (l = !0, u = !0, !i.sps) { - n = new s.a(e.data); - var S = n.readSPS(); - i.width = S.width, i.height = S.height, i.pixelRatio = S.pixelRatio, i.sps = [e.data], i.duration = r._duration; - var R = e.data.subarray(1, 4), - A = "avc1."; - for (d = 0; d < 3; d++) { - var _ = R[d].toString(16); - _.length < 2 && (_ = "0" + _), A += _ - } - i.codec = A - } - break; - case 8: - l = !0, i.pps || (i.pps = [e.data]); - break; - case 9: - l = !1, i.audFound = !0, o && c(o, i), o = r.avcSample = h(!1, t.pts, t.dts, ""); - break; - case 12: - l = !1; - break; - default: - l = !1, o && (o.debug += "unknown NAL " + e.type + " ") - } - if (o && l) { - o.units.push(e) - } - }), e && o && (c(o, i), this.avcSample = null) - }, t.prototype._insertSampleInOrder = function(t, e) { - var r = t.length; - if (r > 0) { - if (e.pts >= t[r - 1].pts) t.push(e); - else - for (var i = r - 1; i >= 0; i--) - if (e.pts < t[i].pts) { - t.splice(i, 0, e); - break - } - } else t.push(e) - }, t.prototype._getLastNalUnit = function() { - var t = this.avcSample, - e = void 0; - if (!t || 0 === t.units.length) { - var r = this._avcTrack, - i = r.samples; - t = i[i.length - 1] - } - if (t) { - var a = t.units; - e = a[a.length - 1] - } - return e - }, t.prototype._parseAVCNALu = function(t) { - var e = 0, - r = t.byteLength, - i = void 0, - a = void 0, - n = this._avcTrack, - o = n.naluState || 0, - s = o, - l = [], - u = void 0, - d = void 0, - c = -1, - h = void 0; - for (-1 === o && (c = 0, h = 31 & t[0], o = 0, e = 1); e < r;) - if (i = t[e++], o) - if (1 !== o) - if (i) - if (1 === i) { - if (c >= 0) u = { - data: t.subarray(c, e - o - 1), - type: h - }, l.push(u); - else { - var f = this._getLastNalUnit(); - if (f && (s && e <= 4 - s && f.state && (f.data = f.data.subarray(0, f.data.byteLength - s)), (a = e - o - 1) > 0)) { - var p = new Uint8Array(f.data.byteLength + a); - p.set(f.data, 0), p.set(t.subarray(0, a), f.data.byteLength), f.data = p - } - } - e < r ? (d = 31 & t[e], c = e, h = d, o = 0) : o = -1 - } else o = 0; - else o = 3; - else o = i ? 0 : 2; - else o = i ? 0 : 1; - if (c >= 0 && o >= 0 && (u = { - data: t.subarray(c, r), - type: h, - state: o - }, l.push(u)), 0 === l.length) { - var v = this._getLastNalUnit(); - if (v) { - var g = new Uint8Array(v.data.byteLength + t.byteLength); - g.set(v.data, 0), g.set(t, v.data.byteLength), v.data = g - } - } - return n.naluState = o, l - }, t.prototype.discardEPB = function(t) { - for (var e = t.byteLength, r = [], i = 1, a = void 0, n = void 0; i < e - 2;) 0 === t[i] && 0 === t[i + 1] && 3 === t[i + 2] ? (r.push(i + 2), i += 2) : i++; - if (0 === r.length) return t; - a = e - r.length, n = new Uint8Array(a); - var o = 0; - for (i = 0; i < a; o++, i++) o === r[0] && (o++, r.shift()), n[i] = t[o]; - return n - }, t.prototype._parseAACPES = function(t) { - var e = this._audioTrack, - r = t.data, - i = t.pts, - n = this.aacOverFlow, - s = this.aacLastPTS, - l = void 0, - c = void 0, - h = void 0, - f = void 0, - p = void 0; - if (n) { - var v = new Uint8Array(n.byteLength + r.byteLength); - v.set(n, 0), v.set(r, n.byteLength), r = v - } - for (h = 0, p = r.length; h < p - 1 && !a.d(r, h); h++); - if (h) { - var g = void 0, - y = void 0; - if (h < p - 1 ? (g = "AAC PES did not start with ADTS header,offset:" + h, y = !1) : (g = "no ADTS header found in AAC PES", y = !0), u.b.warn("parsing error:" + g), this.observer.trigger(o.a.ERROR, { - type: d.b.MEDIA_ERROR, - details: d.a.FRAG_PARSING_ERROR, - fatal: y, - reason: g - }), y) return - } - if (a.c(e, this.observer, r, h, this.audioCodec), c = 0, l = a.b(e.samplerate), n && s) { - var m = s + l; - Math.abs(m - i) > 1 && (u.b.log("AAC: align PTS for overlapping frames by " + Math.round((m - i) / 90)), i = m) - } - for (; h < p;) - if (a.d(r, h) && h + 5 < p) { - var b = a.a(e, r, h, i, c); - if (!b) break; - h += b.length, f = b.sample.pts, c++ - } else h++; - n = h < p ? r.subarray(h, p) : null, this.aacOverFlow = n, this.aacLastPTS = f - }, t.prototype._parseMPEGPES = function(t) { - for (var e = t.data, r = e.length, i = 0, a = 0, o = t.pts; a < r;) - if (n.a.isHeader(e, a)) { - var s = n.a.appendFrame(this._audioTrack, e, a, o, i); - if (!s) break; - a += s.length, i++ - } else a++ - }, t.prototype._parseID3PES = function(t) { - this._id3Track.samples.push(t) - }, t - }(); - e.a = h - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(0), - n = function() { - function t(e) { - i(this, t), this.data = e, this.bytesAvailable = e.byteLength, this.word = 0, this.bitsAvailable = 0 - } - return t.prototype.loadWord = function() { - var t = this.data, - e = this.bytesAvailable, - r = t.byteLength - e, - i = new Uint8Array(4), - a = Math.min(4, e); - if (0 === a) throw new Error("no bytes available"); - i.set(t.subarray(r, r + a)), this.word = new DataView(i.buffer).getUint32(0), this.bitsAvailable = 8 * a, this.bytesAvailable -= a - }, t.prototype.skipBits = function(t) { - var e = void 0; - this.bitsAvailable > t ? (this.word <<= t, this.bitsAvailable -= t) : (t -= this.bitsAvailable, e = t >> 3, t -= e >> 3, this.bytesAvailable -= e, this.loadWord(), this.word <<= t, this.bitsAvailable -= t) - }, t.prototype.readBits = function(t) { - var e = Math.min(this.bitsAvailable, t), - r = this.word >>> 32 - e; - return t > 32 && a.b.error("Cannot read more than 32 bits at a time"), this.bitsAvailable -= e, this.bitsAvailable > 0 ? this.word <<= e : this.bytesAvailable > 0 && this.loadWord(), e = t - e, e > 0 && this.bitsAvailable ? r << e | this.readBits(e) : r - }, t.prototype.skipLZ = function() { - var t = void 0; - for (t = 0; t < this.bitsAvailable; ++t) - if (0 != (this.word & 2147483648 >>> t)) return this.word <<= t, this.bitsAvailable -= t, t; - return this.loadWord(), t + this.skipLZ() - }, t.prototype.skipUEG = function() { - this.skipBits(1 + this.skipLZ()) - }, t.prototype.skipEG = function() { - this.skipBits(1 + this.skipLZ()) - }, t.prototype.readUEG = function() { - var t = this.skipLZ(); - return this.readBits(t + 1) - 1 - }, t.prototype.readEG = function() { - var t = this.readUEG(); - return 1 & t ? 1 + t >>> 1 : -1 * (t >>> 1) - }, t.prototype.readBoolean = function() { - return 1 === this.readBits(1) - }, t.prototype.readUByte = function() { - return this.readBits(8) - }, t.prototype.readUShort = function() { - return this.readBits(16) - }, t.prototype.readUInt = function() { - return this.readBits(32) - }, t.prototype.skipScalingList = function(t) { - var e = 8, - r = 8, - i = void 0, - a = void 0; - for (i = 0; i < t; i++) 0 !== r && (a = this.readEG(), r = (e + a + 256) % 256), e = 0 === r ? e : r - }, t.prototype.readSPS = function() { - var t = 0, - e = 0, - r = 0, - i = 0, - a = void 0, - n = void 0, - o = void 0, - s = void 0, - l = void 0, - u = void 0, - d = void 0, - c = this.readUByte.bind(this), - h = this.readBits.bind(this), - f = this.readUEG.bind(this), - p = this.readBoolean.bind(this), - v = this.skipBits.bind(this), - g = this.skipEG.bind(this), - y = this.skipUEG.bind(this), - m = this.skipScalingList.bind(this); - if (c(), a = c(), h(5), v(3), c(), y(), 100 === a || 110 === a || 122 === a || 244 === a || 44 === a || 83 === a || 86 === a || 118 === a || 128 === a) { - var b = f(); - if (3 === b && v(1), y(), y(), v(1), p()) - for (u = 3 !== b ? 8 : 12, d = 0; d < u; d++) p() && m(d < 6 ? 16 : 64) - } - y(); - var E = f(); - if (0 === E) f(); - else if (1 === E) - for (v(1), g(), g(), n = f(), d = 0; d < n; d++) g(); - y(), v(1), o = f(), s = f(), l = h(1), 0 === l && v(1), v(1), p() && (t = f(), e = f(), r = f(), i = f()); - var T = [1, 1]; - if (p() && p()) { - switch (c()) { - case 1: - T = [1, 1]; - break; - case 2: - T = [12, 11]; - break; - case 3: - T = [10, 11]; - break; - case 4: - T = [16, 11]; - break; - case 5: - T = [40, 33]; - break; - case 6: - T = [24, 11]; - break; - case 7: - T = [20, 11]; - break; - case 8: - T = [32, 11]; - break; - case 9: - T = [80, 33]; - break; - case 10: - T = [18, 11]; - break; - case 11: - T = [15, 11]; - break; - case 12: - T = [64, 33]; - break; - case 13: - T = [160, 99]; - break; - case 14: - T = [4, 3]; - break; - case 15: - T = [3, 2]; - break; - case 16: - T = [2, 1]; - break; - case 255: - T = [c() << 8 | c(), c() << 8 | c()] - } - } - return { - width: Math.ceil(16 * (o + 1) - 2 * t - 2 * e), - height: (2 - l) * (s + 1) * 16 - (l ? 2 : 4) * (r + i), - pixelRatio: T - } - }, t.prototype.readSliceType = function() { - return this.readUByte(), this.readUEG(), this.readUEG() - }, t - }(); - e.a = n - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(13), - n = function() { - function t(e, r, n, o) { - i(this, t), this.decryptdata = n, this.discardEPB = o, this.decrypter = new a.a(e, r, { - removePKCS7Padding: !1 - }) - } - return t.prototype.decryptBuffer = function(t, e) { - this.decrypter.decrypt(t, this.decryptdata.key.buffer, this.decryptdata.iv.buffer, e) - }, t.prototype.decryptAacSample = function(t, e, r, i) { - var a = t[e].unit, - n = a.subarray(16, a.length - a.length % 16), - o = n.buffer.slice(n.byteOffset, n.byteOffset + n.length), - s = this; - this.decryptBuffer(o, function(n) { - n = new Uint8Array(n), a.set(n, 16), i || s.decryptAacSamples(t, e + 1, r) - }) - }, t.prototype.decryptAacSamples = function(t, e, r) { - for (;; e++) { - if (e >= t.length) return void r(); - if (!(t[e].unit.length < 32)) { - var i = this.decrypter.isSync(); - if (this.decryptAacSample(t, e, r, i), !i) return - } - } - }, t.prototype.getAvcEncryptedData = function(t) { - for (var e = 16 * Math.floor((t.length - 48) / 160) + 16, r = new Int8Array(e), i = 0, a = 32; a <= t.length - 16; a += 160, i += 16) r.set(t.subarray(a, a + 16), i); - return r - }, t.prototype.getAvcDecryptedUnit = function(t, e) { - e = new Uint8Array(e); - for (var r = 0, i = 32; i <= t.length - 16; i += 160, r += 16) t.set(e.subarray(r, r + 16), i); - return t - }, t.prototype.decryptAvcSample = function(t, e, r, i, a, n) { - var o = this.discardEPB(a.data), - s = this.getAvcEncryptedData(o), - l = this; - this.decryptBuffer(s.buffer, function(s) { - a.data = l.getAvcDecryptedUnit(o, s), n || l.decryptAvcSamples(t, e, r + 1, i) - }) - }, t.prototype.decryptAvcSamples = function(t, e, r, i) { - for (;; e++, r = 0) { - if (e >= t.length) return void i(); - for (var a = t[e].units; !(r >= a.length); r++) { - var n = a[r]; - if (!(n.length <= 48 || 1 !== n.type && 5 !== n.type)) { - var o = this.decrypter.isSync(); - if (this.decryptAvcSample(t, e, r, i, n, o), !o) return - } - } - } - }, t - }(); - e.a = n - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(7), - n = r(0), - o = r(23), - s = function() { - function t(e, r, a) { - i(this, t), this.observer = e, this.config = a, this.remuxer = r - } - return t.prototype.resetInitSegment = function(t, e, r, i) { - this._audioTrack = { - container: "audio/mpeg", - type: "audio", - id: -1, - sequenceNumber: 0, - isAAC: !1, - samples: [], - len: 0, - manifestCodec: e, - duration: i, - inputTimeScale: 9e4 - } - }, t.prototype.resetTimeStamp = function() {}, t.probe = function(t) { - var e = void 0, - r = void 0, - i = a.a.getID3Data(t, 0); - if (i && void 0 !== a.a.getTimeStamp(i)) - for (e = i.length, r = Math.min(t.length - 1, e + 100); e < r; e++) - if (o.a.probe(t, e)) return n.b.log("MPEG Audio sync word found !"), !0; - return !1 - }, t.prototype.append = function(t, e, r, i) { - for (var n = a.a.getID3Data(t, 0), s = a.a.getTimeStamp(n), l = s ? 90 * s : 9e4 * e, u = n.length, d = t.length, c = 0, h = 0, f = this._audioTrack, p = [{ - pts: l, - dts: l, - data: n - }]; u < d;) - if (o.a.isHeader(t, u)) { - var v = o.a.appendFrame(f, t, u, l, c); - if (!v) break; - u += v.length, h = v.sample.pts, c++ - } else a.a.isHeader(t, u) ? (n = a.a.getID3Data(t, u), p.push({ - pts: h, - dts: h, - data: n - }), u += n.length) : u++; - this.remuxer.remux(f, { - samples: [] - }, { - samples: p, - inputTimeScale: 9e4 - }, { - samples: [] - }, e, r, i) - }, t.prototype.destroy = function() {}, t - }(); - e.a = s - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(44), - n = r(45), - o = r(1), - s = r(2), - l = r(0), - u = function() { - function t(e, r, a, n) { - i(this, t), this.observer = e, this.config = r, this.typeSupported = a; - var o = navigator.userAgent; - this.isSafari = n && n.indexOf("Apple") > -1 && o && !o.match("CriOS"), this.ISGenerated = !1 - } - return t.prototype.destroy = function() {}, t.prototype.resetTimeStamp = function(t) { - this._initPTS = this._initDTS = t - }, t.prototype.resetInitSegment = function() { - this.ISGenerated = !1 - }, t.prototype.remux = function(t, e, r, i, a, n, s) { - if (this.ISGenerated || this.generateIS(t, e, a), this.ISGenerated) { - var u = t.samples.length, - d = e.samples.length, - c = a, - h = a; - if (u && d) { - var f = (t.samples[0].dts - e.samples[0].dts) / e.inputTimeScale; - c += Math.max(0, f), h += Math.max(0, -f) - } - if (u) { - t.timescale || (l.b.warn("regenerate InitSegment as audio detected"), this.generateIS(t, e, a)); - var p = this.remuxAudio(t, c, n, s); - if (d) { - var v = void 0; - p && (v = p.endPTS - p.startPTS), e.timescale || (l.b.warn("regenerate InitSegment as video detected"), this.generateIS(t, e, a)), this.remuxVideo(e, h, n, v, s) - } - } else if (d) { - var g = this.remuxVideo(e, h, n, 0, s); - g && t.codec && this.remuxEmptyAudio(t, c, n, g) - } - } - r.samples.length && this.remuxID3(r, a), i.samples.length && this.remuxText(i, a), this.observer.trigger(o.a.FRAG_PARSED) - }, t.prototype.generateIS = function(t, e, r) { - var i = this.observer, - a = t.samples, - u = e.samples, - d = this.typeSupported, - c = "audio/mp4", - h = {}, - f = { - tracks: h - }, - p = void 0 === this._initPTS, - v = void 0, - g = void 0; - if (p && (v = g = 1 / 0), t.config && a.length && (t.timescale = t.samplerate, l.b.log("audio sampling rate : " + t.samplerate), t.isAAC || (d.mpeg ? (c = "audio/mpeg", t.codec = "") : d.mp3 && (t.codec = "mp3")), h.audio = { - container: c, - codec: t.codec, - initSegment: !t.isAAC && d.mpeg ? new Uint8Array : n.a.initSegment([t]), - metadata: { - channelCount: t.channelCount - } - }, p && (v = g = a[0].pts - t.inputTimeScale * r)), e.sps && e.pps && u.length) { - var y = e.inputTimeScale; - e.timescale = y, h.video = { - container: "video/mp4", - codec: e.codec, - initSegment: n.a.initSegment([e]), - metadata: { - width: e.width, - height: e.height - } - }, p && (v = Math.min(v, u[0].pts - y * r), g = Math.min(g, u[0].dts - y * r), this.observer.trigger(o.a.INIT_PTS_FOUND, { - initPTS: v - })) - } - Object.keys(h).length ? (i.trigger(o.a.FRAG_PARSING_INIT_SEGMENT, f), this.ISGenerated = !0, p && (this._initPTS = v, this._initDTS = g)) : i.trigger(o.a.ERROR, { - type: s.b.MEDIA_ERROR, - details: s.a.FRAG_PARSING_ERROR, - fatal: !1, - reason: "no audio/video samples found" - }) - }, t.prototype.remuxVideo = function(t, e, r, i, a) { - var u = 8, - d = t.timescale, - c = void 0, - h = void 0, - f = void 0, - p = void 0, - v = void 0, - g = void 0, - y = void 0, - m = t.samples, - b = [], - E = m.length, - T = this._PTSNormalize, - S = this._initDTS, - R = this.nextAvcDts, - A = this.isSafari; - if (0 !== E) { - A && (r |= m.length && R && (a && Math.abs(e - R / d) < .1 || Math.abs(m[0].pts - R - S) < d / 5)), r || (R = e * d), m.forEach(function(t) { - t.pts = T(t.pts - S, R), t.dts = T(t.dts - S, R) - }), m.sort(function(t, e) { - var r = t.dts - e.dts, - i = t.pts - e.pts; - return r || i || t.id - e.id - }); - var _ = m.reduce(function(t, e) { - return Math.max(Math.min(t, e.pts - e.dts), -18e3) - }, 0); - if (_ < 0) { - l.b.warn("PTS < DTS detected in video samples, shifting DTS by " + Math.round(_ / 90) + " ms to overcome this issue"); - for (var w = 0; w < m.length; w++) m[w].dts += _ - } - var L = m[0]; - v = Math.max(L.dts, 0), p = Math.max(L.pts, 0); - var D = Math.round((v - R) / 90); - r && D && (D > 1 ? l.b.log("AVC:" + D + " ms hole between fragments detected,filling it") : D < -1 && l.b.log("AVC:" + -D + " ms overlapping between fragments detected"), v = R, m[0].dts = v, p = Math.max(p - D, R), m[0].pts = p, l.b.log("Video/PTS/DTS adjusted: " + Math.round(p / 90) + "/" + Math.round(v / 90) + ",delta:" + D + " ms")), v, L = m[m.length - 1], y = Math.max(L.dts, 0), g = Math.max(L.pts, 0, y), A && (c = Math.round((y - v) / (m.length - 1))); - for (var I = 0, k = 0, O = 0; O < E; O++) { - for (var C = m[O], P = C.units, x = P.length, F = 0, N = 0; N < x; N++) F += P[N].data.length; - k += F, I += x, C.length = F, C.dts = A ? v + O * c : Math.max(C.dts, v), C.pts = Math.max(C.pts, C.dts) - } - var M = k + 4 * I + 8; - try { - h = new Uint8Array(M) - } catch (t) { - return void this.observer.trigger(o.a.ERROR, { - type: s.b.MUX_ERROR, - details: s.a.REMUX_ALLOC_ERROR, - fatal: !1, - bytes: M, - reason: "fail allocating video mdat " + M - }) - } - var U = new DataView(h.buffer); - U.setUint32(0, M), h.set(n.a.types.mdat, 4); - for (var B = 0; B < E; B++) { - for (var G = m[B], K = G.units, j = 0, H = void 0, V = 0, Y = K.length; V < Y; V++) { - var W = K[V], - q = W.data, - X = W.data.byteLength; - U.setUint32(u, X), u += 4, h.set(q, u), u += X, j += 4 + X - } - if (A) H = Math.max(0, c * Math.round((G.pts - G.dts) / c)); - else { - if (B < E - 1) c = m[B + 1].dts - G.dts; - else { - var z = this.config, - Q = G.dts - m[B > 0 ? B - 1 : B].dts; - if (z.stretchShortVideoTrack) { - var $ = z.maxBufferHole, - J = Math.floor($ * d), - Z = (i ? p + i * d : this.nextAudioPts) - G.pts; - Z > J ? (c = Z - Q, c < 0 && (c = Q), l.b.log("It is approximately " + Z / 90 + " ms to the next segment; using duration " + c / 90 + " ms for the last video frame.")) : c = Q - } else c = Q - } - H = Math.round(G.pts - G.dts) - } - b.push({ - size: j, - duration: c, - cts: H, - flags: { - isLeading: 0, - isDependedOn: 0, - hasRedundancy: 0, - degradPrio: 0, - dependsOn: G.key ? 2 : 1, - isNonSync: G.key ? 0 : 1 - } - }) - } - this.nextAvcDts = y + c; - var tt = t.dropped; - if (t.len = 0, t.nbNalu = 0, t.dropped = 0, b.length && navigator.userAgent.toLowerCase().indexOf("chrome") > -1) { - var et = b[0].flags; - et.dependsOn = 2, et.isNonSync = 0 - } - t.samples = b, f = n.a.moof(t.sequenceNumber++, v, t), t.samples = []; - var rt = { - data1: f, - data2: h, - startPTS: p / d, - endPTS: (g + c) / d, - startDTS: v / d, - endDTS: this.nextAvcDts / d, - type: "video", - hasAudio: !1, - hasVideo: !0, - nb: b.length, - dropped: tt - }; - return this.observer.trigger(o.a.FRAG_PARSING_DATA, rt), rt - } - }, t.prototype.remuxAudio = function(t, e, r, i) { - var u = t.inputTimeScale, - d = t.timescale, - c = u / d, - h = t.isAAC ? 1024 : 1152, - f = h * c, - p = this._PTSNormalize, - v = this._initDTS, - g = !t.isAAC && this.typeSupported.mpeg, - y = void 0, - m = void 0, - b = void 0, - E = void 0, - T = void 0, - S = void 0, - R = void 0, - A = t.samples, - _ = [], - w = this.nextAudioPts; - if (r |= A.length && w && (i && Math.abs(e - w / u) < .1 || Math.abs(A[0].pts - w - v) < 20 * f), A.forEach(function(t) { - t.pts = t.dts = p(t.pts - v, e * u) - }), A = A.filter(function(t) { - return t.pts >= 0 - }), 0 !== A.length) { - if (r || (w = i ? e * u : A[0].pts), t.isAAC) - for (var L = this.config.maxAudioFramesDrift, D = 0, I = w; D < A.length;) { - var k, O = A[D], - C = O.pts; - k = C - I; - var P = Math.abs(1e3 * k / u); - if (k <= -L * f) l.b.warn("Dropping 1 audio frame @ " + (I / u).toFixed(3) + "s due to " + Math.round(P) + " ms overlap."), A.splice(D, 1), t.len -= O.unit.length; - else if (k >= L * f && P < 1e4 && I) { - var x = Math.round(k / f); - l.b.warn("Injecting " + x + " audio frame @ " + (I / u).toFixed(3) + "s due to " + Math.round(1e3 * k / u) + " ms gap."); - for (var F = 0; F < x; F++) { - var N = Math.max(I, 0); - b = a.a.getSilentFrame(t.manifestCodec || t.codec, t.channelCount), b || (l.b.log("Unable to get silent frame for given audio codec; duplicating last frame instead."), b = O.unit.subarray()), A.splice(D, 0, { - unit: b, - pts: N, - dts: N - }), t.len += b.length, I += f, D++ - } - O.pts = O.dts = I, I += f, D++ - } else Math.abs(k), O.pts = O.dts = I, I += f, D++ - } - for (var M = 0, U = A.length; M < U; M++) { - var B = A[M], - G = B.unit, - K = B.pts; - if (void 0 !== R) m.duration = Math.round((K - R) / c); - else { - var j = Math.round(1e3 * (K - w) / u), - H = 0; - if (r && t.isAAC && j) { - if (j > 0 && j < 1e4) H = Math.round((K - w) / f), l.b.log(j + " ms hole between AAC samples detected,filling it"), H > 0 && (b = a.a.getSilentFrame(t.manifestCodec || t.codec, t.channelCount), b || (b = G.subarray()), t.len += H * b.length); - else if (j < -12) { - l.b.log("drop overlapping AAC sample, expected/parsed/delta:" + (w / u).toFixed(3) + "s/" + (K / u).toFixed(3) + "s/" + -j + "ms"), t.len -= G.byteLength; - continue - } - K = w - } - if (S = K, !(t.len > 0)) return; - var V = g ? t.len : t.len + 8; - y = g ? 0 : 8; - try { - E = new Uint8Array(V) - } catch (t) { - return void this.observer.trigger(o.a.ERROR, { - type: s.b.MUX_ERROR, - details: s.a.REMUX_ALLOC_ERROR, - fatal: !1, - bytes: V, - reason: "fail allocating audio mdat " + V - }) - } - if (!g) { - new DataView(E.buffer).setUint32(0, V), E.set(n.a.types.mdat, 4) - } - for (var Y = 0; Y < H; Y++) b = a.a.getSilentFrame(t.manifestCodec || t.codec, t.channelCount), b || (l.b.log("Unable to get silent frame for given audio codec; duplicating this frame instead."), b = G.subarray()), E.set(b, y), y += b.byteLength, m = { - size: b.byteLength, - cts: 0, - duration: 1024, - flags: { - isLeading: 0, - isDependedOn: 0, - hasRedundancy: 0, - degradPrio: 0, - dependsOn: 1 - } - }, _.push(m) - } - E.set(G, y); - var W = G.byteLength; - y += W, m = { - size: W, - cts: 0, - duration: 0, - flags: { - isLeading: 0, - isDependedOn: 0, - hasRedundancy: 0, - degradPrio: 0, - dependsOn: 1 - } - }, _.push(m), R = K - } - var q = 0, - X = _.length; - if (X >= 2 && (q = _[X - 2].duration, m.duration = q), X) { - this.nextAudioPts = w = R + c * q, t.len = 0, t.samples = _, T = g ? new Uint8Array : n.a.moof(t.sequenceNumber++, S / c, t), t.samples = []; - var z = S / u, - Q = w / u, - $ = { - data1: T, - data2: E, - startPTS: z, - endPTS: Q, - startDTS: z, - endDTS: Q, - type: "audio", - hasAudio: !0, - hasVideo: !1, - nb: X - }; - return this.observer.trigger(o.a.FRAG_PARSING_DATA, $), $ - } - return null - } - }, t.prototype.remuxEmptyAudio = function(t, e, r, i) { - var n = t.inputTimeScale, - o = t.samplerate ? t.samplerate : n, - s = n / o, - u = this.nextAudioPts, - d = (void 0 !== u ? u : i.startDTS * n) + this._initDTS, - c = i.endDTS * n + this._initDTS, - h = 1024 * s, - f = Math.ceil((c - d) / h), - p = a.a.getSilentFrame(t.manifestCodec || t.codec, t.channelCount); - if (l.b.warn("remux empty Audio"), !p) return void l.b.trace("Unable to remuxEmptyAudio since we were unable to get a silent frame for given audio codec!"); - for (var v = [], g = 0; g < f; g++) { - var y = d + g * h; - v.push({ - unit: p, - pts: y, - dts: y - }), t.len += p.length - } - t.samples = v, this.remuxAudio(t, e, r) - }, t.prototype.remuxID3 = function(t, e) { - var r = t.samples.length, - i = void 0, - a = t.inputTimeScale, - n = this._initPTS, - s = this._initDTS; - if (r) { - for (var l = 0; l < r; l++) i = t.samples[l], i.pts = (i.pts - n) / a, i.dts = (i.dts - s) / a; - this.observer.trigger(o.a.FRAG_PARSING_METADATA, { - samples: t.samples - }) - } - t.samples = [], e = e - }, t.prototype.remuxText = function(t, e) { - t.samples.sort(function(t, e) { - return t.pts - e.pts - }); - var r = t.samples.length, - i = void 0, - a = t.inputTimeScale, - n = this._initPTS; - if (r) { - for (var s = 0; s < r; s++) i = t.samples[s], i.pts = (i.pts - n) / a; - this.observer.trigger(o.a.FRAG_PARSING_USERDATA, { - samples: t.samples - }) - } - t.samples = [], e = e - }, t.prototype._PTSNormalize = function(t, e) { - var r = void 0; - if (void 0 === e) return t; - for (r = e < t ? -8589934592 : 8589934592; Math.abs(t - e) > 4294967296;) t += r; - return t - }, t - }(); - e.a = u - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = function() { - function t() { - i(this, t) - } - return t.getSilentFrame = function(t, e) { - switch (t) { - case "mp4a.40.2": - if (1 === e) return new Uint8Array([0, 200, 0, 128, 35, 128]); - if (2 === e) return new Uint8Array([33, 0, 73, 144, 2, 25, 0, 35, 128]); - if (3 === e) return new Uint8Array([0, 200, 0, 128, 32, 132, 1, 38, 64, 8, 100, 0, 142]); - if (4 === e) return new Uint8Array([0, 200, 0, 128, 32, 132, 1, 38, 64, 8, 100, 0, 128, 44, 128, 8, 2, 56]); - if (5 === e) return new Uint8Array([0, 200, 0, 128, 32, 132, 1, 38, 64, 8, 100, 0, 130, 48, 4, 153, 0, 33, 144, 2, 56]); - if (6 === e) return new Uint8Array([0, 200, 0, 128, 32, 132, 1, 38, 64, 8, 100, 0, 130, 48, 4, 153, 0, 33, 144, 2, 0, 178, 0, 32, 8, 224]); - break; - default: - if (1 === e) return new Uint8Array([1, 64, 34, 128, 163, 78, 230, 128, 186, 8, 0, 0, 0, 28, 6, 241, 193, 10, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 94]); - if (2 === e) return new Uint8Array([1, 64, 34, 128, 163, 94, 230, 128, 186, 8, 0, 0, 0, 0, 149, 0, 6, 241, 161, 10, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 94]); - if (3 === e) return new Uint8Array([1, 64, 34, 128, 163, 94, 230, 128, 186, 8, 0, 0, 0, 0, 149, 0, 6, 241, 161, 10, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 94]) - } - return null - }, t - }(); - e.a = a - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = Math.pow(2, 32) - 1, - n = function() { - function t() { - i(this, t) - } - return t.init = function() { - t.types = { - avc1: [], - avcC: [], - btrt: [], - dinf: [], - dref: [], - esds: [], - ftyp: [], - hdlr: [], - mdat: [], - mdhd: [], - mdia: [], - mfhd: [], - minf: [], - moof: [], - moov: [], - mp4a: [], - ".mp3": [], - mvex: [], - mvhd: [], - pasp: [], - sdtp: [], - stbl: [], - stco: [], - stsc: [], - stsd: [], - stsz: [], - stts: [], - tfdt: [], - tfhd: [], - traf: [], - trak: [], - trun: [], - trex: [], - tkhd: [], - vmhd: [], - smhd: [] - }; - var e = void 0; - for (e in t.types) t.types.hasOwnProperty(e) && (t.types[e] = [e.charCodeAt(0), e.charCodeAt(1), e.charCodeAt(2), e.charCodeAt(3)]); - var r = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 118, 105, 100, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 105, 100, 101, 111, 72, 97, 110, 100, 108, 101, 114, 0]), - i = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 115, 111, 117, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 111, 117, 110, 100, 72, 97, 110, 100, 108, 101, 114, 0]); - t.HDLR_TYPES = { - video: r, - audio: i - }; - var a = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 12, 117, 114, 108, 32, 0, 0, 0, 1]), - n = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]); - t.STTS = t.STSC = t.STCO = n, t.STSZ = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), t.VMHD = new Uint8Array([0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]), t.SMHD = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]), t.STSD = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1]); - var o = new Uint8Array([105, 115, 111, 109]), - s = new Uint8Array([97, 118, 99, 49]), - l = new Uint8Array([0, 0, 0, 1]); - t.FTYP = t.box(t.types.ftyp, o, l, o, s), t.DINF = t.box(t.types.dinf, t.box(t.types.dref, a)) - }, t.box = function(t) { - for (var e = Array.prototype.slice.call(arguments, 1), r = 8, i = e.length, a = i, n = void 0; i--;) r += e[i].byteLength; - for (n = new Uint8Array(r), n[0] = r >> 24 & 255, n[1] = r >> 16 & 255, n[2] = r >> 8 & 255, n[3] = 255 & r, n.set(t, 4), i = 0, r = 8; i < a; i++) n.set(e[i], r), r += e[i].byteLength; - return n - }, t.hdlr = function(e) { - return t.box(t.types.hdlr, t.HDLR_TYPES[e]) - }, t.mdat = function(e) { - return t.box(t.types.mdat, e) - }, t.mdhd = function(e, r) { - r *= e; - var i = Math.floor(r / (a + 1)), - n = Math.floor(r % (a + 1)); - return t.box(t.types.mdhd, new Uint8Array([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, e >> 24 & 255, e >> 16 & 255, e >> 8 & 255, 255 & e, i >> 24, i >> 16 & 255, i >> 8 & 255, 255 & i, n >> 24, n >> 16 & 255, n >> 8 & 255, 255 & n, 85, 196, 0, 0])) - }, t.mdia = function(e) { - return t.box(t.types.mdia, t.mdhd(e.timescale, e.duration), t.hdlr(e.type), t.minf(e)) - }, t.mfhd = function(e) { - return t.box(t.types.mfhd, new Uint8Array([0, 0, 0, 0, e >> 24, e >> 16 & 255, e >> 8 & 255, 255 & e])) - }, t.minf = function(e) { - return "audio" === e.type ? t.box(t.types.minf, t.box(t.types.smhd, t.SMHD), t.DINF, t.stbl(e)) : t.box(t.types.minf, t.box(t.types.vmhd, t.VMHD), t.DINF, t.stbl(e)) - }, t.moof = function(e, r, i) { - return t.box(t.types.moof, t.mfhd(e), t.traf(i, r)) - }, t.moov = function(e) { - for (var r = e.length, i = []; r--;) i[r] = t.trak(e[r]); - return t.box.apply(null, [t.types.moov, t.mvhd(e[0].timescale, e[0].duration)].concat(i).concat(t.mvex(e))) - }, t.mvex = function(e) { - for (var r = e.length, i = []; r--;) i[r] = t.trex(e[r]); - return t.box.apply(null, [t.types.mvex].concat(i)) - }, t.mvhd = function(e, r) { - r *= e; - var i = Math.floor(r / (a + 1)), - n = Math.floor(r % (a + 1)), - o = new Uint8Array([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, e >> 24 & 255, e >> 16 & 255, e >> 8 & 255, 255 & e, i >> 24, i >> 16 & 255, i >> 8 & 255, 255 & i, n >> 24, n >> 16 & 255, n >> 8 & 255, 255 & n, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255]); - return t.box(t.types.mvhd, o) - }, t.sdtp = function(e) { - var r = e.samples || [], - i = new Uint8Array(4 + r.length), - a = void 0, - n = void 0; - for (n = 0; n < r.length; n++) a = r[n].flags, i[n + 4] = a.dependsOn << 4 | a.isDependedOn << 2 | a.hasRedundancy; - return t.box(t.types.sdtp, i) - }, t.stbl = function(e) { - return t.box(t.types.stbl, t.stsd(e), t.box(t.types.stts, t.STTS), t.box(t.types.stsc, t.STSC), t.box(t.types.stsz, t.STSZ), t.box(t.types.stco, t.STCO)) - }, t.avc1 = function(e) { - var r = [], - i = [], - a = void 0, - n = void 0, - o = void 0; - for (a = 0; a < e.sps.length; a++) n = e.sps[a], o = n.byteLength, r.push(o >>> 8 & 255), r.push(255 & o), r = r.concat(Array.prototype.slice.call(n)); - for (a = 0; a < e.pps.length; a++) n = e.pps[a], o = n.byteLength, i.push(o >>> 8 & 255), i.push(255 & o), i = i.concat(Array.prototype.slice.call(n)); - var s = t.box(t.types.avcC, new Uint8Array([1, r[3], r[4], r[5], 255, 224 | e.sps.length].concat(r).concat([e.pps.length]).concat(i))), - l = e.width, - u = e.height, - d = e.pixelRatio[0], - c = e.pixelRatio[1]; - return t.box(t.types.avc1, new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, l >> 8 & 255, 255 & l, u >> 8 & 255, 255 & u, 0, 72, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 1, 18, 100, 97, 105, 108, 121, 109, 111, 116, 105, 111, 110, 47, 104, 108, 115, 46, 106, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 17, 17]), s, t.box(t.types.btrt, new Uint8Array([0, 28, 156, 128, 0, 45, 198, 192, 0, 45, 198, 192])), t.box(t.types.pasp, new Uint8Array([d >> 24, d >> 16 & 255, d >> 8 & 255, 255 & d, c >> 24, c >> 16 & 255, c >> 8 & 255, 255 & c]))) - }, t.esds = function(t) { - var e = t.config.length; - return new Uint8Array([0, 0, 0, 0, 3, 23 + e, 0, 1, 0, 4, 15 + e, 64, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5].concat([e]).concat(t.config).concat([6, 1, 2])) - }, t.mp4a = function(e) { - var r = e.samplerate; - return t.box(t.types.mp4a, new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, e.channelCount, 0, 16, 0, 0, 0, 0, r >> 8 & 255, 255 & r, 0, 0]), t.box(t.types.esds, t.esds(e))) - }, t.mp3 = function(e) { - var r = e.samplerate; - return t.box(t.types[".mp3"], new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, e.channelCount, 0, 16, 0, 0, 0, 0, r >> 8 & 255, 255 & r, 0, 0])) - }, t.stsd = function(e) { - return "audio" === e.type ? e.isAAC || "mp3" !== e.codec ? t.box(t.types.stsd, t.STSD, t.mp4a(e)) : t.box(t.types.stsd, t.STSD, t.mp3(e)) : t.box(t.types.stsd, t.STSD, t.avc1(e)) - }, t.tkhd = function(e) { - var r = e.id, - i = e.duration * e.timescale, - n = e.width, - o = e.height, - s = Math.floor(i / (a + 1)), - l = Math.floor(i % (a + 1)); - return t.box(t.types.tkhd, new Uint8Array([1, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, r >> 24 & 255, r >> 16 & 255, r >> 8 & 255, 255 & r, 0, 0, 0, 0, s >> 24, s >> 16 & 255, s >> 8 & 255, 255 & s, l >> 24, l >> 16 & 255, l >> 8 & 255, 255 & l, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, n >> 8 & 255, 255 & n, 0, 0, o >> 8 & 255, 255 & o, 0, 0])) - }, t.traf = function(e, r) { - var i = t.sdtp(e), - n = e.id, - o = Math.floor(r / (a + 1)), - s = Math.floor(r % (a + 1)); - return t.box(t.types.traf, t.box(t.types.tfhd, new Uint8Array([0, 0, 0, 0, n >> 24, n >> 16 & 255, n >> 8 & 255, 255 & n])), t.box(t.types.tfdt, new Uint8Array([1, 0, 0, 0, o >> 24, o >> 16 & 255, o >> 8 & 255, 255 & o, s >> 24, s >> 16 & 255, s >> 8 & 255, 255 & s])), t.trun(e, i.length + 16 + 20 + 8 + 16 + 8 + 8), i) - }, t.trak = function(e) { - return e.duration = e.duration || 4294967295, t.box(t.types.trak, t.tkhd(e), t.mdia(e)) - }, t.trex = function(e) { - var r = e.id; - return t.box(t.types.trex, new Uint8Array([0, 0, 0, 0, r >> 24, r >> 16 & 255, r >> 8 & 255, 255 & r, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1])) - }, t.trun = function(e, r) { - var i = e.samples || [], - a = i.length, - n = 12 + 16 * a, - o = new Uint8Array(n), - s = void 0, - l = void 0, - u = void 0, - d = void 0, - c = void 0, - h = void 0; - for (r += 8 + n, o.set([0, 0, 15, 1, a >>> 24 & 255, a >>> 16 & 255, a >>> 8 & 255, 255 & a, r >>> 24 & 255, r >>> 16 & 255, r >>> 8 & 255, 255 & r], 0), s = 0; s < a; s++) l = i[s], u = l.duration, d = l.size, c = l.flags, h = l.cts, o.set([u >>> 24 & 255, u >>> 16 & 255, u >>> 8 & 255, 255 & u, d >>> 24 & 255, d >>> 16 & 255, d >>> 8 & 255, 255 & d, c.isLeading << 2 | c.dependsOn, c.isDependedOn << 6 | c.hasRedundancy << 4 | c.paddingValue << 1 | c.isNonSync, 61440 & c.degradPrio, 15 & c.degradPrio, h >>> 24 & 255, h >>> 16 & 255, h >>> 8 & 255, 255 & h], 12 + 16 * s); - return t.box(t.types.trun, o) - }, t.initSegment = function(e) { - t.types || t.init(); - var r = t.moov(e), - i = void 0; - return i = new Uint8Array(t.FTYP.byteLength + r.byteLength), i.set(t.FTYP), i.set(r, t.FTYP.byteLength), i - }, t - }(); - e.a = n - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(1), - n = function() { - function t(e) { - i(this, t), this.observer = e - } - return t.prototype.destroy = function() {}, t.prototype.resetTimeStamp = function() {}, t.prototype.resetInitSegment = function() {}, t.prototype.remux = function(t, e, r, i, n, o, s, l) { - var u = this.observer, - d = ""; - t && (d += "audio"), e && (d += "video"), u.trigger(a.a.FRAG_PARSING_DATA, { - data1: l, - startPTS: n, - startDTS: n, - type: d, - hasAudio: !!t, - hasVideo: !!e, - nb: 1, - dropped: 0 - }), u.trigger(a.a.FRAG_PARSED) - }, t - }(); - e.a = n - }, function(t, e, r) { - "use strict"; - Object.defineProperty(e, "__esModule", { - value: !0 - }); - var i = r(21), - a = r(1), - n = r(0), - o = r(12), - s = r.n(o), - l = function(t) { - var e = new s.a; - e.trigger = function(t) { - for (var r = arguments.length, i = Array(r > 1 ? r - 1 : 0), a = 1; a < r; a++) i[a - 1] = arguments[a]; - e.emit.apply(e, [t, t].concat(i)) - }, e.off = function(t) { - for (var r = arguments.length, i = Array(r > 1 ? r - 1 : 0), a = 1; a < r; a++) i[a - 1] = arguments[a]; - e.removeListener.apply(e, [t].concat(i)) - }; - var r = function(e, r) { - t.postMessage({ - event: e, - data: r - }) - }; - t.addEventListener("message", function(a) { - var o = a.data; - switch (o.cmd) { - case "init": - var s = JSON.parse(o.config); - t.demuxer = new i.a(e, o.typeSupported, s, o.vendor); - try { - Object(n.a)(!0 === s.debug) - } catch (t) { - console.warn("demuxerWorker: unable to enable logs") - } - r("init", null); - break; - case "demux": - t.demuxer.push(o.data, o.decryptdata, o.initSegment, o.audioCodec, o.videoCodec, o.timeOffset, o.discontinuity, o.trackSwitch, o.contiguous, o.duration, o.accurateTimeOffset, o.defaultInitPTS) - } - }), e.on(a.a.FRAG_DECRYPTED, r), e.on(a.a.FRAG_PARSING_INIT_SEGMENT, r), e.on(a.a.FRAG_PARSED, r), e.on(a.a.ERROR, r), e.on(a.a.FRAG_PARSING_METADATA, r), e.on(a.a.FRAG_PARSING_USERDATA, r), e.on(a.a.INIT_PTS_FOUND, r), e.on(a.a.FRAG_PARSING_DATA, function(e, r) { - var i = [], - a = { - event: e, - data: r - }; - r.data1 && (a.data1 = r.data1.buffer, i.push(r.data1.buffer), delete r.data1), r.data2 && (a.data2 = r.data2.buffer, i.push(r.data2.buffer), delete r.data2), t.postMessage(a, i) - }) - }; - e.default = l - }, function(t, e, r) { - "use strict"; - - function i() { - var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 0, - e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0, - r = arguments[2], - i = 0; - if (r.programDateTime) { - var a = Date.parse(r.programDateTime); - isNaN(a) || (i = 1e3 * e + a - 1e3 * t) - } - return i - } - - function a(t) { - var e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : null; - if (!Array.isArray(t) || !t.length || null === e) return null; - if (e < t[0].pdt) return null; - if (e >= t[t.length - 1].endPdt) return null; - for (var r = 0; r < t.length; ++r) { - var i = t[r]; - if (e < i.endPdt) return i - } - return null - } - - function n(t, e) { - var r = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 0, - i = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : 0, - a = arguments.length > 4 && void 0 !== arguments[4] ? arguments[4] : 0, - n = void 0, - l = t ? e[t.sn - e[0].sn + 1] : null; - return r < i && (r > i - a && (a = 0), n = l && !o(r, a, l) ? l : s.a.search(e, o.bind(null, r, a))), n - } - - function o() { - var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 0, - e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0, - r = arguments[2], - i = Math.min(e, r.duration + (r.deltaPTS ? r.deltaPTS : 0)); - return r.start + r.duration - i <= t ? 1 : r.start - i > t && r.start ? -1 : 0 - } - e.a = i, e.b = a, e.c = n, e.d = o; - var s = r(6) - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(1), - s = r(3), - l = r(0), - u = r(2), - d = r(19), - c = r(15), - h = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(t) { - return typeof t - } : function(t) { - return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t - }, - f = function() { - function t(t, e) { - for (var r = 0; r < e.length; r++) { - var i = e[r]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(t, i.key, i) - } - } - return function(e, r, i) { - return r && t(e.prototype, r), i && t(e, i), e - } - }(), - p = window, - v = p.performance, - g = function(t) { - function e(r) { - i(this, e); - var n = a(this, t.call(this, r, o.a.MANIFEST_LOADED, o.a.LEVEL_LOADED, o.a.AUDIO_TRACK_SWITCHED, o.a.FRAG_LOADED, o.a.ERROR)); - return n.canload = !1, n.currentLevelIndex = null, n.manualLevelIndex = -1, n.timer = null, n - } - return n(e, t), e.prototype.onHandlerDestroying = function() { - this.clearTimer(), this.manualLevelIndex = -1 - }, e.prototype.clearTimer = function() { - null !== this.timer && (clearTimeout(this.timer), this.timer = null) - }, e.prototype.startLoad = function() { - var t = this._levels; - this.canload = !0, this.levelRetryCount = 0, t && t.forEach(function(t) { - t.loadError = 0; - var e = t.details; - e && e.live && (t.details = void 0) - }), null !== this.timer && this.loadLevel() - }, e.prototype.stopLoad = function() { - this.canload = !1 - }, e.prototype.onManifestLoaded = function(t) { - var e = [], - r = void 0, - i = {}, - a = null, - n = !1, - s = !1, - h = /chrome|firefox/.test(navigator.userAgent.toLowerCase()), - f = []; - if (t.levels.forEach(function(t) { - t.loadError = 0, t.fragmentError = !1, n = n || !!t.videoCodec, s = s || !!t.audioCodec || !(!t.attrs || !t.attrs.AUDIO), h && t.audioCodec && -1 !== t.audioCodec.indexOf("mp4a.40.34") && (t.audioCodec = void 0), a = i[t.bitrate], a ? a.url.push(t.url) : (t.url = [t.url], t.urlId = 0, i[t.bitrate] = t, e.push(t)), t.attrs && t.attrs.AUDIO && Object(c.a)(a || t, "audio", t.attrs.AUDIO), t.attrs && t.attrs.SUBTITLES && Object(c.a)(a || t, "text", t.attrs.SUBTITLES) - }), n && s && (e = e.filter(function(t) { - return !!t.videoCodec - })), e = e.filter(function(t) { - var e = t.audioCodec, - r = t.videoCodec; - return (!e || Object(d.a)(e)) && (!r || Object(d.a)(r)) - }), t.audioTracks && (f = t.audioTracks.filter(function(t) { - return !t.audioCodec || Object(d.a)(t.audioCodec, "audio") - })), e.length > 0) { - r = e[0].bitrate, e.sort(function(t, e) { - return t.bitrate - e.bitrate - }), this._levels = e; - for (var p = 0; p < e.length; p++) - if (e[p].bitrate === r) { - this._firstLevel = p, l.b.log("manifest loaded," + e.length + " level(s) found, first bitrate:" + r); - break - } this.hls.trigger(o.a.MANIFEST_PARSED, { - levels: e, - audioTracks: f, - firstLevel: this._firstLevel, - stats: t.stats, - audio: s, - video: n, - altAudio: f.length > 0 && n - }) - } else this.hls.trigger(o.a.ERROR, { - type: u.b.MEDIA_ERROR, - details: u.a.MANIFEST_INCOMPATIBLE_CODECS_ERROR, - fatal: !0, - url: this.hls.url, - reason: "no level with compatible codecs found in manifest" - }) - }, e.prototype.setLevelInternal = function(t) { - var e = this._levels, - r = this.hls; - if (t >= 0 && t < e.length) { - if (this.clearTimer(), this.currentLevelIndex !== t) { - l.b.log("switching to level " + t), this.currentLevelIndex = t; - var i = e[t]; - i.level = t, r.trigger(o.a.LEVEL_SWITCHING, i) - } - var a = e[t], - n = a.details; - if (!n || n.live) { - var s = a.urlId; - r.trigger(o.a.LEVEL_LOADING, { - url: a.url[s], - level: t, - id: s - }) - } - } else r.trigger(o.a.ERROR, { - type: u.b.OTHER_ERROR, - details: u.a.LEVEL_SWITCH_ERROR, - level: t, - fatal: !1, - reason: "invalid level idx" - }) - }, e.prototype.onError = function(t) { - if (t.fatal) return void(t.type === u.b.NETWORK_ERROR && this.clearTimer()); - var e = !1, - r = !1, - i = void 0; - switch (t.details) { - case u.a.FRAG_LOAD_ERROR: - case u.a.FRAG_LOAD_TIMEOUT: - case u.a.KEY_LOAD_ERROR: - case u.a.KEY_LOAD_TIMEOUT: - i = t.frag.level, r = !0; - break; - case u.a.LEVEL_LOAD_ERROR: - case u.a.LEVEL_LOAD_TIMEOUT: - i = t.context.level, e = !0; - break; - case u.a.REMUX_ALLOC_ERROR: - i = t.level, e = !0 - } - void 0 !== i && this.recoverLevel(t, i, e, r) - }, e.prototype.recoverLevel = function(t, e, r, i) { - var a = this, - n = this.hls.config, - o = t.details, - s = this._levels[e], - u = void 0, - d = void 0, - c = void 0; - if (s.loadError++, s.fragmentError = i, r) { - if (!(this.levelRetryCount + 1 <= n.levelLoadingMaxRetry)) return l.b.error("level controller, cannot recover from " + o + " error"), this.currentLevelIndex = null, this.clearTimer(), void(t.fatal = !0); - d = Math.min(Math.pow(2, this.levelRetryCount) * n.levelLoadingRetryDelay, n.levelLoadingMaxRetryTimeout), this.timer = setTimeout(function() { - return a.loadLevel() - }, d), t.levelRetry = !0, this.levelRetryCount++, l.b.warn("level controller, " + o + ", retry in " + d + " ms, current retry count is " + this.levelRetryCount) - }(r || i) && (u = s.url.length, u > 1 && s.loadError < u ? (s.urlId = (s.urlId + 1) % u, s.details = void 0, l.b.warn("level controller, " + o + " for level " + e + ": switching to redundant URL-id " + s.urlId)) : -1 === this.manualLevelIndex ? (c = 0 === e ? this._levels.length - 1 : e - 1, l.b.warn("level controller, " + o + ": switch to " + c), this.hls.nextAutoLevel = this.currentLevelIndex = c) : i && (l.b.warn("level controller, " + o + ": reload a fragment"), this.currentLevelIndex = null)) - }, e.prototype.onFragLoaded = function(t) { - var e = t.frag; - if (void 0 !== e && "main" === e.type) { - var r = this._levels[e.level]; - void 0 !== r && (r.fragmentError = !1, r.loadError = 0, this.levelRetryCount = 0) - } - }, e.prototype.onLevelLoaded = function(t) { - var e = this, - r = t.level; - if (r === this.currentLevelIndex) { - var i = this._levels[r]; - i.fragmentError || (i.loadError = 0, this.levelRetryCount = 0); - var a = t.details; - if (a.live) { - var n = 1e3 * (a.averagetargetduration ? a.averagetargetduration : a.targetduration), - o = n, - s = i.details; - s && a.endSN === s.endSN && (o /= 2, l.b.log("same live playlist, reload twice faster")), o -= v.now() - t.stats.trequest, o = Math.max(n / 2, Math.round(o)), l.b.log("live playlist, reload in " + Math.round(o) + " ms"), this.timer = setTimeout(function() { - return e.loadLevel() - }, o) - } else this.clearTimer() - } - }, e.prototype.onAudioTrackSwitched = function(t) { - var e = this.hls.audioTracks[t.id].groupId, - r = this.hls.levels[this.currentLevelIndex]; - if (r && r.audioGroupIds) { - var i = r.audioGroupIds.findIndex(function(t) { - return t === e - }); - i !== r.urlId && (r.urlId = i, this.startLoad()) - } - }, e.prototype.loadLevel = function() { - if (l.b.debug("call to loadLevel"), null !== this.currentLevelIndex && this.canload) { - var t = this._levels[this.currentLevelIndex]; - if ("object" === (void 0 === t ? "undefined" : h(t)) && t.url.length > 0) { - var e = this.currentLevelIndex, - r = t.urlId, - i = t.url[r]; - l.b.log("Attempt loading level index " + e + " with URL-id " + r), this.hls.trigger(o.a.LEVEL_LOADING, { - url: i, - level: e, - id: r - }) - } - } - }, f(e, [{ - key: "levels", - get: function() { - return this._levels - } - }, { - key: "level", - get: function() { - return this.currentLevelIndex - }, - set: function(t) { - var e = this._levels; - e && (t = Math.min(t, e.length - 1), this.currentLevelIndex === t && e[t].details || this.setLevelInternal(t)) - } - }, { - key: "manualLevel", - get: function() { - return this.manualLevelIndex - }, - set: function(t) { - this.manualLevelIndex = t, void 0 === this._startLevel && (this._startLevel = t), -1 !== t && (this.level = t) - } - }, { - key: "firstLevel", - get: function() { - return this._firstLevel - }, - set: function(t) { - this._firstLevel = t - } - }, { - key: "startLevel", - get: function() { - if (void 0 === this._startLevel) { - var t = this.hls.config.startLevel; - return void 0 !== t ? t : this._firstLevel - } - return this._startLevel - }, - set: function(t) { - this._startLevel = t - } - }, { - key: "nextLoadLevel", - get: function() { - return -1 !== this.manualLevelIndex ? this.manualLevelIndex : this.hls.nextAutoLevel - }, - set: function(t) { - this.level = t, -1 === this.manualLevelIndex && (this.hls.nextAutoLevel = t) - } - }]), e - }(s.a); - e.a = g - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(1), - s = r(3), - l = r(7), - u = r(26), - d = function(t) { - function e(r) { - i(this, e); - var n = a(this, t.call(this, r, o.a.MEDIA_ATTACHED, o.a.MEDIA_DETACHING, o.a.FRAG_PARSING_METADATA)); - return n.id3Track = void 0, n.media = void 0, n - } - return n(e, t), e.prototype.destroy = function() { - s.a.prototype.destroy.call(this) - }, e.prototype.onMediaAttached = function(t) { - this.media = t.media, this.media - }, e.prototype.onMediaDetaching = function() { - Object(u.a)(this.id3Track), this.id3Track = void 0, this.media = void 0 - }, e.prototype.getID3Track = function(t) { - for (var e = 0; e < t.length; e++) { - var r = t[e]; - if ("metadata" === r.kind && "id3" === r.label) return Object(u.b)(r, this.media), r - } - return this.media.addTextTrack("metadata", "id3") - }, e.prototype.onFragParsingMetadata = function(t) { - var e = t.frag, - r = t.samples; - this.id3Track || (this.id3Track = this.getID3Track(this.media.textTracks), this.id3Track.mode = "hidden"); - for (var i = window.WebKitDataCue || window.VTTCue || window.TextTrackCue, a = 0; a < r.length; a++) { - var n = l.a.getID3Frames(r[a].data); - if (n) { - var o = r[a].pts, - s = a < r.length - 1 ? r[a + 1].pts : e.endPTS; - o === s && (s += 1e-4); - for (var u = 0; u < n.length; u++) { - var d = n[u]; - if (!l.a.isTimeStampFrame(d)) { - var c = new i(o, s, ""); - c.value = d, this.id3Track.addCue(c) - } - } - } - } - }, e - }(s.a); - e.a = d - }, function(t, e, r) { - "use strict"; - - function i() { - var t = Object(a.a)(), - e = window.SourceBuffer || window.WebKitSourceBuffer, - r = t && "function" == typeof t.isTypeSupported && t.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"'), - i = !e || e.prototype && "function" == typeof e.prototype.appendBuffer && "function" == typeof e.prototype.remove; - return !!r && !!i - } - e.a = i; - var a = r(14) - }, function(t, e, r) { - "use strict"; - r.d(e, "a", function() { - return g - }); - var i = r(53), - a = r(56), - n = r(57), - o = r(58), - s = r(59), - l = r(60), - u = r(61), - d = r(62), - c = r(64), - h = r(68), - f = r(69), - p = r(70), - v = r(71), - g = { - autoStartLoad: !0, - startPosition: -1, - defaultAudioCodec: void 0, - debug: !1, - capLevelOnFPSDrop: !1, - capLevelToPlayerSize: !1, - initialLiveManifestSize: 1, - maxBufferLength: 30, - maxBufferSize: 6e7, - maxBufferHole: .5, - lowBufferWatchdogPeriod: .5, - highBufferWatchdogPeriod: 3, - nudgeOffset: .1, - nudgeMaxRetry: 3, - maxFragLookUpTolerance: .25, - liveSyncDurationCount: 3, - liveMaxLatencyDurationCount: 1 / 0, - liveSyncDuration: void 0, - liveMaxLatencyDuration: void 0, - liveDurationInfinity: !1, - maxMaxBufferLength: 600, - enableWorker: !0, - enableSoftwareAES: !0, - manifestLoadingTimeOut: 1e4, - manifestLoadingMaxRetry: 1, - manifestLoadingRetryDelay: 1e3, - manifestLoadingMaxRetryTimeout: 64e3, - startLevel: void 0, - levelLoadingTimeOut: 1e4, - levelLoadingMaxRetry: 4, - levelLoadingRetryDelay: 1e3, - levelLoadingMaxRetryTimeout: 64e3, - fragLoadingTimeOut: 2e4, - fragLoadingMaxRetry: 6, - fragLoadingRetryDelay: 1e3, - fragLoadingMaxRetryTimeout: 64e3, - startFragPrefetch: !1, - fpsDroppedMonitoringPeriod: 5e3, - fpsDroppedMonitoringThreshold: .2, - appendErrorMaxRetry: 3, - loader: s.a, - fLoader: void 0, - pLoader: void 0, - xhrSetup: void 0, - licenseXhrSetup: void 0, - abrController: i.a, - bufferController: a.a, - capLevelController: n.a, - fpsController: o.a, - stretchShortVideoTrack: !1, - maxAudioFramesDrift: 1, - forceKeyFrameOnDiscontinuity: !0, - abrEwmaFastLive: 3, - abrEwmaSlowLive: 9, - abrEwmaFastVoD: 3, - abrEwmaSlowVoD: 9, - abrEwmaDefaultEstimate: 5e5, - abrBandWidthFactor: .95, - abrBandWidthUpFactor: .7, - abrMaxWithRealBitrate: !1, - maxStarvationDelay: 4, - maxLoadingDelay: 4, - minAutoBitrate: 0, - emeEnabled: !1, - widevineLicenseUrl: void 0, - requestMediaKeySystemAccessFunc: v.a - }; - g.subtitleStreamController = f.a, g.subtitleTrackController = h.a, g.timelineController = c.a, g.cueHandler = d, g.enableCEA708Captions = !0, g.enableWebVTT = !0, g.captionsTextTrack1Label = "English", g.captionsTextTrack1LanguageCode = "en", g.captionsTextTrack2Label = "Spanish", g.captionsTextTrack2LanguageCode = "es", g.audioStreamController = u.a, g.audioTrackController = l.a, g.emeController = p.a - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(1), - s = r(3), - l = r(11), - u = r(2), - d = r(0), - c = r(54), - h = function() { - function t(t, e) { - for (var r = 0; r < e.length; r++) { - var i = e[r]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(t, i.key, i) - } - } - return function(e, r, i) { - return r && t(e.prototype, r), i && t(e, i), e - } - }(), - f = window, - p = f.performance, - v = function(t) { - function e(r) { - i(this, e); - var n = a(this, t.call(this, r, o.a.FRAG_LOADING, o.a.FRAG_LOADED, o.a.FRAG_BUFFERED, o.a.ERROR)); - return n.lastLoadedFragLevel = 0, n._nextAutoLevel = -1, n.hls = r, n.timer = null, n._bwEstimator = null, n.onCheck = n._abandonRulesCheck.bind(n), n - } - return n(e, t), e.prototype.destroy = function() { - this.clearTimer(), s.a.prototype.destroy.call(this) - }, e.prototype.onFragLoading = function(t) { - var e = t.frag; - if ("main" === e.type && (this.timer || (this.fragCurrent = e, this.timer = setInterval(this.onCheck, 100)), !this._bwEstimator)) { - var r = this.hls, - i = r.config, - a = e.level, - n = r.levels[a].details.live, - o = void 0, - s = void 0; - n ? (o = i.abrEwmaFastLive, s = i.abrEwmaSlowLive) : (o = i.abrEwmaFastVoD, s = i.abrEwmaSlowVoD), this._bwEstimator = new c.a(r, s, o, i.abrEwmaDefaultEstimate) - } - }, e.prototype._abandonRulesCheck = function() { - var t = this.hls, - e = t.media, - r = this.fragCurrent; - if (r) { - var i = r.loader, - a = t.minAutoLevel; - if (!i || i.stats && i.stats.aborted) return d.b.warn("frag loader destroy or aborted, disarm abandonRules"), this.clearTimer(), void(this._nextAutoLevel = -1); - var n = i.stats; - if (e && n && (!e.paused && 0 !== e.playbackRate || !e.readyState) && r.autoLevel && r.level) { - var s = p.now() - n.trequest, - u = Math.abs(e.playbackRate); - if (s > 500 * r.duration / u) { - var c = t.levels, - h = Math.max(1, n.bw ? n.bw / 8 : 1e3 * n.loaded / s), - f = c[r.level], - v = f.realBitrate ? Math.max(f.realBitrate, f.bitrate) : f.bitrate, - g = n.total ? n.total : Math.max(n.loaded, Math.round(r.duration * v / 8)), - y = e.currentTime, - m = (g - n.loaded) / h, - b = (l.a.bufferInfo(e, y, t.config.maxBufferHole).end - y) / u; - if (b < 2 * r.duration / u && m > b) { - var E = void 0, - T = void 0; - for (T = r.level - 1; T > a; T--) { - var S = c[T].realBitrate ? Math.max(c[T].realBitrate, c[T].bitrate) : c[T].bitrate; - if ((E = r.duration * S / (6.4 * h)) < b) break - } - E < m && (d.b.warn("loading too slow, abort fragment loading and switch to level " + T + ":fragLoadedDelay[" + T + "]= i; u--) { - var c = l[u], - h = c.details, - f = h ? h.totalduration / h.fragments.length : e, - p = !!h && h.live, - v = void 0; - v = u <= t ? o * r : s * r; - var g = l[u].realBitrate ? Math.max(l[u].realBitrate, l[u].bitrate) : l[u].bitrate, - y = g * f / v; - if (d.b.trace("level/adjustedbw/bitrate/avgDuration/maxFetchDuration/fetchDuration: " + u + "/" + Math.round(v) + "/" + g + "/" + f + "/" + n + "/" + y), v > g && (!y || p && !this.bitrateTestDelay || y < n)) return u - } - return -1 - }, h(e, [{ - key: "nextAutoLevel", - get: function() { - var t = this._nextAutoLevel, - e = this._bwEstimator; - if (!(-1 === t || e && e.canEstimate())) return t; - var r = this._nextABRAutoLevel; - return -1 !== t && (r = Math.min(t, r)), r - }, - set: function(t) { - this._nextAutoLevel = t - } - }, { - key: "_nextABRAutoLevel", - get: function() { - var t = this.hls, - e = t.maxAutoLevel, - r = t.levels, - i = t.config, - a = t.minAutoLevel, - n = t.media, - o = this.lastLoadedFragLevel, - s = this.fragCurrent ? this.fragCurrent.duration : 0, - u = n ? n.currentTime : 0, - c = n && 0 !== n.playbackRate ? Math.abs(n.playbackRate) : 1, - h = this._bwEstimator ? this._bwEstimator.getEstimate() : i.abrEwmaDefaultEstimate, - f = (l.a.bufferInfo(n, u, i.maxBufferHole).end - u) / c, - p = this._findBestLevel(o, s, h, a, e, f, i.abrBandWidthFactor, i.abrBandWidthUpFactor, r); - if (p >= 0) return p; - d.b.trace("rebuffering expected to happen, lets try to find a quality level minimizing the rebuffering"); - var v = s ? Math.min(s, i.maxStarvationDelay) : i.maxStarvationDelay, - g = i.abrBandWidthFactor, - y = i.abrBandWidthUpFactor; - if (0 === f) { - var m = this.bitrateTestDelay; - if (m) { - v = (s ? Math.min(s, i.maxLoadingDelay) : i.maxLoadingDelay) - m, d.b.trace("bitrate test took " + Math.round(1e3 * m) + "ms, set first fragment max fetchDuration to " + Math.round(1e3 * v) + " ms"), g = y = 1 - } - } - return p = this._findBestLevel(o, s, h, a, e, f + v, g, y, r), Math.max(p, 0) - } - }]), e - }(s.a); - e.a = v - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(55), - n = function() { - function t(e, r, n, o) { - i(this, t), this.hls = e, this.defaultEstimate_ = o, this.minWeight_ = .001, this.minDelayMs_ = 50, this.slow_ = new a.a(r), this.fast_ = new a.a(n) - } - return t.prototype.sample = function(t, e) { - t = Math.max(t, this.minDelayMs_); - var r = 8e3 * e / t, - i = t / 1e3; - this.fast_.sample(i, r), this.slow_.sample(i, r) - }, t.prototype.canEstimate = function() { - var t = this.fast_; - return t && t.getTotalWeight() >= this.minWeight_ - }, t.prototype.getEstimate = function() { - return this.canEstimate() ? Math.min(this.fast_.getEstimate(), this.slow_.getEstimate()) : this.defaultEstimate_ - }, t.prototype.destroy = function() {}, t - }(); - e.a = n - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = function() { - function t(e) { - i(this, t), this.alpha_ = e ? Math.exp(Math.log(.5) / e) : 0, this.estimate_ = 0, this.totalWeight_ = 0 - } - return t.prototype.sample = function(t, e) { - var r = Math.pow(this.alpha_, t); - this.estimate_ = e * (1 - r) + r * this.estimate_, this.totalWeight_ += t - }, t.prototype.getTotalWeight = function() { - return this.totalWeight_ - }, t.prototype.getEstimate = function() { - if (this.alpha_) { - var t = 1 - Math.pow(this.alpha_, this.totalWeight_); - return this.estimate_ / t - } - return this.estimate_ - }, t - }(); - e.a = a - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(1), - s = r(3), - l = r(0), - u = r(2), - d = r(14), - c = Object(d.a)(), - h = function(t) { - function e(r) { - i(this, e); - var n = a(this, t.call(this, r, o.a.MEDIA_ATTACHING, o.a.MEDIA_DETACHING, o.a.MANIFEST_PARSED, o.a.BUFFER_RESET, o.a.BUFFER_APPENDING, o.a.BUFFER_CODECS, o.a.BUFFER_EOS, o.a.BUFFER_FLUSHING, o.a.LEVEL_PTS_UPDATED, o.a.LEVEL_UPDATED)); - return n._msDuration = null, n._levelDuration = null, n._live = null, n._objectUrl = null, n.onsbue = n.onSBUpdateEnd.bind(n), n.onsbe = n.onSBUpdateError.bind(n), n.pendingTracks = {}, n.tracks = {}, n - } - return n(e, t), e.prototype.destroy = function() { - s.a.prototype.destroy.call(this) - }, e.prototype.onLevelPtsUpdated = function(t) { - var e = t.type, - r = this.tracks.audio; - if ("audio" === e && r && "audio/mpeg" === r.container) { - var i = this.sourceBuffer.audio; - if (Math.abs(i.timestampOffset - t.start) > .1) { - var a = i.updating; - try { - i.abort() - } catch (t) { - a = !0, l.b.warn("can not abort audio buffer: " + t) - } - a ? this.audioTimestampOffset = t.start : (l.b.warn("change mpeg audio timestamp offset from " + i.timestampOffset + " to " + t.start), i.timestampOffset = t.start) - } - } - }, e.prototype.onManifestParsed = function(t) { - var e = t.audio, - r = t.video || t.levels.length && t.altAudio, - i = 0; - t.altAudio && (e || r) && (i = (e ? 1 : 0) + (r ? 1 : 0), l.b.log(i + " sourceBuffer(s) expected")), this.sourceBufferNb = i - }, e.prototype.onMediaAttaching = function(t) { - var e = this.media = t.media; - if (e) { - var r = this.mediaSource = new c; - this.onmso = this.onMediaSourceOpen.bind(this), this.onmse = this.onMediaSourceEnded.bind(this), this.onmsc = this.onMediaSourceClose.bind(this), r.addEventListener("sourceopen", this.onmso), r.addEventListener("sourceended", this.onmse), r.addEventListener("sourceclose", this.onmsc), e.src = window.URL.createObjectURL(r), this._objectUrl = e.src - } - }, e.prototype.onMediaDetaching = function() { - l.b.log("media source detaching"); - var t = this.mediaSource; - if (t) { - if ("open" === t.readyState) try { - t.endOfStream() - } catch (t) { - l.b.warn("onMediaDetaching:" + t.message + " while calling endOfStream") - } - t.removeEventListener("sourceopen", this.onmso), t.removeEventListener("sourceended", this.onmse), t.removeEventListener("sourceclose", this.onmsc), this.media && (window.URL.revokeObjectURL(this._objectUrl), this.media.src === this._objectUrl ? (this.media.removeAttribute("src"), this.media.load()) : l.b.warn("media.src was changed by a third party - skip cleanup")), this.mediaSource = null, this.media = null, this._objectUrl = null, this.pendingTracks = {}, this.tracks = {}, this.sourceBuffer = {}, this.flushRange = [], this.segments = [], this.appended = 0 - } - this.onmso = this.onmse = this.onmsc = null, this.hls.trigger(o.a.MEDIA_DETACHED) - }, e.prototype.onMediaSourceOpen = function() { - l.b.log("media source opened"), this.hls.trigger(o.a.MEDIA_ATTACHED, { - media: this.media - }); - var t = this.mediaSource; - t && t.removeEventListener("sourceopen", this.onmso), this.checkPendingTracks() - }, e.prototype.checkPendingTracks = function() { - var t = this.pendingTracks, - e = Object.keys(t).length; - e && (this.sourceBufferNb <= e || 0 === this.sourceBufferNb) && (this.createSourceBuffers(t), this.pendingTracks = {}, this.doAppending()) - }, e.prototype.onMediaSourceClose = function() { - l.b.log("media source closed") - }, e.prototype.onMediaSourceEnded = function() { - l.b.log("media source ended") - }, e.prototype.onSBUpdateEnd = function() { - if (this.audioTimestampOffset) { - var t = this.sourceBuffer.audio; - l.b.warn("change mpeg audio timestamp offset from " + t.timestampOffset + " to " + this.audioTimestampOffset), t.timestampOffset = this.audioTimestampOffset, delete this.audioTimestampOffset - } - this._needsFlush && this.doFlush(), this._needsEos && this.checkEos(), this.appending = !1; - var e = this.parent, - r = this.segments.reduce(function(t, r) { - return r.parent === e ? t + 1 : t - }, 0), - i = {}, - a = this.sourceBuffer; - for (var n in a) i[n] = a[n].buffered; - this.hls.trigger(o.a.BUFFER_APPENDED, { - parent: e, - pending: r, - timeRanges: i - }), this._needsFlush || this.doAppending(), this.updateMediaElementDuration() - }, e.prototype.onSBUpdateError = function(t) { - l.b.error("sourceBuffer error:", t), this.hls.trigger(o.a.ERROR, { - type: u.b.MEDIA_ERROR, - details: u.a.BUFFER_APPENDING_ERROR, - fatal: !1 - }) - }, e.prototype.onBufferReset = function() { - var t = this.sourceBuffer; - for (var e in t) { - var r = t[e]; - try { - this.mediaSource.removeSourceBuffer(r), r.removeEventListener("updateend", this.onsbue), r.removeEventListener("error", this.onsbe) - } catch (t) {} - } - this.sourceBuffer = {}, this.flushRange = [], this.segments = [], this.appended = 0 - }, e.prototype.onBufferCodecs = function(t) { - if (0 === Object.keys(this.sourceBuffer).length) { - for (var e in t) this.pendingTracks[e] = t[e]; - var r = this.mediaSource; - r && "open" === r.readyState && this.checkPendingTracks() - } - }, e.prototype.createSourceBuffers = function(t) { - var e = this.sourceBuffer, - r = this.mediaSource; - for (var i in t) - if (!e[i]) { - var a = t[i], - n = a.levelCodec || a.codec, - s = a.container + ";codecs=" + n; - l.b.log("creating sourceBuffer(" + s + ")"); - try { - var d = e[i] = r.addSourceBuffer(s); - d.addEventListener("updateend", this.onsbue), d.addEventListener("error", this.onsbe), this.tracks[i] = { - codec: n, - container: a.container - }, a.buffer = d - } catch (t) { - l.b.error("error while trying to add sourceBuffer:" + t.message), this.hls.trigger(o.a.ERROR, { - type: u.b.MEDIA_ERROR, - details: u.a.BUFFER_ADD_CODEC_ERROR, - fatal: !1, - err: t, - mimeType: s - }) - } - } this.hls.trigger(o.a.BUFFER_CREATED, { - tracks: t - }) - }, e.prototype.onBufferAppending = function(t) { - this._needsFlush || (this.segments ? this.segments.push(t) : this.segments = [t], this.doAppending()) - }, e.prototype.onBufferAppendFail = function(t) { - l.b.error("sourceBuffer error:", t.event), this.hls.trigger(o.a.ERROR, { - type: u.b.MEDIA_ERROR, - details: u.a.BUFFER_APPENDING_ERROR, - fatal: !1 - }) - }, e.prototype.onBufferEos = function(t) { - var e = this.sourceBuffer, - r = t.type; - for (var i in e) r && i !== r || e[i].ended || (e[i].ended = !0, l.b.log(i + " sourceBuffer now EOS")); - this.checkEos() - }, e.prototype.checkEos = function() { - var t = this.sourceBuffer, - e = this.mediaSource; - if (!e || "open" !== e.readyState) return void(this._needsEos = !1); - for (var r in t) { - var i = t[r]; - if (!i.ended) return; - if (i.updating) return void(this._needsEos = !0) - } - l.b.log("all media data available, signal endOfStream() to MediaSource and stop loading fragment"); - try { - e.endOfStream() - } catch (t) { - l.b.warn("exception while calling mediaSource.endOfStream()") - } - this._needsEos = !1 - }, e.prototype.onBufferFlushing = function(t) { - this.flushRange.push({ - start: t.startOffset, - end: t.endOffset, - type: t.type - }), this.flushBufferCounter = 0, this.doFlush() - }, e.prototype.onLevelUpdated = function(t) { - var e = t.details; - e.fragments.length > 0 && (this._levelDuration = e.totalduration + e.fragments[0].start, this._live = e.live, this.updateMediaElementDuration()) - }, e.prototype.updateMediaElementDuration = function() { - var t = this.hls.config, - e = void 0; - if (null !== this._levelDuration && this.media && this.mediaSource && this.sourceBuffer && 0 !== this.media.readyState && "open" === this.mediaSource.readyState) { - for (var r in this.sourceBuffer) - if (!0 === this.sourceBuffer[r].updating) return; - e = this.media.duration, null === this._msDuration && (this._msDuration = this.mediaSource.duration), !0 === this._live && !0 === t.liveDurationInfinity ? (l.b.log("Media Source duration is set to Infinity"), this._msDuration = this.mediaSource.duration = 1 / 0) : (this._levelDuration > this._msDuration && this._levelDuration > e || e === 1 / 0 || isNaN(e)) && (l.b.log("Updating Media Source duration to " + this._levelDuration.toFixed(3)), this._msDuration = this.mediaSource.duration = this._levelDuration) - } - }, e.prototype.doFlush = function() { - for (; this.flushRange.length;) { - var t = this.flushRange[0]; - if (!this.flushBuffer(t.start, t.end, t.type)) return void(this._needsFlush = !0); - this.flushRange.shift(), this.flushBufferCounter = 0 - } - if (0 === this.flushRange.length) { - this._needsFlush = !1; - var e = 0, - r = this.sourceBuffer; - try { - for (var i in r) e += r[i].buffered.length - } catch (t) { - l.b.error("error while accessing sourceBuffer.buffered") - } - this.appended = e, this.hls.trigger(o.a.BUFFER_FLUSHED) - } - }, e.prototype.doAppending = function() { - var t = this.hls, - e = this.sourceBuffer, - r = this.segments; - if (Object.keys(e).length) { - if (this.media.error) return this.segments = [], void l.b.error("trying to append although a media error occured, flush segment and abort"); - if (this.appending) return; - if (r && r.length) { - var i = r.shift(); - try { - var a = i.type, - n = e[a]; - n ? n.updating ? r.unshift(i) : (n.ended = !1, this.parent = i.parent, n.appendBuffer(i.data), this.appendError = 0, this.appended++, this.appending = !0) : this.onSBUpdateEnd() - } catch (e) { - l.b.error("error while trying to append buffer:" + e.message), r.unshift(i); - var s = { - type: u.b.MEDIA_ERROR, - parent: i.parent - }; - 22 !== e.code ? (this.appendError ? this.appendError++ : this.appendError = 1, s.details = u.a.BUFFER_APPEND_ERROR, this.appendError > t.config.appendErrorMaxRetry ? (l.b.log("fail " + t.config.appendErrorMaxRetry + " times to append segment in sourceBuffer"), r = [], s.fatal = !0, t.trigger(o.a.ERROR, s)) : (s.fatal = !1, t.trigger(o.a.ERROR, s))) : (this.segments = [], s.details = u.a.BUFFER_FULL_ERROR, s.fatal = !1, t.trigger(o.a.ERROR, s)) - } - } - } - }, e.prototype.flushBuffer = function(t, e, r) { - var i = void 0, - a = void 0, - n = void 0, - o = void 0, - s = void 0, - u = void 0, - d = this.sourceBuffer; - if (Object.keys(d).length) { - if (l.b.log("flushBuffer,pos/start/end: " + this.media.currentTime.toFixed(3) + "/" + t + "/" + e), this.flushBufferCounter < this.appended) { - for (var c in d) - if (!r || c === r) { - if (i = d[c], i.ended = !1, i.updating) return l.b.warn("cannot flush, sb updating in progress"), !1; - try { - for (a = 0; a < i.buffered.length; a++) - if (n = i.buffered.start(a), o = i.buffered.end(a), -1 !== navigator.userAgent.toLowerCase().indexOf("firefox") && e === Number.POSITIVE_INFINITY ? (s = t, u = e) : (s = Math.max(n, t), u = Math.min(o, e)), Math.min(u, o) - s > .5) return this.flushBufferCounter++, l.b.log("flush " + c + " [" + s + "," + u + "], of [" + n + "," + o + "], pos:" + this.media.currentTime), i.remove(s, u), !1 - } catch (t) { - l.b.warn("exception while accessing sourcebuffer, it might have been removed from MediaSource") - } - } - } else l.b.warn("abort flushing too many retries"); - l.b.log("buffer flushed") - } - return !0 - }, e - }(s.a); - e.a = h - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(1), - s = r(3), - l = function() { - function t(t, e) { - for (var r = 0; r < e.length; r++) { - var i = e[r]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(t, i.key, i) - } - } - return function(e, r, i) { - return r && t(e.prototype, r), i && t(e, i), e - } - }(), - u = function(t) { - function e(r) { - i(this, e); - var n = a(this, t.call(this, r, o.a.FPS_DROP_LEVEL_CAPPING, o.a.MEDIA_ATTACHING, o.a.MANIFEST_PARSED, o.a.BUFFER_CODECS)); - return n.autoLevelCapping = Number.POSITIVE_INFINITY, n.firstLevel = null, n.levels = [], n.media = null, n.restrictedLevels = [], n.timer = null, n - } - return n(e, t), e.prototype.destroy = function() { - this.hls.config.capLevelToPlayerSize && (this.media = null, this._stopCapping()) - }, e.prototype.onFpsDropLevelCapping = function(t) { - e.isLevelAllowed(t.droppedLevel, this.restrictedLevels) && this.restrictedLevels.push(t.droppedLevel) - }, e.prototype.onMediaAttaching = function(t) { - this.media = t.media instanceof window.HTMLVideoElement ? t.media : null - }, e.prototype.onManifestParsed = function(t) { - var e = this.hls; - this.restrictedLevels = [], this.levels = t.levels, this.firstLevel = t.firstLevel, e.config.capLevelToPlayerSize && (t.video || t.levels.length && t.altAudio) && this._startCapping() - }, e.prototype.onBufferCodecs = function(t) { - this.hls.config.capLevelToPlayerSize && t.video && this._startCapping() - }, e.prototype.onLevelsUpdated = function(t) { - this.levels = t.levels - }, e.prototype.detectPlayerSize = function() { - if (this.media) { - var t = this.levels ? this.levels.length : 0; - if (t) { - var e = this.hls; - e.autoLevelCapping = this.getMaxLevel(t - 1), e.autoLevelCapping > this.autoLevelCapping && e.streamController.nextLevelSwitch(), this.autoLevelCapping = e.autoLevelCapping - } - } - }, e.prototype.getMaxLevel = function(t) { - var r = this; - if (!this.levels) return -1; - var i = this.levels.filter(function(i, a) { - return e.isLevelAllowed(a, r.restrictedLevels) && a <= t - }); - return e.getMaxLevelByMediaSize(i, this.mediaWidth, this.mediaHeight) - }, e.prototype._startCapping = function() { - this.timer || (this.autoLevelCapping = Number.POSITIVE_INFINITY, this.hls.firstLevel = this.getMaxLevel(this.firstLevel), clearInterval(this.timer), this.timer = setInterval(this.detectPlayerSize.bind(this), 1e3), this.detectPlayerSize()) - }, e.prototype._stopCapping = function() { - this.restrictedLevels = [], this.firstLevel = null, this.autoLevelCapping = Number.POSITIVE_INFINITY, this.timer && (this.timer = clearInterval(this.timer), this.timer = null) - }, e.isLevelAllowed = function(t) { - return -1 === (arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : []).indexOf(t) - }, e.getMaxLevelByMediaSize = function(t, e, r) { - if (!t || t && !t.length) return -1; - for (var i = t.length - 1, a = 0; a < t.length; a += 1) { - var n = t[a]; - if ((n.width >= e || n.height >= r) && function(t, e) { - return !e || (t.width !== e.width || t.height !== e.height) - }(n, t[a + 1])) { - i = a; - break - } - } - return i - }, l(e, [{ - key: "mediaWidth", - get: function() { - var t = void 0, - r = this.media; - return r && (t = r.width || r.clientWidth || r.offsetWidth, t *= e.contentScaleFactor), t - } - }, { - key: "mediaHeight", - get: function() { - var t = void 0, - r = this.media; - return r && (t = r.height || r.clientHeight || r.offsetHeight, t *= e.contentScaleFactor), t - } - }], [{ - key: "contentScaleFactor", - get: function() { - var t = 1; - try { - t = window.devicePixelRatio - } catch (t) {} - return t - } - }]), e - }(s.a); - e.a = u - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(1), - s = r(3), - l = r(0), - u = window, - d = u.performance, - c = function(t) { - function e(r) { - return i(this, e), a(this, t.call(this, r, o.a.MEDIA_ATTACHING)) - } - return n(e, t), e.prototype.destroy = function() { - this.timer && clearInterval(this.timer), this.isVideoPlaybackQualityAvailable = !1 - }, e.prototype.onMediaAttaching = function(t) { - var e = this.hls.config; - if (e.capLevelOnFPSDrop) { - "function" == typeof(this.video = t.media instanceof window.HTMLVideoElement ? t.media : null).getVideoPlaybackQuality && (this.isVideoPlaybackQualityAvailable = !0), clearInterval(this.timer), this.timer = setInterval(this.checkFPSInterval.bind(this), e.fpsDroppedMonitoringPeriod) - } - }, e.prototype.checkFPS = function(t, e, r) { - var i = d.now(); - if (e) { - if (this.lastTime) { - var a = i - this.lastTime, - n = r - this.lastDroppedFrames, - s = e - this.lastDecodedFrames, - u = 1e3 * n / a, - c = this.hls; - if (c.trigger(o.a.FPS_DROP, { - currentDropped: n, - currentDecoded: s, - totalDroppedFrames: r - }), u > 0 && n > c.config.fpsDroppedMonitoringThreshold * s) { - var h = c.currentLevel; - l.b.warn("drop FPS ratio greater than max allowed value for currentLevel: " + h), h > 0 && (-1 === c.autoLevelCapping || c.autoLevelCapping >= h) && (h -= 1, c.trigger(o.a.FPS_DROP_LEVEL_CAPPING, { - level: h, - droppedLevel: c.currentLevel - }), c.autoLevelCapping = h, c.streamController.nextLevelSwitch()) - } - } - this.lastTime = i, this.lastDroppedFrames = r, this.lastDecodedFrames = e - } - }, e.prototype.checkFPSInterval = function() { - var t = this.video; - if (t) - if (this.isVideoPlaybackQualityAvailable) { - var e = t.getVideoPlaybackQuality(); - this.checkFPS(t, e.totalVideoFrames, e.droppedVideoFrames) - } else this.checkFPS(t, t.webkitDecodedFrameCount, t.webkitDroppedFrameCount) - }, e - }(s.a); - e.a = c - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = r(0), - n = window, - o = n.performance, - s = n.XMLHttpRequest, - l = function() { - function t(e) { - i(this, t), e && e.xhrSetup && (this.xhrSetup = e.xhrSetup) - } - return t.prototype.destroy = function() { - this.abort(), this.loader = null - }, t.prototype.abort = function() { - var t = this.loader; - t && 4 !== t.readyState && (this.stats.aborted = !0, t.abort()), window.clearTimeout(this.requestTimeout), this.requestTimeout = null, window.clearTimeout(this.retryTimeout), this.retryTimeout = null - }, t.prototype.load = function(t, e, r) { - this.context = t, this.config = e, this.callbacks = r, this.stats = { - trequest: o.now(), - retry: 0 - }, this.retryDelay = e.retryDelay, this.loadInternal() - }, t.prototype.loadInternal = function() { - var t = void 0, - e = this.context; - t = this.loader = new s; - var r = this.stats; - r.tfirst = 0, r.loaded = 0; - var i = this.xhrSetup; - try { - if (i) try { - i(t, e.url) - } catch (r) { - t.open("GET", e.url, !0), i(t, e.url) - } - t.readyState || t.open("GET", e.url, !0) - } catch (r) { - return void this.callbacks.onError({ - code: t.status, - text: r.message - }, e, t) - } - e.rangeEnd && t.setRequestHeader("Range", "bytes=" + e.rangeStart + "-" + (e.rangeEnd - 1)), t.onreadystatechange = this.readystatechange.bind(this), t.onprogress = this.loadprogress.bind(this), t.responseType = e.responseType, this.requestTimeout = window.setTimeout(this.loadtimeout.bind(this), this.config.timeout), t.send() - }, t.prototype.readystatechange = function(t) { - var e = t.currentTarget, - r = e.readyState, - i = this.stats, - n = this.context, - s = this.config; - if (!i.aborted && r >= 2) - if (window.clearTimeout(this.requestTimeout), 0 === i.tfirst && (i.tfirst = Math.max(o.now(), i.trequest)), 4 === r) { - var l = e.status; - if (l >= 200 && l < 300) { - i.tload = Math.max(i.tfirst, o.now()); - var u = void 0, - d = void 0; - "arraybuffer" === n.responseType ? (u = e.response, d = u.byteLength) : (u = e.responseText, d = u.length), i.loaded = i.total = d; - var c = { - url: e.responseURL, - data: u - }; - this.callbacks.onSuccess(c, i, n, e) - } else i.retry >= s.maxRetry || l >= 400 && l < 499 ? (a.b.error(l + " while loading " + n.url), this.callbacks.onError({ - code: l, - text: e.statusText - }, n, e)) : (a.b.warn(l + " while loading " + n.url + ", retrying in " + this.retryDelay + "..."), this.destroy(), this.retryTimeout = window.setTimeout(this.loadInternal.bind(this), this.retryDelay), this.retryDelay = Math.min(2 * this.retryDelay, s.maxRetryDelay), i.retry++) - } else this.requestTimeout = window.setTimeout(this.loadtimeout.bind(this), s.timeout) - }, t.prototype.loadtimeout = function() { - a.b.warn("timeout while loading " + this.context.url), this.callbacks.onTimeout(this.stats, this.context, null) - }, t.prototype.loadprogress = function(t) { - var e = t.currentTarget, - r = this.stats; - r.loaded = t.loaded, t.lengthComputable && (r.total = t.total); - var i = this.callbacks.onProgress; - i && i(r, this.context, null, e) - }, t - }(); - e.a = l - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(1), - s = r(8), - l = r(0), - u = r(2), - d = function() { - function t(t, e) { - for (var r = 0; r < e.length; r++) { - var i = e[r]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(t, i.key, i) - } - } - return function(e, r, i) { - return r && t(e.prototype, r), i && t(e, i), e - } - }(), - c = function(t) { - function e(r) { - i(this, e); - var n = a(this, t.call(this, r, o.a.MANIFEST_LOADING, o.a.MANIFEST_PARSED, o.a.AUDIO_TRACK_LOADED, o.a.AUDIO_TRACK_SWITCHED, o.a.LEVEL_LOADED, o.a.ERROR)); - return n.trackId = -1, n.tracks = [], n.trackIdBlacklist = Object.create(null), n.audioGroupId = null, n - } - return n(e, t), e.prototype.onManifestLoading = function() { - this.tracks = [], this.trackId = -1 - }, e.prototype.onManifestParsed = function(t) { - var e = this.tracks = t.audioTracks || []; - this.hls.trigger(o.a.AUDIO_TRACKS_UPDATED, { - audioTracks: e - }) - }, e.prototype.onAudioTrackLoaded = function(t) { - if (t.id >= this.tracks.length) return void l.b.warn("Invalid audio track id:", t.id); - if (l.b.log("audioTrack " + t.id + " loaded"), this.tracks[t.id].details = t.details, t.details.live && !this.hasInterval()) { - var e = 1e3 * t.details.targetduration; - this.setInterval(e) - }!t.details.live && this.hasInterval() && this.clearInterval() - }, e.prototype.onAudioTrackSwitched = function(t) { - var e = this.tracks[t.id].groupId; - e && this.audioGroupId !== e && (this.audioGroupId = e) - }, e.prototype.onLevelLoaded = function(t) { - var e = this.hls.levels[t.level]; - if (e.audioGroupIds) { - var r = e.audioGroupIds[e.urlId]; - this.audioGroupId !== r && (this.audioGroupId = r, this._selectInitialAudioTrack()) - } - }, e.prototype.onError = function(t) { - t.type === u.b.NETWORK_ERROR && (t.fatal && this.clearInterval(), t.details === u.a.AUDIO_TRACK_LOAD_ERROR && (l.b.warn("Network failure on audio-track id:", t.context.id), this._handleLoadError())) - }, e.prototype.doTick = function() { - this._updateTrack(this.trackId) - }, e.prototype._selectInitialAudioTrack = function() { - var t = this, - e = this.tracks; - if (e.length) { - var r = this.tracks[this.trackId], - i = null; - r && (i = r.name); - var a = e.filter(function(t) { - return t.default - }); - a.length ? e = a : l.b.warn("No default audio tracks defined"); - var n = !1, - s = function() { - e.forEach(function(e) { - n || t.audioGroupId && e.groupId !== t.audioGroupId || i && i !== e.name || (t.audioTrack = e.id, n = !0) - }) - }; - s(), n || (i = null, s()), n || (l.b.error("No track found for running audio group-ID: " + this.audioGroupId), this.hls.trigger(o.a.ERROR, { - type: u.b.MEDIA_ERROR, - details: u.a.AUDIO_TRACK_LOAD_ERROR, - fatal: !0 - })) - } - }, e.prototype._needsTrackLoading = function(t) { - var e = t.details; - return !e || (!!e.live || void 0) - }, e.prototype._loadTrackDetailsIfNeeded = function(t) { - if (this._needsTrackLoading(t)) { - var e = t.url, - r = t.id; - l.b.log("loading audio-track playlist for id: " + r), this.hls.trigger(o.a.AUDIO_TRACK_LOADING, { - url: e, - id: r - }) - } - }, e.prototype._updateTrack = function(t) { - if (!(t < 0 || t >= this.tracks.length)) { - this.clearInterval(), this.trackId = t, l.b.log("trying to update audio-track " + t); - var e = this.tracks[t]; - this._loadTrackDetailsIfNeeded(e) - } - }, e.prototype._handleLoadError = function() { - this.trackIdBlacklist[this.trackId] = !0; - var t = this.trackId, - e = this.tracks[t], - r = e.name, - i = e.language, - a = e.groupId; - l.b.warn("Loading failed on audio track id: " + t + ", group-id: " + a + ', name/language: "' + r + '" / "' + i + '"'); - for (var n = t, o = 0; o < this.tracks.length; o++) - if (!this.trackIdBlacklist[o]) { - var s = this.tracks[o]; - if (s.name === r) { - n = o; - break - } - } if (n === t) return void l.b.warn('No fallback audio-track found for name/language: "' + r + '" / "' + i + '"'); - l.b.log("Attempting audio-track fallback id:", n, "group-id:", this.tracks[n].groupId), this.audioTrack = n - }, d(e, [{ - key: "audioTracks", - get: function() { - return this.tracks - } - }, { - key: "audioTrack", - get: function() { - return this.trackId - }, - set: function(t) { - if (this.trackId === t && this.tracks[this.trackId].details) return void l.b.debug("Same id as current audio-track passed, and track details available -> no-op"); - if (t < 0 || t >= this.tracks.length) return void l.b.warn("Invalid id passed to audio-track controller"); - var e = this.tracks[t]; - l.b.log("Now switching to audio-track index " + t), this.clearInterval(), this.trackId = t; - var r = e.url, - i = e.type, - a = e.id; - this.hls.trigger(o.a.AUDIO_TRACK_SWITCHING, { - id: a, - type: i, - url: r - }), this._loadTrackDetailsIfNeeded(e) - } - }]), e - }(s.a); - e.a = c - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(6), - s = r(11), - l = r(20), - u = r(1), - d = r(15), - c = r(24), - h = r(2), - f = r(0), - p = r(25), - v = r(8), - g = r(10), - y = r(9), - m = function() { - function t(t, e) { - for (var r = 0; r < e.length; r++) { - var i = e[r]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(t, i.key, i) - } - } - return function(e, r, i) { - return r && t(e.prototype, r), i && t(e, i), e - } - }(), - b = window, - E = b.performance, - T = { - STOPPED: "STOPPED", - STARTING: "STARTING", - IDLE: "IDLE", - PAUSED: "PAUSED", - KEY_LOADING: "KEY_LOADING", - FRAG_LOADING: "FRAG_LOADING", - FRAG_LOADING_WAITING_RETRY: "FRAG_LOADING_WAITING_RETRY", - WAITING_TRACK: "WAITING_TRACK", - PARSING: "PARSING", - PARSED: "PARSED", - BUFFER_FLUSHING: "BUFFER_FLUSHING", - ENDED: "ENDED", - ERROR: "ERROR", - WAITING_INIT_PTS: "WAITING_INIT_PTS" - }, - S = function(t) { - function e(r, n) { - i(this, e); - var o = a(this, t.call(this, r, u.a.MEDIA_ATTACHED, u.a.MEDIA_DETACHING, u.a.AUDIO_TRACKS_UPDATED, u.a.AUDIO_TRACK_SWITCHING, u.a.AUDIO_TRACK_LOADED, u.a.KEY_LOADED, u.a.FRAG_LOADED, u.a.FRAG_PARSING_INIT_SEGMENT, u.a.FRAG_PARSING_DATA, u.a.FRAG_PARSED, u.a.ERROR, u.a.BUFFER_RESET, u.a.BUFFER_CREATED, u.a.BUFFER_APPENDED, u.a.BUFFER_FLUSHED, u.a.INIT_PTS_FOUND)); - return o.fragmentTracker = n, o.config = r.config, o.audioCodecSwap = !1, o._state = T.STOPPED, o.initPTS = [], o.waitingFragment = null, o.videoTrackCC = null, o - } - return n(e, t), e.prototype.onHandlerDestroying = function() { - this.stopLoad(), t.prototype.onHandlerDestroying.call(this) - }, e.prototype.onHandlerDestroyed = function() { - this.state = T.STOPPED, this.fragmentTracker = null, t.prototype.onHandlerDestroyed.call(this) - }, e.prototype.onInitPtsFound = function(t) { - var e = t.id, - r = t.frag.cc, - i = t.initPTS; - "main" === e && (this.initPTS[r] = i, this.videoTrackCC = r, f.b.log("InitPTS for cc: " + r + " found from video track: " + i), this.state === T.WAITING_INIT_PTS && this.tick()) - }, e.prototype.startLoad = function(t) { - if (this.tracks) { - var e = this.lastCurrentTime; - this.stopLoad(), this.setInterval(100), this.fragLoadError = 0, e > 0 && -1 === t ? (f.b.log("audio:override startPosition with lastCurrentTime @" + e.toFixed(3)), this.state = T.IDLE) : (this.lastCurrentTime = this.startPosition ? this.startPosition : t, this.state = T.STARTING), this.nextLoadPosition = this.startPosition = this.lastCurrentTime, this.tick() - } else this.startPosition = t, this.state = T.STOPPED - }, e.prototype.stopLoad = function() { - var t = this.fragCurrent; - t && (t.loader && t.loader.abort(), this.fragmentTracker.removeFragment(t), this.fragCurrent = null), this.fragPrevious = null, this.demuxer && (this.demuxer.destroy(), this.demuxer = null), this.state = T.STOPPED - }, e.prototype.doTick = function() { - var t = void 0, - e = void 0, - r = void 0, - i = this.hls, - a = i.config; - switch (this.state) { - case T.ERROR: - case T.PAUSED: - case T.BUFFER_FLUSHING: - break; - case T.STARTING: - this.state = T.WAITING_TRACK, this.loadedmetadata = !1; - break; - case T.IDLE: - var n = this.tracks; - if (!n) break; - if (!this.media && (this.startFragRequested || !a.startFragPrefetch)) break; - if (this.loadedmetadata) t = this.media.currentTime; - else if (void 0 === (t = this.nextLoadPosition)) break; - var l = this.mediaBuffer ? this.mediaBuffer : this.media, - d = this.videoBuffer ? this.videoBuffer : this.media, - c = s.a.bufferInfo(l, t, a.maxBufferHole), - h = s.a.bufferInfo(d, t, a.maxBufferHole), - v = c.len, - y = c.end, - m = this.fragPrevious, - b = Math.min(a.maxBufferLength, a.maxMaxBufferLength), - S = Math.max(b, h.len), - R = this.audioSwitch, - A = this.trackId; - if ((v < S || R) && A < n.length) { - if (void 0 === (r = n[A].details)) { - this.state = T.WAITING_TRACK; - break - } - if (!R && !r.live && m && m.sn === r.endSN && !c.nextStart && (!this.media.seeking || this.media.duration - y < m.duration / 2)) { - this.hls.trigger(u.a.BUFFER_EOS, { - type: "audio" - }), this.state = T.ENDED; - break - } - var _ = r.fragments, - w = _.length, - L = _[0].start, - D = _[w - 1].start + _[w - 1].duration, - I = void 0; - if (R) - if (r.live && !r.PTSKnown) f.b.log("switching audiotrack, live stream, unknown PTS,load first fragment"), y = 0; - else if (y = t, r.PTSKnown && t < L) { - if (!(c.end > L || c.nextStart)) return; - f.b.log("alt audio track ahead of main track, seek to start of alt audio track"), this.media.currentTime = L + .05 - } - if (r.initSegment && !r.initSegment.data) I = r.initSegment; - else if (y <= L) { - if (I = _[0], null !== this.videoTrackCC && I.cc !== this.videoTrackCC && (I = Object(p.b)(_, this.videoTrackCC)), r.live && I.loadIdx && I.loadIdx === this.fragLoadIdx) { - var k = c.nextStart ? c.nextStart : L; - return f.b.log("no alt audio available @currentTime:" + this.media.currentTime + ", seeking @" + (k + .05)), void(this.media.currentTime = k + .05) - } - } else { - var O = void 0, - C = a.maxFragLookUpTolerance, - P = m ? _[m.sn - _[0].sn + 1] : void 0, - x = function(t) { - var e = Math.min(C, t.duration); - return t.start + t.duration - e <= y ? 1 : t.start - e > y && t.start ? -1 : 0 - }; - y < D ? (y > D - C && (C = 0), O = P && !x(P) ? P : o.a.search(_, x)) : O = _[w - 1], O && (I = O, L = O.start, m && I.level === m.level && I.sn === m.sn && (I.sn < r.endSN ? (I = _[I.sn + 1 - r.startSN], f.b.log("SN just loaded, load next one: " + I.sn)) : I = null)) - } - I && (I.encrypted ? (f.b.log("Loading key for " + I.sn + " of [" + r.startSN + " ," + r.endSN + "],track " + A), this.state = T.KEY_LOADING, i.trigger(u.a.KEY_LOADING, { - frag: I - })) : (f.b.log("Loading " + I.sn + ", cc: " + I.cc + " of [" + r.startSN + " ," + r.endSN + "],track " + A + ", currentTime:" + t + ",bufferEnd:" + y.toFixed(3)), (R || this.fragmentTracker.getState(I) === g.a.NOT_LOADED) && (this.fragCurrent = I, this.startFragRequested = !0, isNaN(I.sn) || (this.nextLoadPosition = I.start + I.duration), i.trigger(u.a.FRAG_LOADING, { - frag: I - }), this.state = T.FRAG_LOADING))) - } - break; - case T.WAITING_TRACK: - e = this.tracks[this.trackId], e && e.details && (this.state = T.IDLE); - break; - case T.FRAG_LOADING_WAITING_RETRY: - var F = E.now(), - N = this.retryDate; - l = this.media; - var M = l && l.seeking; - (!N || F >= N || M) && (f.b.log("audioStreamController: retryDate reached, switch back to IDLE state"), this.state = T.IDLE); - break; - case T.WAITING_INIT_PTS: - var U = this.videoTrackCC; - if (void 0 === this.initPTS[U]) break; - var B = this.waitingFragment; - if (B) { - var G = B.frag.cc; - U !== G ? (e = this.tracks[this.trackId], e.details && e.details.live && (f.b.warn("Waiting fragment CC (" + G + ") does not match video track CC (" + U + ")"), this.waitingFragment = null, this.state = T.IDLE)) : (this.state = T.FRAG_LOADING, this.onFragLoaded(this.waitingFragment), this.waitingFragment = null) - } else this.state = T.IDLE; - break; - case T.STOPPED: - case T.FRAG_LOADING: - case T.PARSING: - case T.PARSED: - case T.ENDED: - } - }, e.prototype.onMediaAttached = function(t) { - var e = this.media = this.mediaBuffer = t.media; - this.onvseeking = this.onMediaSeeking.bind(this), this.onvended = this.onMediaEnded.bind(this), e.addEventListener("seeking", this.onvseeking), e.addEventListener("ended", this.onvended); - var r = this.config; - this.tracks && r.autoStartLoad && this.startLoad(r.startPosition) - }, e.prototype.onMediaDetaching = function() { - var t = this.media; - t && t.ended && (f.b.log("MSE detaching and video ended, reset startPosition"), this.startPosition = this.lastCurrentTime = 0), t && (t.removeEventListener("seeking", this.onvseeking), t.removeEventListener("ended", this.onvended), this.onvseeking = this.onvseeked = this.onvended = null), this.media = this.mediaBuffer = this.videoBuffer = null, this.loadedmetadata = !1, this.stopLoad() - }, e.prototype.onMediaSeeking = function() { - this.state === T.ENDED && (this.state = T.IDLE), this.media && (this.lastCurrentTime = this.media.currentTime), this.tick() - }, e.prototype.onMediaEnded = function() { - this.startPosition = this.lastCurrentTime = 0 - }, e.prototype.onAudioTracksUpdated = function(t) { - f.b.log("audio tracks updated"), this.tracks = t.audioTracks - }, e.prototype.onAudioTrackSwitching = function(t) { - var e = !!t.url; - this.trackId = t.id, this.fragCurrent = null, this.state = T.PAUSED, this.waitingFragment = null, e ? this.setInterval(100) : this.demuxer && (this.demuxer.destroy(), this.demuxer = null), e && (this.audioSwitch = !0, this.state = T.IDLE), this.tick() - }, e.prototype.onAudioTrackLoaded = function(t) { - var e = t.details, - r = t.id, - i = this.tracks[r], - a = e.totalduration, - n = 0; - if (f.b.log("track " + r + " loaded [" + e.startSN + "," + e.endSN + "],duration:" + a), e.live) { - var o = i.details; - o && e.fragments.length > 0 ? (d.b(o, e), n = e.fragments[0].start, e.PTSKnown ? f.b.log("live audio playlist sliding:" + n.toFixed(3)) : f.b.log("live audio playlist - outdated PTS, unknown sliding")) : (e.PTSKnown = !1, f.b.log("live audio playlist - first load, unknown sliding")) - } else e.PTSKnown = !1; - if (i.details = e, !this.startFragRequested) { - if (-1 === this.startPosition) { - var s = e.startTimeOffset; - isNaN(s) ? this.startPosition = 0 : (f.b.log("start time offset found in playlist, adjust startPosition to " + s), this.startPosition = s) - } - this.nextLoadPosition = this.startPosition - } - this.state === T.WAITING_TRACK && (this.state = T.IDLE), this.tick() - }, e.prototype.onKeyLoaded = function() { - this.state === T.KEY_LOADING && (this.state = T.IDLE, this.tick()) - }, e.prototype.onFragLoaded = function(t) { - var e = this.fragCurrent, - r = t.frag; - if (this.state === T.FRAG_LOADING && e && "audio" === r.type && r.level === e.level && r.sn === e.sn) { - var i = this.tracks[this.trackId], - a = i.details, - n = a.totalduration, - o = e.level, - s = e.sn, - d = e.cc, - c = this.config.defaultAudioCodec || i.audioCodec || "mp4a.40.2", - h = this.stats = t.stats; - if ("initSegment" === s) this.state = T.IDLE, h.tparsed = h.tbuffered = E.now(), a.initSegment.data = t.payload, this.hls.trigger(u.a.FRAG_BUFFERED, { - stats: h, - frag: e, - id: "audio" - }), this.tick(); - else { - this.state = T.PARSING, this.appended = !1, this.demuxer || (this.demuxer = new l.a(this.hls, "audio")); - var p = this.initPTS[d], - v = a.initSegment ? a.initSegment.data : []; - if (a.initSegment || void 0 !== p) { - this.pendingBuffering = !0, f.b.log("Demuxing " + s + " of [" + a.startSN + " ," + a.endSN + "],track " + o); - this.demuxer.push(t.payload, v, c, null, e, n, !1, p) - } else f.b.log("unknown video PTS for continuity counter " + d + ", waiting for video PTS before demuxing audio frag " + s + " of [" + a.startSN + " ," + a.endSN + "],track " + o), this.waitingFragment = t, this.state = T.WAITING_INIT_PTS - } - } - this.fragLoadError = 0 - }, e.prototype.onFragParsingInitSegment = function(t) { - var e = this.fragCurrent, - r = t.frag; - if (e && "audio" === t.id && r.sn === e.sn && r.level === e.level && this.state === T.PARSING) { - var i = t.tracks, - a = void 0; - if (i.video && delete i.video, a = i.audio) { - a.levelCodec = a.codec, a.id = t.id, this.hls.trigger(u.a.BUFFER_CODECS, i), f.b.log("audio track:audio,container:" + a.container + ",codecs[level/parsed]=[" + a.levelCodec + "/" + a.codec + "]"); - var n = a.initSegment; - if (n) { - var o = { - type: "audio", - data: n, - parent: "audio", - content: "initSegment" - }; - this.audioSwitch ? this.pendingData = [o] : (this.appended = !0, this.pendingBuffering = !0, this.hls.trigger(u.a.BUFFER_APPENDING, o)) - } - this.tick() - } - } - }, e.prototype.onFragParsingData = function(t) { - var e = this, - r = this.fragCurrent, - i = t.frag; - if (r && "audio" === t.id && "audio" === t.type && i.sn === r.sn && i.level === r.level && this.state === T.PARSING) { - var a = this.trackId, - n = this.tracks[a], - o = this.hls; - isNaN(t.endPTS) && (t.endPTS = t.startPTS + r.duration, t.endDTS = t.startDTS + r.duration), r.addElementaryStream(y.a.ElementaryStreamTypes.AUDIO), f.b.log("parsed " + t.type + ",PTS:[" + t.startPTS.toFixed(3) + "," + t.endPTS.toFixed(3) + "],DTS:[" + t.startDTS.toFixed(3) + "/" + t.endDTS.toFixed(3) + "],nb:" + t.nb), d.c(n.details, r, t.startPTS, t.endPTS); - var s = this.audioSwitch, - l = this.media, - c = !1; - if (s && l) - if (l.readyState) { - var p = l.currentTime; - f.b.log("switching audio track : currentTime:" + p), p >= t.startPTS && (f.b.log("switching audio track : flushing all audio"), this.state = T.BUFFER_FLUSHING, o.trigger(u.a.BUFFER_FLUSHING, { - startOffset: 0, - endOffset: Number.POSITIVE_INFINITY, - type: "audio" - }), c = !0, this.audioSwitch = !1, o.trigger(u.a.AUDIO_TRACK_SWITCHED, { - id: a - })) - } else this.audioSwitch = !1, o.trigger(u.a.AUDIO_TRACK_SWITCHED, { - id: a - }); - var v = this.pendingData; - if (!v) return f.b.warn("Apparently attempt to enqueue media payload without codec initialization data upfront"), void o.trigger(u.a.ERROR, { - type: h.b.MEDIA_ERROR, - details: null, - fatal: !0 - }); - this.audioSwitch || ([t.data1, t.data2].forEach(function(e) { - e && e.length && v.push({ - type: t.type, - data: e, - parent: "audio", - content: "data" - }) - }), !c && v.length && (v.forEach(function(t) { - e.state === T.PARSING && (e.pendingBuffering = !0, e.hls.trigger(u.a.BUFFER_APPENDING, t)) - }), this.pendingData = [], this.appended = !0)), this.tick() - } - }, e.prototype.onFragParsed = function(t) { - var e = this.fragCurrent, - r = t.frag; - e && "audio" === t.id && r.sn === e.sn && r.level === e.level && this.state === T.PARSING && (this.stats.tparsed = E.now(), this.state = T.PARSED, this._checkAppendedParsed()) - }, e.prototype.onBufferReset = function() { - this.mediaBuffer = this.videoBuffer = null, this.loadedmetadata = !1 - }, e.prototype.onBufferCreated = function(t) { - var e = t.tracks.audio; - e && (this.mediaBuffer = e.buffer, this.loadedmetadata = !0), t.tracks.video && (this.videoBuffer = t.tracks.video.buffer) - }, e.prototype.onBufferAppended = function(t) { - if ("audio" === t.parent) { - var e = this.state; - e !== T.PARSING && e !== T.PARSED || (this.pendingBuffering = t.pending > 0, this._checkAppendedParsed()) - } - }, e.prototype._checkAppendedParsed = function() { - if (!(this.state !== T.PARSED || this.appended && this.pendingBuffering)) { - var t = this.fragCurrent, - e = this.stats, - r = this.hls; - if (t) { - this.fragPrevious = t, e.tbuffered = E.now(), r.trigger(u.a.FRAG_BUFFERED, { - stats: e, - frag: t, - id: "audio" - }); - var i = this.mediaBuffer ? this.mediaBuffer : this.media; - f.b.log("audio buffered : " + c.a.toString(i.buffered)), this.audioSwitch && this.appended && (this.audioSwitch = !1, r.trigger(u.a.AUDIO_TRACK_SWITCHED, { - id: this.trackId - })), this.state = T.IDLE - } - this.tick() - } - }, e.prototype.onError = function(t) { - var e = t.frag; - if (!e || "audio" === e.type) switch (t.details) { - case h.a.FRAG_LOAD_ERROR: - case h.a.FRAG_LOAD_TIMEOUT: - var r = t.frag; - if (r && "audio" !== r.type) break; - if (!t.fatal) { - var i = this.fragLoadError; - i ? i++ : i = 1; - var a = this.config; - if (i <= a.fragLoadingMaxRetry) { - this.fragLoadError = i; - var n = Math.min(Math.pow(2, i - 1) * a.fragLoadingRetryDelay, a.fragLoadingMaxRetryTimeout); - f.b.warn("AudioStreamController: frag loading failed, retry in " + n + " ms"), this.retryDate = E.now() + n, this.state = T.FRAG_LOADING_WAITING_RETRY - } else f.b.error("AudioStreamController: " + t.details + " reaches max retry, redispatch as fatal ..."), t.fatal = !0, this.state = T.ERROR - } - break; - case h.a.AUDIO_TRACK_LOAD_ERROR: - case h.a.AUDIO_TRACK_LOAD_TIMEOUT: - case h.a.KEY_LOAD_ERROR: - case h.a.KEY_LOAD_TIMEOUT: - this.state !== T.ERROR && (this.state = t.fatal ? T.ERROR : T.IDLE, f.b.warn("AudioStreamController: " + t.details + " while loading frag, now switching to " + this.state + " state ...")); - break; - case h.a.BUFFER_FULL_ERROR: - if ("audio" === t.parent && (this.state === T.PARSING || this.state === T.PARSED)) { - var o = this.mediaBuffer, - l = this.media.currentTime; - if (o && s.a.isBuffered(o, l) && s.a.isBuffered(o, l + .5)) { - var d = this.config; - d.maxMaxBufferLength >= d.maxBufferLength && (d.maxMaxBufferLength /= 2, f.b.warn("AudioStreamController: reduce max buffer length to " + d.maxMaxBufferLength + "s")), this.state = T.IDLE - } else f.b.warn("AudioStreamController: buffer full error also media.currentTime is not buffered, flush audio buffer"), this.fragCurrent = null, this.state = T.BUFFER_FLUSHING, this.hls.trigger(u.a.BUFFER_FLUSHING, { - startOffset: 0, - endOffset: Number.POSITIVE_INFINITY, - type: "audio" - }) - } - } - }, e.prototype.onBufferFlushed = function() { - var t = this, - e = this.pendingData; - e && e.length ? (f.b.log("AudioStreamController: appending pending audio data after buffer flushed"), e.forEach(function(e) { - t.hls.trigger(u.a.BUFFER_APPENDING, e) - }), this.appended = !0, this.pendingData = [], this.state = T.PARSED) : (this.state = T.IDLE, this.fragPrevious = null, this.tick()) - }, m(e, [{ - key: "state", - set: function(t) { - if (this.state !== t) { - var e = this.state; - this._state = t, f.b.log("audio stream:" + e + "->" + t) - } - }, - get: function() { - return this._state - } - }]), e - }(v.a); - e.a = S - }, function(t, e, r) { - "use strict"; - - function i(t, e, r, i) { - for (var n = void 0, o = void 0, s = void 0, l = void 0, u = void 0, d = window.VTTCue || window.TextTrackCue, c = 0; c < i.rows.length; c++) - if (n = i.rows[c], s = !0, l = 0, u = "", !n.isEmpty()) { - for (var h = 0; h < n.chars.length; h++) n.chars[h].uchar.match(/\s/) && s ? l++ : (u += n.chars[h].uchar, s = !1); - n.cueStartTime = e, e === r && (r += 1e-4), o = new d(e, r, Object(a.b)(u.trim())), l >= 16 ? l-- : l++, navigator.userAgent.match(/Firefox\//) ? o.line = c + 1 : o.line = c > 7 ? c - 2 : c + 1, o.align = "left", o.position = Math.max(0, Math.min(100, l / 32 * 100 + (navigator.userAgent.match(/Firefox\//) ? 50 : 0))), t.addCue(o) - } - } - Object.defineProperty(e, "__esModule", { - value: !0 - }), e.newCue = i; - var a = r(27) - }, function(t, e, r) { - "use strict"; - e.a = function() { - function t(t) { - return "string" == typeof t && (!!n[t.toLowerCase()] && t.toLowerCase()) - } - - function e(t) { - return "string" == typeof t && (!!o[t.toLowerCase()] && t.toLowerCase()) - } - - function r(t) { - for (var e = 1; e < arguments.length; e++) { - var r = arguments[e]; - for (var i in r) t[i] = r[i] - } - return t - } - - function i(i, n, o) { - var s = this, - l = function() { - if ("undefined" != typeof navigator) return /MSIE\s8\.0/.test(navigator.userAgent) - }(), - u = {}; - l ? s = document.createElement("custom") : u.enumerable = !0, s.hasBeenReset = !1; - var d = "", - c = !1, - h = i, - f = n, - p = o, - v = null, - g = "", - y = !0, - m = "auto", - b = "start", - E = 50, - T = "middle", - S = 50, - R = "middle"; - if (Object.defineProperty(s, "id", r({}, u, { - get: function() { - return d - }, - set: function(t) { - d = "" + t - } - })), Object.defineProperty(s, "pauseOnExit", r({}, u, { - get: function() { - return c - }, - set: function(t) { - c = !!t - } - })), Object.defineProperty(s, "startTime", r({}, u, { - get: function() { - return h - }, - set: function(t) { - if ("number" != typeof t) throw new TypeError("Start time must be set to a number."); - h = t, this.hasBeenReset = !0 - } - })), Object.defineProperty(s, "endTime", r({}, u, { - get: function() { - return f - }, - set: function(t) { - if ("number" != typeof t) throw new TypeError("End time must be set to a number."); - f = t, this.hasBeenReset = !0 - } - })), Object.defineProperty(s, "text", r({}, u, { - get: function() { - return p - }, - set: function(t) { - p = "" + t, this.hasBeenReset = !0 - } - })), Object.defineProperty(s, "region", r({}, u, { - get: function() { - return v - }, - set: function(t) { - v = t, this.hasBeenReset = !0 - } - })), Object.defineProperty(s, "vertical", r({}, u, { - get: function() { - return g - }, - set: function(e) { - var r = t(e); - if (!1 === r) throw new SyntaxError("An invalid or illegal string was specified."); - g = r, this.hasBeenReset = !0 - } - })), Object.defineProperty(s, "snapToLines", r({}, u, { - get: function() { - return y - }, - set: function(t) { - y = !!t, this.hasBeenReset = !0 - } - })), Object.defineProperty(s, "line", r({}, u, { - get: function() { - return m - }, - set: function(t) { - if ("number" != typeof t && t !== a) throw new SyntaxError("An invalid number or illegal string was specified."); - m = t, this.hasBeenReset = !0 - } - })), Object.defineProperty(s, "lineAlign", r({}, u, { - get: function() { - return b - }, - set: function(t) { - var r = e(t); - if (!r) throw new SyntaxError("An invalid or illegal string was specified."); - b = r, this.hasBeenReset = !0 - } - })), Object.defineProperty(s, "position", r({}, u, { - get: function() { - return E - }, - set: function(t) { - if (t < 0 || t > 100) throw new Error("Position must be between 0 and 100."); - E = t, this.hasBeenReset = !0 - } - })), Object.defineProperty(s, "positionAlign", r({}, u, { - get: function() { - return T - }, - set: function(t) { - var r = e(t); - if (!r) throw new SyntaxError("An invalid or illegal string was specified."); - T = r, this.hasBeenReset = !0 - } - })), Object.defineProperty(s, "size", r({}, u, { - get: function() { - return S - }, - set: function(t) { - if (t < 0 || t > 100) throw new Error("Size must be between 0 and 100."); - S = t, this.hasBeenReset = !0 - } - })), Object.defineProperty(s, "align", r({}, u, { - get: function() { - return R - }, - set: function(t) { - var r = e(t); - if (!r) throw new SyntaxError("An invalid or illegal string was specified."); - R = r, this.hasBeenReset = !0 - } - })), s.displayState = void 0, l) return s - } - if ("undefined" != typeof window && window.VTTCue) return window.VTTCue; - var a = "auto", - n = { - "": !0, - lr: !0, - rl: !0 - }, - o = { - start: !0, - middle: !0, - end: !0, - left: !0, - right: !0 - }; - return i.prototype.getCueAsHTML = function() { - return window.WebVTT.convertCueToDOMTree(window, this.text) - }, i - }() - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - - function o(t, e) { - return t && t.label === e.name && !(t.textTrack1 || t.textTrack2) - } - - function s(t, e, r, i) { - return Math.min(e, i) - Math.max(t, r) - } - var l = r(1), - u = r(3), - d = r(65), - c = r(66), - h = r(67), - f = r(0), - p = r(26), - v = function(t) { - function e(r) { - i(this, e); - var n = a(this, t.call(this, r, l.a.MEDIA_ATTACHING, l.a.MEDIA_DETACHING, l.a.FRAG_PARSING_USERDATA, l.a.FRAG_DECRYPTED, l.a.MANIFEST_LOADING, l.a.MANIFEST_LOADED, l.a.FRAG_LOADED, l.a.LEVEL_SWITCHING, l.a.INIT_PTS_FOUND)); - if (n.hls = r, n.config = r.config, n.enabled = !0, n.Cues = r.config.cueHandler, n.textTracks = [], n.tracks = [], n.unparsedVttFrags = [], n.initPTS = void 0, n.cueRanges = [], n.captionsTracks = {}, n.captionsProperties = { - textTrack1: { - label: n.config.captionsTextTrack1Label, - languageCode: n.config.captionsTextTrack1LanguageCode - }, - textTrack2: { - label: n.config.captionsTextTrack2Label, - languageCode: n.config.captionsTextTrack2LanguageCode - } - }, n.config.enableCEA708Captions) { - var o = new c.a(n, "textTrack1"), - s = new c.a(n, "textTrack2"); - n.cea608Parser = new d.a(0, o, s) - } - return n - } - return n(e, t), e.prototype.addCues = function(t, e, r, i) { - for (var a = this.cueRanges, n = !1, o = a.length; o--;) { - var l = a[o], - u = s(l[0], l[1], e, r); - if (u >= 0 && (l[0] = Math.min(l[0], e), l[1] = Math.max(l[1], r), n = !0, u / (r - e) > .5)) return - } - n || a.push([e, r]), this.Cues.newCue(this.captionsTracks[t], e, r, i) - }, e.prototype.onInitPtsFound = function(t) { - var e = this; - void 0 === this.initPTS && (this.initPTS = t.initPTS), this.unparsedVttFrags.length && (this.unparsedVttFrags.forEach(function(t) { - e.onFragLoaded(t) - }), this.unparsedVttFrags = []) - }, e.prototype.getExistingTrack = function(t) { - var e = this.media; - if (e) - for (var r = 0; r < e.textTracks.length; r++) { - var i = e.textTracks[r]; - if (i[t]) return i - } - return null - }, e.prototype.createCaptionsTrack = function(t) { - var e = this.captionsProperties[t], - r = e.label, - i = e.languageCode, - a = this.captionsTracks; - if (!a[t]) { - var n = this.getExistingTrack(t); - if (n) a[t] = n, Object(p.a)(a[t]), Object(p.b)(a[t], this.media); - else { - var o = this.createTextTrack("captions", r, i); - o && (o[t] = !0, a[t] = o) - } - } - }, e.prototype.createTextTrack = function(t, e, r) { - var i = this.media; - if (i) return i.addTextTrack(t, e, r) - }, e.prototype.destroy = function() { - u.a.prototype.destroy.call(this) - }, e.prototype.onMediaAttaching = function(t) { - this.media = t.media, this._cleanTracks() - }, e.prototype.onMediaDetaching = function() { - var t = this.captionsTracks; - Object.keys(t).forEach(function(e) { - Object(p.a)(t[e]), delete t[e] - }) - }, e.prototype.onManifestLoading = function() { - this.lastSn = -1, this.prevCC = -1, this.vttCCs = { - ccOffset: 0, - presentationOffset: 0 - }, this._cleanTracks() - }, e.prototype._cleanTracks = function() { - var t = this.media; - if (t) { - var e = t.textTracks; - if (e) - for (var r = 0; r < e.length; r++) Object(p.a)(e[r]) - } - }, e.prototype.onManifestLoaded = function(t) { - var e = this; - if (this.textTracks = [], this.unparsedVttFrags = this.unparsedVttFrags || [], this.initPTS = void 0, this.cueRanges = [], this.config.enableWebVTT) { - this.tracks = t.subtitles || []; - var r = this.media ? this.media.textTracks : []; - this.tracks.forEach(function(t, i) { - var a = void 0; - if (i < r.length) { - var n = r[i]; - o(n, t) && (a = n) - } - a || (a = e.createTextTrack("subtitles", t.name, t.lang)), t.default ? a.mode = e.hls.subtitleDisplay ? "showing" : "hidden" : a.mode = "disabled", e.textTracks.push(a) - }) - } - }, e.prototype.onLevelSwitching = function() { - this.enabled = "NONE" !== this.hls.currentLevel.closedCaptions - }, e.prototype.onFragLoaded = function(t) { - var e = t.frag, - r = t.payload; - if ("main" === e.type) { - var i = e.sn; - if (i !== this.lastSn + 1) { - var a = this.cea608Parser; - a && a.reset() - } - this.lastSn = i - } else if ("subtitle" === e.type) - if (r.byteLength) { - if (void 0 === this.initPTS) return void this.unparsedVttFrags.push(t); - var n = e.decryptdata; - null != n && null != n.key && "AES-128" === n.method || this._parseVTTs(e, r) - } else this.hls.trigger(l.a.SUBTITLE_FRAG_PROCESSED, { - success: !1, - frag: e - }) - }, e.prototype._parseVTTs = function(t, e) { - var r = this.vttCCs; - r[t.cc] || (r[t.cc] = { - start: t.start, - prevCC: this.prevCC, - new: !0 - }, this.prevCC = t.cc); - var i = this.textTracks, - a = this.hls; - h.a.parse(e, this.initPTS, r, t.cc, function(e) { - var r = i[t.trackId]; - if ("disabled" === r.mode) return void a.trigger(l.a.SUBTITLE_FRAG_PROCESSED, { - success: !1, - frag: t - }); - e.forEach(function(t) { - if (!r.cues.getCueById(t.id)) try { - r.addCue(t) - } catch (i) { - var e = new window.TextTrackCue(t.startTime, t.endTime, t.text); - e.id = t.id, r.addCue(e) - } - }), a.trigger(l.a.SUBTITLE_FRAG_PROCESSED, { - success: !0, - frag: t - }) - }, function(e) { - f.b.log("Failed to parse VTT cue: " + e), a.trigger(l.a.SUBTITLE_FRAG_PROCESSED, { - success: !1, - frag: t - }) - }) - }, e.prototype.onFragDecrypted = function(t) { - var e = t.payload, - r = t.frag; - if ("subtitle" === r.type) { - if (void 0 === this.initPTS) return void this.unparsedVttFrags.push(t); - this._parseVTTs(r, e) - } - }, e.prototype.onFragParsingUserdata = function(t) { - if (this.enabled && this.config.enableCEA708Captions) - for (var e = 0; e < t.samples.length; e++) { - var r = this.extractCea608Data(t.samples[e].bytes); - this.cea608Parser.addData(t.samples[e].pts, r) - } - }, e.prototype.extractCea608Data = function(t) { - for (var e = 31 & t[0], r = 2, i = void 0, a = void 0, n = void 0, o = void 0, s = void 0, l = [], u = 0; u < e; u++) i = t[r++], a = 127 & t[r++], n = 127 & t[r++], o = 0 != (4 & i), s = 3 & i, 0 === a && 0 === n || o && 0 === s && (l.push(a), l.push(n)); - return l - }, e - }(u.a); - e.a = v - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = { - 42: 225, - 92: 233, - 94: 237, - 95: 243, - 96: 250, - 123: 231, - 124: 247, - 125: 209, - 126: 241, - 127: 9608, - 128: 174, - 129: 176, - 130: 189, - 131: 191, - 132: 8482, - 133: 162, - 134: 163, - 135: 9834, - 136: 224, - 137: 32, - 138: 232, - 139: 226, - 140: 234, - 141: 238, - 142: 244, - 143: 251, - 144: 193, - 145: 201, - 146: 211, - 147: 218, - 148: 220, - 149: 252, - 150: 8216, - 151: 161, - 152: 42, - 153: 8217, - 154: 9473, - 155: 169, - 156: 8480, - 157: 8226, - 158: 8220, - 159: 8221, - 160: 192, - 161: 194, - 162: 199, - 163: 200, - 164: 202, - 165: 203, - 166: 235, - 167: 206, - 168: 207, - 169: 239, - 170: 212, - 171: 217, - 172: 249, - 173: 219, - 174: 171, - 175: 187, - 176: 195, - 177: 227, - 178: 205, - 179: 204, - 180: 236, - 181: 210, - 182: 242, - 183: 213, - 184: 245, - 185: 123, - 186: 125, - 187: 92, - 188: 94, - 189: 95, - 190: 124, - 191: 8764, - 192: 196, - 193: 228, - 194: 214, - 195: 246, - 196: 223, - 197: 165, - 198: 164, - 199: 9475, - 200: 197, - 201: 229, - 202: 216, - 203: 248, - 204: 9487, - 205: 9491, - 206: 9495, - 207: 9499 - }, - n = function(t) { - var e = t; - return a.hasOwnProperty(t) && (e = a[t]), String.fromCharCode(e) - }, - o = 15, - s = 100, - l = { - 17: 1, - 18: 3, - 21: 5, - 22: 7, - 23: 9, - 16: 11, - 19: 12, - 20: 14 - }, - u = { - 17: 2, - 18: 4, - 21: 6, - 22: 8, - 23: 10, - 19: 13, - 20: 15 - }, - d = { - 25: 1, - 26: 3, - 29: 5, - 30: 7, - 31: 9, - 24: 11, - 27: 12, - 28: 14 - }, - c = { - 25: 2, - 26: 4, - 29: 6, - 30: 8, - 31: 10, - 27: 13, - 28: 15 - }, - h = ["white", "green", "blue", "cyan", "red", "yellow", "magenta", "black", "transparent"], - f = { - verboseFilter: { - DATA: 3, - DEBUG: 3, - INFO: 2, - WARNING: 2, - TEXT: 1, - ERROR: 0 - }, - time: null, - verboseLevel: 0, - setTime: function(t) { - this.time = t - }, - log: function(t, e) { - this.verboseFilter[t]; - this.verboseLevel - } - }, - p = function(t) { - for (var e = [], r = 0; r < t.length; r++) e.push(t[r].toString(16)); - return e - }, - v = function() { - function t(e, r, a, n, o) { - i(this, t), this.foreground = e || "white", this.underline = r || !1, this.italics = a || !1, this.background = n || "black", this.flash = o || !1 - } - return t.prototype.reset = function() { - this.foreground = "white", this.underline = !1, this.italics = !1, this.background = "black", this.flash = !1 - }, t.prototype.setStyles = function(t) { - for (var e = ["foreground", "underline", "italics", "background", "flash"], r = 0; r < e.length; r++) { - var i = e[r]; - t.hasOwnProperty(i) && (this[i] = t[i]) - } - }, t.prototype.isDefault = function() { - return "white" === this.foreground && !this.underline && !this.italics && "black" === this.background && !this.flash - }, t.prototype.equals = function(t) { - return this.foreground === t.foreground && this.underline === t.underline && this.italics === t.italics && this.background === t.background && this.flash === t.flash - }, t.prototype.copy = function(t) { - this.foreground = t.foreground, this.underline = t.underline, this.italics = t.italics, this.background = t.background, this.flash = t.flash - }, t.prototype.toString = function() { - return "color=" + this.foreground + ", underline=" + this.underline + ", italics=" + this.italics + ", background=" + this.background + ", flash=" + this.flash - }, t - }(), - g = function() { - function t(e, r, a, n, o, s) { - i(this, t), this.uchar = e || " ", this.penState = new v(r, a, n, o, s) - } - return t.prototype.reset = function() { - this.uchar = " ", this.penState.reset() - }, t.prototype.setChar = function(t, e) { - this.uchar = t, this.penState.copy(e) - }, t.prototype.setPenState = function(t) { - this.penState.copy(t) - }, t.prototype.equals = function(t) { - return this.uchar === t.uchar && this.penState.equals(t.penState) - }, t.prototype.copy = function(t) { - this.uchar = t.uchar, this.penState.copy(t.penState) - }, t.prototype.isEmpty = function() { - return " " === this.uchar && this.penState.isDefault() - }, t - }(), - y = function() { - function t() { - i(this, t), this.chars = []; - for (var e = 0; e < s; e++) this.chars.push(new g); - this.pos = 0, this.currPenState = new v - } - return t.prototype.equals = function(t) { - for (var e = !0, r = 0; r < s; r++) - if (!this.chars[r].equals(t.chars[r])) { - e = !1; - break - } return e - }, t.prototype.copy = function(t) { - for (var e = 0; e < s; e++) this.chars[e].copy(t.chars[e]) - }, t.prototype.isEmpty = function() { - for (var t = !0, e = 0; e < s; e++) - if (!this.chars[e].isEmpty()) { - t = !1; - break - } return t - }, t.prototype.setCursor = function(t) { - this.pos !== t && (this.pos = t), this.pos < 0 ? (f.log("ERROR", "Negative cursor position " + this.pos), this.pos = 0) : this.pos > s && (f.log("ERROR", "Too large cursor position " + this.pos), this.pos = s) - }, t.prototype.moveCursor = function(t) { - var e = this.pos + t; - if (t > 1) - for (var r = this.pos + 1; r < e + 1; r++) this.chars[r].setPenState(this.currPenState); - this.setCursor(e) - }, t.prototype.backSpace = function() { - this.moveCursor(-1), this.chars[this.pos].setChar(" ", this.currPenState) - }, t.prototype.insertChar = function(t) { - t >= 144 && this.backSpace(); - var e = n(t); - if (this.pos >= s) return void f.log("ERROR", "Cannot insert " + t.toString(16) + " (" + e + ") at position " + this.pos + ". Skipping it!"); - this.chars[this.pos].setChar(e, this.currPenState), this.moveCursor(1) - }, t.prototype.clearFromPos = function(t) { - var e = void 0; - for (e = t; e < s; e++) this.chars[e].reset() - }, t.prototype.clear = function() { - this.clearFromPos(0), this.pos = 0, this.currPenState.reset() - }, t.prototype.clearToEndOfRow = function() { - this.clearFromPos(this.pos) - }, t.prototype.getTextString = function() { - for (var t = [], e = !0, r = 0; r < s; r++) { - var i = this.chars[r].uchar; - " " !== i && (e = !1), t.push(i) - } - return e ? "" : t.join("") - }, t.prototype.setPenStyles = function(t) { - this.currPenState.setStyles(t), this.chars[this.pos].setPenState(this.currPenState) - }, t - }(), - m = function() { - function t() { - i(this, t), this.rows = []; - for (var e = 0; e < o; e++) this.rows.push(new y); - this.currRow = o - 1, this.nrRollUpRows = null, this.reset() - } - return t.prototype.reset = function() { - for (var t = 0; t < o; t++) this.rows[t].clear(); - this.currRow = o - 1 - }, t.prototype.equals = function(t) { - for (var e = !0, r = 0; r < o; r++) - if (!this.rows[r].equals(t.rows[r])) { - e = !1; - break - } return e - }, t.prototype.copy = function(t) { - for (var e = 0; e < o; e++) this.rows[e].copy(t.rows[e]) - }, t.prototype.isEmpty = function() { - for (var t = !0, e = 0; e < o; e++) - if (!this.rows[e].isEmpty()) { - t = !1; - break - } return t - }, t.prototype.backSpace = function() { - this.rows[this.currRow].backSpace() - }, t.prototype.clearToEndOfRow = function() { - this.rows[this.currRow].clearToEndOfRow() - }, t.prototype.insertChar = function(t) { - this.rows[this.currRow].insertChar(t) - }, t.prototype.setPen = function(t) { - this.rows[this.currRow].setPenStyles(t) - }, t.prototype.moveCursor = function(t) { - this.rows[this.currRow].moveCursor(t) - }, t.prototype.setCursor = function(t) { - f.log("INFO", "setCursor: " + t), this.rows[this.currRow].setCursor(t) - }, t.prototype.setPAC = function(t) { - f.log("INFO", "pacData = " + JSON.stringify(t)); - var e = t.row - 1; - if (this.nrRollUpRows && e < this.nrRollUpRows - 1 && (e = this.nrRollUpRows - 1), this.nrRollUpRows && this.currRow !== e) { - for (var r = 0; r < o; r++) this.rows[r].clear(); - var i = this.currRow + 1 - this.nrRollUpRows, - a = this.lastOutputScreen; - if (a) { - var n = a.rows[i].cueStartTime; - if (n && n < f.time) - for (var s = 0; s < this.nrRollUpRows; s++) this.rows[e - this.nrRollUpRows + s + 1].copy(a.rows[i + s]) - } - } - this.currRow = e; - var l = this.rows[this.currRow]; - if (null !== t.indent) { - var u = t.indent, - d = Math.max(u - 1, 0); - l.setCursor(t.indent), t.color = l.chars[d].penState.foreground - } - var c = { - foreground: t.color, - underline: t.underline, - italics: t.italics, - background: "black", - flash: !1 - }; - this.setPen(c) - }, t.prototype.setBkgData = function(t) { - f.log("INFO", "bkgData = " + JSON.stringify(t)), this.backSpace(), this.setPen(t), this.insertChar(32) - }, t.prototype.setRollUpRows = function(t) { - this.nrRollUpRows = t - }, t.prototype.rollUp = function() { - if (null === this.nrRollUpRows) return void f.log("DEBUG", "roll_up but nrRollUpRows not set yet"); - f.log("TEXT", this.getDisplayText()); - var t = this.currRow + 1 - this.nrRollUpRows, - e = this.rows.splice(t, 1)[0]; - e.clear(), this.rows.splice(this.currRow, 0, e), f.log("INFO", "Rolling up") - }, t.prototype.getDisplayText = function(t) { - t = t || !1; - for (var e = [], r = "", i = -1, a = 0; a < o; a++) { - var n = this.rows[a].getTextString(); - n && (i = a + 1, t ? e.push("Row " + i + ": '" + n + "'") : e.push(n.trim())) - } - return e.length > 0 && (r = t ? "[" + e.join(" | ") + "]" : e.join("\n")), r - }, t.prototype.getTextAndFormat = function() { - return this.rows - }, t - }(), - b = function() { - function t(e, r) { - i(this, t), this.chNr = e, this.outputFilter = r, this.mode = null, this.verbose = 0, this.displayedMemory = new m, this.nonDisplayedMemory = new m, this.lastOutputScreen = new m, this.currRollUpRow = this.displayedMemory.rows[o - 1], this.writeScreen = this.displayedMemory, this.mode = null, this.cueStartTime = null - } - return t.prototype.reset = function() { - this.mode = null, this.displayedMemory.reset(), this.nonDisplayedMemory.reset(), this.lastOutputScreen.reset(), this.currRollUpRow = this.displayedMemory.rows[o - 1], this.writeScreen = this.displayedMemory, this.mode = null, this.cueStartTime = null, this.lastCueEndTime = null - }, t.prototype.getHandler = function() { - return this.outputFilter - }, t.prototype.setHandler = function(t) { - this.outputFilter = t - }, t.prototype.setPAC = function(t) { - this.writeScreen.setPAC(t) - }, t.prototype.setBkgData = function(t) { - this.writeScreen.setBkgData(t) - }, t.prototype.setMode = function(t) { - t !== this.mode && (this.mode = t, f.log("INFO", "MODE=" + t), "MODE_POP-ON" === this.mode ? this.writeScreen = this.nonDisplayedMemory : (this.writeScreen = this.displayedMemory, this.writeScreen.reset()), "MODE_ROLL-UP" !== this.mode && (this.displayedMemory.nrRollUpRows = null, this.nonDisplayedMemory.nrRollUpRows = null), this.mode = t) - }, t.prototype.insertChars = function(t) { - for (var e = 0; e < t.length; e++) this.writeScreen.insertChar(t[e]); - var r = this.writeScreen === this.displayedMemory ? "DISP" : "NON_DISP"; - f.log("INFO", r + ": " + this.writeScreen.getDisplayText(!0)), "MODE_PAINT-ON" !== this.mode && "MODE_ROLL-UP" !== this.mode || (f.log("TEXT", "DISPLAYED: " + this.displayedMemory.getDisplayText(!0)), this.outputDataUpdate()) - }, t.prototype.ccRCL = function() { - f.log("INFO", "RCL - Resume Caption Loading"), this.setMode("MODE_POP-ON") - }, t.prototype.ccBS = function() { - f.log("INFO", "BS - BackSpace"), "MODE_TEXT" !== this.mode && (this.writeScreen.backSpace(), this.writeScreen === this.displayedMemory && this.outputDataUpdate()) - }, t.prototype.ccAOF = function() {}, t.prototype.ccAON = function() {}, t.prototype.ccDER = function() { - f.log("INFO", "DER- Delete to End of Row"), this.writeScreen.clearToEndOfRow(), this.outputDataUpdate() - }, t.prototype.ccRU = function(t) { - f.log("INFO", "RU(" + t + ") - Roll Up"), this.writeScreen = this.displayedMemory, this.setMode("MODE_ROLL-UP"), this.writeScreen.setRollUpRows(t) - }, t.prototype.ccFON = function() { - f.log("INFO", "FON - Flash On"), this.writeScreen.setPen({ - flash: !0 - }) - }, t.prototype.ccRDC = function() { - f.log("INFO", "RDC - Resume Direct Captioning"), this.setMode("MODE_PAINT-ON") - }, t.prototype.ccTR = function() { - f.log("INFO", "TR"), this.setMode("MODE_TEXT") - }, t.prototype.ccRTD = function() { - f.log("INFO", "RTD"), this.setMode("MODE_TEXT") - }, t.prototype.ccEDM = function() { - f.log("INFO", "EDM - Erase Displayed Memory"), this.displayedMemory.reset(), this.outputDataUpdate(!0) - }, t.prototype.ccCR = function() { - f.log("CR - Carriage Return"), this.writeScreen.rollUp(), this.outputDataUpdate(!0) - }, t.prototype.ccENM = function() { - f.log("INFO", "ENM - Erase Non-displayed Memory"), this.nonDisplayedMemory.reset() - }, t.prototype.ccEOC = function() { - if (f.log("INFO", "EOC - End Of Caption"), "MODE_POP-ON" === this.mode) { - var t = this.displayedMemory; - this.displayedMemory = this.nonDisplayedMemory, this.nonDisplayedMemory = t, this.writeScreen = this.nonDisplayedMemory, f.log("TEXT", "DISP: " + this.displayedMemory.getDisplayText()) - } - this.outputDataUpdate(!0) - }, t.prototype.ccTO = function(t) { - f.log("INFO", "TO(" + t + ") - Tab Offset"), this.writeScreen.moveCursor(t) - }, t.prototype.ccMIDROW = function(t) { - var e = { - flash: !1 - }; - if (e.underline = t % 2 == 1, e.italics = t >= 46, e.italics) e.foreground = "white"; - else { - var r = Math.floor(t / 2) - 16, - i = ["white", "green", "blue", "cyan", "red", "yellow", "magenta"]; - e.foreground = i[r] - } - f.log("INFO", "MIDROW: " + JSON.stringify(e)), this.writeScreen.setPen(e) - }, t.prototype.outputDataUpdate = function() { - var t = arguments.length > 0 && void 0 !== arguments[0] && arguments[0], - e = f.time; - null !== e && this.outputFilter && (null !== this.cueStartTime || this.displayedMemory.isEmpty() ? this.displayedMemory.equals(this.lastOutputScreen) || (this.outputFilter.newCue && (this.outputFilter.newCue(this.cueStartTime, e, this.lastOutputScreen), !0 === t && this.outputFilter.dispatchCue && this.outputFilter.dispatchCue()), this.cueStartTime = this.displayedMemory.isEmpty() ? null : e) : this.cueStartTime = e, this.lastOutputScreen.copy(this.displayedMemory)) - }, t.prototype.cueSplitAtTime = function(t) { - this.outputFilter && (this.displayedMemory.isEmpty() || (this.outputFilter.newCue && this.outputFilter.newCue(this.cueStartTime, t, this.displayedMemory), this.cueStartTime = t)) - }, t - }(), - E = function() { - function t(e, r, a) { - i(this, t), this.field = e || 1, this.outputs = [r, a], this.channels = [new b(1, r), new b(2, a)], this.currChNr = -1, this.lastCmdA = null, this.lastCmdB = null, this.bufferedData = [], this.startTime = null, this.lastTime = null, this.dataCounters = { - padding: 0, - char: 0, - cmd: 0, - other: 0 - } - } - return t.prototype.getHandler = function(t) { - return this.channels[t].getHandler() - }, t.prototype.setHandler = function(t, e) { - this.channels[t].setHandler(e) - }, t.prototype.addData = function(t, e) { - var r = void 0, - i = void 0, - a = void 0, - n = !1; - this.lastTime = t, f.setTime(t); - for (var o = 0; o < e.length; o += 2) - if (i = 127 & e[o], a = 127 & e[o + 1], 0 !== i || 0 !== a) { - if (f.log("DATA", "[" + p([e[o], e[o + 1]]) + "] -> (" + p([i, a]) + ")"), r = this.parseCmd(i, a), r || (r = this.parseMidrow(i, a)), r || (r = this.parsePAC(i, a)), r || (r = this.parseBackgroundAttributes(i, a)), !r && (n = this.parseChars(i, a))) - if (this.currChNr && this.currChNr >= 0) { - var s = this.channels[this.currChNr - 1]; - s.insertChars(n) - } else f.log("WARNING", "No channel found yet. TEXT-MODE?"); - r ? this.dataCounters.cmd += 2 : n ? this.dataCounters.char += 2 : (this.dataCounters.other += 2, f.log("WARNING", "Couldn't parse cleaned data " + p([i, a]) + " orig: " + p([e[o], e[o + 1]]))) - } else this.dataCounters.padding += 2 - }, t.prototype.parseCmd = function(t, e) { - var r = null, - i = (20 === t || 28 === t) && e >= 32 && e <= 47, - a = (23 === t || 31 === t) && e >= 33 && e <= 35; - if (!i && !a) return !1; - if (t === this.lastCmdA && e === this.lastCmdB) return this.lastCmdA = null, this.lastCmdB = null, f.log("DEBUG", "Repeated command (" + p([t, e]) + ") is dropped"), !0; - r = 20 === t || 23 === t ? 1 : 2; - var n = this.channels[r - 1]; - return 20 === t || 28 === t ? 32 === e ? n.ccRCL() : 33 === e ? n.ccBS() : 34 === e ? n.ccAOF() : 35 === e ? n.ccAON() : 36 === e ? n.ccDER() : 37 === e ? n.ccRU(2) : 38 === e ? n.ccRU(3) : 39 === e ? n.ccRU(4) : 40 === e ? n.ccFON() : 41 === e ? n.ccRDC() : 42 === e ? n.ccTR() : 43 === e ? n.ccRTD() : 44 === e ? n.ccEDM() : 45 === e ? n.ccCR() : 46 === e ? n.ccENM() : 47 === e && n.ccEOC() : n.ccTO(e - 32), this.lastCmdA = t, this.lastCmdB = e, this.currChNr = r, !0 - }, t.prototype.parseMidrow = function(t, e) { - var r = null; - if ((17 === t || 25 === t) && e >= 32 && e <= 47) { - if ((r = 17 === t ? 1 : 2) !== this.currChNr) return f.log("ERROR", "Mismatch channel in midrow parsing"), !1; - return this.channels[r - 1].ccMIDROW(e), f.log("DEBUG", "MIDROW (" + p([t, e]) + ")"), !0 - } - return !1 - }, t.prototype.parsePAC = function(t, e) { - var r = null, - i = null, - a = (t >= 17 && t <= 23 || t >= 25 && t <= 31) && e >= 64 && e <= 127, - n = (16 === t || 24 === t) && e >= 64 && e <= 95; - if (!a && !n) return !1; - if (t === this.lastCmdA && e === this.lastCmdB) return this.lastCmdA = null, this.lastCmdB = null, !0; - r = t <= 23 ? 1 : 2, i = e >= 64 && e <= 95 ? 1 === r ? l[t] : d[t] : 1 === r ? u[t] : c[t]; - var o = this.interpretPAC(i, e); - return this.channels[r - 1].setPAC(o), this.lastCmdA = t, this.lastCmdB = e, this.currChNr = r, !0 - }, t.prototype.interpretPAC = function(t, e) { - var r = e, - i = { - color: null, - italics: !1, - indent: null, - underline: !1, - row: t - }; - return r = e > 95 ? e - 96 : e - 64, i.underline = 1 == (1 & r), r <= 13 ? i.color = ["white", "green", "blue", "cyan", "red", "yellow", "magenta", "white"][Math.floor(r / 2)] : r <= 15 ? (i.italics = !0, i.color = "white") : i.indent = 4 * Math.floor((r - 16) / 2), i - }, t.prototype.parseChars = function(t, e) { - var r = null, - i = null, - a = null; - if (t >= 25 ? (r = 2, a = t - 8) : (r = 1, a = t), a >= 17 && a <= 19) { - var o = e; - o = 17 === a ? e + 80 : 18 === a ? e + 112 : e + 144, f.log("INFO", "Special char '" + n(o) + "' in channel " + r), i = [o] - } else t >= 32 && t <= 127 && (i = 0 === e ? [t] : [t, e]); - if (i) { - var s = p(i); - f.log("DEBUG", "Char codes = " + s.join(",")), this.lastCmdA = null, this.lastCmdB = null - } - return i - }, t.prototype.parseBackgroundAttributes = function(t, e) { - var r = void 0, - i = void 0, - a = void 0, - n = void 0, - o = (16 === t || 24 === t) && e >= 32 && e <= 47, - s = (23 === t || 31 === t) && e >= 45 && e <= 47; - return !(!o && !s) && (r = {}, 16 === t || 24 === t ? (i = Math.floor((e - 32) / 2), r.background = h[i], e % 2 == 1 && (r.background = r.background + "_semi")) : 45 === e ? r.background = "transparent" : (r.foreground = "black", 47 === e && (r.underline = !0)), a = t < 24 ? 1 : 2, n = this.channels[a - 1], n.setBkgData(r), this.lastCmdA = null, this.lastCmdB = null, !0) - }, t.prototype.reset = function() { - for (var t = 0; t < this.channels.length; t++) this.channels[t] && this.channels[t].reset(); - this.lastCmdA = null, this.lastCmdB = null - }, t.prototype.cueSplitAtTime = function(t) { - for (var e = 0; e < this.channels.length; e++) this.channels[e] && this.channels[e].cueSplitAtTime(t) - }, t - }(); - e.a = E - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - var a = function() { - function t(e, r) { - i(this, t), this.timelineController = e, this.trackName = r, this.startTime = null, this.endTime = null, this.screen = null - } - return t.prototype.dispatchCue = function() { - null !== this.startTime && (this.timelineController.addCues(this.trackName, this.startTime, this.endTime, this.screen), this.startTime = null) - }, t.prototype.newCue = function(t, e, r) { - (null === this.startTime || this.startTime > t) && (this.startTime = t), this.endTime = e, this.screen = r, this.timelineController.createCaptionsTrack(this.trackName) - }, t - }(); - e.a = a - }, function(t, e, r) { - "use strict"; - var i = r(27), - a = r(7), - n = function(t, e, r) { - return t.substr(r || 0, e.length) === e - }, - o = function(t) { - var e = parseInt(t.substr(-3)), - r = parseInt(t.substr(-6, 2)), - i = parseInt(t.substr(-9, 2)), - a = t.length > 9 ? parseInt(t.substr(0, t.indexOf(":"))) : 0; - return isNaN(e) || isNaN(r) || isNaN(i) || isNaN(a) ? -1 : (e += 1e3 * r, e += 6e4 * i, e += 36e5 * a) - }, - s = function(t) { - for (var e = 5381, r = t.length; r;) e = 33 * e ^ t.charCodeAt(--r); - return (e >>> 0).toString() - }, - l = function(t, e, r) { - var i = t[e], - a = t[i.prevCC]; - if (!a || !a.new && i.new) return t.ccOffset = t.presentationOffset = i.start, void(i.new = !1); - for (; a && a.new;) t.ccOffset += i.start - a.start, i.new = !1, i = a, a = t[i.prevCC]; - t.presentationOffset = r - }, - u = { - parse: function(t, e, r, u, d, c) { - var h = /\r\n|\n\r|\n|\r/g, - f = Object(a.b)(new Uint8Array(t)).trim().replace(h, "\n").split("\n"), - p = "00:00.000", - v = 0, - g = 0, - y = 0, - m = [], - b = void 0, - E = !0, - T = new i.a; - T.oncue = function(t) { - var e = r[u], - i = r.ccOffset; - e && e.new && (void 0 !== g ? i = r.ccOffset = e.start : l(r, u, y)), y && (i = y + r.ccOffset - r.presentationOffset), t.startTime += i - g, t.endTime += i - g, t.id = s(t.startTime.toString()) + s(t.endTime.toString()) + s(t.text), t.text = decodeURIComponent(encodeURIComponent(t.text)), t.endTime > 0 && m.push(t) - }, T.onparsingerror = function(t) { - b = t - }, T.onflush = function() { - if (b && c) return void c(b); - d(m) - }, f.forEach(function(t) { - if (E) { - if (n(t, "X-TIMESTAMP-MAP=")) { - E = !1, t.substr(16).split(",").forEach(function(t) { - n(t, "LOCAL:") ? p = t.substr(6) : n(t, "MPEGTS:") && (v = parseInt(t.substr(7))) - }); - try { - e = e < 0 ? e + 8589934592 : e, v -= e, g = o(p) / 1e3, y = v / 9e4, -1 === g && (b = new Error("Malformed X-TIMESTAMP-MAP: " + t)) - } catch (e) { - b = new Error("Malformed X-TIMESTAMP-MAP: " + t) - } - return - } - "" === t && (E = !1) - } - T.parse(t + "\n") - }), T.flush() - } - }; - e.a = u - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - - function o(t) { - for (var e = [], r = 0; r < t.length; r++) "subtitles" === t[r].kind && e.push(t[r]); - return e - } - var s = r(1), - l = r(3), - u = r(0), - d = function() { - function t(t, e) { - for (var r = 0; r < e.length; r++) { - var i = e[r]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(t, i.key, i) - } - } - return function(e, r, i) { - return r && t(e.prototype, r), i && t(e, i), e - } - }(), - c = function(t) { - function e(r) { - i(this, e); - var n = a(this, t.call(this, r, s.a.MEDIA_ATTACHED, s.a.MEDIA_DETACHING, s.a.MANIFEST_LOADING, s.a.MANIFEST_LOADED, s.a.SUBTITLE_TRACK_LOADED)); - return n.tracks = [], n.trackId = -1, n.media = null, n.subtitleDisplay = !0, n - } - return n(e, t), e.prototype._onTextTracksChanged = function() { - if (this.media) { - for (var t = -1, e = o(this.media.textTracks), r = 0; r < e.length; r++) - if ("hidden" === e[r].mode) t = r; - else if ("showing" === e[r].mode) { - t = r; - break - } - this.subtitleTrack = t - } - }, e.prototype.destroy = function() { - l.a.prototype.destroy.call(this) - }, e.prototype.onMediaAttached = function(t) { - var e = this; - this.media = t.media, this.media && (this.queuedDefaultTrack && (this.subtitleTrack = this.queuedDefaultTrack, delete this.queuedDefaultTrack), this.trackChangeListener = this._onTextTracksChanged.bind(this), this.useTextTrackPolling = !(this.media.textTracks && "onchange" in this.media.textTracks), this.useTextTrackPolling ? this.subtitlePollingInterval = setInterval(function() { - e.trackChangeListener() - }, 500) : this.media.textTracks.addEventListener("change", this.trackChangeListener)) - }, e.prototype.onMediaDetaching = function() { - this.media && (this.useTextTrackPolling ? clearInterval(this.subtitlePollingInterval) : this.media.textTracks.removeEventListener("change", this.trackChangeListener), this.media = null) - }, e.prototype.onManifestLoading = function() { - this.tracks = [], this.trackId = -1 - }, e.prototype.onManifestLoaded = function(t) { - var e = this, - r = t.subtitles || []; - this.tracks = r, this.trackId = -1, this.hls.trigger(s.a.SUBTITLE_TRACKS_UPDATED, { - subtitleTracks: r - }), r.forEach(function(t) { - t.default && (e.media ? e.subtitleTrack = t.id : e.queuedDefaultTrack = t.id) - }) - }, e.prototype.onTick = function() { - var t = this.trackId, - e = this.tracks[t]; - if (e) { - var r = e.details; - r && !r.live || (u.b.log("(re)loading playlist for subtitle track " + t), this.hls.trigger(s.a.SUBTITLE_TRACK_LOADING, { - url: e.url, - id: t - })) - } - }, e.prototype.onSubtitleTrackLoaded = function(t) { - var e = this; - t.id < this.tracks.length && (u.b.log("subtitle track " + t.id + " loaded"), this.tracks[t.id].details = t.details, t.details.live && !this.timer && (this.timer = setInterval(function() { - e.onTick() - }, 1e3 * t.details.targetduration, this)), !t.details.live && this.timer && this._stopTimer()) - }, e.prototype.setSubtitleTrackInternal = function(t) { - var e = this.hls, - r = this.tracks; - if (!("number" != typeof t || t < -1 || t >= r.length) && (this._stopTimer(), this.trackId = t, u.b.log("switching to subtitle track " + t), e.trigger(s.a.SUBTITLE_TRACK_SWITCH, { - id: t - }), -1 !== t)) { - var i = r[t], - a = i.details; - a && !a.live || (u.b.log("(re)loading playlist for subtitle track " + t), e.trigger(s.a.SUBTITLE_TRACK_LOADING, { - url: i.url, - id: t - })) - } - }, e.prototype._stopTimer = function() { - this.timer && (clearInterval(this.timer), this.timer = null) - }, e.prototype._toggleTrackModes = function(t) { - var e = this.media, - r = this.subtitleDisplay, - i = this.trackId; - if (e) { - var a = o(e.textTracks); - if (-1 === t)[].slice.call(a).forEach(function(t) { - t.mode = "disabled" - }); - else { - var n = a[i]; - n && (n.mode = "disabled") - } - var s = a[t]; - s && (s.mode = r ? "showing" : "hidden") - } - }, d(e, [{ - key: "subtitleTracks", - get: function() { - return this.tracks - } - }, { - key: "subtitleTrack", - get: function() { - return this.trackId - }, - set: function(t) { - this.trackId !== t && (this._toggleTrackModes(t), this.setSubtitleTrackInternal(t)) - } - }]), e - }(l.a); - e.a = c - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(1), - s = r(0), - l = r(13), - u = r(8), - d = window, - c = d.performance, - h = { - STOPPED: "STOPPED", - IDLE: "IDLE", - KEY_LOADING: "KEY_LOADING", - FRAG_LOADING: "FRAG_LOADING" - }, - f = function(t) { - function e(r) { - i(this, e); - var n = a(this, t.call(this, r, o.a.MEDIA_ATTACHED, o.a.ERROR, o.a.KEY_LOADED, o.a.FRAG_LOADED, o.a.SUBTITLE_TRACKS_UPDATED, o.a.SUBTITLE_TRACK_SWITCH, o.a.SUBTITLE_TRACK_LOADED, o.a.SUBTITLE_FRAG_PROCESSED)); - return n.config = r.config, n.vttFragSNsProcessed = {}, n.vttFragQueues = void 0, n.currentlyProcessing = null, n.state = h.STOPPED, n.currentTrackId = -1, n.decrypter = new l.a(r.observer, r.config), n - } - return n(e, t), e.prototype.onHandlerDestroyed = function() { - this.state = h.STOPPED - }, e.prototype.clearVttFragQueues = function() { - var t = this; - this.vttFragQueues = {}, this.tracks.forEach(function(e) { - t.vttFragQueues[e.id] = [] - }) - }, e.prototype.nextFrag = function() { - if (null === this.currentlyProcessing && this.currentTrackId > -1 && this.vttFragQueues[this.currentTrackId].length) { - var t = this.currentlyProcessing = this.vttFragQueues[this.currentTrackId].shift(); - this.fragCurrent = t, this.hls.trigger(o.a.FRAG_LOADING, { - frag: t - }), this.state = h.FRAG_LOADING - } - }, e.prototype.onSubtitleFragProcessed = function(t) { - t.success && this.vttFragSNsProcessed[t.frag.trackId].push(t.frag.sn), this.currentlyProcessing = null, this.state = h.IDLE, this.nextFrag() - }, e.prototype.onMediaAttached = function() { - this.state = h.IDLE - }, e.prototype.onError = function(t) { - var e = t.frag; - e && "subtitle" !== e.type || this.currentlyProcessing && (this.currentlyProcessing = null, this.nextFrag()) - }, e.prototype.doTick = function() { - var t = this; - switch (this.state) { - case h.IDLE: - var e = this.tracks, - r = this.currentTrackId, - i = this.vttFragSNsProcessed[r], - a = this.vttFragQueues[r], - n = this.currentlyProcessing ? this.currentlyProcessing.sn : -1, - l = function(t) { - return i.indexOf(t.sn) > -1 - }, - u = function(t) { - return a.some(function(e) { - return e.sn === t.sn - }) - }; - if (!e) break; - var d; - if (r < e.length && (d = e[r].details), void 0 === d) break; - d.fragments.forEach(function(e) { - l(e) || e.sn === n || u(e) || (e.encrypted ? (s.b.log("Loading key for " + e.sn), t.state = h.KEY_LOADING, t.hls.trigger(o.a.KEY_LOADING, { - frag: e - })) : (e.trackId = r, a.push(e), t.nextFrag())) - }) - } - }, e.prototype.onSubtitleTracksUpdated = function(t) { - var e = this; - s.b.log("subtitle tracks updated"), this.tracks = t.subtitleTracks, this.clearVttFragQueues(), this.vttFragSNsProcessed = {}, this.tracks.forEach(function(t) { - e.vttFragSNsProcessed[t.id] = [] - }) - }, e.prototype.onSubtitleTrackSwitch = function(t) { - if (this.currentTrackId = t.id, this.tracks && -1 !== this.currentTrackId) { - var e = this.tracks[this.currentTrackId]; - e && e.details && this.tick() - } - }, e.prototype.onSubtitleTrackLoaded = function() { - this.tick() - }, e.prototype.onKeyLoaded = function() { - this.state === h.KEY_LOADING && (this.state = h.IDLE, this.tick()) - }, e.prototype.onFragLoaded = function(t) { - var e = this.fragCurrent, - r = t.frag.decryptdata, - i = t.frag, - a = this.hls; - if (this.state === h.FRAG_LOADING && e && "subtitle" === t.frag.type && e.sn === t.frag.sn && t.payload.byteLength > 0 && null != r && null != r.key && "AES-128" === r.method) { - var n = void 0; - try { - n = c.now() - } catch (t) { - n = Date.now() - } - this.decrypter.decrypt(t.payload, r.key.buffer, r.iv.buffer, function(t) { - var e = void 0; - try { - e = c.now() - } catch (t) { - e = Date.now() - } - a.trigger(o.a.FRAG_DECRYPTED, { - frag: i, - payload: t, - stats: { - tstart: n, - tdecrypt: e - } - }) - }) - } - }, e - }(u.a); - e.a = f - }, function(t, e, r) { - "use strict"; - - function i(t, e) { - if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") - } - - function a(t, e) { - if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || "object" != typeof e && "function" != typeof e ? t : e - } - - function n(t, e) { - if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t.prototype = Object.create(e && e.prototype, { - constructor: { - value: t, - enumerable: !1, - writable: !0, - configurable: !0 - } - }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) - } - var o = r(3), - s = r(1), - l = r(2), - u = r(0), - d = function() { - function t(t, e) { - for (var r = 0; r < e.length; r++) { - var i = e[r]; - i.enumerable = i.enumerable || !1, i.configurable = !0, "value" in i && (i.writable = !0), Object.defineProperty(t, i.key, i) - } - } - return function(e, r, i) { - return r && t(e.prototype, r), i && t(e, i), e - } - }(), - c = window, - h = c.XMLHttpRequest, - f = { - WIDEVINE: "com.widevine.alpha", - PLAYREADY: "com.microsoft.playready" - }, - p = function(t, e, r) { - var i = { - videoCapabilities: [] - }; - return e.forEach(function(t) { - i.videoCapabilities.push({ - contentType: 'video/mp4; codecs="' + t + '"' - }) - }), [i] - }, - v = function(t, e, r) { - switch (t) { - case f.WIDEVINE: - return p(0, r); - default: - throw Error("Unknown key-system: " + t) - } - }, - g = function(t) { - function e(r) { - i(this, e); - var n = a(this, t.call(this, r, s.a.MEDIA_ATTACHED, s.a.MANIFEST_PARSED)); - return n._widevineLicenseUrl = r.config.widevineLicenseUrl, n._licenseXhrSetup = r.config.licenseXhrSetup, n._emeEnabled = r.config.emeEnabled, n._requestMediaKeySystemAccess = r.config.requestMediaKeySystemAccessFunc, n._mediaKeysList = [], n._media = null, n._hasSetMediaKeys = !1, n._isMediaEncrypted = !1, n._requestLicenseFailureCount = 0, n - } - return n(e, t), e.prototype.getLicenseServerUrl = function(t) { - var e = void 0; - switch (t) { - case f.WIDEVINE: - e = this._widevineLicenseUrl; - break; - default: - e = null - } - return e || (u.b.error('No license server URL configured for key-system "' + t + '"'), this.hls.trigger(s.a.ERROR, { - type: l.b.KEY_SYSTEM_ERROR, - details: l.a.KEY_SYSTEM_LICENSE_REQUEST_FAILED, - fatal: !0 - })), e - }, e.prototype._attemptKeySystemAccess = function(t, e, r) { - var i = this, - a = v(t, 0, r); - if (!a) return void u.b.warn("Can not create config for key-system (maybe because platform is not supported):", t); - u.b.log("Requesting encrypted media key-system access"), this.requestMediaKeySystemAccess(t, a).then(function(e) { - i._onMediaKeySystemAccessObtained(t, e) - }).catch(function(e) { - u.b.error('Failed to obtain key-system "' + t + '" access:', e) - }) - }, e.prototype._onMediaKeySystemAccessObtained = function(t, e) { - var r = this; - u.b.log('Access for key-system "' + t + '" obtained'); - var i = { - mediaKeys: null, - mediaKeysSession: null, - mediaKeysSessionInitialized: !1, - mediaKeySystemAccess: e, - mediaKeySystemDomain: t - }; - this._mediaKeysList.push(i), e.createMediaKeys().then(function(e) { - i.mediaKeys = e, u.b.log('Media-keys created for key-system "' + t + '"'), r._onMediaKeysCreated() - }).catch(function(t) { - u.b.error("Failed to create media-keys:", t) - }) - }, e.prototype._onMediaKeysCreated = function() { - var t = this; - this._mediaKeysList.forEach(function(e) { - e.mediaKeysSession || (e.mediaKeysSession = e.mediaKeys.createSession(), t._onNewMediaKeySession(e.mediaKeysSession)) - }) - }, e.prototype._onNewMediaKeySession = function(t) { - var e = this; - u.b.log("New key-system session " + t.sessionId), t.addEventListener("message", function(r) { - e._onKeySessionMessage(t, r.message) - }, !1) - }, e.prototype._onKeySessionMessage = function(t, e) { - u.b.log("Got EME message event, creating license request"), this._requestLicense(e, function(e) { - u.b.log("Received license data, updating key-session"), t.update(e) - }) - }, e.prototype._onMediaEncrypted = function(t, e) { - u.b.log('Media is encrypted using "' + t + '" init data type'), this._isMediaEncrypted = !0, this._mediaEncryptionInitDataType = t, this._mediaEncryptionInitData = e, this._attemptSetMediaKeys(), this._generateRequestWithPreferredKeySession() - }, e.prototype._attemptSetMediaKeys = function() { - if (!this._hasSetMediaKeys) { - var t = this._mediaKeysList[0]; - if (!t || !t.mediaKeys) return u.b.error("Fatal: Media is encrypted but no CDM access or no keys have been obtained yet"), void this.hls.trigger(s.a.ERROR, { - type: l.b.KEY_SYSTEM_ERROR, - details: l.a.KEY_SYSTEM_NO_KEYS, - fatal: !0 - }); - u.b.log("Setting keys for encrypted media"), this._media.setMediaKeys(t.mediaKeys), this._hasSetMediaKeys = !0 - } - }, e.prototype._generateRequestWithPreferredKeySession = function() { - var t = this, - e = this._mediaKeysList[0]; - if (!e) return u.b.error("Fatal: Media is encrypted but not any key-system access has been obtained yet"), void this.hls.trigger(s.a.ERROR, { - type: l.b.KEY_SYSTEM_ERROR, - details: l.a.KEY_SYSTEM_NO_ACCESS, - fatal: !0 - }); - if (e.mediaKeysSessionInitialized) return void u.b.warn("Key-Session already initialized but requested again"); - var r = e.mediaKeysSession; - r || (u.b.error("Fatal: Media is encrypted but no key-session existing"), this.hls.trigger(s.a.ERROR, { - type: l.b.KEY_SYSTEM_ERROR, - details: l.a.KEY_SYSTEM_NO_SESSION, - fatal: !0 - })); - var i = this._mediaEncryptionInitDataType, - a = this._mediaEncryptionInitData; - u.b.log('Generating key-session request for "' + i + '" init data type'), e.mediaKeysSessionInitialized = !0, r.generateRequest(i, a).then(function() { - u.b.debug("Key-session generation succeeded") - }).catch(function(e) { - u.b.error("Error generating key-session request:", e), t.hls.trigger(s.a.ERROR, { - type: l.b.KEY_SYSTEM_ERROR, - details: l.a.KEY_SYSTEM_NO_SESSION, - fatal: !1 - }) - }) - }, e.prototype._createLicenseXhr = function(t, e, r) { - var i = new h, - a = this._licenseXhrSetup; - try { - if (a) try { - a(i, t) - } catch (e) { - i.open("POST", t, !0), a(i, t) - } - i.readyState || i.open("POST", t, !0) - } catch (t) { - return u.b.error("Error setting up key-system license XHR", t), void this.hls.trigger(s.a.ERROR, { - type: l.b.KEY_SYSTEM_ERROR, - details: l.a.KEY_SYSTEM_LICENSE_REQUEST_FAILED, - fatal: !0 - }) - } - return i.responseType = "arraybuffer", i.onreadystatechange = this._onLicenseRequestReadyStageChange.bind(this, i, t, e, r), i - }, e.prototype._onLicenseRequestReadyStageChange = function(t, e, r, i) { - switch (t.readyState) { - case 4: - if (200 === t.status) this._requestLicenseFailureCount = 0, u.b.log("License request succeeded"), i(t.response); - else { - if (u.b.error("License Request XHR failed (" + e + "). Status: " + t.status + " (" + t.statusText + ")"), ++this._requestLicenseFailureCount <= 3) { - var a = 3 - this._requestLicenseFailureCount + 1; - return u.b.warn("Retrying license request, " + a + " attempts left"), void this._requestLicense(r, i) - } - this.hls.trigger(s.a.ERROR, { - type: l.b.KEY_SYSTEM_ERROR, - details: l.a.KEY_SYSTEM_LICENSE_REQUEST_FAILED, - fatal: !0 - }) - } - } - }, e.prototype._generateLicenseRequestChallenge = function(t, e) { - var r = void 0; - return t.mediaKeySystemDomain === f.PLAYREADY ? u.b.error("PlayReady is not supported (yet)") : t.mediaKeySystemDomain === f.WIDEVINE ? r = e : u.b.error("Unsupported key-system:", t.mediaKeySystemDomain), r - }, e.prototype._requestLicense = function(t, e) { - u.b.log("Requesting content license for key-system"); - var r = this._mediaKeysList[0]; - if (!r) return u.b.error("Fatal error: Media is encrypted but no key-system access has been obtained yet"), void this.hls.trigger(s.a.ERROR, { - type: l.b.KEY_SYSTEM_ERROR, - details: l.a.KEY_SYSTEM_NO_ACCESS, - fatal: !0 - }); - var i = this.getLicenseServerUrl(r.mediaKeySystemDomain), - a = this._createLicenseXhr(i, t, e); - u.b.log("Sending license request to URL: " + i), a.send(this._generateLicenseRequestChallenge(r, t)) - }, e.prototype.onMediaAttached = function(t) { - var e = this; - if (this._emeEnabled) { - var r = t.media; - this._media = r, r.addEventListener("encrypted", function(t) { - e._onMediaEncrypted(t.initDataType, t.initData) - }) - } - }, e.prototype.onManifestParsed = function(t) { - if (this._emeEnabled) { - var e = t.levels.map(function(t) { - return t.audioCodec - }), - r = t.levels.map(function(t) { - return t.videoCodec - }); - this._attemptKeySystemAccess(f.WIDEVINE, e, r) - } - }, d(e, [{ - key: "requestMediaKeySystemAccess", - get: function() { - if (!this._requestMediaKeySystemAccess) throw new Error("No requestMediaKeySystemAccess function configured"); - return this._requestMediaKeySystemAccess - } - }]), e - }(o.a); - e.a = g - }, function(t, e, r) { - "use strict"; - r.d(e, "a", function() { - return i - }); - var i = function() { - return "undefined" != typeof window && window.navigator && window.navigator.requestMediaKeySystemAccess ? window.navigator.requestMediaKeySystemAccess.bind(window.navigator) : null - }() - }, function(t, e) { /*! http://mths.be/endswith v0.2.0 by @mathias */ - String.prototype.endsWith || function() { - "use strict"; - var t = function() { - try { - var t = {}, - e = Object.defineProperty, - r = e(t, t, t) && e - } catch (t) {} - return r - }(), - e = {}.toString, - r = function(t) { - if (null == this) throw TypeError(); - var r = String(this); - if (t && "[object RegExp]" == e.call(t)) throw TypeError(); - var i = r.length, - a = String(t), - n = a.length, - o = i; - if (arguments.length > 1) { - var s = arguments[1]; - void 0 !== s && (o = s ? Number(s) : 0) != o && (o = 0) - } - var l = Math.min(Math.max(o, 0), i), - u = l - n; - if (u < 0) return !1; - for (var d = -1; ++d < n;) - if (r.charCodeAt(u + d) != a.charCodeAt(d)) return !1; - return !0 - }; - t ? t(String.prototype, "endsWith", { - value: r, - configurable: !0, - writable: !0 - }) : String.prototype.endsWith = r - }() - }]).default -}); -//# sourceMappingURL=hls.min.js.map \ No newline at end of file diff --git a/src/bower_components/hlsjs/hls.js.sublime-project b/src/bower_components/hlsjs/hls.js.sublime-project deleted file mode 100644 index e9087ac17a..0000000000 --- a/src/bower_components/hlsjs/hls.js.sublime-project +++ /dev/null @@ -1,19 +0,0 @@ -{ - "folders": - [ - { - "path": ".", - "folder_exclude_patterns": [ - ".git", - "node_modules", - "dist", - "lib" - ], - "file_exclude_patterns": [ - ".gitignore", - "hls.js.sublime-project", - "hls.js.sublime-workspace" - ] - } - ] -} diff --git a/src/bundle.js b/src/bundle.js index e49067fce9..3e33a4a1ec 100644 --- a/src/bundle.js +++ b/src/bundle.js @@ -4,6 +4,11 @@ // Use define from require.js not webpack's define var _define = window.define; +// jstree var jstree = require("jstree"); require("jstree/dist/themes/default/style.css"); _define("jstree", ["jQuery"], function() { return jstree; }); + +// hlsjs +var hlsjs = require("hls.js"); +_define("hlsjs", function() { return hlsjs; }); diff --git a/src/scripts/site.js b/src/scripts/site.js index 838608c661..7ba16d68d7 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -713,7 +713,6 @@ var AppInfo = {}; pluginManager: componentsPath + "/pluginManager", packageManager: componentsPath + "/packagemanager" }; - paths.hlsjs = bowerPath + "/hlsjs/dist/hls.min"; paths.flvjs = "thirdparty/flvjs/flv.min"; paths.shaka = "thirdparty/shaka/shaka-player.compiled"; define("chromecastHelper", [componentsPath + "/chromecast/chromecasthelpers"], returnFirstDependency); @@ -819,7 +818,7 @@ var AppInfo = {}; } }, bundles: { - bundle: ["jstree"] + bundle: ["jstree", "hlsjs"] }, urlArgs: urlArgs, paths: paths, diff --git a/webpack.config.js b/webpack.config.js index 9fabd9bc9d..c99ad3df1c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -7,7 +7,7 @@ module.exports = { output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), - libraryTarget: 'amd' + libraryTarget: 'amd-require' }, externals: [{ diff --git a/yarn.lock b/yarn.lock index 774ccc021b..a3f6e7a329 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1121,6 +1121,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +eventemitter3@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" + integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA== + events@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" @@ -1526,6 +1531,14 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hls.js@^0.12.4: + version "0.12.4" + resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-0.12.4.tgz#c155b7b2825a11117c111b781973c0ffa759006b" + integrity sha512-e8OPxQ60dBVsdkv4atdxR21KzC1mgwspM41qpozpj3Uv1Fz4CaeQy3FWoaV2O+QKKbNRvV5hW+/LipCWdrwnMQ== + dependencies: + eventemitter3 "3.1.0" + url-toolkit "^2.1.6" + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -3359,6 +3372,11 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= +url-toolkit@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/url-toolkit/-/url-toolkit-2.1.6.tgz#6d03246499e519aad224c44044a4ae20544154f2" + integrity sha512-UaZ2+50am4HwrV2crR/JAf63Q4VvPYphe63WGeoJxeu8gmOm0qxPt+KsukfakPNrX9aymGNEkkaoICwn+OuvBw== + url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" From a640781d4eed9ad76d29b7cbaa1cf871e6a5c683 Mon Sep 17 00:00:00 2001 From: tluciomiranda Date: Wed, 11 Sep 2019 11:15:32 +0000 Subject: [PATCH 43/80] 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 | 265 ++++++++++++++++++++++++----------------- 1 file changed, 156 insertions(+), 109 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index a740ce4c3e..710a2405f5 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -3,14 +3,14 @@ "Add": "Adicionar", "AddToPlaylist": "Adicionar à lista de reprodução", "AdditionalNotificationServices": "Explore o catálogo de extensões para instalar serviços adicionais de notificação.", - "All": "Tudo", + "All": "Todos", "AttributeNew": "Novo", "Audio": "Áudio", "Backdrops": "Imagens de Fundo", "BrowsePluginCatalogMessage": "Procure extensões disponíveis no nosso catálogo.", "ButtonAdd": "Adicionar", "ButtonAddMediaLibrary": "Adicionar Biblioteca de Multimédia", - "ButtonAddScheduledTaskTrigger": "Adicionar Disparador", + "ButtonAddScheduledTaskTrigger": "Adicionar tarefa agendada", "ButtonAddServer": "Adicionar Servidor", "ButtonAddUser": "Adicionar Utilizador", "ButtonArrowDown": "Baixo", @@ -20,14 +20,14 @@ "ButtonBack": "Voltar", "ButtonCancel": "Cancelar", "ButtonChangeServer": "Alterar Servidor", - "ButtonConnect": "Conectar", + "ButtonConnect": "Ligar", "ButtonDelete": "Remover", "ButtonDeleteImage": "Apagar imagem", "ButtonEdit": "Editar", "ButtonEditOtherUserPreferences": "Editar este perfil de utilizador, imagem e preferências pessoais.", "ButtonFilter": "Filtro", "ButtonForgotPassword": "Esqueci-me da palavra-passe", - "ButtonFullscreen": "Ecrã Inteiro", + "ButtonFullscreen": "Ecrã inteiro", "ButtonHelp": "Ajuda", "ButtonHome": "Início", "ButtonInfo": "Informação", @@ -44,10 +44,10 @@ "ButtonProfile": "Perfil", "ButtonQuickStartGuide": "Guia de Início Rápido", "ButtonRefresh": "Atualizar", - "ButtonRefreshGuideData": "Atualizar Programação da TV", + "ButtonRefreshGuideData": "Atualizar Programação de TV", "ButtonRemove": "Remover", "ButtonRepeat": "Repetir", - "ButtonResetEasyPassword": "Redefinir código pin fácil", + "ButtonResetEasyPassword": "Redefinir código PIN", "ButtonResetPassword": "Redefinir palavra-passe", "ButtonRestart": "Reiniciar", "ButtonResume": "Retomar", @@ -78,7 +78,7 @@ "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?", "ConfirmDeletion": "Confirmar Exclusão", - "Connect": "Conectar", + "Connect": "Ligar", "Continuing": "A Continuar", "CustomDlnaProfilesHelp": "Crie um perfil personalizado para um novo dispositivo ou para sobrepor um perfil de sistema.", "Delete": "Remover", @@ -94,8 +94,8 @@ "Edit": "Editar", "EnableCinemaMode": "Ativar modo cinema", "Ended": "Terminado", - "ErrorAddingMediaPathToVirtualFolder": "Ocorreu um erro ao adicionar o local dos seus ficheiros. Por favor, assegure-se que o local é valido e que o processo do Jellyfin Server tenha acesso a essa localização.", - "ErrorGettingTvLineups": "Ocorreu um erro ao transferir a programação da TV. Por favor, certifique-se que a sua informação está correta e tente novamente.", + "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.", + "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", "FastForward": "Avanço rápido", @@ -105,17 +105,17 @@ "FolderTypeBooks": "Livros", "FolderTypeMovies": "Filmes", "FolderTypeMusic": "Música", - "FolderTypeMusicVideos": "Vídeos musicais", + "FolderTypeMusicVideos": "Videoclips", "FolderTypeTvShows": "Programas TV", "Friday": "Sexta", "Fullscreen": "Ecrã inteiro", "GuideProviderSelectListings": "Selecionar Listas", - "HeaderAccessSchedule": "Agendamento de Acesso", - "HeaderAccessScheduleHelp": "Criar um agendamento de acesso para limitar o acesso a certas horas.", + "HeaderAccessSchedule": "Restrição Horária de Acesso", + "HeaderAccessScheduleHelp": "Crie uma restrição horária de acesso para limitar o acesso ao Jellyfin a determinadas horas.", "HeaderActiveDevices": "Dispositivos Ativos", - "HeaderActiveRecordings": "Gravações ativas", + "HeaderActiveRecordings": "Gravações Ativas", "HeaderActivity": "Atividade", - "HeaderAddScheduledTaskTrigger": "Adicionar Disparador", + "HeaderAddScheduledTaskTrigger": "Adicionar Tarefa Agendada", "HeaderAddToCollection": "Adicionar à Coleção", "HeaderAddUpdateImage": "Adicionar/Atualizar Imagem", "HeaderAddUser": "Adicionar Utilizador", @@ -135,7 +135,7 @@ "HeaderCodecProfileHelp": "Perfis do Codec indicam as limitações de um dispositivo ao reproduzir codecs específicos. Se uma limitação ocorre, o ficheiro multimédia será transcodificado, mesmo se o codec estiver configurado para reprodução direta.", "HeaderConfirmProfileDeletion": "Confirmar Remoção do Perfil", "HeaderConfirmRevokeApiKey": "Revogar Chave da API", - "HeaderConnectToServer": "Conectar ao Servidor", + "HeaderConnectToServer": "Ligar ao Servidor", "HeaderContainerProfile": "Perfil do Container", "HeaderContainerProfileHelp": "Perfis do Container indicam as limitações de um dispositivo ao reproduzir formatos específicos. Se uma limitação ocorre, o ficheiro multimédia será transcodificado, mesmo se o formato estiver configurado para reprodução direta.", "HeaderContinueWatching": "Continuar a Ver", @@ -143,7 +143,7 @@ "HeaderDateIssued": "Data da Emissão", "HeaderDeleteItem": "Remover item", "HeaderDeleteItems": "Remover Itens", - "HeaderDeleteTaskTrigger": "Excluir Disparador da Tarefa", + "HeaderDeleteTaskTrigger": "Excluir Tarefa Agendada", "HeaderDeveloperInfo": "Informação do Programador", "HeaderDeviceAccess": "Acesso ao Dispositivo", "HeaderDevices": "Dispositivos", @@ -157,17 +157,17 @@ "HeaderError": "Erro", "HeaderFeatureAccess": "Acesso a Características", "HeaderFeatures": "Recursos", - "HeaderFetchImages": "Buscar Imagens:", + "HeaderFetchImages": "Procurar Imagens:", "HeaderFilters": "Filtros", "HeaderForgotPassword": "Esqueci-me da palavra-passe", - "HeaderFrequentlyPlayed": "Reproduzido frequentemente", - "HeaderGenres": "Gêneros", - "HeaderGuideProviders": "Provedores de Programação da TV", + "HeaderFrequentlyPlayed": "Reproduzido Frequentemente", + "HeaderGenres": "Géneros", + "HeaderGuideProviders": "Provedores de Programação de TV", "HeaderHttpHeaders": "Cabeçalhos HTTP", "HeaderIdentification": "Identificação", - "HeaderIdentificationCriteriaHelp": "Digite, pelo menos, um critério de identificação.", + "HeaderIdentificationCriteriaHelp": "Introduza, pelo menos, um critério de identificação.", "HeaderIdentificationHeader": "Cabeçalho de Identificação", - "HeaderIdentifyItemHelp": "Digite um ou mais critérios de busca. Exclua o critério para aumentar os resultados da busca.", + "HeaderIdentifyItemHelp": "Introduza um ou mais critérios de pesquisa. Exclua o critério para aumentar os resultados da procura.", "HeaderImageSettings": "Opções da Imagem", "HeaderInstall": "Instalar", "HeaderInstantMix": "Mix instantâneo", @@ -195,11 +195,11 @@ "HeaderPassword": "Palavra-passe", "HeaderPasswordReset": "Redefinição de Palavra-Passe", "HeaderPaths": "Localizações", - "HeaderPendingInvitations": "Convites pendentes", + "HeaderPendingInvitations": "Convites Pendentes", "HeaderPeople": "Pessoas", - "HeaderPinCodeReset": "Redefinir Código Pin", + "HeaderPinCodeReset": "Redefinir Código PIN", "HeaderPlayAll": "Reproduzir Todos", - "HeaderPlayback": "Reprodução de Mídia", + "HeaderPlayback": "Reprodução de Multimédia", "HeaderPlaybackError": "Erro na Reprodução", "HeaderPlaybackSettings": "Opções de Reprodução", "HeaderPleaseSignIn": "Iniciar Sessão", @@ -207,7 +207,7 @@ "HeaderProfile": "Perfil", "HeaderProfileInformation": "Informação do Perfil", "HeaderProfileServerSettingsHelp": "Estes valores controlam como o Servidor Jellyfin se apresenta a si mesmo para o dispositivo.", - "HeaderRecentlyPlayed": "Reproduzido recentemente", + "HeaderRecentlyPlayed": "Reproduzido Recentemente", "HeaderRemoteControl": "Controlo Remoto", "HeaderRemoveMediaFolder": "Excluir Pasta Multimédia", "HeaderRemoveMediaLocation": "Remover Localização dos ficheiros multimédia", @@ -218,20 +218,20 @@ "HeaderRunningTasks": "Tarefas em Execução", "HeaderScenes": "Cenas", "HeaderSchedule": "Agendamento", - "HeaderSelectCertificatePath": "Selecione o Local do Certificado", - "HeaderSelectMetadataPath": "Selecione o Local dos Metadados", - "HeaderSelectMetadataPathHelp": "Localize ou digite o local que você gostaria de armazenar os metadados. A pasta deve ser gravável.", + "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.", "HeaderSelectPath": "Selecione o Local", "HeaderSelectServer": "Selecionar Servidor", - "HeaderSelectServerCachePath": "Selecione o Local do Cache do Servidor", - "HeaderSelectServerCachePathHelp": "Localize ou digite o local para armazenar o cache do servidor. A pasta deve permitir gravação.", + "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": "Localize ou insira o local para usar para os ficheiros temporários de transcodificação. A pasta deve permitir a escrita.", + "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.", "HeaderSendMessage": "Enviar mensagem", "HeaderSeries": "Série", "HeaderServerSettings": "Opções do Servidor", "HeaderSettings": "Configurações", - "HeaderSetupLibrary": "Configurar as suas bibliotecas multimédia", + "HeaderSetupLibrary": "Configurar Bibliotecas Multimédia", "HeaderShutdown": "Encerrar", "HeaderSpecialEpisodeInfo": "Informação do Episódio Especial", "HeaderSpecialFeatures": "Extras", @@ -241,7 +241,7 @@ "HeaderSubtitleProfilesHelp": "Perfis da legenda descrevem os formatos da legenda suportados pelo dispositivo.", "HeaderSubtitleSettings": "Configurações de Legendas", "HeaderSystemDlnaProfiles": "Perfis de Sistema", - "HeaderTaskTriggers": "Disparadores de Tarefa", + "HeaderTaskTriggers": "Tarefas Agendadas", "HeaderThisUserIsCurrentlyDisabled": "Este utilizador está desativado atualmente", "HeaderTranscodingProfile": "Perfil da Transcodificação", "HeaderTranscodingProfileHelp": "Adicionar perfis de transcodificação que indiquem que formatos deverão ser usados quando a transcodificação é necessária.", @@ -261,7 +261,7 @@ "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 exibida dentro das temporadas e séries. Isto pode aumentar significativamente a duração da análise da biblioteca.", + "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.", "InstantMix": "Mix instântaneo", "ItemCount": "{0} itens", "Label3DFormat": "Formato 3D:", @@ -270,9 +270,9 @@ "LabelAccessStart": "Hora de Início:", "LabelAirDays": "Dias da Exibição:", "LabelAirTime": "Horário:", - "LabelAirsAfterSeason": "Exibido depois da temporada:", - "LabelAirsBeforeEpisode": "Exibido antes do episódio:", - "LabelAirsBeforeSeason": "Exibido antes da temporada:", + "LabelAirsAfterSeason": "Estreou depois da temporada:", + "LabelAirsBeforeEpisode": "Estreou antes do episódio:", + "LabelAirsBeforeSeason": "Estreou antes da temporada:", "LabelAlbum": "Álbum:", "LabelAlbumArtMaxHeight": "Altura máxima da capa do álbum:", "LabelAlbumArtMaxHeightHelp": "Resolução máxima da capa do álbum exposta via upnp:albumArtURI.", @@ -318,7 +318,7 @@ "LabelDisplayMissingEpisodesWithinSeasons": "Mostrar episódios em falta dentro das temporadas", "LabelDisplayName": "Nome para apresentação:", "LabelDisplayOrder": "Ordem de apresentação:", - "LabelDisplaySpecialsWithinSeasons": "Exibir especiais dentro das temporadas em que são exibidos", + "LabelDisplaySpecialsWithinSeasons": "Mostrar epsódios especiais dentro das temporadas em que estrearam", "LabelDownMixAudioScale": "Reforço de áudio durante o downmix:", "LabelDownMixAudioScaleHelp": "Aumentar o volume de áudio durante o downmix. O valor 1 preserva o volume original.", "LabelDownloadLanguages": "Transferir os idiomas:", @@ -357,7 +357,7 @@ "LabelFriendlyName": "Nome amigável:", "LabelServerNameHelp": "Este nome será utilizado para identificar o servidor. Se não for preenchido, será usado o nome do computador.", "LabelGroupMoviesIntoCollections": "Agrupar filmes em coleções", - "LabelGroupMoviesIntoCollectionsHelp": "Ao mostrar listas de filmes, filmes que pertençam a uma coleção serão exibidos como um único item agrupado.", + "LabelGroupMoviesIntoCollectionsHelp": "Ao mostrar listas de filmes, filmes que pertençam a uma coleção serão mostrados como um único item agrupado.", "LabelHardwareAccelerationType": "Aceleração por hardware:", "LabelHardwareAccelerationTypeHelp": "Disponível apenas em sistemas suportados.", "LabelHttpsPort": "Número do porto HTTPS local:", @@ -369,8 +369,8 @@ "LabelIdentificationFieldHelp": "Uma substring ou expressão regex que não diferencia maiúscula de minúsculas.", "LabelImageType": "Tipo de imagem:", "LabelImportOnlyFavoriteChannels": "Restringir a canais marcados como favoritos", - "LabelInNetworkSignInWithEasyPassword": "Ativar acesso dentro da rede com meu código pin fácil", - "LabelInNetworkSignInWithEasyPasswordHelp": "Se ativado, você poderá usar um código pin fácil para entrar nos apps do Jellyfin dentro de sua rede. A sua senha normal só será necessária fora de sua casa. Se o código pin for deixado em branco, não será necessária uma senha dentro de sua rede doméstica.", + "LabelInNetworkSignInWithEasyPassword": "Ativar acesso dentro da rede com código PIN", + "LabelInNetworkSignInWithEasyPasswordHelp": "Se ativado, poderá utilizar um código PIN para entrar no Jellyfin dentro da rede. A palavra-passe só será necessária fora da rede. Se o código PIN for deixado em branco, não será necessária autenticação dentro da rede.", "LabelKodiMetadataDateFormat": "Formato da data de lançamento:", "LabelKodiMetadataDateFormatHelp": "Todas as datas dentro dos nfo's serão lidas e gravadas usando este formato.", "LabelKodiMetadataEnableExtraThumbs": "Copiar extrafanart para extrathumbs", @@ -378,61 +378,61 @@ "LabelKodiMetadataEnablePathSubstitution": "Ativar substituição de local", "LabelKodiMetadataEnablePathSubstitutionHelp": "Ativa a substituição do local das imagens usando as opções de substituição de caminho no servidor.", "LabelKodiMetadataSaveImagePaths": "Guardar a localização de imagens em ficheiros nfo", - "LabelKodiMetadataSaveImagePathsHelp": "Esta opção é recomendada se você tiver nomes de arquivos de imagem que não estão de acordo às recomendações do Kodi.", + "LabelKodiMetadataSaveImagePathsHelp": "Esta opção é recomendada se existirem nomes de imagens que não estejam de acordo com as recomendações do Kodi.", "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.", "LabelLockItemToPreventChanges": "Bloquear este item para evitar alterações futuras", - "LabelLoginDisclaimer": "Aviso legal no login:", + "LabelLoginDisclaimer": "Aviso legal de login:", "LabelLoginDisclaimerHelp": "Este aviso será exibido na parte inferior da página de login.", - "LabelManufacturer": "Fabricante", - "LabelManufacturerUrl": "URL do fabricante", - "LabelMatchType": "Tipo de Correspondência:", + "LabelManufacturer": "Fabricante:", + "LabelManufacturerUrl": "URL do fabricante:", + "LabelMatchType": "Tipo de correspondência:", "LabelMaxBackdropsPerItem": "Número máximo de imagens de fundo por item:", - "LabelMaxParentalRating": "Controlo Parental máximo permitido:", + "LabelMaxParentalRating": "Controlo parental máximo permitido:", "LabelMaxResumePercentage": "Percentagem máxima para retomar:", "LabelMaxResumePercentageHelp": "Os títulos são considerados totalmente assistidos se parados depois deste tempo", - "LabelMaxScreenshotsPerItem": "Número máximo de imagens de ecrã por item:", - "LabelMaxStreamingBitrateHelp": "Defina uma taxa máxima de streaming.", + "LabelMaxScreenshotsPerItem": "Número máximo de capturas de ecrã por item:", + "LabelMaxStreamingBitrateHelp": "Defina uma taxa máxima de transmissão.", "LabelMessageText": "Texto da mensagem:", "LabelMessageTitle": "Titulo da mensagem:", "LabelMetadata": "Metadados:", "LabelMetadataDownloadLanguage": "Idioma preferido para download:", "LabelMetadataPath": "Localização dos metadados:", - "LabelMetadataPathHelp": "Define um local para artwork e metadados baixados da internet.", + "LabelMetadataPathHelp": "Introduza a localização para guardar capas de álbum e metadados transferidos da Internet.", "LabelMethod": "Método:", - "LabelMinBackdropDownloadWidth": "Transferir Imagens de fundo com o tamanho mínimo:", - "LabelMinResumeDuration": "Duração mínima da retoma:", + "LabelMinBackdropDownloadWidth": "Transferir imagens de fundo com este tamanho mínimo:", + "LabelMinResumeDuration": "Duração mínima para permitir retoma de visualização:", "LabelMinResumeDurationHelp": "Conteúdos com duração inferior não permitirão parar e retomar a reprodução", - "LabelMinResumePercentage": "Percentagem mínima para retomar:", + "LabelMinResumePercentage": "Percentagem mínima de visualização para permitir retomar:", "LabelMinResumePercentageHelp": "Os títulos são considerados não assistidos se parados antes deste tempo", - "LabelMinScreenshotDownloadWidth": "Transferir imagens de ecrã com o tamanho mínimo:", + "LabelMinScreenshotDownloadWidth": "Transferir capturas de ecrã com este tamanho mínimo:", "LabelModelDescription": "Descrição do modelo", "LabelModelName": "Nome do modelo", "LabelModelNumber": "Número do modelo", "LabelModelUrl": "URL do modelo", "LabelMonitorUsers": "Monitorizar atividade de:", - "LabelMusicStreamingTranscodingBitrate": "Taxa de transcodificação das músicas:", - "LabelMusicStreamingTranscodingBitrateHelp": "Defina a taxa máxima ao fazer streaming das músicas", + "LabelMusicStreamingTranscodingBitrate": "Taxa de transcodificação de música:", + "LabelMusicStreamingTranscodingBitrateHelp": "Defina a taxa máxima ao fazer transmissão de música.", "LabelName": "Nome:", "LabelNewPassword": "Nova palavra-passe:", "LabelNewPasswordConfirm": "Confirmar nova palavra-passe:", "LabelNext": "Seguinte", "LabelNotificationEnabled": "Ativar esta notificação", - "LabelNumberOfGuideDays": "Número de dias de programação da TV para transferir:", - "LabelNumberOfGuideDaysHelp": "Transferir mais dias de programação da TV permite agendar com maior antecedência e ver mais listagens, no entanto, irá levar mais tempo a transferir. Se selecionar Automático, será escolhido o período baseado no número de canais.", + "LabelNumberOfGuideDays": "Número de dias de programação de TV para transferir:", + "LabelNumberOfGuideDaysHelp": "Transferir mais dias de programação de TV permite agendar com maior antecedência e ver mais listagens, no entanto, irá levar mais tempo a transferir. Se selecionar Automático, será escolhido o período baseado no número de canais.", "LabelOriginalAspectRatio": "Proporção da imagem original:", "LabelOverview": "Sinopse:", "LabelParentalRating": "Classificação parental:", "LabelPassword": "Palavra-Passe:", - "LabelPasswordConfirm": "Palavra-Passe (confirmar):", - "LabelPasswordRecoveryPinCode": "Código pin:", + "LabelPasswordConfirm": "Palavra-passe (confirmar):", + "LabelPasswordRecoveryPinCode": "Código PIN:", "LabelPath": "Local:", "LabelPersonRole": "Personagem:", "LabelPlaceOfBirth": "Local de nascimento:", "LabelPlayDefaultAudioTrack": "Reproduzir a faixa de áudio padrão independentemente do idioma", - "LabelPreferredDisplayLanguage": "Idioma de visualização preferencial:", + "LabelPreferredDisplayLanguage": "Idioma de visualização preferido:", "LabelPreferredDisplayLanguageHelp": "A tradução do Jellyfin é um projeto contínuo.", "LabelPrevious": "Anterior", "LabelProfileAudioCodecs": "Codecs do áudio:", @@ -447,44 +447,44 @@ "LabelPublicHttpPortHelp": "Número do porto público que deverá ser mapeado para o porto HTTP local.", "LabelPublicHttpsPort": "Número do porto público HTTPS:", "LabelPublicHttpsPortHelp": "Número do porto público que deverá ser mapeado para o porto HTTPS local.", - "LabelReadHowYouCanContribute": "Aprenda como pode contribuir.", + "LabelReadHowYouCanContribute": "Veja como pode contribuir.", "LabelRecordingPath": "Localização predefinida das gravações:", - "LabelReleaseDate": "Data do lançamento:", - "LabelRemoteClientBitrateLimit": "Limite de taxa de bits para streaming da Internet (Mbps):", + "LabelReleaseDate": "Data de lançamento:", + "LabelRemoteClientBitrateLimit": "Taxa de bits máxima para transmissão para a Internet (Mbps):", "LabelRuntimeMinutes": "Duração (minutos):", "LabelSaveLocalMetadata": "Guardar imagens e metadados nas pastas multimédia", "LabelSaveLocalMetadataHelp": "Guardar imagens e metadados diretamente nas pastas multimédia, vai colocá-los num local de fácil acesso para poderem ser editados facilmente.", - "LabelScheduledTaskLastRan": "Última execução {0}, demorando {1}.", + "LabelScheduledTaskLastRan": "Última execução há {0}. Tempo de execução {1}.", "LabelSeasonNumber": "Número da temporada:", "LabelSelectUsers": "Selecionar utilizadores:", "LabelSelectVersionToInstall": "Selecione a versão para instalar:", "LabelSendNotificationToUsers": "Enviar notificação para:", "LabelSerialNumber": "Número de série", "LabelServerHost": "Servidor:", - "LabelServerHostHelp": "192.168.1.100 ou https://meuservidor.com", + "LabelServerHostHelp": "192.168.1.100 ou https://omeudominio.com", "LabelServerPort": "Porto:", "LabelSkipIfAudioTrackPresent": "Ignorar se a faixa de áudio padrão coincidir com o idioma de download", "LabelSkipIfAudioTrackPresentHelp": "Desmarque esta opção para garantir que todos os vídeos têm legendas, independentemente do idioma do áudio.", - "LabelSkipIfGraphicalSubsPresent": "Ignorar se o vídeo já possuir legendas embutidas", + "LabelSkipIfGraphicalSubsPresent": "Ignorar se o vídeo já possuir legendas integradas", "LabelSkipIfGraphicalSubsPresentHelp": "Manter versões das legendas em texto resultará em uma entrega mais eficiente e diminuirá a necessidade de transcodificação do vídeo.", "LabelSonyAggregationFlags": "Flags de agregação da Sony:", "LabelSonyAggregationFlagsHelp": "Determina o conteúdo do elemento aggregationFlags no namespace urn:schemas-sonycom:av.", "LabelSource": "Fonte:", - "LabelStartWhenPossible": "Começar quando possível:", + "LabelStartWhenPossible": "Começar, quando possível:", "LabelStatus": "Estado:", - "LabelStopWhenPossible": "Parar quando possível:", - "LabelStopping": "Parando", + "LabelStopWhenPossible": "Parar, quando possível:", + "LabelStopping": "A Parar", "LabelSubtitleFormatHelp": "Exemplo: srt", "LabelSubtitlePlaybackMode": "Modo da Legenda:", "LabelSupportedMediaTypes": "Tipos de Conteúdos Suportados:", "LabelTagline": "Slogan:", "LabelTime": "Tempo:", "LabelTimeLimitHours": "Limite de tempo (horas):", - "LabelTranscodingAudioCodec": "Codec do Áudio:", + "LabelTranscodingAudioCodec": "Codec de áudio:", "LabelTranscodingContainer": "Contentor:", - "LabelTranscodingTempPathHelp": "Esta pasta contém arquivos ativos usados pelo transcodificador. Especifique um local personalizado ou deixe em branco para usar o padrão dentro da pasta de dados do servidor.", - "LabelTranscodingThreadCount": "Contagem de threads da transcodificação:", - "LabelTranscodingThreadCountHelp": "Selecione o número máximo de threads a ser usado quando transcodificar. Reduzir o número de threads irá diminuir o uso da CPU, mas pode não converter rápido o suficiente para uma experiência de reprodução suave.", + "LabelTranscodingTempPathHelp": "Esta pasta contém ficheiros ativos utilizados pelo transcodificador. Indique uma localização personalizada ou deixe em branco para utilizar o caminho por defeito.", + "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.", "LabelTranscodingVideoCodec": "Codec do vídeo:", "LabelTriggerType": "Tipo do Acionador:", "LabelTunerIpAddress": "Endereço IP do Sintonizador:", @@ -511,25 +511,25 @@ "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 abruptamente.", + "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.", "MessageConfirmShutdown": "Tem a certeza de que deseja encerrar o Servidor Jellyfin?", "MessageDeleteTaskTrigger": "Tem a certeza de que deseja remover o agendamento desta tarefa?", - "MessageDirectoryPickerBSDInstruction": "Para BSD, você precisará configurar o disco dentro de seu Jail do FreeNAS para permitir que o Jellyfin tenha acesso a ele.", - "MessageDirectoryPickerInstruction": "Os locais de rede podem ser digitados manualmente caso o botão de Rede não consiga localizar seus dispositivos. Por exemplo, {0} ou {1}.", + "MessageDirectoryPickerBSDInstruction": "Num sistema operativo BSD, é necessário configurar o disco Jail FreeNAS para permitir o acesso do Servidor Jellyfin.", + "MessageDirectoryPickerInstruction": "As localizações de rede podem ser escritas manualmente caso o botão \"Rede\" não consiga encontrar os dispositivos. Por exemplo, {0} ou {1}.", "MessageDirectoryPickerLinuxInstruction": "Para Linux no Arch Linux, CentOS, Debian, Fedora, OpenSuse ou Ubuntu, você deve permitir que o utilizador Jellyfin tenha ao menos acesso de leitura no seu disco.", "MessageEnablingOptionLongerScans": "Ativar esta opção pode aumentar significativamente a duração da análise da biblioteca.", - "MessageFileReadError": "Ocorreu um erro ao ler este arquivo.", + "MessageFileReadError": "Ocorreu um erro ao ler este ficheiro.", "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.", - "MessageNoAvailablePlugins": "Sem extensões disponíveis.", + "MessageNoAvailablePlugins": "Não existem extensões disponíveis.", "MessageNoMovieSuggestionsAvailable": "Não existem sugestões de filmes disponíveis atualmente. Comece por assistir e avaliar seus filmes e, então, volte para verificar suas recomendações.", - "MessageNoPluginsInstalled": "Você não possui plugins instalados.", - "MessageNoTrailersFound": "Nenhum trailer encontrado. Instale o canal Trailer para melhorar sua experiência com filmes, adicionando uma biblioteca de trailers da internet.", + "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.", "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á activa.", + "MessagePleaseEnsureInternetMetadata": "Certifique-se que a transferência de metadados da Internet está ativa.", "MessageReenableUser": "Veja abaixo para reativar", "MessageTheFollowingLocationWillBeRemovedFromLibrary": "As localizações dos ficheiros multimédia abaixo serão excluídas de sua biblioteca Jellyfin:", "MinutesAfter": "minutos depois", @@ -571,12 +571,12 @@ "OptionCustomUsers": "Personalizado", "OptionDaily": "Diariamente", "OptionDateAdded": "Data de adição", - "OptionDateAddedFileTime": "Usar a data de criação do arquivo", - "OptionDateAddedImportTime": "Usar a data obtida na biblioteca", + "OptionDateAddedFileTime": "Usar a data de criação do ficheiro", + "OptionDateAddedImportTime": "Usar a data de importação para a biblioteca", "OptionDatePlayed": "Data de reprodução", "OptionDescending": "Descendente", "OptionDisableUser": "Desativar este utilizador", - "OptionDisableUserHelp": "Se desativado, o servidor não permite nenhuma conexão deste utilizador. Conexões existentes serão terminadas.", + "OptionDisableUserHelp": "Se desativado, o servidor não permite nenhuma ligação com este nome de utilizador. Ligações existentes serão terminadas.", "OptionDislikes": "Não gostos", "OptionDownloadArtImage": "Arte", "OptionDownloadBackImage": "Traseira", @@ -622,7 +622,7 @@ "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\".", - "OptionPlainVideoItems": "Exibir todos os vídeos como itens de vídeo simples", + "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\".", "OptionPlayCount": "N.º Visualizações", "OptionPlayed": "Reproduzido", @@ -658,7 +658,7 @@ "PasswordResetConfirmation": "Tem a certeza de que deseja redefinir a palavra-passe?", "PasswordResetHeader": "Redefinir Palavra-Passe", "PasswordSaved": "Palavra-passe guardada.", - "PinCodeResetComplete": "O código pin foi redefinido.", + "PinCodeResetComplete": "O código PIN foi redefinido.", "PinCodeResetConfirmation": "Tem a certeza de que devia repôr o código PIN?", "Play": "Reproduzir", "PlayNextEpisodeAutomatically": "Reproduzir próximo episódio automaticamente", @@ -680,7 +680,7 @@ "Save": "Guardar", "ScanLibrary": "Analisar biblioteca", "Search": "Busca", - "SearchForCollectionInternetMetadata": "Procurar na internet por imagens e metadados", + "SearchForCollectionInternetMetadata": "Procurar na Internet por imagens e metadados", "SearchForSubtitles": "Buscar Legendas", "SendMessage": "Enviar mensagem", "Series": "Séries", @@ -714,14 +714,14 @@ "TabMetadata": "Metadados", "TabMovies": "Filmes", "TabMusic": "Música", - "TabMusicVideos": "Videos Musicais", - "TabMyPlugins": "As minhas extensões", + "TabMusicVideos": "Videoclips", + "TabMyPlugins": "As Minhas Extensões", "TabNetworks": "Redes", "TabNfoSettings": "Definições de ficheiros NFO", "TabNotifications": "Notificações", "TabOther": "Outro", "TabParentalControl": "Controlo Parental", - "TabPassword": "Palavra-Passe", + "TabPassword": "Palavra-passe", "TabPlayback": "Reprodução", "TabPlaylist": "Lista de Reprodução", "TabPlaylists": "Listas de Reprodução", @@ -747,8 +747,8 @@ "TrackCount": "{0} faixas", "Tuesday": "Terça", "UninstallPluginConfirmation": "Tem a certeza de que deseja desinstalar {0}?", - "UninstallPluginHeader": "Desinstalar extensão", - "Unmute": "Ativar Som", + "UninstallPluginHeader": "Desinstalar Extensão", + "Unmute": "Ativar som", "UserProfilesIntro": "O Jellyfin inclui suporte nativo de perfis de utilizadores, permitindo que cada utilizador tenha as suas configurações de visualização, estado da reprodução e controlos parentais.", "ValueAudioCodec": "Codec de Áudio: {0}", "ValueConditions": "Condições: {0}", @@ -758,7 +758,7 @@ "ValueVideoCodec": "Codec de Vídeo: {0}", "Wednesday": "Quarta", "WelcomeToProject": "Bem-vindo ao Jellyfin!", - "WizardCompleted": "É tudo, de momento. O Jellyfin iniciou a recolha de informações da sua biblioteca multimédia. Reveja algumas das nossas aplicações e, de seguida, clique Terminar para ver o Painel Principal do Servidor.", + "WizardCompleted": "É tudo, de momento. O Jellyfin iniciou a recolha de informações da sua biblioteca multimédia. Conheça algumas das nossas aplicações e, de seguida, clique Terminar para ver o Painel Principal do Servidor.", "Writer": "Escritor", "XmlDocumentAttributeListHelp": "Estes atributos são aplicados ao elemento principal de cada resposta xml.", "AccessRestrictedTryAgainLater": "Acesso restrito. Por favor, tente mais tarde.", @@ -788,7 +788,7 @@ "Artists": "Artistas", "Ascending": "Crescente", "AspectRatio": "Formato", - "AuthProviderHelp": "Selecione 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 deste utilizador.", "Auto": "Automático", "AutoBasedOnLanguageSetting": "Auomático (baseado no idioma definido)", "BirthDateValue": "Nascimento: {0}", @@ -814,21 +814,21 @@ "Songs": "Músicas", "Sync": "Sincronização", "Absolute": "Absoluto", - "CriticRating": "Avaliação dos críticos", + "CriticRating": "Avaliação da crítica", "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 do Servidor Jellyfin, em definições da Biblioteca", "CommunityRating": "Avaliação da comunidade", "ChannelNumber": "Número do canal", "ChannelNameOnly": "Apenas canal {0}", "ChangingMetadataImageSettingsNewContent": "Alterações às definições de transferência de metadados ou capas apenas serão aplicadas a conteúdo novo adicionado à biblioteca. Para aplicar as alterações aos itens já existentes, necessitará de atualizar manualmente os metadados.", "Categories": "Categorias", - "CancelSeries": "Cancelar série", + "CancelSeries": "Cancelar gravação de série", "CancelRecording": "Cancelar gravação", "ButtonWebsite": "Website", "ButtonTrailer": "Trailer", - "ButtonSelectServer": "Selecionar Servidor", + "ButtonSelectServer": "Selecionar servidor", "ButtonRename": "Alterar o nome", "ButtonParentalControl": "Controlo parental", "ButtonOther": "Outro", @@ -865,11 +865,11 @@ "HeaderDeleteDevice": "Apagar Dispositivo", "HeaderDefaultRecordingSettings": "Definições de Gravação por Defeito", "HeaderContinueListening": "Continuar a Ouvir", - "HeaderConnectionFailure": "Falha de ligação", - "HeaderConfirmPluginInstallation": "Confirmar instalação de Plug-In", + "HeaderConnectionFailure": "Falha de Ligação", + "HeaderConfirmPluginInstallation": "Confirmar Instalação de Extensão", "HeaderConfigureRemoteAccess": "Configurar Acesso Remoto", "HeaderChapterImages": "Imagens do Capítulo", - "HeaderCancelSeries": "Cancelar Série", + "HeaderCancelSeries": "Cancelar Gravação de Série", "HeaderCancelRecording": "Cancelar Gravação", "HeaderBooks": "Livros", "HeaderAudioBooks": "Livros de Áudio", @@ -893,7 +893,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 encontrar-se 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 de novo.", "Extras": "Extras", "ExtraLarge": "Extra grande", "EveryNDays": "A cada {0} dias", @@ -904,7 +904,7 @@ "ErrorAddingXmlTvFile": "Ocorreu um erro ao aceder ao ficheiro XmlTV. Por favor, garanta que o ficheiro está acessível e tente de novo.", "Episodes": "Episódios", "EndsAtValue": "Termina às {0}", - "EnablePhotosHelp": "Fotografias serão detectadas e mostradas em conjunto com outros ficheiros multimédia.", + "EnablePhotosHelp": "Fotografias serão detetadas e mostradas em conjunto com outros ficheiros multimédia.", "EnablePhotos": "Ativar fotografias", "EnableNextVideoInfoOverlayHelp": "No final de um vídeo, mostrar informação sobre o próximo vídeo da lista de reprodução.", "EnableNextVideoInfoOverlay": "Ativar informação sobre o próximo vídeo durante a reprodução", @@ -921,7 +921,7 @@ "Download": "Transferir", "DoNotRecord": "Não gravar", "DisplayModeHelp": "Selecione o tipo de ecrã onde o Jellyfin será utilizado.", - "DisplayMissingEpisodesWithinSeasonsHelp": "Deve também ser ativado para as bibliotecas de TV no painel de controlo do Servidor Jellyfin.", + "DisplayMissingEpisodesWithinSeasonsHelp": "Deve também ser ativado para as bibliotecas de TV no Painel Principal do Servidor Jellyfin.", "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", @@ -943,7 +943,7 @@ "UserAgentHelp": "Forneça um user-agent HTTP personalizado, se necessário.", "OptionProtocolHttp": "HTTP", "OptionProtocolHls": "Emissão HTTP em direto", - "LabelHomeScreenSectionValue": "Secção {0} do painel principal:", + "LabelHomeScreenSectionValue": "Secção {0} do Painel Principal:", "LabelHomeNetworkQuality": "Qualidade da rede interna:", "LabelH264EncodingPreset": "Preset para codificação H264:", "LabelH264Crf": "CRF para codificação H264:", @@ -987,10 +987,57 @@ "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 da TV. O utilizador é responsável por criar e manter o ficheiro atualizado.", + "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 por criar e manter o ficheiro atualizado.", "TV": "TV", "LiveTV": "TV em Direto", "LabelSelectFolderGroups": "Agrupar automaticamente o conteúdo das seguintes pastas em vistas como Filmes, Música e TV:", "HeaderUpcomingOnTV": "A Seguir", - "HeaderLiveTvTunerSetup": "Configurar Sintonizador de TV" + "HeaderLiveTvTunerSetup": "Configurar Sintonizador de TV", + "ButtonUp": "Para cima", + "ButtonDown": "Para baixo", + "RecordSeries": "Gravar série", + "LabelKeepUpTo": "Manter, no máximo:", + "AroundTime": "Por volta das {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", + "Screenshots": "Capturas de Ecrã", + "Screenshot": "Captura de Ecrã", + "Schedule": "Horário", + "ScanForNewAndUpdatedFiles": "Procurar ficheiros novos ou atualizados", + "SaveSubtitlesIntoMediaFoldersHelp": "Guardar ficheiros de legendas junto aos ficheiros vídeo facilita a gestão.", + "SaveSubtitlesIntoMediaFolders": "Guardar legendas nas pastas multimédia", + "Runtime": "Duração", + "RunAtStartup": "Executar no arranque", + "ResumeAt": "Retomar a partir de {0}", + "RestartPleaseWaitMessage": "Por favor aguarde enquanto o Servidor Jellyfin reinicia. Poderá demorar alguns minutos.", + "RequiredForAllRemoteConnections": "Necessário para todas as ligações externas", + "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.", + "NoPluginConfigurationMessage": "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.", + "MessagePluginConfigurationRequiresLocalAccess": "Para configurar esta extensão, inicie sessão localmente no servidor.", + "MessageInstallPluginFromApp": "Esta extensão deverá ser instalada a partir da aplicação onde tem intenção de a utilizar.", + "HeaderPluginInstallation": "Instalação de Extensão", + "PluginInstalledMessage": "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}.", + "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", + "PlayNext": "Reproduzir a seguir", + "PlayFromBeginning": "Reproduzir do início", + "PlayCount": "Número de reproduções", + "PlaybackData": "Dados de Reprodução", + "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.", + "Overview": "Resumo", + "OriginalAirDateValue": "Data de estreia original: {0}", + "OptionSubstring": "Parte de palavra" } From f1ba5c63c0b91b3148de2b40c6de5a1f8a6eb797 Mon Sep 17 00:00:00 2001 From: Daniel Hartung <22015466+dhartung@users.noreply.github.com> Date: Wed, 11 Sep 2019 16:59:47 +0200 Subject: [PATCH 44/80] Toast notification when copy-stream is executed --- src/components/itemcontextmenu.js | 4 ++++ src/strings/de.json | 2 ++ src/strings/en-gb.json | 3 ++- src/strings/en-us.json | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/itemcontextmenu.js b/src/components/itemcontextmenu.js index 7348eeef30..77bc88a25b 100644 --- a/src/components/itemcontextmenu.js +++ b/src/components/itemcontextmenu.js @@ -319,6 +319,10 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter', textArea.select(); try { document.execCommand('copy'); + + require(['toast'], function (toast) { + toast(globalize.translate('CopyStreamURLSuccess')); + }); } catch (err) { console.error("Failed to copy to clipboard"); } diff --git a/src/strings/de.json b/src/strings/de.json index d144818b0e..2fa89108f5 100644 --- a/src/strings/de.json +++ b/src/strings/de.json @@ -1295,6 +1295,8 @@ "ButtonTrailer": "Trailer", "ButtonWebsite": "Webseite", "ChangingMetadataImageSettingsNewContent": "Änderungen an Metadaten- und Artwork-Einstellungen betreffen nur der Bibliothek neu hinzugefügte Inhalte. Um diese Änderungen auf existierende Medien anzuwenden müssen die Metadaten manuell aktualisiert werden.", + "CopyStreamURL": "Kopiere Streaminglink", + "CopyStreamURLSuccess": "Link erfolgreich kopiert.", "Desktop": "Desktop", "Download": "Download", "Extras": "Extras", diff --git a/src/strings/en-gb.json b/src/strings/en-gb.json index 941beab405..0304deef2c 100644 --- a/src/strings/en-gb.json +++ b/src/strings/en-gb.json @@ -454,5 +454,6 @@ "HeaderPasswordReset": "Password Reset", "HeaderPaths": "Paths", "HeaderPendingInvitations": "Pending Invitations", - "CopyStreamURL": "Copy Stream URL" + "CopyStreamURL": "Copy Stream URL", + "CopyStreamURLSuccess": "URL copied successfully." } diff --git a/src/strings/en-us.json b/src/strings/en-us.json index aa648bd56d..cead11c76e 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -161,6 +161,7 @@ "ContinueWatching": "Continue watching", "Continuing": "Continuing", "CopyStreamURL": "Copy Stream URL", + "CopyStreamURLSuccess": "URL copied successfully.", "CriticRating": "Critic rating", "CustomDlnaProfilesHelp": "Create a custom profile to target a new device or override a system profile.", "DateAdded": "Date added", From ffe4087f0a50f5a7d5edcb4479d3132282a8c78f Mon Sep 17 00:00:00 2001 From: tluciomiranda Date: Wed, 11 Sep 2019 13:52:23 +0000 Subject: [PATCH 45/80] 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 | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index 710a2405f5..041c937497 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -391,8 +391,8 @@ "LabelMatchType": "Tipo de correspondência:", "LabelMaxBackdropsPerItem": "Número máximo de imagens de fundo por item:", "LabelMaxParentalRating": "Controlo parental máximo permitido:", - "LabelMaxResumePercentage": "Percentagem máxima para retomar:", - "LabelMaxResumePercentageHelp": "Os títulos são considerados totalmente assistidos se parados depois deste tempo", + "LabelMaxResumePercentage": "Percentagem máxima de visualização para permitir retomar:", + "LabelMaxResumePercentageHelp": "Os títulos são considerados como vistos se parados após esta percentagem da duração", "LabelMaxScreenshotsPerItem": "Número máximo de capturas de ecrã por item:", "LabelMaxStreamingBitrateHelp": "Defina uma taxa máxima de transmissão.", "LabelMessageText": "Texto da mensagem:", @@ -406,7 +406,7 @@ "LabelMinResumeDuration": "Duração mínima para permitir retoma de visualização:", "LabelMinResumeDurationHelp": "Conteúdos com duração inferior não permitirão parar e retomar a reprodução", "LabelMinResumePercentage": "Percentagem mínima de visualização para permitir retomar:", - "LabelMinResumePercentageHelp": "Os títulos são considerados não assistidos se parados antes deste tempo", + "LabelMinResumePercentageHelp": "Os títulos são considerados como não vistos se parados antes desta percentagem da duração", "LabelMinScreenshotDownloadWidth": "Transferir capturas de ecrã com este tamanho mínimo:", "LabelModelDescription": "Descrição do modelo", "LabelModelName": "Nome do modelo", @@ -684,7 +684,7 @@ "SearchForSubtitles": "Buscar Legendas", "SendMessage": "Enviar mensagem", "Series": "Séries", - "ServerUpdateNeeded": "Este Servidor Jellyfin precisa ser atualizado. Para fazer download da versão mais recente, por favor visite {0}", + "ServerUpdateNeeded": "Este Servidor Jellyfin precisa de ser atualizado. Para transferir a versão mais recente, por favor visite {0}", "Settings": "Configurações", "SettingsSaved": "Configurações guardadas.", "Share": "Partilhar", @@ -1039,5 +1039,10 @@ "PackageInstallCancelled": "Instalação de {0} cancelada.", "Overview": "Resumo", "OriginalAirDateValue": "Data de estreia original: {0}", - "OptionSubstring": "Parte de palavra" + "OptionSubstring": "Parte de palavra", + "LatestFromLibrary": "Últimos", + "HideWatchedContentFromLatestMedia": "Ocultar títulos já vistos do conteúdo recente", + "MessageUnableToConnectToServer": "Não foi possível estabelecer ligação ao servidor. Por favor, certifique-se de que o servidor está a correr e tente de novo.", + "HeaderStartNow": "Iniciar", + "HeaderOnNow": "No Ar" } From 2240edce26176d6b0d99e6156ce08af3a0b3aa90 Mon Sep 17 00:00:00 2001 From: tluciomiranda Date: Wed, 11 Sep 2019 15:15:23 +0000 Subject: [PATCH 46/80] 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 | 80 +++++++++++++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 21 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index 041c937497..4acbd9c016 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -90,7 +90,7 @@ "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": "Diretor", - "EasyPasswordHelp": "Seu código pin fácil é usado para acesso off-line com apps suportados pelo Jellyfin e pode ser usado para acesso fácil dentro da rede.", + "EasyPasswordHelp": "O código PIN é utilizado para acesso off-line com aplicações suportados pelo Jellyfin e pode ser usado para um acesso fácil dentro da rede.", "Edit": "Editar", "EnableCinemaMode": "Ativar modo cinema", "Ended": "Terminado", @@ -149,8 +149,8 @@ "HeaderDevices": "Dispositivos", "HeaderDirectPlayProfile": "Perfil da Reprodução Direta", "HeaderDirectPlayProfileHelp": "Adicionar perfis de reprodução direta que indiquem que formatos o dispositivo pode suportar nativamente.", - "HeaderDisplay": "Exibição", - "HeaderDisplaySettings": "Apresentar Configurações", + "HeaderDisplay": "Visualização", + "HeaderDisplaySettings": "Configurações de Visualização", "HeaderEasyPinCode": "Código PIN", "HeaderEnabledFields": "Campos Ativados", "HeaderEnabledFieldsHelp": "Desmarque um campo para bloqueá-lo e evitar que seus dados sejam alterados.", @@ -168,7 +168,7 @@ "HeaderIdentificationCriteriaHelp": "Introduza, pelo menos, um critério de identificação.", "HeaderIdentificationHeader": "Cabeçalho de Identificação", "HeaderIdentifyItemHelp": "Introduza um ou mais critérios de pesquisa. Exclua o critério para aumentar os resultados da procura.", - "HeaderImageSettings": "Opções da Imagem", + "HeaderImageSettings": "Configurações de Imagem", "HeaderInstall": "Instalar", "HeaderInstantMix": "Mix instantâneo", "HeaderLatestEpisodes": "Últimos Episódios", @@ -178,8 +178,8 @@ "HeaderLatestRecordings": "Últimas Gravações", "HeaderLibraries": "Bibliotecas", "HeaderLibraryAccess": "Acesso à Biblioteca", - "HeaderLibraryFolders": "Pastas multimédia", - "HeaderLibrarySettings": "Definições da Biblioteca", + "HeaderLibraryFolders": "Pastas Multimédia", + "HeaderLibrarySettings": "Configurações da Biblioteca", "HeaderLiveTV": "TV em Direto", "HeaderLiveTv": "TV em Direto", "HeaderLoginFailure": "Falha no Login", @@ -201,7 +201,7 @@ "HeaderPlayAll": "Reproduzir Todos", "HeaderPlayback": "Reprodução de Multimédia", "HeaderPlaybackError": "Erro na Reprodução", - "HeaderPlaybackSettings": "Opções de Reprodução", + "HeaderPlaybackSettings": "Configurações de Reprodução", "HeaderPleaseSignIn": "Iniciar Sessão", "HeaderPreferredMetadataLanguage": "Idioma Preferencial dos Metadados", "HeaderProfile": "Perfil", @@ -229,7 +229,7 @@ "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.", "HeaderSendMessage": "Enviar mensagem", "HeaderSeries": "Série", - "HeaderServerSettings": "Opções do Servidor", + "HeaderServerSettings": "Configurações do Servidor", "HeaderSettings": "Configurações", "HeaderSetupLibrary": "Configurar Bibliotecas Multimédia", "HeaderShutdown": "Encerrar", @@ -385,7 +385,7 @@ "LabelLocalHttpServerPortNumberHelp": "Número do porto TCP em que o servidor HTTP do Jellyfin ficará à escuta.", "LabelLockItemToPreventChanges": "Bloquear este item para evitar alterações futuras", "LabelLoginDisclaimer": "Aviso legal de login:", - "LabelLoginDisclaimerHelp": "Este aviso será exibido na parte inferior da página de login.", + "LabelLoginDisclaimerHelp": "Este aviso será mostrado na parte inferior da página de login.", "LabelManufacturer": "Fabricante:", "LabelManufacturerUrl": "URL do fabricante:", "LabelMatchType": "Tipo de correspondência:", @@ -463,10 +463,10 @@ "LabelServerHost": "Servidor:", "LabelServerHostHelp": "192.168.1.100 ou https://omeudominio.com", "LabelServerPort": "Porto:", - "LabelSkipIfAudioTrackPresent": "Ignorar se a faixa de áudio padrão coincidir com o idioma de download", + "LabelSkipIfAudioTrackPresent": "Ignorar no caso de o idioma da faixa de áudio principal coincidir com o idioma de transferência", "LabelSkipIfAudioTrackPresentHelp": "Desmarque esta opção para garantir que todos os vídeos têm legendas, independentemente do idioma do áudio.", "LabelSkipIfGraphicalSubsPresent": "Ignorar se o vídeo já possuir legendas integradas", - "LabelSkipIfGraphicalSubsPresentHelp": "Manter versões das legendas em texto resultará em uma entrega mais eficiente e diminuirá a necessidade de transcodificação do vídeo.", + "LabelSkipIfGraphicalSubsPresentHelp": "Manter versões das legendas em texto resultará numa transmissão mais eficiente e diminuirá a necessidade de transcodificação de vídeo.", "LabelSonyAggregationFlags": "Flags de agregação da Sony:", "LabelSonyAggregationFlagsHelp": "Determina o conteúdo do elemento aggregationFlags no namespace urn:schemas-sonycom:av.", "LabelSource": "Fonte:", @@ -493,8 +493,8 @@ "LabelTypeText": "Texto", "LabelUseNotificationServices": "Usar os seguintes serviços:", "LabelUser": "Utilizador:", - "LabelUserLibrary": "Biblioteca do utilizador:", - "LabelUserLibraryHelp": "Selecione qual é a biblioteca de utilizador a mostrar no dispositivo. Deixe em branco para herdar a definição padrão.", + "LabelUserLibrary": "Biblioteca do Utilizador:", + "LabelUserLibraryHelp": "Selecione qual a biblioteca de utilizador a mostrar no dispositivo. Deixe em branco para herdar a definição padrão.", "LabelUsername": "Nome de Utilizador:", "LabelValue": "Valor:", "LabelVersionInstalled": "{0} instalado", @@ -582,7 +582,7 @@ "OptionDownloadBackImage": "Traseira", "OptionDownloadBoxImage": "Caixa", "OptionDownloadDiscImage": "Disco", - "OptionDownloadImagesInAdvanceHelp": "Por padrão, a maioria das imagens são descarregadas só quando uma aplicação do Jellyfin solicita. Ativar 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ã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.", "OptionDownloadPrimaryImage": "Principal", "OptionDownloadThumbImage": "Miniatura", "OptionDvd": "DVD", @@ -624,7 +624,7 @@ "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\".", "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\".", - "OptionPlayCount": "N.º Visualizações", + "OptionPlayCount": "N.º de Visualizações", "OptionPlayed": "Reproduzido", "OptionPremiereDate": "Data de Estreia", "OptionProfileAudio": "Áudio", @@ -704,7 +704,7 @@ "TabDashboard": "Painel Principal", "TabDevices": "Dispositivos", "TabDirectPlay": "Reprodução Direta", - "TabDisplay": "Exibição", + "TabDisplay": "Visualização", "TabEpisodes": "Episódios", "TabFavorites": "Favoritos", "TabGenres": "Géneros", @@ -774,7 +774,7 @@ "AllEpisodes": "Todos os episódios", "AllLanguages": "Todos os idiomas", "AllLibraries": "Todas as bibliotecas", - "AllowHWTranscodingHelp": "Quando ativado, permite ao sintonizador converter streams em tempo real. Poderá reduzir a necessidade de conversão a fazer pelo Jellyfin Server.", + "AllowHWTranscodingHelp": "Quando ativado, permite ao sintonizador converter emissões em tempo real. Poderá reduzir a necessidade de conversão a fazer pelo Jellyfin Server.", "AllowMediaConversion": "Permitir conversão multimédia", "AllowMediaConversionHelp": "Permitir ou negar acesso à funcionalidade de conversão multimédia.", "AllowOnTheFlySubtitleExtraction": "Permitir a extração de legendas em tempo real", @@ -822,7 +822,7 @@ "CommunityRating": "Avaliação da comunidade", "ChannelNumber": "Número do canal", "ChannelNameOnly": "Apenas canal {0}", - "ChangingMetadataImageSettingsNewContent": "Alterações às definições de transferência de metadados ou capas apenas serão aplicadas a conteúdo novo adicionado à biblioteca. Para aplicar as alterações aos itens já existentes, necessitará de atualizar manualmente os metadados.", + "ChangingMetadataImageSettingsNewContent": "Alterações às definições de transferência de metadados ou capas apenas serão aplicadas a conteúdo novo adicionado à Biblioteca. Para aplicar as alterações aos itens já existentes, necessitará de atualizar manualmente os metadados.", "Categories": "Categorias", "CancelSeries": "Cancelar gravação de série", "CancelRecording": "Cancelar gravação", @@ -950,7 +950,7 @@ "LabelFont": "Tipo de Letra:", "LabelFileOrUrl": "Ficheiro ou URL:", "LabelDynamicExternalId": "{0} ID:", - "LabelDropShadow": "Sombra:", + "LabelDropShadow": "Realce:", "LabelDropImageHere": "Arraste a imagem para aqui, ou clique para procurar.", "LabelDisplayMode": "Modo de apresentação:", "LabelDisplayLanguageHelp": "A tradução do Jellyfin é um projeto em desenvolvimento contínuo.", @@ -1028,7 +1028,7 @@ "Played": "Reproduzido", "PlayNext": "Reproduzir a seguir", "PlayFromBeginning": "Reproduzir do início", - "PlayCount": "Número de reproduções", + "PlayCount": "N.º de Reproduções", "PlaybackData": "Dados de Reprodução", "PlayAllFromHere": "Reproduzir todos a partir daqui", "PerfectMatch": "Correspondência perfeita", @@ -1044,5 +1044,43 @@ "HideWatchedContentFromLatestMedia": "Ocultar títulos já vistos do conteúdo recente", "MessageUnableToConnectToServer": "Não foi possível estabelecer ligação ao servidor. Por favor, certifique-se de que o servidor está a correr e tente de novo.", "HeaderStartNow": "Iniciar", - "HeaderOnNow": "No Ar" + "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.", + "MarkUnplayed": "Marcar como Não Visto", + "MarkPlayed": "Marcar como Visto", + "LabelSelectFolderGroupsHelp": "Pastas não selecionadas serão apresentadas sozinhas, na sua própria vista.", + "LabelPlaylist": "Lista de Reprodução:", + "HeaderPlayOn": "Reproduzir Em", + "HeaderNextVideoPlayingInValue": "Reprodução do próximo vídeo a iniciar em {0}", + "HeaderNextEpisodePlayingInValue": "Reprodução do próximo episódio a iniciar em {0}", + "HardwareAccelerationWarning": "Ativar a aceleração por hardware pode causar instabilidade em alguns ambientes. Garanta que o sistema operativo e os controladores da placa gráfica estão completamente atualizados. Se tiver dificuldades em reproduzir vídeo depois de alterar esta opção, pode ser necessário repôr em \\\"Auto\\\".", + "Display": "Visualização", + "ManageLibrary": "Gerir biblioteca", + "HeaderLibraryOrder": "Ordenação da Biblioteca", + "EnableThemeVideosHelp": "Se ativado, serão reproduzidos vídeos do tema em plano de fundo durante a navegação pela Biblioteca.", + "EnableThemeSongsHelp": "Se ativado, serão reproduzidas músicas do tema em plano de fundo durante a navegação pela Biblioteca.", + "EnableBackdropsHelp": "Se ativado, serão mostradas imagens de fundo em algumas páginas durante a navegação pela Biblioteca.", + "MediaInfoSize": "Tamanho", + "LabelTextSize": "Tamanho do Texto:", + "HeaderSubtitleAppearance": "Aparência das Legendas", + "ShowAdvancedSettings": "Mostrar configurações avançadas", + "OptionDownloadImagesInAdvance": "Tansferir imagens antecipadamente", + "SkipEpisodesAlreadyInMyLibraryHelp": "Os episódios vão ser comparados utilizando os números de episódio e temporada, quando disponíveis.", + "SkipEpisodesAlreadyInMyLibrary": "Não gravar episódios que já estejam presentes na Biblioteca", + "LabelSkipForwardLength": "Recuar reprodução (segundos):", + "LabelSkipBackLength": "Avançar reprodução (segundos):", + "DropShadow": "Sombreado", + "Uniform": "Uniforme", + "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.", + "TabStreaming": "Transmissão", + "SimultaneousConnectionLimitHelp": "Número máximo de transmissões permitido. Zero equivale a sem limite.", + "LabelSimultaneousConnectionLimit": "Limite de transmissões simultâneas:", + "LabelMaxStreamingBitrate": "Qualidade máxima de transmissão:", + "LabelMaxChromecastBitrate": "Qualidade de transmissão para Chromecast:", + "EnableStreamLoopingHelp": "Ative esta opção no caso de a transmissão em direto apenas conter alguns segundos de dados, e necessitar de ser continuamente requisitada. Ativar esta opção quando não é necessário pode causar problemas." } From 1a9432b6423d5216b648b0fe3ae7625483bb9c23 Mon Sep 17 00:00:00 2001 From: Daniel Hartung <22015466+dhartung@users.noreply.github.com> Date: Wed, 11 Sep 2019 17:59:00 +0200 Subject: [PATCH 47/80] Added original (native) title --- src/controllers/itemdetailpage.js | 18 +++++++++++++++++- src/itemdetails.html | 4 ++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/controllers/itemdetailpage.js b/src/controllers/itemdetailpage.js index e46a1d226e..e6e3a5a022 100644 --- a/src/controllers/itemdetailpage.js +++ b/src/controllers/itemdetailpage.js @@ -235,7 +235,23 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuild var name = itemHelper.getDisplayName(item, { includeParentInfo: !1 }); - html && !parentNameLast ? html += '

' + name + "

" : html = parentNameLast ? '

' + name + "

" + html : '

' + name + "

" + html, container.innerHTML = html, html.length ? container.classList.remove("hide") : container.classList.add("hide") + + if (html && !parentNameLast) { + html += '

' + name + '

'; + } else { + if (parentNameLast) { + html = '

' + name + "

" + html; + } else { + html = '

' + name + "

" + html; + } + } + + if (item.OriginalTitle) { + html += '

' + item.OriginalTitle + '

'; + } + + container.innerHTML = html; + html.length ? container.classList.remove("hide") : container.classList.add("hide") } function setTrailerButtonVisibility(page, item) { diff --git a/src/itemdetails.html b/src/itemdetails.html index 45e4a40dff..0da8254c48 100644 --- a/src/itemdetails.html +++ b/src/itemdetails.html @@ -30,6 +30,10 @@
+
+ +
+
From ebbd3f11ab517a34f836537dfdaf5097d3ac6e6a Mon Sep 17 00:00:00 2001 From: Daniel Hartung <22015466+dhartung@users.noreply.github.com> Date: Wed, 11 Sep 2019 18:19:17 +0200 Subject: [PATCH 48/80] Styling tweaks --- src/controllers/itemdetailpage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/itemdetailpage.js b/src/controllers/itemdetailpage.js index e6e3a5a022..2a0ec3bee7 100644 --- a/src/controllers/itemdetailpage.js +++ b/src/controllers/itemdetailpage.js @@ -246,8 +246,8 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuild } } - if (item.OriginalTitle) { - html += '

' + item.OriginalTitle + '

'; + if (item.OriginalTitle && item.OriginalTitle != item.Name) { + html += '

' + item.OriginalTitle + '

'; } container.innerHTML = html; From f8d894b269cce5e4f1d239e6128e332de60fecbe Mon Sep 17 00:00:00 2001 From: Daniel Hartung <22015466+dhartung@users.noreply.github.com> Date: Wed, 11 Sep 2019 18:29:52 +0200 Subject: [PATCH 49/80] Simplification and style fix --- src/controllers/itemdetailpage.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/controllers/itemdetailpage.js b/src/controllers/itemdetailpage.js index 2a0ec3bee7..3dcfc39c21 100644 --- a/src/controllers/itemdetailpage.js +++ b/src/controllers/itemdetailpage.js @@ -236,18 +236,15 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuild includeParentInfo: !1 }); + var offset = parentNameLast ? ".25em" : ".5em"; if (html && !parentNameLast) { html += '

' + name + '

'; } else { - if (parentNameLast) { - html = '

' + name + "

" + html; - } else { - html = '

' + name + "

" + html; - } + html = '

' + name + "

" + html; } if (item.OriginalTitle && item.OriginalTitle != item.Name) { - html += '

' + item.OriginalTitle + '

'; + html += '

' + item.OriginalTitle + '

'; } container.innerHTML = html; From 8ee530c0ec01907c0040c6718807f4fc0fe00aee Mon Sep 17 00:00:00 2001 From: Daniel Hartung <22015466+dhartung@users.noreply.github.com> Date: Wed, 11 Sep 2019 18:47:39 +0200 Subject: [PATCH 50/80] Expanded minified javascript --- src/controllers/itemdetailpage.js | 71 ++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/src/controllers/itemdetailpage.js b/src/controllers/itemdetailpage.js index 3dcfc39c21..22f3d331b3 100644 --- a/src/controllers/itemdetailpage.js +++ b/src/controllers/itemdetailpage.js @@ -544,22 +544,63 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuild } function renderDetails(page, item, apiClient, context, isStatic) { - renderSimilarItems(page, item, context), renderMoreFromSeason(page, item, apiClient), renderMoreFromArtist(page, item, apiClient), renderDirector(page, item, apiClient, context, isStatic), renderGenres(page, item, apiClient, context, isStatic), renderChannelGuide(page, apiClient, item); + renderSimilarItems(page, item, context); + renderMoreFromSeason(page, item, apiClient); + renderMoreFromArtist(page, item, apiClient); + renderDirector(page, item, apiClient, context, isStatic); + renderGenres(page, item, apiClient, context, isStatic); + renderChannelGuide(page, apiClient, item); + var taglineElement = page.querySelector(".tagline"); - item.Taglines && item.Taglines.length ? (taglineElement.classList.remove("hide"), taglineElement.innerHTML = item.Taglines[0]) : taglineElement.classList.add("hide"); - var overview = page.querySelector(".overview"), - externalLinksElem = page.querySelector(".itemExternalLinks"); - "Season" !== item.Type && "MusicAlbum" !== item.Type && "MusicArtist" !== item.Type || (overview.classList.add("detailsHiddenOnMobile"), externalLinksElem.classList.add("detailsHiddenOnMobile")), renderOverview([overview], item); - var i, length, itemMiscInfo = page.querySelectorAll(".itemMiscInfo-primary"); - for (i = 0, length = itemMiscInfo.length; i < length; i++) mediaInfo.fillPrimaryMediaInfo(itemMiscInfo[i], item, { - interactive: !0, - episodeTitle: !1, - subtitles: !1 - }), itemMiscInfo[i].innerHTML && "SeriesTimer" !== item.Type ? itemMiscInfo[i].classList.remove("hide") : itemMiscInfo[i].classList.add("hide"); - for (itemMiscInfo = page.querySelectorAll(".itemMiscInfo-secondary"), i = 0, length = itemMiscInfo.length; i < length; i++) mediaInfo.fillSecondaryMediaInfo(itemMiscInfo[i], item, { - interactive: !0 - }), itemMiscInfo[i].innerHTML ? itemMiscInfo[i].classList.remove("hide") : itemMiscInfo[i].classList.add("hide"); - reloadUserDataButtons(page, item), renderLinks(externalLinksElem, item), renderTags(page, item), renderSeriesAirTime(page, item, isStatic) + if (item.Taglines && item.Taglines.length) { + taglineElement.classList.remove("hide"); + taglineElement.innerHTML = item.Taglines[0]; + } else { + taglineElement.classList.add("hide"); + } + + var overview = page.querySelector(".overview"); + var externalLinksElem = page.querySelector(".itemExternalLinks"); + + if ("Season" !== item.Type && "MusicAlbum" !== item.Type && "MusicArtist" !== item.Type) { + overview.classList.add("detailsHiddenOnMobile"); + externalLinksElem.classList.add("detailsHiddenOnMobile"); + } + renderOverview([overview], item); + + var i, itemMiscInfo; + itemMiscInfo = page.querySelectorAll(".itemMiscInfo-primary"); + for (i = 0; i < itemMiscInfo.length; i++) { + mediaInfo.fillPrimaryMediaInfo(itemMiscInfo[i], item, { + interactive: !0, + episodeTitle: !1, + subtitles: !1 + }); + + if (itemMiscInfo[i].innerHTML && "SeriesTimer" !== item.Type) { + itemMiscInfo[i].classList.remove("hide"); + } else { + itemMiscInfo[i].classList.add("hide"); + } + } + + itemMiscInfo = page.querySelectorAll(".itemMiscInfo-secondary") + for (i = 0; i < itemMiscInfo.length; i++) { + mediaInfo.fillSecondaryMediaInfo(itemMiscInfo[i], item, { + interactive: !0 + }) + + if (itemMiscInfo[i].innerHTML && "SeriesTimer" !== item.Type) { + itemMiscInfo[i].classList.remove("hide"); + } else { + itemMiscInfo[i].classList.add("hide"); + } + } + + reloadUserDataButtons(page, item); + renderLinks(externalLinksElem, item); + renderTags(page, item); + renderSeriesAirTime(page, item, isStatic) } function enableScrollX() { From f7d5d4480d82344a5c617f0a40423c0e07071862 Mon Sep 17 00:00:00 2001 From: Daniel Hartung <22015466+dhartung@users.noreply.github.com> Date: Wed, 11 Sep 2019 19:58:31 +0200 Subject: [PATCH 51/80] Added last played information --- src/controllers/itemdetailpage.js | 13 +++++++++++++ src/itemdetails.html | 2 ++ 2 files changed, 15 insertions(+) diff --git a/src/controllers/itemdetailpage.js b/src/controllers/itemdetailpage.js index 22f3d331b3..cd701a481a 100644 --- a/src/controllers/itemdetailpage.js +++ b/src/controllers/itemdetailpage.js @@ -393,6 +393,18 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuild } } + function renderUserInfo(page, item) { + var lastPlayedElement = page.querySelector(".itemLastPlayed"); + + if (item.UserData && item.UserData.LastPlayedDate) { + lastPlayedElement.classList.remove("hide"); + var datePlayed = datetime.parseISO8601Date(item.UserData.LastPlayedDate); + lastPlayedElement.innerHTML = globalize.translate("DatePlayed") + " " + datetime.toLocaleDateString(datePlayed) + " " + datetime.getDisplayTime(datePlayed); + } else { + lastPlayedElement.classList.add("hide"); + } + } + function renderLinks(linksElem, item) { var html = []; if (item.DateCreated && itemHelper.enableDateAddedDisplay(item)) { @@ -599,6 +611,7 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuild reloadUserDataButtons(page, item); renderLinks(externalLinksElem, item); + renderUserInfo(page, item); renderTags(page, item); renderSeriesAirTime(page, item, isStatic) } diff --git a/src/itemdetails.html b/src/itemdetails.html index 0da8254c48..1af02d2395 100644 --- a/src/itemdetails.html +++ b/src/itemdetails.html @@ -195,6 +195,7 @@
+

@@ -206,6 +207,7 @@
+ From fdbdaa19821ff1ad399b15f19001a60209ed40e9 Mon Sep 17 00:00:00 2001 From: Daniel Hartung <22015466+dhartung@users.noreply.github.com> Date: Wed, 11 Sep 2019 20:57:12 +0200 Subject: [PATCH 52/80] Not all players support xxxSubtitleOffset --- src/components/playback/playbackmanager.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index a82078c956..ada0c019fc 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1643,7 +1643,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla self.disableShowingSubtitleOffset = function(player) { player = player || self._currentPlayer; - player.disableShowingSubtitleOffset(); + if (player.disableShowingSubtitleOffset) { + player.disableShowingSubtitleOffset(); + } } self.isShowingSubtitleOffsetEnabled = function(player) { @@ -1658,12 +1660,16 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla self.setSubtitleOffset = function (value, player) { player = player || self._currentPlayer; - player.setSubtitleOffset(value); + if (player.setSubtitleOffset) { + player.setSubtitleOffset(value); + } }; self.getPlayerSubtitleOffset = function(player) { player = player || self._currentPlayer; - return player.getSubtitleOffset(); + if (player.getPlayerSubtitleOffset) { + return player.getSubtitleOffset(); + } } self.canHandleOffsetOnCurrentSubtitle = function(player) { From f2123d03cc5fc5540c3907425fc8deca41af6b09 Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Wed, 11 Sep 2019 22:27:43 +0300 Subject: [PATCH 53/80] fix folder style --- src/scripts/editorsidebar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/editorsidebar.js b/src/scripts/editorsidebar.js index 796ad96310..f4126a7d9b 100644 --- a/src/scripts/editorsidebar.js +++ b/src/scripts/editorsidebar.js @@ -43,7 +43,7 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { } var htmlName = "
"; if (item.IsFolder) { - htmlName += 'folder'; + htmlName += 'folder'; } else if (item.MediaType === "Video") { htmlName += 'movie'; From 4f084bad1c25c43511def430a3a21c7d2e6eb7d2 Mon Sep 17 00:00:00 2001 From: Tyler W <19383474+leftl@users.noreply.github.com> Date: Wed, 11 Sep 2019 20:40:21 +0000 Subject: [PATCH 54/80] Add media file size to Playback Data (#439) * Add media file size to Playback Data * change file units to base-2 and fix output will also remove any trailing zeros from decimal. * Fix file size unit * add i18n files and strings to dialog, fix conflict --- src/components/playerstats/playerstats.js | 54 +++++++++++++++-------- src/strings/en-us.json | 13 ++++++ 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/components/playerstats/playerstats.js b/src/components/playerstats/playerstats.js index d395d609c4..5e097f2fe2 100644 --- a/src/components/playerstats/playerstats.js +++ b/src/components/playerstats/playerstats.js @@ -132,7 +132,7 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth if (videoCodec) { sessionStats.push({ - label: 'Video codec:', + label: globalize.translate("LabelVideoCodec"), value: session.TranscodingInfo.IsVideoDirect ? (videoCodec.toUpperCase() + ' (direct)') : videoCodec.toUpperCase() }); } @@ -140,7 +140,7 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth if (audioCodec) { sessionStats.push({ - label: 'Audio codec:', + label: globalize.translate("LabelAudioCodec"), value: session.TranscodingInfo.IsAudioDirect ? (audioCodec.toUpperCase() + ' (direct)') : audioCodec.toUpperCase() }); } @@ -157,28 +157,28 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth if (totalBitrate) { sessionStats.push({ - label: 'Bitrate:', + label: globalize.translate("LabelBitrate"), value: getDisplayBitrate(totalBitrate) }); } if (session.TranscodingInfo.CompletionPercentage) { sessionStats.push({ - label: 'Transcoding progress:', + label: globalize.translate("LabelTranscodingProgress"), value: session.TranscodingInfo.CompletionPercentage.toFixed(1) + '%' }); } if (session.TranscodingInfo.Framerate) { sessionStats.push({ - label: 'Transcoding framerate:', + label: globalize.translate("LabelTranscodingFramerate"), value: session.TranscodingInfo.Framerate + ' fps' }); } if (session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo.TranscodeReasons.length) { sessionStats.push({ - label: 'Reason for transcoding:', + label: globalize.translate("LabelReasonForTranscoding"), value: session.TranscodingInfo.TranscodeReasons.map(translateReason).join('
') }); } @@ -196,24 +196,42 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth } } + function getReadableSize(size) { + if (size >= 1073741824) { + return parseFloat((size / 1073741824).toFixed(1)) + ' GiB'; + } else if (size >= 1048576) { + return parseFloat((size / 1048576).toFixed(1)) + ' MiB'; + } else { + return Math.floor(size / 1024) + ' KiB'; + } + } + function getMediaSourceStats(session, player, displayPlayMethod) { var sessionStats = []; var mediaSource = playbackManager.currentMediaSource(player) || {}; var totalBitrate = mediaSource.Bitrate; + var mediaFileSize = mediaSource.Size; if (mediaSource.Container) { sessionStats.push({ - label: 'Container:', + label: globalize.translate("LabelProfileContainer"), value: mediaSource.Container }); } + if (mediaFileSize) { + sessionStats.push({ + label: globalize.translate("LabelSize"), + value: getReadableSize(mediaFileSize) + }); + } + if (totalBitrate) { sessionStats.push({ - label: 'Bitrate:', + label: globalize.translate("LabelBitrate"), value: getDisplayBitrate(totalBitrate) }); } @@ -249,14 +267,14 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth if (videoInfos.length) { sessionStats.push({ - label: 'Video codec:', + label: globalize.translate("LabelVideoCodec"), value: videoInfos.join(' ') }); } if (videoStream.BitRate) { sessionStats.push({ - label: 'Video bitrate:', + label: globalize.translate("LabelVideoBitrate"), value: getDisplayBitrate(videoStream.BitRate) }); } @@ -273,35 +291,35 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth if (audioInfos.length) { sessionStats.push({ - label: 'Audio codec:', + label: globalize.translate("LabelAudioCodec"), value: audioInfos.join(' ') }); } if (audioStream.BitRate) { sessionStats.push({ - label: 'Audio bitrate:', + label: globalize.translate("LabelAudioBitrate"), value: getDisplayBitrate(audioStream.BitRate) }); } if (audioChannels) { sessionStats.push({ - label: 'Audio channels:', + label: globalize.translate("LabelAudioChannels"), value: audioChannels }); } if (audioStream.SampleRate) { sessionStats.push({ - label: 'Audio sample rate:', + label: globalize.translate("LabelAudioSampleRate"), value: audioStream.SampleRate + ' Hz' }); } if (audioStream.BitDepth) { sessionStats.push({ - label: 'Audio bit depth:', + label: globalize.translate("LabelAudioBitDepth"), value: audioStream.BitDepth }); } @@ -328,12 +346,12 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth }; baseCategory.stats.unshift({ - label: 'Play method:', + label: globalize.translate("LabelPlayMethod"), value: displayPlayMethod }); baseCategory.stats.unshift({ - label: 'Player:', + label: globalize.translate("LabelPlayer"), value: player.name }); @@ -463,4 +481,4 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth }; return PlayerStats; -}); \ No newline at end of file +}); diff --git a/src/strings/en-us.json b/src/strings/en-us.json index aa648bd56d..e44311ff8f 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -551,13 +551,19 @@ "LabelArtists": "Artists:", "LabelArtistsHelp": "Separate multiple using ;", "LabelAudio": "Audio:", + "LabelAudioBitDepth": "Audio bit depth:", + "LabelAudioBitrate": "Audio bitrate:", + "LabelAudioChannels": "Audio channels:", + "LabelAudioCodec": "Audio codec:", "LabelAudioLanguagePreference": "Preferred audio language:", + "LabelAudioSampleRate": "Audio sample rate:", "LabelAuthProvider": "Authentication Provider:", "LabelAutomaticallyRefreshInternetMetadataEvery": "Automatically refresh metadata from the internet:", "LabelBindToLocalNetworkAddress": "Bind to local network address:", "LabelBindToLocalNetworkAddressHelp": "Optional. Override the local IP address to bind the http server to. If left empty, the server will bind to all availabile addresses. Changing this value requires restarting Jellyfin Server.", "LabelBirthDate": "Birth date:", "LabelBirthYear": "Birth year:", + "LabelBitrate": "Bitrate:", "LabelBlastMessageInterval": "Alive message interval (seconds)", "LabelBlastMessageIntervalHelp": "Determines the duration in seconds between server alive messages.", "LabelBlockContentWithTags": "Block items with tags:", @@ -755,7 +761,9 @@ "LabelPersonRoleHelp": "Example: Ice cream truck driver", "LabelPlaceOfBirth": "Place of birth:", "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", + "LabelPlayer": "Player:", "LabelPlaylist": "Playlist:", + "LabelPlayMethod": "Play method:", "LabelPostProcessor": "Post-processing application:", "LabelPostProcessorArguments": "Post-processor command line arguments:", "LabelPostProcessorArgumentsHelp": "Use {path} as the path to the recording file.", @@ -804,6 +812,7 @@ "LabelServerName": "Server name:", "LabelServerPort": "Port:", "LabelSimultaneousConnectionLimit": "Simultaneous stream limit:", + "LabelSize": "Size:", "LabelSkin": "Skin:", "LabelSkipBackLength": "Skip back length:", "LabelSkipForwardLength": "Skip forward length:", @@ -845,6 +854,8 @@ "LabelTranscodePath": "Transcode path:", "LabelTranscodingTempPathHelp": "This folder contains working files used by the transcoder. Specify a custom path, or leave empty to use the default within the server's data folder.", "LabelTranscodes": "Transcodes:", + "LabelTranscodingFramerate": "Transcoding framerate:", + "LabelTranscodingProgress": "Transcoding progress:", "LabelTranscodingThreadCount": "Transcoding thread count:", "LabelTranscodingThreadCountHelp": "Select the maximum number of threads to use when transcoding. Reducing the thread count will lower cpu usage but may not convert fast enough for a smooth playback experience.", "LabelTranscodingVideoCodec": "Video codec:", @@ -872,6 +883,8 @@ "DashboardOperatingSystem": "Operating System: {0}", "DashboardArchitecture": "Architecture: {0}", "LabelVideo": "Video:", + "LabelVideoBitrate": "Video bitrate:", + "LabelVideoCodec": "Video codec:", "LabelWeb": "Web: ", "LabelXDlnaCap": "X-Dlna cap:", "LabelXDlnaCapHelp": "Determines the content of the X_DLNACAP element in the urn:schemas-dlna-org:device-1-0 namespace.", From e9e9b4bca9473619a74afceca929e8f8f6697518 Mon Sep 17 00:00:00 2001 From: tluciomiranda Date: Wed, 11 Sep 2019 11:16:48 +0000 Subject: [PATCH 55/80] Translated using Weblate (English (United States)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/en_US/ --- src/strings/en-us.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/en-us.json b/src/strings/en-us.json index e44311ff8f..427de7a5ef 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -39,7 +39,7 @@ "AspectRatio": "Aspect ratio", "AttributeNew": "New", "Audio": "Audio", - "AuthProviderHelp": "Select an Authentication Provider to be used to authenticate this user's password", + "AuthProviderHelp": "Select an Authentication Provider to be used to authenticate this user's password.", "Auto": "Auto", "AutoBasedOnLanguageSetting": "Auto (based on language setting)", "Backdrop": "Backdrop", From 52136b57a2dd7181d5312a9b13a988bb24dd6690 Mon Sep 17 00:00:00 2001 From: tluciomiranda Date: Wed, 11 Sep 2019 17:11:26 +0000 Subject: [PATCH 56/80] 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 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index 4acbd9c016..7f885d2774 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -1082,5 +1082,7 @@ "LabelSimultaneousConnectionLimit": "Limite de transmissões simultâneas:", "LabelMaxStreamingBitrate": "Qualidade máxima de transmissão:", "LabelMaxChromecastBitrate": "Qualidade de transmissão para Chromecast:", - "EnableStreamLoopingHelp": "Ative esta opção no caso de a transmissão em direto apenas conter alguns segundos de dados, e necessitar de ser continuamente requisitada. Ativar esta opção quando não é necessário pode causar problemas." + "EnableStreamLoopingHelp": "Ative esta opção no caso de a transmissão em direto apenas conter alguns segundos de dados, e necessitar de ser continuamente requisitada. Ativar esta opção quando não é necessário pode causar problemas.", + "LiveBroadcasts": "Emissões em Direto", + "Live": "Em Direto" } From 54ca2e9381b34a818b5999f20c2d0821f8f29d2e Mon Sep 17 00:00:00 2001 From: dkanada Date: Fri, 6 Sep 2019 22:33:15 -0700 Subject: [PATCH 57/80] improve button style when focused --- src/components/actionsheet/actionsheet.css | 1 + .../displaysettings.template.html | 1 + src/components/emby-button/emby-button.css | 52 ++++++++----------- src/components/emby-button/emby-button.js | 24 +++------ .../emby-button/paper-icon-button-light.js | 5 +- .../emby-checkbox/emby-checkbox.css | 7 ++- src/components/emby-checkbox/emby-checkbox.js | 5 -- src/components/emby-slider/emby-slider.css | 8 +-- src/components/emby-tabs/emby-tabs.css | 27 +++------- src/components/guide/guide.css | 2 +- .../homescreensettings.template.html | 2 +- src/components/listview/listview.css | 24 +++++---- src/components/themes/appletv/theme.css | 26 +++++----- src/components/themes/blueradiance/theme.css | 17 +++--- src/components/themes/dark/theme.css | 28 +++++----- src/components/themes/emby/theme.css | 27 +++++----- src/components/themes/light/theme.css | 27 +++++----- src/components/themes/purple-haze/theme.css | 23 ++++---- src/components/themes/wmc/theme.css | 20 +++---- src/css/site.css | 3 +- src/mypreferencesmenu.html | 14 ++--- src/strings/en-us.json | 1 + 22 files changed, 148 insertions(+), 196 deletions(-) diff --git a/src/components/actionsheet/actionsheet.css b/src/components/actionsheet/actionsheet.css index 611fafa5ca..c1b169889c 100644 --- a/src/components/actionsheet/actionsheet.css +++ b/src/components/actionsheet/actionsheet.css @@ -36,6 +36,7 @@ font-weight: inherit; box-shadow: none; flex-shrink: 0; + border-radius: 0; } .actionSheetMenuItem:focus { diff --git a/src/components/displaysettings/displaysettings.template.html b/src/components/displaysettings/displaysettings.template.html index a426973df7..f469d8d5ce 100644 --- a/src/components/displaysettings/displaysettings.template.html +++ b/src/components/displaysettings/displaysettings.template.html @@ -119,6 +119,7 @@
${DisplayModeHelp}
+
${LabelPleaseRestart}
diff --git a/src/components/emby-button/emby-button.css b/src/components/emby-button/emby-button.css index a37a28ebe4..b7d27a6007 100644 --- a/src/components/emby-button/emby-button.css +++ b/src/components/emby-button/emby-button.css @@ -3,7 +3,7 @@ display: inline-flex; align-items: center; box-sizing: border-box; - margin: 0 .29em; + margin: 0 0.3em; text-align: center; font-size: inherit; font-family: inherit; @@ -15,11 +15,11 @@ user-select: none; cursor: pointer; z-index: 0; - padding: .86em 1em; + padding: 0.9em 1em; vertical-align: middle; border: 0; vertical-align: middle; - border-radius: .2em; + border-radius: 0.2em; /* These are getting an outline in opera tv browsers, which run chrome 30 */ outline: none !important; position: relative; @@ -29,6 +29,13 @@ text-decoration: none; /* Not crazy about this but it normalizes heights between anchors and buttons */ line-height: 1.35; + transform-origin: center; + transition: 0.2s; +} + +.emby-button.show-focus:focus { + transform: scale(1.4); + z-index: 1; } .emby-button::-moz-focus-inner { @@ -54,17 +61,6 @@ text-decoration: underline; } -.emby-button-focusscale { - transition: transform 180ms ease-out !important; - -webkit-transform-origin: center center; - transform-origin: center center; -} - -.emby-button-focusscale:focus { - transform: scale(1.16); - z-index: 1; -} - .emby-button > i { /* For non-fab buttons that have icons */ font-size: 1.36em; @@ -77,7 +73,7 @@ .fab { display: inline-flex; border-radius: 50%; - padding: .6em; + padding: 0.6em; box-sizing: border-box; align-items: center; justify-content: center; @@ -125,14 +121,22 @@ /* Disable webkit tap highlighting */ -webkit-tap-highlight-color: rgba(0,0,0,0); justify-content: center; + transform-origin: center; + transition: 0.2s; +} + +.paper-icon-button-light.show-focus:focus { + transform: scale(1.6); + z-index: 1; } .paper-icon-button-light::-moz-focus-inner { border: 0; } - .paper-icon-button-light[disabled] { - opacity: .3; + .paper-icon-button-light:disabled { + opacity: 0.3; + cursor: default; } .paper-icon-button-light > i { @@ -145,8 +149,6 @@ .paper-icon-button-light > img { width: 1.72em; - /* Can't use 100% height or it will stretch past the boundaries in safari */ - /*height: 100%;*/ max-height: 100%; /* Make sure its on top of the ripple */ position: relative; @@ -159,17 +161,6 @@ z-index: 1; } -.icon-button-focusscale { - transition: transform 180ms ease-out !important; - -webkit-transform-origin: center center; - transform-origin: center center; -} - -.icon-button-focusscale:focus { - transform: scale(1.3); - z-index: 1; -} - .btnFilterWithBubble { position: relative; } @@ -180,7 +171,6 @@ background: #444; top: 0; right: 0; - /* padding: .5em; */ width: 1.6em; height: 1.6em; z-index: 100000000; diff --git a/src/components/emby-button/emby-button.js b/src/components/emby-button/emby-button.js index 6df7aebb5c..8134ba3070 100644 --- a/src/components/emby-button/emby-button.js +++ b/src/components/emby-button/emby-button.js @@ -21,30 +21,23 @@ define(['browser', 'dom', 'layoutManager', 'shell', 'appRouter', 'apphost', 'css } EmbyButtonPrototype.createdCallback = function () { - if (this.classList.contains('emby-button')) { return; } this.classList.add('emby-button'); - if (layoutManager.tv) { - if (this.getAttribute('data-focusscale') !== 'false') { - this.classList.add('emby-button-focusscale'); - } - this.classList.add('emby-button-tv'); + // handles all special css for tv layout + // the old method was element-showfocus + // this method utilizes class chaining instead + this.classList.add('show-focus'); } }; EmbyButtonPrototype.attachedCallback = function () { - if (this.tagName === 'A') { - - dom.removeEventListener(this, 'click', onAnchorClick, { - }); - - dom.addEventListener(this, 'click', onAnchorClick, { - }); + dom.removeEventListener(this, 'click', onAnchorClick, {}); + dom.addEventListener(this, 'click', onAnchorClick, {}); if (this.getAttribute('data-autohide') === 'true') { if (appHost.supports('externallinks')) { @@ -57,9 +50,7 @@ define(['browser', 'dom', 'layoutManager', 'shell', 'appRouter', 'apphost', 'css }; EmbyButtonPrototype.detachedCallback = function () { - - dom.removeEventListener(this, 'click', onAnchorClick, { - }); + dom.removeEventListener(this, 'click', onAnchorClick, {}); }; EmbyLinkButtonPrototype.createdCallback = EmbyButtonPrototype.createdCallback; @@ -75,6 +66,5 @@ define(['browser', 'dom', 'layoutManager', 'shell', 'appRouter', 'apphost', 'css extends: 'a' }); - // For extension purposes return EmbyButtonPrototype; }); diff --git a/src/components/emby-button/paper-icon-button-light.js b/src/components/emby-button/paper-icon-button-light.js index 70304ffc24..7eda76baec 100644 --- a/src/components/emby-button/paper-icon-button-light.js +++ b/src/components/emby-button/paper-icon-button-light.js @@ -4,11 +4,10 @@ define(['layoutManager', 'css!./emby-button', 'registerElement'], function (layo var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype); EmbyButtonPrototype.createdCallback = function () { - this.classList.add('paper-icon-button-light'); if (layoutManager.tv) { - this.classList.add('icon-button-focusscale'); + this.classList.add('show-focus'); } }; @@ -16,4 +15,4 @@ define(['layoutManager', 'css!./emby-button', 'registerElement'], function (layo prototype: EmbyButtonPrototype, extends: 'button' }); -}); \ No newline at end of file +}); diff --git a/src/components/emby-checkbox/emby-checkbox.css b/src/components/emby-checkbox/emby-checkbox.css index ed70747db2..5641893f63 100644 --- a/src/components/emby-checkbox/emby-checkbox.css +++ b/src/components/emby-checkbox/emby-checkbox.css @@ -73,13 +73,12 @@ } .emby-checkbox:checked + span + .checkboxOutline > .checkboxIcon-checked { - /* background-color set by theme */ - /*background-color: #52B54B;*/ + /* background color set by theme */ display: flex !important; } .emby-checkbox:checked + span + .checkboxOutline > .checkboxIcon-unchecked { - /* background-color set by theme */ + /* background color set by theme */ display: none !important; } @@ -94,7 +93,7 @@ .checkboxList > .emby-checkbox-label { display: flex; - margin: .5em 0; + margin: 0.5em 0; } .checkboxList-verticalwrap { diff --git a/src/components/emby-checkbox/emby-checkbox.js b/src/components/emby-checkbox/emby-checkbox.js index 6144f6892b..1721bf3ca7 100644 --- a/src/components/emby-checkbox/emby-checkbox.js +++ b/src/components/emby-checkbox/emby-checkbox.js @@ -4,7 +4,6 @@ define(['browser', 'dom', 'css!./emby-checkbox', 'registerElement'], function (b var EmbyCheckboxPrototype = Object.create(HTMLInputElement.prototype); function onKeyDown(e) { - // Don't submit form on enter if (e.keyCode === 13) { e.preventDefault(); @@ -22,7 +21,6 @@ define(['browser', 'dom', 'css!./emby-checkbox', 'registerElement'], function (b var enableRefreshHack = browser.tizen || browser.orsay || browser.operaTv || browser.web0s ? true : false; function forceRefresh(loading) { - var elem = this.parentNode; elem.style.webkitAnimationName = 'repaintChrome'; @@ -36,7 +34,6 @@ define(['browser', 'dom', 'css!./emby-checkbox', 'registerElement'], function (b } EmbyCheckboxPrototype.attachedCallback = function () { - if (this.getAttribute('data-embycheckbox') === 'true') { return; } @@ -68,7 +65,6 @@ define(['browser', 'dom', 'css!./emby-checkbox', 'registerElement'], function (b this.addEventListener('keydown', onKeyDown); if (enableRefreshHack) { - forceRefresh.call(this, true); dom.addEventListener(this, 'click', forceRefresh, { passive: true @@ -86,7 +82,6 @@ define(['browser', 'dom', 'css!./emby-checkbox', 'registerElement'], function (b }; EmbyCheckboxPrototype.detachedCallback = function () { - this.removeEventListener('keydown', onKeyDown); dom.removeEventListener(this, 'click', forceRefresh, { diff --git a/src/components/emby-slider/emby-slider.css b/src/components/emby-slider/emby-slider.css index b27190e487..bd258d3bc5 100644 --- a/src/components/emby-slider/emby-slider.css +++ b/src/components/emby-slider/emby-slider.css @@ -70,8 +70,8 @@ _:-ms-input-placeholder { .mdl-slider::-webkit-slider-thumb { -webkit-appearance: none; - width: 1.8em; - height: 1.8em; + width: 1.2em; + height: 1.2em; box-sizing: border-box; border-radius: 50%; background: #00a4dc; @@ -80,11 +80,11 @@ _:-ms-input-placeholder { } .mdl-slider-hoverthumb::-webkit-slider-thumb { - transform: scale(.7, .7); + transform: none; } .mdl-slider:hover::-webkit-slider-thumb { - transform: none; + transform: scale(1.6); } .slider-no-webkit-thumb::-webkit-slider-thumb { diff --git a/src/components/emby-tabs/emby-tabs.css b/src/components/emby-tabs/emby-tabs.css index 3a542ee7e6..00abd7efae 100644 --- a/src/components/emby-tabs/emby-tabs.css +++ b/src/components/emby-tabs/emby-tabs.css @@ -2,7 +2,7 @@ background: transparent; box-shadow: none; cursor: pointer; - outline: none !important; + outline: none; width: auto; font-family: inherit; font-size: inherit; @@ -10,36 +10,25 @@ vertical-align: middle; flex-shrink: 0; margin: 0; - padding: 1em .9em; + padding: 1em 0.9em; position: relative; height: auto; min-width: initial; line-height: initial; - border-radius: 0 !important; + border-radius: 0; overflow: hidden; font-weight: 600; } - /*.emby-tab-button-active { - color: #52B54B; +.emby-tab-button.show-focus:focus { + /* these buttons are small so scale larger than usual */ + transform: scale(1.6) !important; + background: 0 !important; } - .emby-tab-button-active.emby-button-tv { - color: #fff; - }*/ - - .emby-tab-button.emby-button-tv:focus { - /*color: #52B54B;*/ - transform: scale(1.32); - transform-origin: center center; - } - .emby-tabs-slider { position: relative; -} - -.emby-tab-button-ripple-effect { - background: rgba(0,0,0,.7) !important; + overflow: hidden; } .tabContent:not(.is-active) { diff --git a/src/components/guide/guide.css b/src/components/guide/guide.css index fcac17f272..7dd0594149 100644 --- a/src/components/guide/guide.css +++ b/src/components/guide/guide.css @@ -424,7 +424,7 @@ border-color: transparent !important; } - .guide-date-tab-button.emby-button-tv:focus { + .guide-date-tab-button.show-focus:focus { border-radius: .15em !important; transform: none !important; } diff --git a/src/components/homescreensettings/homescreensettings.template.html b/src/components/homescreensettings/homescreensettings.template.html index 2cb1dcbe14..56be1bc5a8 100644 --- a/src/components/homescreensettings/homescreensettings.template.html +++ b/src/components/homescreensettings/homescreensettings.template.html @@ -7,7 +7,7 @@ -
Changes take effect after signing out or restarting the app.
+
${LabelPleaseRestart}
diff --git a/src/components/listview/listview.css b/src/components/listview/listview.css index 312bf14a16..d91a5377ba 100644 --- a/src/components/listview/listview.css +++ b/src/components/listview/listview.css @@ -39,8 +39,16 @@ } .listItem-border { - border-bottom-width: .1em; - border-bottom-style: solid; + display: block; + margin: 0; + padding: 0; + border-width: 0 0 0.1em 0; + border-style: solid; + border-radius: 0; +} + +.listItem-border.show-focus:focus { + transform: scale(1.0) !important; } .listItemImage, .listItemIcon, .listItemAside { @@ -126,21 +134,20 @@ } .listItemImageButton:hover { - transform: scale(1.2, 1.2); + transform: scale(1.2, 1.2); } .listItemImageButton-icon { background: rgba(0,0,0,.4); - border: .08em solid currentColor; + border: 0.1em solid currentColor; border-radius: 100em; display: flex; justify-content: center; align-items: center; - padding: .21em; + padding: 0.2em; } @media all and (max-width: 64em) { - .listItemImage-large { width: 33.75vw; height: 22.5vw; @@ -148,7 +155,7 @@ } .listItemImageButton { - font-size: 1.02em !important; + font-size: 1em !important; } .listItemBody { @@ -157,7 +164,6 @@ } @media all and (max-width: 50em) { - .listItemBody { padding-right: .5em; } @@ -245,14 +251,12 @@ } @media all and (max-width: 50em) { - .listItem .endsAt, .listItem .criticRating, .listItem-overview { display: none !important; } } @media all and (min-width: 50em) { - .listItem-bottomoverview { display: none !important; } diff --git a/src/components/themes/appletv/theme.css b/src/components/themes/appletv/theme.css index fa0617a655..8b4d543b9c 100644 --- a/src/components/themes/appletv/theme.css +++ b/src/components/themes/appletv/theme.css @@ -71,13 +71,12 @@ html { background: #f0f0f0 } -.paper-icon-button-light:hover { +.paper-icon-button-light:hover:not(:disabled) { color: #00a4dc; background-color: rgba(0,164,220, .2); - transition: 0.2s; } -.paper-icon-button-light:focus { +.paper-icon-button-light.show-focus:focus { color: #00a4dc; } @@ -341,24 +340,25 @@ html { color: #fff } -.emby-button-focusscale:focus { +.emby-button.show-focus:focus { background: #00a4dc; color: #fff } .emby-tab-button { color: #999; - color: rgba(0, 0, 0, .5) } -.emby-tab-button-active, -.emby-tab-button-active.emby-button-tv { - color: #fff -} - -.emby-tab-button.emby-button-tv:focus { +.emby-tab-button-active { + color: #fff; +} + +.emby-tab-button.show-focus:focus { + color: #fff; +} + +.emby-tab-button:hover { color: #fff; - background: 0 0 } .channelPrograms, @@ -413,7 +413,7 @@ html { color: #00a4dc } -.guide-date-tab-button.emby-button-tv:focus { +.guide-date-tab-button.show-focus:focus { background-color: #00a4dc; color: #fff } diff --git a/src/components/themes/blueradiance/theme.css b/src/components/themes/blueradiance/theme.css index 7f581454a8..9413e6a664 100644 --- a/src/components/themes/blueradiance/theme.css +++ b/src/components/themes/blueradiance/theme.css @@ -58,13 +58,12 @@ html { } } -.paper-icon-button-light:hover { +.paper-icon-button-light:hover:not(:disabled) { color: #00a4dc; background-color: rgba(0,164,220, .2); - transition: 0.2s; } -.paper-icon-button-light:focus { +.paper-icon-button-light.show-focus:focus { color: #00a4dc; } @@ -327,27 +326,25 @@ html { color: #fff } -.emby-button-focusscale:focus { +.emby-button.show-focus:focus { background: #00a4dc; color: #fff } .emby-tab-button { color: #999; - color: rgba(255, 255, 255, .4) } .emby-tab-button-active { color: #00a4dc } -.emby-tab-button-active.emby-button-tv { - color: #fff +.emby-tab-button.show-focus:focus { + color: #00a4dc; } -.emby-tab-button.emby-button-tv:focus { +.emby-tab-button:hover { color: #00a4dc; - background: 0 0 } .channelPrograms, @@ -401,7 +398,7 @@ html { color: #00a4dc } -.guide-date-tab-button.emby-button-tv:focus { +.guide-date-tab-button.show-focus:focus { background-color: #00a4dc; color: #fff } diff --git a/src/components/themes/dark/theme.css b/src/components/themes/dark/theme.css index 4670b57459..78cd4c8cfa 100644 --- a/src/components/themes/dark/theme.css +++ b/src/components/themes/dark/theme.css @@ -39,13 +39,12 @@ html { background-color: rgba(0, 0, 0, .86) } -.paper-icon-button-light:hover { +.paper-icon-button-light:hover:not(:disabled) { color: #00a4dc; background-color: rgba(0,164,220, .2); - transition: 0.2s; } -.paper-icon-button-light:focus { +.paper-icon-button-light.show-focus:focus { color: #00a4dc; } @@ -304,28 +303,25 @@ html { color: #fff } -.emby-button-focusscale:focus { +.emby-button.show-focus:focus { background: #00a4dc; color: #fff } .emby-tab-button { color: #999; - color: rgba(255, 255, 255, .4) } .emby-tab-button-active { - color: #fff -} - -.emby-tab-button-active.emby-button-tv { - color: #999; - color: rgba(255, 255, 255, .4) -} - -.emby-tab-button.emby-button-tv:focus { color: #fff; - background: 0 0 +} + +.emby-tab-button.show-focus:focus { + color: #00a4dc; +} + +.emby-tab-button:hover { + color: #00a4dc; } .channelPrograms, @@ -379,7 +375,7 @@ html { color: #00a4dc } -.guide-date-tab-button.emby-button-tv:focus { +.guide-date-tab-button.show-focus:focus { background-color: #00a4dc; color: #fff } diff --git a/src/components/themes/emby/theme.css b/src/components/themes/emby/theme.css index 542aa5f8d6..890ee0a696 100644 --- a/src/components/themes/emby/theme.css +++ b/src/components/themes/emby/theme.css @@ -39,13 +39,12 @@ html { background-color: rgba(0, 0, 0, .86) } -.paper-icon-button-light:hover { +.paper-icon-button-light:hover:not(:disabled) { color: #52b54b; background-color: rgba(82, 181, 75, .2); - transition: 0.2s; } -.paper-icon-button-light:focus { +.paper-icon-button-light.show-focus:focus { color: #52b54b; } @@ -304,27 +303,25 @@ html { color: #fff } -.emby-button-focusscale:focus { +.emby-button.show-focus:focus { background: #52b54b; color: #fff } .emby-tab-button { color: #999; - color: rgba(255, 255, 255, .4) } .emby-tab-button-active { - color: #52b54b -} - -.emby-tab-button-active.emby-button-tv { - color: #fff -} - -.emby-tab-button.emby-button-tv:focus { color: #52b54b; - background: 0 0 +} + +.emby-tab-button.show-focus:focus { + color: #52b54b; +} + +.emby-tab-button:hover { + color: #52b54b; } .channelPrograms, @@ -378,7 +375,7 @@ html { color: #52b54b } -.guide-date-tab-button.emby-button-tv:focus { +.guide-date-tab-button.show-focus:focus { background-color: #52b54b; color: #fff } diff --git a/src/components/themes/light/theme.css b/src/components/themes/light/theme.css index c2f01bab93..0752fbf5cc 100644 --- a/src/components/themes/light/theme.css +++ b/src/components/themes/light/theme.css @@ -55,13 +55,12 @@ html { background-color: #f0f0f0 } -.paper-icon-button-light:hover { +.paper-icon-button-light:hover:not(:disabled) { color: #00a4dc; background-color: rgba(0,164,220, .2); - transition: 0.2s; } -.paper-icon-button-light:focus { +.paper-icon-button-light.show-focus:focus { color: #00a4dc; } @@ -323,27 +322,25 @@ html { color: #fff } -.emby-button-focusscale:focus { +.emby-button.show-focus:focus { background: #00a4dc; color: #fff } .emby-tab-button { color: #999; - color: rgba(255, 255, 255, .5) } .emby-tab-button-active { - color: #00a4dc -} - -.emby-tab-button-active.emby-button-tv { - color: #fff -} - -.emby-tab-button.emby-button-tv:focus { color: #00a4dc; - background: 0 0 +} + +.emby-tab-button.show-focus:focus { + color: #00a4dc; +} + +.emby-tab-button:hover { + color: #00a4dc; } .channelPrograms, @@ -397,7 +394,7 @@ html { color: #00a4dc } -.guide-date-tab-button.emby-button-tv:focus { +.guide-date-tab-button.show-focus:focus { background-color: #00a4dc; color: #fff } diff --git a/src/components/themes/purple-haze/theme.css b/src/components/themes/purple-haze/theme.css index cdd58e83ef..4f99a0d909 100644 --- a/src/components/themes/purple-haze/theme.css +++ b/src/components/themes/purple-haze/theme.css @@ -58,13 +58,12 @@ html { } } -.paper-icon-button-light:hover { +.paper-icon-button-light:hover:not(:disabled) { color: rgb(12, 232, 214); background-color: rgba(0,164,220, .2); - transition: 0.2s; } -.paper-icon-button-light:focus { +.paper-icon-button-light.show-focus:focus { color: #ff77f1; } @@ -420,27 +419,25 @@ a[data-role=button] { color: #f8f8fe } -.emby-button-focusscale:focus { +.emby-button.show-focus:focus { background: #8ae9c1; color: #f8f8fe } .emby-tab-button { color: #999; - color: rgba(255, 255, 255, .4) } .emby-tab-button-active { - color: #f8f8fe + color: #f8f8fe; } -.emby-tab-button-active.emby-button-tv { - color: #f8f8fe -} - -.emby-tab-button.emby-button-tv:focus { +.emby-tab-button.show-focus:focus { + color: #ff77f1; +} + +.emby-tab-button:hover { color: #ff77f1; - background: 0 0 } .channelPrograms, @@ -494,7 +491,7 @@ a[data-role=button] { color: #ff77f1 } -.guide-date-tab-button.emby-button-tv:focus { +.guide-date-tab-button.show-focus:focus { background-color: #48C3C8; color: #fff } diff --git a/src/components/themes/wmc/theme.css b/src/components/themes/wmc/theme.css index 0685adfb0b..376541f397 100644 --- a/src/components/themes/wmc/theme.css +++ b/src/components/themes/wmc/theme.css @@ -64,13 +64,12 @@ html { background: rgba(17, 98, 164, .9) } -.paper-icon-button-light:hover { +.paper-icon-button-light:hover:not(:disabled) { color: #00a4dc; background-color: rgba(0,164,220, .2); - transition: 0.2s; } -.paper-icon-button-light:focus { +.paper-icon-button-light.show-focus:focus { color: #00a4dc; } @@ -325,24 +324,25 @@ html { color: #fff } -.emby-button-focusscale:focus { +.emby-button.show-focus:focus { background: #00a4dc; color: #fff } .emby-tab-button { color: #999; - color: rgba(255, 255, 255, .5) } -.emby-tab-button-active, -.emby-tab-button-active.emby-button-tv { +.emby-tab-button-active { color: #fff } -.emby-tab-button.emby-button-tv:focus { +.emby-tab-button.show-focus:focus { + color: #fff; +} + +.emby-tab-button:hover { color: #fff; - background: 0 0 } .channelPrograms, @@ -397,7 +397,7 @@ html { color: #00a4dc } -.guide-date-tab-button.emby-button-tv:focus { +.guide-date-tab-button.show-focus:focus { background-color: #00a4dc; color: #fff } diff --git a/src/css/site.css b/src/css/site.css index 65f8ffdbce..87ce6841ae 100644 --- a/src/css/site.css +++ b/src/css/site.css @@ -70,11 +70,10 @@ div[data-role=page] { .page, .pageWithAbsoluteTabs .pageTabContent { /* provides room for the music controls */ - padding-bottom: 5em !important + padding-bottom: 5em !important; } @media all and (min-width:50em) { - .readOnlyContent, form { max-width: 54em diff --git a/src/mypreferencesmenu.html b/src/mypreferencesmenu.html index 008c39b431..0344ddc0ad 100644 --- a/src/mypreferencesmenu.html +++ b/src/mypreferencesmenu.html @@ -4,7 +4,7 @@

- +
person
@@ -13,7 +13,7 @@
- +
tv
@@ -22,7 +22,7 @@
- +
home
@@ -31,7 +31,7 @@
- +
play_circle_filled
@@ -40,7 +40,7 @@
- +
closed_caption
@@ -70,7 +70,7 @@

${HeaderUser}

-
+
wifi
@@ -78,7 +78,7 @@
- +
exit_to_app
diff --git a/src/strings/en-us.json b/src/strings/en-us.json index 427de7a5ef..e88864ec97 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -764,6 +764,7 @@ "LabelPlayer": "Player:", "LabelPlaylist": "Playlist:", "LabelPlayMethod": "Play method:", + "LabelPleaseRestart": "Changes will take effect after manually reloading the web client.", "LabelPostProcessor": "Post-processing application:", "LabelPostProcessorArguments": "Post-processor command line arguments:", "LabelPostProcessorArgumentsHelp": "Use {path} as the path to the recording file.", From c2a0de8202628c63c3aba53a746f412a7f162598 Mon Sep 17 00:00:00 2001 From: dkanada Date: Wed, 11 Sep 2019 15:35:37 -0700 Subject: [PATCH 58/80] improve comments for tv layout css --- src/components/emby-button/emby-button.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/emby-button/emby-button.js b/src/components/emby-button/emby-button.js index 8134ba3070..be52b1d512 100644 --- a/src/components/emby-button/emby-button.js +++ b/src/components/emby-button/emby-button.js @@ -26,10 +26,10 @@ define(['browser', 'dom', 'layoutManager', 'shell', 'appRouter', 'apphost', 'css } this.classList.add('emby-button'); + // TODO replace all instances of element-showfocus with this method if (layoutManager.tv) { // handles all special css for tv layout - // the old method was element-showfocus - // this method utilizes class chaining instead + // this method utilizes class chaining this.classList.add('show-focus'); } }; From 9ab6756e39ce7dcc7eb97771180bab92ba213ce0 Mon Sep 17 00:00:00 2001 From: dkanada Date: Thu, 12 Sep 2019 06:05:40 -0700 Subject: [PATCH 59/80] add back comment about clipping --- src/components/emby-button/emby-button.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/emby-button/emby-button.css b/src/components/emby-button/emby-button.css index b7d27a6007..f6da6b040f 100644 --- a/src/components/emby-button/emby-button.css +++ b/src/components/emby-button/emby-button.css @@ -149,6 +149,8 @@ .paper-icon-button-light > img { width: 1.72em; + /* Can't use 100% height or it will stretch past the boundaries in safari */ + /*height: 100%;*/ max-height: 100%; /* Make sure its on top of the ripple */ position: relative; From ed956f8ebac07416081ce3be3a82f301a8291413 Mon Sep 17 00:00:00 2001 From: tluciomiranda Date: Thu, 12 Sep 2019 09:12:11 +0000 Subject: [PATCH 60/80] 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 | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index 7f885d2774..ea16d5603a 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -90,7 +90,7 @@ "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": "Diretor", - "EasyPasswordHelp": "O código PIN é utilizado para acesso off-line com aplicações suportados pelo Jellyfin e pode ser usado para um acesso fácil dentro da rede.", + "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.", "Edit": "Editar", "EnableCinemaMode": "Ativar modo cinema", "Ended": "Terminado", @@ -303,7 +303,7 @@ "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 CSS customizado à interface web.", + "LabelCustomCssHelp": "Aplica um ficheiro de estilos customizado à interface web.", "LabelCustomDeviceDisplayName": "Nome a ser mostrado:", "LabelCustomDeviceDisplayNameHelp": "Forneça um nome a ser mostrado, ou deixe em branco para utilizar o nome reportado pelo dispositivo.", "LabelCustomRating": "Classificação personalizada:", @@ -334,9 +334,9 @@ "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": "O Servidor Jellyfin pode detectar dispositivos na rede e oferecer a possibilidade de os controlar.", + "LabelEnableDlnaPlayToHelp": "Detetar dispositivos na rede e oferecer a possibilidade de os controlar.", "LabelEnableDlnaServer": "Ativar servidor DLNA", - "LabelEnableDlnaServerHelp": "Permite que dispositivos UPnP na rede naveguem e reproduzam conteúdo do Servidor Jellyfin.", + "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.", @@ -347,7 +347,7 @@ "LabelEvent": "Evento:", "LabelEveryXMinutes": "A cada:", "LabelExternalDDNS": "Domínio externo:", - "LabelExternalDDNSHelp": "Se tem um servidor DNS dinâmico insira-o aqui. As aplicações do Jellyfin irão usá-lo ao ligar-se remotamente. Este campo é obrigatório quando usado com um certificado SSL personalizado. Exemplo: omeudominio.com.", + "LabelExternalDDNSHelp": "Se tem um servidor DNS dinâmico insira-o aqui para que os clientes possam utilizá-lo ao ligar-se remotamente. Este campo é obrigatório quando usado com um certificado SSL personalizado. Exemplo: omeudominio.com.", "LabelExtractChaptersDuringLibraryScan": "Extrair imagens dos capítulos durante a atualização da biblioteca", "LabelExtractChaptersDuringLibraryScanHelp": "Se ativado, as imagens dos capítulos serão extraídas quando os vídeos forem importados durante a atualização da biblioteca. Se desativado, serão extraídas 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", @@ -392,7 +392,7 @@ "LabelMaxBackdropsPerItem": "Número máximo de imagens de fundo por item:", "LabelMaxParentalRating": "Controlo parental máximo permitido:", "LabelMaxResumePercentage": "Percentagem máxima de visualização para permitir retomar:", - "LabelMaxResumePercentageHelp": "Os títulos são considerados como vistos se parados após esta percentagem da duração", + "LabelMaxResumePercentageHelp": "Os títulos são considerados como vistos se parados após esta percentagem da duração.", "LabelMaxScreenshotsPerItem": "Número máximo de capturas de ecrã por item:", "LabelMaxStreamingBitrateHelp": "Defina uma taxa máxima de transmissão.", "LabelMessageText": "Texto da mensagem:", @@ -404,9 +404,9 @@ "LabelMethod": "Método:", "LabelMinBackdropDownloadWidth": "Transferir imagens de fundo com este tamanho mínimo:", "LabelMinResumeDuration": "Duração mínima para permitir retoma de visualização:", - "LabelMinResumeDurationHelp": "Conteúdos com duração inferior não permitirão parar e retomar a reprodução", + "LabelMinResumeDurationHelp": "Conteúdos com duração inferior não permitirão parar e retomar a reprodução.", "LabelMinResumePercentage": "Percentagem mínima de visualização para permitir retomar:", - "LabelMinResumePercentageHelp": "Os títulos são considerados como não vistos se parados antes desta percentagem da duração", + "LabelMinResumePercentageHelp": "Os títulos são considerados como não vistos se parados antes desta percentagem da duração.", "LabelMinScreenshotDownloadWidth": "Transferir capturas de ecrã com este tamanho mínimo:", "LabelModelDescription": "Descrição do modelo", "LabelModelName": "Nome do modelo", @@ -504,7 +504,7 @@ "LabelYourFirstName": "O seu primeiro nome:", "LabelYoureDone": "Concluiu!", "LabelZipCode": "CEP:", - "LibraryAccessHelp": "Escolha as pastas multimédia a partilhar com este utilizador. Os Administradores poderão editar todas as pastas, usando o Gestor de Metadados.", + "LibraryAccessHelp": "Escolha as Bibliotecas a partilhar com este utilizador. Os Administradores poderão editar todas as pastas, usando o Gestor de Metadados.", "MaxParentalRatingHelp": "Conteúdo com classificação mais elevada será escondida deste utilizador.", "MessageAreYouSureDeleteSubtitles": "Tem a certeza de que deseja remover este ficheiro de legendas?", "MessageAreYouSureYouWishToRemoveMediaFolder": "Tem a certeza de que deseja remover esta pasta?", @@ -516,7 +516,7 @@ "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.", "MessageDirectoryPickerInstruction": "As localizações de rede podem ser escritas manualmente caso o botão \"Rede\" não consiga encontrar os dispositivos. Por exemplo, {0} ou {1}.", - "MessageDirectoryPickerLinuxInstruction": "Para Linux no Arch Linux, CentOS, Debian, Fedora, OpenSuse ou Ubuntu, você deve permitir que o utilizador Jellyfin tenha ao menos acesso de leitura no seu disco.", + "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.", "MessageInvalidUser": "Nome de utilizador ou palavra-passe inválidos. Por favor, tente novamente.", @@ -531,7 +531,7 @@ "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.", "MessageReenableUser": "Veja abaixo para reativar", - "MessageTheFollowingLocationWillBeRemovedFromLibrary": "As localizações dos ficheiros multimédia abaixo serão excluídas de sua biblioteca Jellyfin:", + "MessageTheFollowingLocationWillBeRemovedFromLibrary": "As seguintes pastas multimédia serão removidas da Biblioteca:", "MinutesAfter": "minutos depois", "MinutesBefore": "minutos antes", "Monday": "Segunda", @@ -717,7 +717,7 @@ "TabMusicVideos": "Videoclips", "TabMyPlugins": "As Minhas Extensões", "TabNetworks": "Redes", - "TabNfoSettings": "Definições de ficheiros NFO", + "TabNfoSettings": "Definições de Ficheiros NFO", "TabNotifications": "Notificações", "TabOther": "Outro", "TabParentalControl": "Controlo Parental", @@ -778,7 +778,7 @@ "AllowMediaConversion": "Permitir conversão multimédia", "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 as aplicações Jellyfin para evitar transcode. Em certos dispositivos, isto é uma operação demorada e pode 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.", + "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, é uma operação demorada e pode 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.", "AllowRemoteAccess": "Permitir ligações remotas a este Jellyfin Server.", "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.", From e2cc98c7a41740e81804f4b2eaea2559923a4812 Mon Sep 17 00:00:00 2001 From: PrplHaz4 Date: Fri, 13 Sep 2019 09:49:37 -0400 Subject: [PATCH 61/80] update apphost appVersion to 10.4.0 The only place I saw this appear was in a log entry, so not sure what else this will impact (or if it's deliberately being held back). It looks like it is also passed in when the ApiClient is created. ``` [13:23:15] [INF] Playback stopped reported by app Jellyfin Web 10.3.6 playing cam-basement. Stopped at 29411 ms ``` --- src/components/apphost.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/apphost.js b/src/components/apphost.js index b7783186c2..e67d795227 100644 --- a/src/components/apphost.js +++ b/src/components/apphost.js @@ -313,7 +313,7 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet var deviceId; var deviceName; var appName = "Jellyfin Web"; - var appVersion = "10.3.6"; + var appVersion = "10.4.0"; var visibilityChange; var visibilityState; From 4196e279eada6d06a7179c103d6b50437d361e7c Mon Sep 17 00:00:00 2001 From: tluciomiranda Date: Fri, 13 Sep 2019 14:32:45 +0000 Subject: [PATCH 62/80] 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 | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index ea16d5603a..89f7dc703c 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -217,7 +217,7 @@ "HeaderRevisionHistory": "Histórico de Versões", "HeaderRunningTasks": "Tarefas em Execução", "HeaderScenes": "Cenas", - "HeaderSchedule": "Agendamento", + "HeaderSchedule": "Agendamentos", "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.", @@ -834,7 +834,7 @@ "ButtonOther": "Outro", "ButtonOk": "OK", "ButtonLibraryAccess": "Acesso à biblioteca", - "ButtonGuide": "Guia", + "ButtonGuide": "Programação", "ButtonGotIt": "Entendido", "ButtonEditImages": "Editar imagens", "ButtonDownload": "Transferir", @@ -880,7 +880,7 @@ "HandledByProxy": "Gerido pelo proxy inverso", "HDPrograms": "Programas HD", "H264EncodingPresetHelp": "Escolha um valor mais rápido para melhorar o desempenho, ou um valor mais lento para melhorar a qualidade.", - "Guide": "Guia", + "Guide": "Programação", "GuestStar": "Estrela convidada", "GroupVersions": "Agrupar versões", "GroupBySeries": "Agrupar por série", @@ -1003,7 +1003,7 @@ "SearchForMissingMetadata": "Procurar metadados em falta", "Screenshots": "Capturas de Ecrã", "Screenshot": "Captura de Ecrã", - "Schedule": "Horário", + "Schedule": "Agendamentos", "ScanForNewAndUpdatedFiles": "Procurar ficheiros novos ou atualizados", "SaveSubtitlesIntoMediaFoldersHelp": "Guardar ficheiros de legendas junto aos ficheiros vídeo facilita a gestão.", "SaveSubtitlesIntoMediaFolders": "Guardar legendas nas pastas multimédia", @@ -1084,5 +1084,7 @@ "LabelMaxChromecastBitrate": "Qualidade de transmissão para Chromecast:", "EnableStreamLoopingHelp": "Ative esta opção no caso de a transmissão em direto apenas conter alguns segundos de dados, e necessitar de ser continuamente requisitada. Ativar esta opção quando não é necessário pode causar problemas.", "LiveBroadcasts": "Emissões em Direto", - "Live": "Em Direto" + "Live": "Em Direto", + "Sports": "Desporto", + "News": "Notícias" } From f8c018b77e52b58cff1ea680eb022af29013b38d Mon Sep 17 00:00:00 2001 From: tluciomiranda Date: Fri, 13 Sep 2019 14:39:52 +0000 Subject: [PATCH 63/80] 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 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index 89f7dc703c..c1b9c9b8a7 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -524,7 +524,7 @@ "MessageItemsAdded": "Itens adicionados.", "MessageLeaveEmptyToInherit": "Deixar em branco para herdar as configurações do item pai, ou o valor global por defeito.", "MessageNoAvailablePlugins": "Não existem extensões disponíveis.", - "MessageNoMovieSuggestionsAvailable": "Não existem sugestões de filmes disponíveis atualmente. Comece por assistir e avaliar seus filmes e, então, volte para verificar suas recomendações.", + "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.", "MessageNothingHere": "Nada aqui.", @@ -1086,5 +1086,7 @@ "LiveBroadcasts": "Emissões em Direto", "Live": "Em Direto", "Sports": "Desporto", - "News": "Notícias" + "News": "Notícias", + "Programs": "Programas", + "HeaderMovies": "Filmes" } From db8410602a0ce5e7dd9e560b048cf1daceb84563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Schw=C3=B6rer?= Date: Fri, 13 Sep 2019 15:16:40 +0000 Subject: [PATCH 64/80] 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, 6 insertions(+), 2 deletions(-) diff --git a/src/strings/de.json b/src/strings/de.json index 2fa89108f5..166d4512a2 100644 --- a/src/strings/de.json +++ b/src/strings/de.json @@ -156,7 +156,7 @@ "CriticRating": "Kritiker Bewertung", "CustomDlnaProfilesHelp": "Erstelle ein benutzerdefiniertes Profil für ein neues Zielgerät, oder um ein vorhandenes Systemprofil zu überschreiben.", "DateAdded": "Hinzugefügt am", - "DatePlayed": "Gesehen am", + "DatePlayed": "Abgespielt am", "DeathDateValue": "Gestorben: {0}", "Default": "Standard", "DefaultErrorMessage": "Es gab einen Fehler beim verarbeiten der Anfrage. Bitte versuche es später erneut.", @@ -1443,5 +1443,9 @@ "PasswordResetProviderHelp": "Wählen Sie einen Password Reset Provider, der verwendet werden soll, wenn dieser Benutzer ein Passwort zurücksetzen möchte", "Box": "Box", "HeaderHome": "Home", - "HeaderHomeSettings": "Home Einstellungen" + "HeaderHomeSettings": "Home Einstellungen", + "LabelAudioCodec": "Audiocodec:", + "LabelAudioChannels": "Audiokanäle:", + "HeaderTypeImageFetchers": "{0} Bildquellen", + "CopyStreamURL": "Stream URL kopieren" } From 2d917f38076cbbd056336939bed4fdd43bd98aff Mon Sep 17 00:00:00 2001 From: tluciomiranda Date: Fri, 13 Sep 2019 14:43:53 +0000 Subject: [PATCH 65/80] 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 | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index c1b9c9b8a7..7a432eb4cb 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -55,7 +55,7 @@ "ButtonSave": "Guardar", "ButtonScanAllLibraries": "Analisar todas as Bibliotecas", "ButtonSearch": "Procurar", - "ButtonSelectDirectory": "Selecione a diretoria", + "ButtonSelectDirectory": "Selecione a Pasta", "ButtonSelectView": "Selecionar visualização", "ButtonSend": "Enviar", "ButtonSettings": "Configurações", @@ -89,7 +89,7 @@ "DeleteUser": "Apagar Utilizador", "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": "Diretor", + "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.", "Edit": "Editar", "EnableCinemaMode": "Ativar modo cinema", @@ -188,7 +188,7 @@ "HeaderMediaInfo": "Informações Multimédia", "HeaderMetadataSettings": "Configurações de Metadados", "HeaderMusicVideos": "Vídeos de Música", - "HeaderMyMedia": "A Minha Multimédia", + "HeaderMyMedia": "O Meu Conteúdo", "HeaderNewApiKey": "Nova Chave da API", "HeaderNextUp": "A Seguir", "HeaderParentalRatings": "Classificações Parentais", @@ -1040,7 +1040,7 @@ "Overview": "Resumo", "OriginalAirDateValue": "Data de estreia original: {0}", "OptionSubstring": "Parte de palavra", - "LatestFromLibrary": "Últimos", + "LatestFromLibrary": "Mais Recentes em {0}", "HideWatchedContentFromLatestMedia": "Ocultar títulos já vistos do conteúdo recente", "MessageUnableToConnectToServer": "Não foi possível estabelecer ligação ao servidor. Por favor, certifique-se de que o servidor está a correr e tente de novo.", "HeaderStartNow": "Iniciar", @@ -1088,5 +1088,7 @@ "Sports": "Desporto", "News": "Notícias", "Programs": "Programas", - "HeaderMovies": "Filmes" + "HeaderMovies": "Filmes", + "DirectorsValue": "Realização: {0}", + "DirectorValue": "Realizador: {0}" } From 81e98409d07e0fa1cf16f5276406570b2663b967 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Fri, 13 Sep 2019 20:03:07 +0000 Subject: [PATCH 66/80] Translated using Weblate (Russian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/ru/ --- src/strings/ru.json | 71 ++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/src/strings/ru.json b/src/strings/ru.json index 67f6333d16..b3d5b623e5 100644 --- a/src/strings/ru.json +++ b/src/strings/ru.json @@ -23,7 +23,7 @@ "AllowMediaConversion": "Разрешить преобразование медиаданных", "AllowMediaConversionHelp": "Предоставить или запретить доступ к компоненте преобразования медиаданных.", "AllowOnTheFlySubtitleExtraction": "Разрешить динамическое извлечение субтитров", - "AllowOnTheFlySubtitleExtractionHelp": "Внедрённые субтитры возможно извлекать из видео и доставлять Jellyfin-приложениям в виде обычного текста, в целях предотвращения перекодировки видео. На некоторых системах это может занять продолжительное время и вызывать задержки воспроизведения видео в процессе извлечения. Отключите это, для прошивки внедрённых субтитров во время перекодировки видео, при отсутствии встроенной поддержки их в клиентском устройстве.", + "AllowOnTheFlySubtitleExtractionHelp": "Внедрённые субтитры возможно извлекать из видео и доставлять клиентам в виде обычного текста, в целях предотвращения перекодировки видео. На некоторых системах это может занять продолжительное время и вызывать задержки воспроизведения видео в процессе извлечения. Отключите это, для прошивки внедрённых субтитров во время перекодировки видео, при отсутствии встроенной поддержки их в клиентском устройстве.", "AllowRemoteAccess": "Разрешение удалённого доступа к данному серверу Jellyfin Server.", "AllowRemoteAccessHelp": "Если флажок снят, то все удалённые подключения будут заблокированы.", "AllowedRemoteAddressesHelp": "Список разделённых запятыми IP-адресов или записей IP/netmask для сетей, которым разрешено удалённое соединение. Если не заполнять, то будут использованы все внешние адреса.", @@ -202,7 +202,7 @@ "DownloadsValue": "Загрузки: {0}", "DrmChannelsNotImported": "Каналы с DRM не будут импортироваться.", "DropShadow": "Теневая", - "EasyPasswordHelp": "Простой PIN-код используется для автономного доступа с поддерживаемых Jellyfin-приложений, и может также использоваться для удобного внутрисетевого входа.", + "EasyPasswordHelp": "Простой PIN-код используется для автономного доступа на поддерживаемых клиентах и может также использоваться для удобного внутрисетевого входа.", "Edit": "Правка", "EditImages": "Править рисунки", "EditMetadata": "Править метаданные", @@ -240,7 +240,7 @@ "EveryNDays": "Каждые {0} дней", "ExitFullscreen": "Выход с полного экрана", "ExtraLarge": "Очень крупный", - "ExtractChapterImagesHelp": "Извлечение рисунков сцен предоставляет возможности Jellyfin-приложениям для отображения графических меню выбора сцены. Данный процесс может быть медленным, нагружает ЦП и может понадобиться несколько гигабайт пространства. Он работает при обнаружении видеофайлов, а также, как задача, назначенная на ночь. Расписание возможно перенастроить в области Назначенных задач. Не рекомендуется запускать данную задачу в часы пик.", + "ExtractChapterImagesHelp": "Извлечение рисунков сцен предоставляет возможности клиентам для отображения графических меню выбора сцены. Данный процесс может быть медленным, нагружает ЦП и может понадобиться несколько гигабайт пространства. Он работает при обнаружении видеофайлов, а также, как задача, назначенная на ночь. Расписание возможно перенастроить в области Назначенных задач. Не рекомендуется запускать данную задачу в часы пик.", "Extras": "Допматериалы", "FFmpegSavePathNotFound": "Мы не смогли обнаружить FFmpeg по введённому вами пути. FFprobe также необходим и должен быть в той же самой папке. Эти компоненты обычно поставляются вместе в одном загрузочном пакете. Проверьте путь и повторите попытку.", "FastForward": "Быстро вперёд", @@ -562,7 +562,7 @@ "LabelCustomCertificatePath": "Путь к пользовательскому SSL-сертификату:", "LabelCustomCertificatePathHelp": "Путь к файлу PKCS #12, содержащему сертификат и \tзакрытый ключ для включения поддержки TLS на произвольном домене.", "LabelCustomCss": "Настраиваемые CSS:", - "LabelCustomCssHelp": "Применяйте свои собственные настраиваемые стили CSS к веб-интерфейсу.", + "LabelCustomCssHelp": "Применяйте свою собственную настраиваемую стилизацию к веб-интерфейсу.", "LabelCustomDeviceDisplayName": "Отображаемое название:", "LabelCustomDeviceDisplayNameHelp": "Приведите произвольное имя для отображения или не заполняйте, чтобы использовать имя, выданное устройством.", "LabelCustomRating": "Произвольная возрастная категория:", @@ -601,11 +601,11 @@ "LabelEnableDlnaClientDiscoveryInterval": "Интервал обнаружения клиентов", "LabelEnableDlnaClientDiscoveryIntervalHelp": "Определяется длительность в секундах между SSDP-запросами от Jellyfin.", "LabelEnableDlnaDebugLogging": "Включить журналирование отладки DLNA", - "LabelEnableDlnaDebugLoggingHelp": "Это приведет к увеличению обьема файлов Журнала, рекомендуется использовать только для поиска неполадок.", + "LabelEnableDlnaDebugLoggingHelp": "Создаются большие файлы Журнала, рекомендуется использовать только для поиска неполадок.", "LabelEnableDlnaPlayTo": "Включить DLNA-функцию Воспроизвести На", - "LabelEnableDlnaPlayToHelp": "В Jellyfin имеется способность обнаруживать устройства внутри своей сети, а также предоставляется возможность удалённо управлять ими.", + "LabelEnableDlnaPlayToHelp": "Обнаруживаются устройства внутри своей сети, а также предоставляется возможность удалённо управлять ими.", "LabelEnableDlnaServer": "Включить DLNA-сервер", - "LabelEnableDlnaServerHelp": "UPnP-устройствам в домашней сети предоставляются возможности для навигации по содержанию Jellyfin и его воспроизведения.", + "LabelEnableDlnaServerHelp": "Для UPnP-устройств домашней сети возможна навигация по содержанию и его воспроизведение.", "LabelEnableHardwareDecodingFor": "Включить аппаратное декодирование для:", "LabelEnableRealtimeMonitor": "Включить отслеживание в реальном времени", "LabelEnableRealtimeMonitorHelp": "В поддерживаемых файловых системах правки файлов будут обрабатываться незамедлительно.", @@ -616,7 +616,7 @@ "LabelEvent": "Событие:", "LabelEveryXMinutes": "Каждые:", "LabelExternalDDNS": "Внешний домен:", - "LabelExternalDDNSHelp": "Если имеется динамический DNS, введите его здесь. Это будет использоваться Jellyfin-приложениями при удаленном подключении. Это поле требуется, когда используется вместе с пользовательским ssl-сертификатом. Например: mydomain.com.", + "LabelExternalDDNSHelp": "Если имеется динамический DNS, введите его здесь для использования клиентами при удаленном подключении. Это поле требуется, когда используется вместе с пользовательским ssl-сертификатом. Например: mydomain.com.", "LabelExtractChaptersDuringLibraryScan": "Извлекать рисунки сцен в процессе сканирования медиатеки", "LabelExtractChaptersDuringLibraryScanHelp": "При включении, рисунки сцен будут извлечены, когда видео импортируется в процессе сканирования медиатеки. При отключении, они будут извлечены в процессе назначенной задачи «Рисунки сцен», позволяя регулярному сканированию медиатеки завершаться быстрее.", "LabelFailed": "Неудачно", @@ -667,7 +667,7 @@ "LabelLocalHttpServerPortNumberHelp": "TCP-порт, ко которому следует создать привязку HTTP-сервера Jellyfin.", "LabelLockItemToPreventChanges": "Зафиксировать данный элемент, чтобы запретить будущие правки", "LabelLoginDisclaimer": "Предупреждение при входе:", - "LabelLoginDisclaimerHelp": "Это будет отображаться в нижней части страницы входа в систему.", + "LabelLoginDisclaimerHelp": "Сообщение будет отображаться в нижней части страницы входа в систему.", "LabelLogs": "Журналы:", "LabelManufacturer": "Производитель", "LabelManufacturerUrl": "URL производителя", @@ -676,7 +676,7 @@ "LabelMaxChromecastBitrate": "Качество трансляции Chromecast:", "LabelMaxParentalRating": "Макс. допустимая возрастная категория:", "LabelMaxResumePercentage": "Макс. доля для возобновления, %:", - "LabelMaxResumePercentageHelp": "Произведения предполагаются воспроизведёнными полностью, при остановке после данного момента", + "LabelMaxResumePercentageHelp": "Произведения предполагаются воспроизведёнными полностью, при остановке с данного момента.", "LabelMaxScreenshotsPerItem": "Макс. число снимков экрана на элемент:", "LabelMaxStreamingBitrate": "Макс. качество трансляции:", "LabelMaxStreamingBitrateHelp": "Укажите макс. потоковую скорость трансляции.", @@ -694,9 +694,9 @@ "LabelMethod": "Метод:", "LabelMinBackdropDownloadWidth": "Мин. ширина загружаемого задника:", "LabelMinResumeDuration": "Мин. длительность для возобновления:", - "LabelMinResumeDurationHelp": "Наименьшая длительность видео в секундах, при которой сохраняется позиция воспроизведения и позволяется возобновление", + "LabelMinResumeDurationHelp": "Наименьшая длительность видео в секундах, при которой сохраняется позиция воспроизведения и позволяется возобновление.", "LabelMinResumePercentage": "Мин. доля для возобновления, %:", - "LabelMinResumePercentageHelp": "Произведения предполагаются не воспроизведёнными, при остановке до данного момента", + "LabelMinResumePercentageHelp": "Произведения предполагаются не воспроизведёнными, при остановке до данного момента.", "LabelMinScreenshotDownloadWidth": "Мин. ширина загружаемого снимка экрана:", "LabelModelDescription": "Описание модели", "LabelModelName": "Наименование модели", @@ -835,7 +835,7 @@ "LabelUserAgent": "Агент пользователя:", "LabelUserLibrary": "Медиатека пользователя:", "LabelUserLibraryHelp": "Выберите, чью медиатеку отображать на устройстве. Не заполняйте, чтобы наследовать параметр по умолчанию.", - "LabelUserRemoteClientBitrateLimitHelp": "Это переопределит глобальные значения по умолчанию, установленные в параметрах воспроизведения сервера.", + "LabelUserRemoteClientBitrateLimitHelp": "Переопределияются глобальные значения по умолчанию, установленные в параметрах воспроизведения сервера.", "LabelUsername": "Имя пользователя:", "LabelVaapiDevice": "Устройство VA-API:", "LabelVaapiDeviceHelp": "Это является узлом отрисовки, который используется для аппаратного ускорения.", @@ -858,7 +858,7 @@ "Large": "Крупный", "LatestFromLibrary": "Новейшее: {0}", "LearnHowYouCanContribute": "Изучите, как вы можете внести свой вклад.", - "LibraryAccessHelp": "Выделите медиапапки, чтобы дать доступ этому пользователю. Администраторы могут изменять все папки с помощью «Диспетчера метаданных».", + "LibraryAccessHelp": "Выделите медиатеки, чтобы дать доступ этому пользователю. Администраторы могут изменять все папки с помощью «Диспетчера метаданных».", "Like": "Нравится", "LinksValue": "Ссылки: {0}", "List": "Список", @@ -914,7 +914,7 @@ "MessageDeleteTaskTrigger": "Вы действительно хотите удалить данный триггер задачи?", "MessageDirectoryPickerBSDInstruction": "Касаемо BSD, возможно, потребуется конфигурировать хранилище в вашем FreeNAS Jail для того, чтобы разрешить Jellyfin получить к нему доступ.", "MessageDirectoryPickerInstruction": "Сетевые пути возможно ввести вручную, в том случае, если при нажатии кнопки «Сеть» происходит сбой обнаружения устройств. Например: {0} или {1}.", - "MessageDirectoryPickerLinuxInstruction": "Для Linux на Arch Linux, CentOS, Debian, Fedora, OpenSuse или Ubuntu, вы должны предоставить системному пользователю Jellyfin, по крайней мере, доступ для чтения к расположениям хранилища.", + "MessageDirectoryPickerLinuxInstruction": "Для Linux на Arch Linux, CentOS, Debian, Fedora, OpenSuse или Ubuntu, вы должны предоставить пользователю службы, по крайней мере, доступ для чтения к расположениям хранилища.", "MessageDownloadQueued": "Загрузка в очереди.", "MessageEnablingOptionLongerScans": "Включение этой опции может привести к значительному увеличению времени сканирования медиатеки.", "MessageFileReadError": "Произошла ошибка при считывании файла. Повторите попытку позже.", @@ -925,21 +925,21 @@ "MessageInvalidUser": "Недопустимое имя пользователя или пароль. Повторите попытку.", "MessageItemSaved": "Элемент сохранён.", "MessageItemsAdded": "Элементы добавлены.", - "MessageLeaveEmptyToInherit": "Не заполняйте, чтобы наследовать параметры от родительского элемента, или глобальное значение по умолчанию.", + "MessageLeaveEmptyToInherit": "Оставьте пустым, для наследования параметров от родительского элемента или глобального значения по умолчанию.", "MessageNoAvailablePlugins": "Плагинов не имеется.", "MessageNoMovieSuggestionsAvailable": "В настоящее время предложений фильмов не имеются. Начните смотреть и оценивать свои фильмы, а затем вернитесь, чтобы просмотреть рекомендации.", "MessageNoPluginsInstalled": "Нет установленных плагинов.", "MessageNoTrailersFound": "Трейлеры не найдены. Установите канал трейлеров, чтобы повысить своё впечатление от фильма путём добавления собрания интернет-трейлеров.", "MessageNothingHere": "Здесь ничего нет.", "MessagePasswordResetForUsers": "Следующие пользователи сбросили свои пароли. Теперь они могут войти с помощью PIN-кодов, которые использовались для сброса.", - "MessagePlayAccessRestricted": "Воспроизведение данного содержания в настоящее время ограничено. За дополнительными сведениями. обратитесь к вашему администратору Jellyfin Server.", + "MessagePlayAccessRestricted": "Воспроизведение данного содержания в настоящее время ограничено. За дополнительными сведениями обратитесь к администратору сервера.", "MessagePleaseEnsureInternetMetadata": "Убедитесь, что включена загрузка метаданных из Интернета.", "MessagePleaseWait": "Подождите. Это может занять минуту.", "MessagePluginConfigurationRequiresLocalAccess": "Чтобы конфигурировать данный плагин войдите непосредственно в свой локальный сервер.", "MessagePluginInstallDisclaimer": "Плагины, созданные членами сообщества Jellyfin являются отличным способом повышения эффективности Jellyfin с помощью дополнительных функций и компонентов. Перед установкой примите во внимание влияние, которое они могут оказать на Jellyfin Server, например, длительные сканирования медиатеки, дополнительную фоновую обработку и снижение системной стабильности.", "MessageReenableUser": "См. ниже для разблокировки", "MessageSettingsSaved": "Параметры сохранены.", - "MessageTheFollowingLocationWillBeRemovedFromLibrary": "Из вашей медиатеки Jellyfin будут изъяты следующие расположения медиаданных :", + "MessageTheFollowingLocationWillBeRemovedFromLibrary": "Из вашей медиатеки будут изъяты следующие расположения медиаданных:", "MessageUnableToConnectToServer": "Мы не можем подсоединиться к выбранному серверу в данный момент. Убедитесь, что он запущен и повторите попытку.", "MessageUnsetContentHelp": "Содержание отображается как обычные папки. Для наилучших результатов используйте диспетчер метаданных, чтобы задать тип содержания подпапок.", "MessageYouHaveVersionInstalled": "В настоящее время установлена версия {0}.", @@ -951,7 +951,7 @@ "Mobile": "Мобильный / Планшетный", "Monday": "понедельник", "MoreFromValue": "Ещё в {0}", - "MoreUsersCanBeAddedLater": "Потом можно добавить ещё пользователей в «Панели».", + "MoreUsersCanBeAddedLater": "Потом можно добавить ещё пользователей изнутри «Панели».", "MoveLeft": "Двигать влево", "MoveRight": "Двигать вправо", "MovieLibraryHelp": "Просмотрите {0}Руководство Jellyfin по именованию фильмов{1}.", @@ -982,7 +982,7 @@ "OneChannel": "Один канал", "OnlyForcedSubtitles": "Только форсированные субтитры", "OnlyForcedSubtitlesHelp": "Загружены будут только форсированные субтитры.", - "OnlyImageFormats": "Только графические форматы (VOBSUB, PGS, SUB/IDX и т.д.)", + "OnlyImageFormats": "Только графические форматы (VOBSUB, PGS, SUB и т.д.)", "OptionAdminUsers": "Администраторы", "OptionAlbum": "Альбом", "OptionAlbumArtist": "Исп. альбома", @@ -1385,11 +1385,11 @@ "ChangingMetadataImageSettingsNewContent": "Изменения в настройках загрузки метаданных или иллюстраций применяются только к новому содержанию, добавляемому в медиатеку. Чтобы применить изменения к наличным произведениям, необходимо обновить их метаданные вручную.", "HeaderAudioLanguages": "Языки аудио", "LabelDynamicExternalId": "{0} Ид:", - "LeaveBlankToNotSetAPassword": "Необязательно - оставьте пустым, чтобы не назначать пароль", + "LeaveBlankToNotSetAPassword": "Оставьте пустым, чтобы не назначать пароль.", "MessageImageFileTypeAllowed": "Поддерживаются только файлы JPEG и PNG.", "MessageImageTypeNotSelected": "Выберите тип рисунка из выпадающего меню.", "OptionResElement": "res-элемент", - "AuthProviderHelp": "Выберите поставщика аутентификации, который будет использоваться для аутентификации пароля этого пользователя", + "AuthProviderHelp": "Выберите поставщика аутентификации, который будет использоваться для аутентификации пароля этого пользователя.", "HeaderFavoriteMovies": "Избранные фильмы", "HeaderFavoriteShows": "Избранные передачи", "HeaderFavoriteEpisodes": "Избранные эпизоды", @@ -1411,8 +1411,8 @@ "DashboardOperatingSystem": "Операционная система: {0}", "DashboardArchitecture": "Архитектура: {0}", "LabelWeb": "Веб: ", - "LaunchWebAppOnStartup": "Запустить веб-приложение Jellyfin в моем веб-браузере при запуске Jellyfin Server", - "LaunchWebAppOnStartupHelp": "Это откроет веб-приложение в веб-браузере по умолчанию при начальном запуске Jellyfin Server. Это не произойдет при использовании функции перезапуска сервера.", + "LaunchWebAppOnStartup": "Запустить веб-интерфейс при запуске Jellyfin Server", + "LaunchWebAppOnStartupHelp": "Открывается веб-клиент в браузере по умолчанию при начальном запуске сервера. Это не произойдет при использовании функции перезапуска сервера.", "MediaInfoSoftware": "ПО", "MediaInfoStreamTypeAudio": "Аудио", "MediaInfoStreamTypeData": "Данные", @@ -1431,7 +1431,7 @@ "OptionIsSD": "SD", "OptionList": "Список", "OptionLoginAttemptsBeforeLockout": "Определяет, сколько неудачных попыток входа можно сделать до блокировки.", - "OptionLoginAttemptsBeforeLockoutHelp": "0 означает наследование по умолчанию, 3 для не-администратора и 5 для администратора, -1 отключает блокировку", + "OptionLoginAttemptsBeforeLockoutHelp": "При значении 0 наследуются по умолчанию три попытки для обычных пользователей и пять для администратора. При установке этого значения в -1 функция отключается.", "OptionPoster": "Постер", "OptionPosterCard": "Постер-карта", "OptionThumb": "Бегунок", @@ -1439,5 +1439,24 @@ "PasswordResetProviderHelp": "Выберите поставщика сброса пароля, который будет использоваться, когда этот пользователь запрашивает сброс пароля", "PlaybackData": "Данные воспроизведения", "SubtitleOffset": "Сдвиг субтитров", - "TabNetworking": "Работа в сети" + "TabNetworking": "Работа в сети", + "LabelBaseUrlHelp": "Здесь вы можете добавить пользовательский подкаталог для доступа к серверу с более уникального URL.", + "LabelPlayer": "Игрок:", + "MoreMediaInfo": "О медиаданных", + "LabelVideoCodec": "Видео кодек:", + "LabelVideoBitrate": "Потоковая скорость аудио:", + "LabelTranscodingProgress": "Прогресс перекодировки:", + "LabelTranscodingFramerate": "Частота кадров перекодировки:", + "LabelSize": "Размер:", + "LabelPlayMethod": "Метод воспроизведения:", + "LabelFolder": "Папка:", + "LabelBaseUrl": "Базовый URL:", + "LabelBitrate": "Поток. ск-ть:", + "LabelAudioSampleRate": "Ч-та дискр-ии аудио:", + "LabelAudioCodec": "Аудио кодек:", + "LabelAudioChannels": "Аудио каналы:", + "LabelAudioBitrate": "Потоковая скорость аудио:", + "LabelAudioBitDepth": "Битовая глубина аудио:", + "HeaderFavoriteBooks": "Избранные книги", + "CopyStreamURL": "Копировать URL потока" } From c5e008a73a8c5c1cc387d4bf3cfeed290e123ad9 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Sat, 14 Sep 2019 21:41:21 +0000 Subject: [PATCH 67/80] Translated using Weblate (Russian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/ru/ --- src/strings/ru.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/strings/ru.json b/src/strings/ru.json index b3d5b623e5..046674c779 100644 --- a/src/strings/ru.json +++ b/src/strings/ru.json @@ -1458,5 +1458,7 @@ "LabelAudioBitrate": "Потоковая скорость аудио:", "LabelAudioBitDepth": "Битовая глубина аудио:", "HeaderFavoriteBooks": "Избранные книги", - "CopyStreamURL": "Копировать URL потока" + "CopyStreamURL": "Копировать URL потока", + "LabelPleaseRestart": "Изменения вступят в силу после перезагрузки веб-клиента вручную.", + "CopyStreamURLSuccess": "URL скопирован успешно." } From 75195a48466bccb4bc916a3510f620fbece66a04 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Sun, 15 Sep 2019 09:36:18 +0000 Subject: [PATCH 68/80] Translated using Weblate (Kazakh) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/kk/ --- src/strings/kk.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strings/kk.json b/src/strings/kk.json index d5d899d509..2514b34089 100644 --- a/src/strings/kk.json +++ b/src/strings/kk.json @@ -1474,5 +1474,6 @@ "PasswordResetProviderHelp": "Bul paıdalanýshy paróldi ysyrý saýalyn jibergen kezde paıdalanylatyn paróldi ysyrý jetkizýshisin tańdańyz", "PlaybackData": "Oınatý derekteri", "SubtitleOffset": "Sýbtıtrler yǵysýy", - "TabNetworking": "Jelilik jumys" + "TabNetworking": "Jelilik jumys", + "HeaderFavoriteBooks": "Tańdaýly kitaptar" } From a12954f4f96432efb6a99fbc46e0580eac14db08 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Sun, 15 Sep 2019 07:49:54 +0000 Subject: [PATCH 69/80] Translated using Weblate (Russian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/ru/ --- src/strings/ru.json | 68 ++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/strings/ru.json b/src/strings/ru.json index 046674c779..078cf6055f 100644 --- a/src/strings/ru.json +++ b/src/strings/ru.json @@ -19,7 +19,7 @@ "AllEpisodes": "Все эпизоды", "AllLanguages": "Все языки", "AllLibraries": "Все медиатеки", - "AllowHWTranscodingHelp": "При включении, тюнеру разрешается динамически перекодировать транслируемые потоки. Это может помочь уменьшить перекодировку, требуемую в Jellyfin Server.", + "AllowHWTranscodingHelp": "Тюнеру разрешается динамически перекодировать транслируемые потоки. Это может помочь уменьшить перекодировку, требуемую сервером.", "AllowMediaConversion": "Разрешить преобразование медиаданных", "AllowMediaConversionHelp": "Предоставить или запретить доступ к компоненте преобразования медиаданных.", "AllowOnTheFlySubtitleExtraction": "Разрешить динамическое извлечение субтитров", @@ -54,7 +54,7 @@ "BoxRear": "Спинка коробки", "Browse": "Навигация", "BrowsePluginCatalogMessage": "Просмотрите каталог плагинов, чтобы ознакомиться с имеющимися плагинами.", - "BurnSubtitlesHelp": "Определяется, должен ли сервер внедрять субтитры при преобразовании видео в зависимости от формата субтитров. Избегание внедрения субтитров улучшит производительность сервера. Выберите «Авто» для записи основанных на графике форматов (например, VOBSUB, PGS, SUB/IDX и т.п.), а также некоторых субтитров ASS/SSA.", + "BurnSubtitlesHelp": "Определяется, должен ли сервер внедрять субтитры при преобразовании видео в зависимости от формата субтитров. Избегание внедрения субтитров улучшит производительность сервера. Выберите «Авто» для записи основанных на графике форматов (VOBSUB, PGS, SUB/IDX и т.п.) и некоторых субтитров ASS/SSA.", "ButtonAdd": "Добавить", "ButtonAddMediaLibrary": "Добавить медиатеку", "ButtonAddScheduledTaskTrigger": "Добавить триггер", @@ -180,7 +180,7 @@ "DetectingDevices": "Обнаруживются устройства", "DeviceAccessHelp": "Это относится только к устройствам, которые могут быть однозначно распознаны и не препятствует доступу через браузер. Фильтрация доступа пользовательского устройства запретит использование новых устройств до тех пор, пока они не будут одобрены.", "DirectPlaying": "Воспроизводится напрямую", - "DirectStreamHelp1": "Медиаданные совместимы с устройством в отношении разрешения и типа медиаданных (H.264, AC3, и т.д.), но в несовместимом файловом контейнере (.mkv, .avi, .wmv и т.д.). Видео будет повторно упаковано динамически перед его трансляцией на устройство.", + "DirectStreamHelp1": "Медиаданные совместимы с устройством в отношении разрешения и типа медиаданных (H.264, AC3, и т.д.), но в несовместимом файловом контейнере (mkv, avi, wmv и т.д.). Видео будет повторно упаковано динамически перед его трансляцией на устройство.", "DirectStreamHelp2": "При прямой трансляции файла расходуется очень мало вычислительной мощности без потери качества видео.", "DirectStreaming": "Транслируется напрямую", "Director": "Режиссёр", @@ -194,7 +194,7 @@ "DisplayInMyMedia": "Показывать на главном экране", "DisplayInOtherHomeScreenSections": "Показывать в разделах главного экрана (нпр., новейшие медиаданные, продолжение просмотра и т.п.)", "DisplayMissingEpisodesWithinSeasons": "Отображать отсутствующие эпизоды в пределах сезонов", - "DisplayMissingEpisodesWithinSeasonsHelp": "Это также должно быть включено для ТВ-медиатек при установке и настройке Jellyfin Server.", + "DisplayMissingEpisodesWithinSeasonsHelp": "Это также должно быть включено для ТВ-медиатек в конфигурации сервера.", "DisplayModeHelp": "Выберите тип экрана, где запущен Jellyfin.", "DoNotRecord": "Не записывать", "Down": "Вниз", @@ -207,24 +207,24 @@ "EditImages": "Править рисунки", "EditMetadata": "Править метаданные", "EditSubtitles": "Править субтитры", - "EnableBackdrops": "Включить задники", - "EnableBackdropsHelp": "При включении, задники будут отображаться фоном некоторых страниц при просмотре медиатеки.", - "EnableCinemaMode": "Включить режим кинозала", - "EnableColorCodedBackgrounds": "Включить цветовой фон", - "EnableDisplayMirroring": "Включить дублирование отображения", - "EnableExternalVideoPlayers": "Включить внешние проигрыватели видео", + "EnableBackdrops": "Задники", + "EnableBackdropsHelp": "Задники будут отображаются фоном на некоторых страницах при просмотре медиатеки.", + "EnableCinemaMode": "Режим кинозала", + "EnableColorCodedBackgrounds": "Обозначеннные цветом фоны", + "EnableDisplayMirroring": "Дублирование отображения", + "EnableExternalVideoPlayers": "Внешние проигрыватели видео", "EnableExternalVideoPlayersHelp": "Меню внешнего проигрывателя будет показано при запуске воспроизведения видео.", "EnableHardwareEncoding": "Включить аппаратное кодирование", - "EnableNextVideoInfoOverlay": "Включать во время воспроизведения сведения о последующем видео", + "EnableNextVideoInfoOverlay": "Показывать сведения о следующем видео во время воспроизведения", "EnableNextVideoInfoOverlayHelp": "В конце видео отображать информацию о последующем видео в текущем плей-листе.", - "EnablePhotos": "Включить фотографии", - "EnablePhotosHelp": "Фото будут обнаруживаться и отображаться наряду с другими медиафайлами.", + "EnablePhotos": "Отображать фотографии", + "EnablePhotosHelp": "Рисунки будут обнаруживаться и отображаться наряду с другими медиафайлами.", "EnableStreamLooping": "Автоциклирование трансляций", "EnableStreamLoopingHelp": "Включайте, если трансляции содержат данные только на несколько секунд и необходимо непрерывно их запрашивать. Включение этого без необходимости может породить проблемы.", - "EnableThemeSongs": "Включить тематические композиции", - "EnableThemeSongsHelp": "При включении, тематические композиции будут воспроизводиться фоном при просмотре медиатеки.", - "EnableThemeVideos": "Включить тематические видео", - "EnableThemeVideosHelp": "При включении, тематические видео будут воспроизводиться фоном при просмотре медиатеки.", + "EnableThemeSongs": "Тематические композиции", + "EnableThemeSongsHelp": "Воспроизведение тематических композиций в фоновом режиме при навигации по медиатеке.", + "EnableThemeVideos": "Тематические видео", + "EnableThemeVideosHelp": "Воспроизведение тематических видео в фоновом режиме при навигации по медиатеке.", "Ended": "Прекращённое", "EndsAtValue": "Конец в {0}", "Episodes": "Эпизоды", @@ -240,7 +240,7 @@ "EveryNDays": "Каждые {0} дней", "ExitFullscreen": "Выход с полного экрана", "ExtraLarge": "Очень крупный", - "ExtractChapterImagesHelp": "Извлечение рисунков сцен предоставляет возможности клиентам для отображения графических меню выбора сцены. Данный процесс может быть медленным, нагружает ЦП и может понадобиться несколько гигабайт пространства. Он работает при обнаружении видеофайлов, а также, как задача, назначенная на ночь. Расписание возможно перенастроить в области Назначенных задач. Не рекомендуется запускать данную задачу в часы пик.", + "ExtractChapterImagesHelp": "Извлечение рисунков сцен предоставляет возможности клиентам для отображения графических меню выбора сцены. Данный процесс может быть медленным, потребляет ресурсы, и могут понадобиться несколько гигабайт пространства. Он работает при обнаружении видеофайлов, а также, как задача, назначенная на ночь. Расписание возможно перенастроить в области Назначенных задач. Не рекомендуется запускать данную задачу в часы пик.", "Extras": "Допматериалы", "FFmpegSavePathNotFound": "Мы не смогли обнаружить FFmpeg по введённому вами пути. FFprobe также необходим и должен быть в той же самой папке. Эти компоненты обычно поставляются вместе в одном загрузочном пакете. Проверьте путь и повторите попытку.", "FastForward": "Быстро вперёд", @@ -528,7 +528,7 @@ "LabelAll": "Все", "LabelAllowHWTranscoding": "Разрешить аппаратную перекодировку", "LabelAllowServerAutoRestart": "Разрешить автоматический перезапуск сервера для применения обновлений", - "LabelAllowServerAutoRestartHelp": "Сервер будет перезапускаться только в периоды простоя, когда никакие пользователи не активны.", + "LabelAllowServerAutoRestartHelp": "Сервер будет перезапускаться только в периоды простоя, когда нет активности пользователей.", "LabelAllowedRemoteAddresses": "Фильтр внешних IP-адресов:", "LabelAllowedRemoteAddressesMode": "Режим фильтра внешних IP-адресов:", "LabelAppName": "Название приложения", @@ -543,7 +543,7 @@ "LabelBirthDate": "Дата рождения:", "LabelBirthYear": "Год рождения:", "LabelBlastMessageInterval": "Интервал сообщений проверки активности, с", - "LabelBlastMessageIntervalHelp": "Определяет длительность в секундах между сообщениями проверки активности сервера.", + "LabelBlastMessageIntervalHelp": "Определяет длительность в секундах между сообщениями проверки активности.", "LabelBlockContentWithTags": "Блокирование элементов с тегами:", "LabelBurnSubtitles": "Внедрение субтитров:", "LabelCache": "Кэш:", @@ -587,7 +587,7 @@ "LabelDisplayOrder": "Порядок отображения:", "LabelDisplaySpecialsWithinSeasons": "Отображать специальные эпизоды в пределах тех сезонов, когда они выходили в эфир", "LabelDownMixAudioScale": "Коэффициент усиления при понижающем микшировании:", - "LabelDownMixAudioScaleHelp": "Коэффициент компенсирующего усиления звука при понижающем до стерео микшировании. Задайте 1, чтобы не менять исходные значения уровня.", + "LabelDownMixAudioScaleHelp": "Коэффициент компенсирующего усиления звука при понижающем до стерео микшировании. Значение 1 сохраняет исходный уровень.", "LabelDownloadLanguages": "Загружаемые языки:", "LabelDropImageHere": "Перетащите рисунок сюда или щёлкните для навигации.", "LabelDropShadow": "Окантовка:", @@ -618,7 +618,7 @@ "LabelExternalDDNS": "Внешний домен:", "LabelExternalDDNSHelp": "Если имеется динамический DNS, введите его здесь для использования клиентами при удаленном подключении. Это поле требуется, когда используется вместе с пользовательским ssl-сертификатом. Например: mydomain.com.", "LabelExtractChaptersDuringLibraryScan": "Извлекать рисунки сцен в процессе сканирования медиатеки", - "LabelExtractChaptersDuringLibraryScanHelp": "При включении, рисунки сцен будут извлечены, когда видео импортируется в процессе сканирования медиатеки. При отключении, они будут извлечены в процессе назначенной задачи «Рисунки сцен», позволяя регулярному сканированию медиатеки завершаться быстрее.", + "LabelExtractChaptersDuringLibraryScanHelp": "Генерируются рисунки сцен при импорте видео в процессе сканирования медиатеки. В противном случае, они будут извлечены в процессе назначенной задачи «Рисунки сцен», позволяя регулярному сканированию медиатеки завершаться быстрее.", "LabelFailed": "Неудачно", "LabelFileOrUrl": "Файл или URL:", "LabelFinish": "Завершить", @@ -626,13 +626,13 @@ "LabelForgotPasswordUsernameHelp": "Введите имя пользователя, если помните его.", "LabelFormat": "Формат:", "LabelFriendlyName": "Понятное имя:", - "LabelServerNameHelp": "Данное имя используется для распознавания данного сервера. Если не заполнять, то будет использовано имя компьютера.", + "LabelServerNameHelp": "Это имя используется для распознавания сервера и будет по умолчанию именем компьютера.", "LabelGroupMoviesIntoCollections": "Группировать фильмы внутрь коллекций", "LabelGroupMoviesIntoCollectionsHelp": "При отображении списка фильмов, элементы, принадлежащие к одной коллекции будут отображаться как единый сгруппированный элемент.", "LabelH264Crf": "Значение CRF H264-кодирования:", "LabelH264EncodingPreset": "Предустановка H264-кодирования:", "LabelHardwareAccelerationType": "Аппаратное ускорение:", - "LabelHardwareAccelerationTypeHelp": "Имеется только на поддерживаемых системах.", + "LabelHardwareAccelerationTypeHelp": "Это экспериментальная функция, имеющаяся только на поддерживаемых системах.", "LabelHomeNetworkQuality": "Качество в домашней сети:", "LabelHomeScreenSectionValue": "Главная страница - раздел {0}:", "LabelHttpsPort": "Номер локального HTTPS-порта:", @@ -646,20 +646,20 @@ "LabelImageType": "Тип рисунка:", "LabelImportOnlyFavoriteChannels": "Ограничиваться каналами обозначенными как избранное", "LabelInNetworkSignInWithEasyPassword": "Включить внутрисетевой вход со своим простым PIN-кодом", - "LabelInNetworkSignInWithEasyPasswordHelp": "При включении, возможно использовать простой PIN-код для входа в Jellyfin-приложения изнутри своей домашней сети. Ваш обычный пароль будет необходим только вне дома. Если PIN-код не заполнен, то внутри своей домашней сети не потребуется пароль.", + "LabelInNetworkSignInWithEasyPasswordHelp": "Используется простой PIN-код для входа в клиенты внутри своей локальной сети. Ваш обычный пароль будет необходим только вне дома. Если PIN-код не заполнен, то внутри своей домашней сети не потребуется пароль.", "LabelInternetQuality": "Качество в Интернете:", "LabelKeepUpTo": "Хранить до:", "LabelKidsCategories": "Детские категории:", "LabelKodiMetadataDateFormat": "Формат даты выпуска:", - "LabelKodiMetadataDateFormatHelp": "Все даты в пределах NFO-файлов будут считываться и записываться по данному формату.", - "LabelKodiMetadataEnableExtraThumbs": "Копировать extrafanart внутрь extrathumbs", + "LabelKodiMetadataDateFormatHelp": "Все даты в пределах NFO-файлов будут разбираться по данному формату.", + "LabelKodiMetadataEnableExtraThumbs": "Копировать extrafanart в поле extrathumbs", "LabelKodiMetadataEnableExtraThumbsHelp": "При загрузке рисунков, их возможно сохранять внутрь extrafanart и extrathumbs для максимальной совместимости с оболочкой Kodi.", "LabelKodiMetadataEnablePathSubstitution": "Включить подстановки путей", "LabelKodiMetadataEnablePathSubstitutionHelp": "Включаются подстановки путей к рисункам с помощью параметров подстановки путей сервера.", "LabelKodiMetadataSaveImagePaths": "Сохранять пути рисунков в пределах NFO-файлов", "LabelKodiMetadataSaveImagePathsHelp": "Рекомендуется, если имена файлов рисунков не соответствуют руководящим принципам Kodi.", "LabelKodiMetadataUser": "Сохранение в NFO-файле данных о просмотре пользователем:", - "LabelKodiMetadataUserHelp": "Включите, чтобы сохранять данные о просмотрах в NFO-файлах для использования в других приложениях.", + "LabelKodiMetadataUserHelp": "Сохраняет данные о просмотрах в NFO-файлах для использования в других приложениях.", "LabelLanNetworks": "Домашние сети:", "LabelLanguage": "Язык:", "LabelLineup": "Список сопоставления:", @@ -705,7 +705,7 @@ "LabelMonitorUsers": "Отслеживание деятельности от:", "LabelMovieCategories": "Фильмовые категории:", "LabelMoviePrefix": "Префикс фильма:", - "LabelMoviePrefixHelp": "При применении к названиям фильмов префикса, введите его здесь, чтобы он правильно обрабатывался в Jellyfin.", + "LabelMoviePrefixHelp": "При применении к названиям фильмов префикса, введите его здесь, чтобы он правильно обрабатывался на сервере.", "LabelMovieRecordingPath": "Путь к записываемым фильмам (необязательно):", "LabelMusicStreamingTranscodingBitrate": "Поток. скорость перекодировки музыки:", "LabelMusicStreamingTranscodingBitrateHelp": "Укажите максимальную потоковую скорость при трансляции музыки", @@ -820,7 +820,7 @@ "LabelTrackNumber": "Номер дорожки:", "LabelTranscodingAudioCodec": "Аудио профиль:", "LabelTranscodingContainer": "Контейнер:", - "LabelTranscodingTempPathHelp": "В данной папке содержатся рабочие файлы, используемые при перекодировке. Укажите произвольный путь, или не заполняйте, чтобы использовать стандартный в пределах серверной папки data.", + "LabelTranscodingTempPathHelp": "Укажите произвольный путь для файлов перекодировки, служащие для клиентов. Оставьте пустым, чтобы использовать умолчания сервера.", "LabelTranscodingThreadCount": "Количество перекодирующих подпотоков:", "LabelTranscodingThreadCountHelp": "Выберите максимальное число подпотоков для использования при перекодировке. Сокращение числа подпотоков понижает нагрузку на ЦП, но преобразование может оказаться недостаточно быстрым для впечатления плавного воспроизведения.", "LabelTranscodingVideoCodec": "Видео кодек:", @@ -948,7 +948,7 @@ "MetadataSettingChangeHelp": "Изменение параметров метаданных повлияет на новое содержание, которое будет добавляться в дальнейшем. Чтобы обновить существующие содержание, откройте экран с подробностями и нажмите кнопку Обновить, или выполните массовое обновление, с помощью Диспетчера метаданных.", "MinutesAfter": "минут(у/ы) после", "MinutesBefore": "минут(у/ы) до", - "Mobile": "Мобильный / Планшетный", + "Mobile": "Мобильный", "Monday": "понедельник", "MoreFromValue": "Ещё в {0}", "MoreUsersCanBeAddedLater": "Потом можно добавить ещё пользователей изнутри «Панели».", @@ -1030,7 +1030,7 @@ "OptionDisableUserHelp": "При блокировании, этому пользователю не разрешаются любые подключения к серверу. Имеющиеся соединения будут разорваны.", "OptionDislikes": "Не нравящиеся", "OptionDisplayFolderView": "Отображать аспект Папки для просмотра обычных медиапапок", - "OptionDisplayFolderViewHelp": "При включении, в Jellyfin-приложениях будет отображаться аспект Папки наряду с вашей медиатекой. Это полезно, если вам нравится вид обычных папок.", + "OptionDisplayFolderViewHelp": "Отображение аспекта \"Папки\" рядом с другими вашими медиатеками. Это может быть полезно, если вы хотите вид обычных папок.", "OptionDownloadArtImage": "Виньетка", "OptionDownloadBackImage": "Задник", "OptionDownloadBannerImage": "Баннер", @@ -1069,7 +1069,7 @@ "OptionHideUser": "Скрыть этого пользователя с экрана входа", "OptionHideUserFromLoginHelp": "Целесообразно для личных или скрытых администраторских учётных записей. Пользователю будет нужно входить в систему вручную, вводя своё имя пользователя и пароль.", "OptionHlsSegmentedSubtitles": "Сегмент. субтитры HLS", - "OptionHomeVideos": "Дом. видео и фото", + "OptionHomeVideos": "Фотографии", "OptionIgnoreTranscodeByteRangeRequests": "Игнорировать запросы диапазона байтов перекодировки", "OptionIgnoreTranscodeByteRangeRequestsHelp": "При включении, эти запросы будут учтены, но заголовок диапазона байтов будет проигнорирован.", "OptionImdbRating": "Оценка IMDb", @@ -1251,7 +1251,7 @@ "StopRecording": "Остановить запись", "Studios": "Студии", "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Эти параметры также применимы к любому Chromecast-воспроизведению запущенному данным устройством.", - "SubtitleAppearanceSettingsDisclaimer": "Данные параметры не применимы к графическим субтитрам (PGS, DVD и т.д.) или к субтитрам, которые имеют внедрённые свои собственные стили (ASS/SSA).", + "SubtitleAppearanceSettingsDisclaimer": "Данные параметры не применяются к графическим субтитрам (PGS, DVD и т.д.) или субтитрам ASS/SSA, внедряющим свои собственные стили.", "SubtitleDownloadersHelp": "Включите и ранжируйте предпочитаемые загрузчики субтитров в порядке приоритета.", "Subtitles": "Субтитры", "Suggestions": "Предлагаемое", From b06e9b584256b6edb8d6b7f0f437503ef7b5dd37 Mon Sep 17 00:00:00 2001 From: Anthony Lavado Date: Mon, 16 Sep 2019 05:08:53 +0000 Subject: [PATCH 70/80] Translated using Weblate (Arabic) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/ar/ --- src/strings/ar.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/ar.json b/src/strings/ar.json index e3e14a9600..a02dfd166d 100644 --- a/src/strings/ar.json +++ b/src/strings/ar.json @@ -517,7 +517,7 @@ "LabelSerialNumber": "الرقم التسلسلي", "LabelSeriesRecordingPath": "مسار تسجيل المسلسلات (خيارية):", "LabelServerHost": "المضيف:", - "LabelServerHostHelp": "192.168.1.100 أو https://myserver.com", + "LabelServerHostHelp": "192.168.1.100:8096 أو https://myserver.com", "LabelServerPort": "المنفذ:", "LabelSkipIfAudioTrackPresent": "تخطّىإن كان المقطع الصوتي الافتراضي يتوافق مع اللغة المنزلة", "LabelSkipIfAudioTrackPresentHelp": "لا تختر هذه لكي تؤكد وجود ترجمة لجميع الفيديوهات، بغض النظر عن لغة الصوت.", From df82636845323f5e97dbab910cbb2a81a583bac5 Mon Sep 17 00:00:00 2001 From: Anthony Lavado Date: Mon, 16 Sep 2019 05:07:42 +0000 Subject: [PATCH 71/80] Translated using Weblate (English (United States)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/en_US/ --- src/strings/en-us.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/en-us.json b/src/strings/en-us.json index cd709fe55d..d8f4e83933 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -810,7 +810,7 @@ "LabelSerialNumber": "Serial number", "LabelSeriesRecordingPath": "Series recording path (optional):", "LabelServerHost": "Host:", - "LabelServerHostHelp": "192.168.1.100 or https://myserver.com", + "LabelServerHostHelp": "192.168.1.100:8096 or https://myserver.com", "LabelServerName": "Server name:", "LabelServerPort": "Port:", "LabelSimultaneousConnectionLimit": "Simultaneous stream limit:", From d2984b7abd30bc40affa90d37e81c2337734a375 Mon Sep 17 00:00:00 2001 From: ZsiGiT Date: Mon, 16 Sep 2019 12:45:32 +0000 Subject: [PATCH 72/80] Translated using Weblate (Hungarian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/hu/ --- src/strings/hu.json | 48 +++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/src/strings/hu.json b/src/strings/hu.json index 0c3c56e3de..e998841a4f 100644 --- a/src/strings/hu.json +++ b/src/strings/hu.json @@ -93,18 +93,18 @@ "Dislike": "Nem tettszik", "Display": "Megjelenítés", "DisplayMissingEpisodesWithinSeasons": "Hiányzó évad epizódok megjelenítése", - "DisplayMissingEpisodesWithinSeasonsHelp": "Ezt engedélyezni kell a Jellyfin Szerver beállításban lévő TV könyvtárak esetében is.", + "DisplayMissingEpisodesWithinSeasonsHelp": "Ezt engedélyezni kell a szerver beállításában lévő TV könyvtárak esetében is.", "Down": "Le", "Download": "Letöltés", "Edit": "Szerkesztés", "EditImages": "Képek szerkesztése", "EditMetadata": "Metaadat szerkesztés", "EditSubtitles": "Feliratok szerkesztése", - "EnableBackdrops": "Háttérképek engedélyezve", - "EnableBackdropsHelp": "Ha engedélyezve van, akkor a háttérképek a könyvtár böngészése közben néhány oldal hátterében jelennek meg.", + "EnableBackdrops": "Háttérképek", + "EnableBackdropsHelp": "A háttérképek a könyvtár böngészése közben néhány oldal hátterében jelennek meg.", "EnableHardwareEncoding": "Hardveres kódolás engedélyezése", - "EnableThemeSongs": "Főcím dalok engedélyezése", - "EnableThemeSongsHelp": "Ha engedélyezve van, a főcím dalok a háttérben játszódnak le a könyvtár böngészése közben.", + "EnableThemeSongs": "Főcím dalok", + "EnableThemeSongsHelp": "Főcím dalok lejátszása háttérben a könyvtár böngészése közben.", "EndsAtValue": "Várható befejezés {0}", "Episodes": "Epizódok", "ExitFullscreen": "Kilépés a teljes képernyőből", @@ -117,9 +117,9 @@ "FolderTypeBooks": "Könyvek", "FolderTypeMovies": "Filmek", "FolderTypeMusic": "Zenék", - "FolderTypeMusicVideos": "Zenei videók", - "FolderTypeTvShows": "TV Műsorok", - "FolderTypeUnset": "Vegyes tartalom", + "FolderTypeMusicVideos": "Zenei Videók", + "FolderTypeTvShows": "Műsorok", + "FolderTypeUnset": "Vegyes Tartalom", "Folders": "Könyvtárak", "Friday": "Péntek", "Fullscreen": "Teljes képernyő", @@ -678,15 +678,15 @@ "DownloadsValue": "{0} letöltés", "DrmChannelsNotImported": "A csatornák DRM-el nem kerülnek importálásra.", "DropShadow": "Árnyék", - "EasyPasswordHelp": "Az egyszerű PIN kódot az offline hozzáféréshez használják a támogatott Jellyfin alkalmazásokban, valamint hálózaton belüli bejelentkezéshez is használható.", - "EnableCinemaMode": "Cinema Mode engedélyezése", - "EnableColorCodedBackgrounds": "Színes kódolt háttérképek engedélyezése", - "EnableDisplayMirroring": "Kijelző tükrözés engedélyezése", - "EnableExternalVideoPlayers": "Külső videolejátszók engedélyezése", + "EasyPasswordHelp": "Az egyszerű PIN kódot az offline hozzáféréshez használják a támogatott kliens alkalmazásokban, valamint hálózaton belüli bejelentkezéshez is használható.", + "EnableCinemaMode": "Cinema Mode", + "EnableColorCodedBackgrounds": "Színkódolt háttérképek", + "EnableDisplayMirroring": "Kijelző tükrözés", + "EnableExternalVideoPlayers": "Külső videolejátszók", "EnableExternalVideoPlayersHelp": "A külső lejátszó menü a videó indításakor jelenik meg.", "EnableNextVideoInfoOverlay": "A következő videó adatainak megjelenítése lejátszás közben", "EnableNextVideoInfoOverlayHelp": "A videó végén megjeleníti az aktuális lejátszási listában lévő következő videó adatait.", - "EnablePhotos": "Fotók engedélyezése", + "EnablePhotos": "Fotók megjelenítése", "EnablePhotosHelp": "A fényképeket a médiafájlok mellett észleli és megjeleníti.", "Ended": "Befejeződött", "ErrorAddingMediaPathToVirtualFolder": "Hiba történt a média elérésekor. Kérlek győződjön meg róla, hogy az elérési út érvényes és a Jellyfin szerver hozzáfér az adott helyhez.", @@ -801,8 +801,8 @@ "Shows": "Műsorok", "Songs": "Dalok", "ValueSpecialEpisodeName": "Special - {0}", - "EnableThemeVideos": "Videók témájának engedélyezése", - "EnableThemeVideosHelp": "Ha engedélyezve van, a videó témája a háttérben játszódik le a könyvtár böngészése közben.", + "EnableThemeVideos": "Videók témák", + "EnableThemeVideosHelp": "Videó témájának lejátszása háttérben a könyvtár böngészése közben.", "HeaderBlockItemsWithNoRating": "Blokkolja azokat az elemeket amelyek tiltott, vagy nem felismerhető minősítésűek:", "HeaderSchedule": "Ütemezés", "HeaderSeriesStatus": "Sorozat állapot", @@ -863,8 +863,8 @@ "LabelCertificatePasswordHelp": "Ha a tanúsítványhoz jelszó szükséges, írd ide.", "LabelChannels": "Csatornák:", "LabelCustomCertificatePath": "Egyéni SSL tanúsítvány elérési útvonala:", - "LabelCustomCss": "Egyéni css:", - "LabelCustomCssHelp": "Egyéni css módosítások a webes felülethez.", + "LabelCustomCss": "Egyedi CSS:", + "LabelCustomCssHelp": "Egyedi CSS stílusok alkalmazása a webes felülethez.", "LabelCustomizeOptionsPerMediaType": "A média típusának testreszabása:", "LabelDeathDate": "Halálának dátuma:", "LabelDefaultScreen": "Alapértelmezett képernyő:", @@ -1374,5 +1374,15 @@ "XmlDocumentAttributeListHelp": "Ezek a tulajdonságok minden xml válaszüzenet gyökér elemére alkalmazásra kerülnek.", "Thumb": "Thumb", "MediaInfoStreamTypeData": "Adat", - "MediaInfoStreamTypeEmbeddedImage": "Beágyazott kép" + "MediaInfoStreamTypeEmbeddedImage": "Beágyazott kép", + "LabelBitrate": "Bitráta:", + "LabelAudioSampleRate": "Audió mintavételi ráta:", + "LabelAudioCodec": "Audió kódek:", + "LabelAudioChannels": "Audió csatorna:", + "LabelAudioBitrate": "Audió bitráta:", + "LabelAudioBitDepth": "Audió bitmélység:", + "HeaderFavoriteBooks": "Kedvenc Könyvek", + "CopyStreamURLSuccess": "URL másolása sikeres.", + "CopyStreamURL": "Stream URL másolása", + "PlaybackData": "Lejátszási adatok" } From e6f55c4ecabb5948cd2b1095f30434cf731b232b Mon Sep 17 00:00:00 2001 From: Anthony Lavado Date: Mon, 16 Sep 2019 05:13:19 +0000 Subject: [PATCH 73/80] 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 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/es-mx.json b/src/strings/es-mx.json index 54ff64336c..caad44e9b9 100644 --- a/src/strings/es-mx.json +++ b/src/strings/es-mx.json @@ -767,7 +767,7 @@ "LabelSerialNumber": "Número de serie", "LabelSeriesRecordingPath": "Ruta para grabaciones de Series (Opcional):", "LabelServerHost": "Servidor:", - "LabelServerHostHelp": "192.168.1.100 O https://miservidor.com", + "LabelServerHostHelp": "192.168.1.100:8096 o https://miservidor.com", "LabelServerPort": "Puerto:", "LabelSimultaneousConnectionLimit": "Limite de transmisiones simultaneas:", "LabelSkin": "Piel:", From 13f65932d4d8b64be3b3c9c103c9b0bff8ba983f Mon Sep 17 00:00:00 2001 From: WWWesten Date: Tue, 17 Sep 2019 06:44:28 +0000 Subject: [PATCH 74/80] Translated using Weblate (Kazakh) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/kk/ --- src/strings/kk.json | 140 ++++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/src/strings/kk.json b/src/strings/kk.json index 2514b34089..0528ae0075 100644 --- a/src/strings/kk.json +++ b/src/strings/kk.json @@ -19,11 +19,11 @@ "AllEpisodes": "Barlyq bólimder", "AllLanguages": "Barlyq tilder", "AllLibraries": "Barlyq tasyǵyshhanalar", - "AllowHWTranscodingHelp": "Qosylǵanda, aǵyndardy naqty ýaqytta qaıta kodtaýǵa túnerge múmkindik beredi. Bul Jellyfin Server arqyly qaıta kodtaý talabyn azaıtýǵa kómektesýi múmkin.", + "AllowHWTranscodingHelp": "Aǵyndardy naqty ýaqytta qaıta kodtaýǵa túnerge múmkindik beredi. Bul server arqyly qaıta kodtaý talabyn azaıtýǵa kómektesýi múmkin.", "AllowMediaConversion": "Tasyǵyshderekterdi túrlendirýge ruqsat etý", "AllowMediaConversionHelp": "Tasyǵyshderekterdi túrlendirý ereksheligine qatynaý úshin jol berý nemese tıym salý.", "AllowOnTheFlySubtitleExtraction": "Naqty ýaqytta sýbtıtrlerdi shyǵarýǵa ruqsat etý", - "AllowOnTheFlySubtitleExtractionHelp": "Beıne qaıta kodtaýyna tıym salýǵa kómektesý úshin endirilgen sýbtıtrler beıneden shyǵarylyp, Jellyfin qoldanbalaryna kádimgi mátinge pishiminde jetkizilý múmkin. Keıbir júıelerde buǵan uzaq ýaqyt ketýi jáne shyǵarý úrdisi barysynda beıne oınatý toqtatylýy múmkin. Tutynǵysh qurylǵyda olarǵa qoldaý kórsetilmegen kezde, beıne qaıta kodtalý arqyly endirilgen sýbtıtrler jazylýy úshin ony óshirińiz.", + "AllowOnTheFlySubtitleExtractionHelp": "Beıne qaıta kodtaýyna tıym salýǵa kómektesý úshin endirilgen sýbtıtrler beıneden shyǵarylyp, klıentterge kádimgi mátinben jetkizilý múmkin. Keıbir júıelerde buǵan uzaq ýaqyt ketýi jáne shyǵarý úrdisi barysynda beıne oınatý toqtatylýy múmkin. Tutynǵysh qurylǵyda olarǵa qoldaý kórsetilmegen kezde, beıne qaıta kodtalý arqyly endirilgen sýbtıtrler jazylýy úshin ony óshirińiz.", "AllowRemoteAccess": "Osy Jellyfin Serverine syrtqy qosylymdar úshin ruqsat etý.", "AllowRemoteAccessHelp": "Eger jalaýsha alastalǵan bolsa, baryq syrtqy baılanystar qursaýlanady.", "AllowedRemoteAddressesHelp": "Qashyqtan qosylýǵa ruqsat etiletin jeliler úshin útirlermen bólingen IP-mekenjaılarynyń tizbesi nemese IP/netmask jazbalar Eger bos qaldyrylsa, barlyq qashyqtaǵy mekenjaılarǵa ruqsat etiledi.", @@ -56,7 +56,7 @@ "BoxRear": "Qorap arty", "Browse": "Sharlaý", "BrowsePluginCatalogMessage": "Qoljetimdi plagındermen tanysý úshin plagın tizimdemesin sholyńyz.", - "BurnSubtitlesHelp": "Sýbtıtrler pishimine baılanysty beıneni túrlendirgen kezde server sýbtıtrlerdi jazyýyn anyqtaıdy. Sýbtıtrler jazýdy qashqaqtaý serverdiń ónimdiligin jaqsartady. Sýretke negizdelgen pishimderdi (mysaly, VOBSUB, PGS, SUB/IDX j.t.b.), sondaı-aq keıbir ASS/SSA sýbtıtrlerin jazý úshin Avtomattyny tańdańyz.", + "BurnSubtitlesHelp": "Sýbtıtrler pishimine baılanysty beıneni túrlendirgen kezde server sýbtıtrlerdi jazyýyn anyqtaıdy. Sýbtıtrler jazýdy qashqaqtaý serverdiń ónimdiligin jaqsartady. Sýretke negizdelgen pishimderdi (VOBSUB, PGS, SUB/IDX j.t.b.) jáne keıbir ASS/SSA sýbtıtrlerin jazý úshin Avtomattyny tańdańyz.", "ButtonAdd": "Ústeý", "ButtonAddMediaLibrary": "Tasyǵyshhanany ústeý", "ButtonAddScheduledTaskTrigger": "Trıggerdi ústeý", @@ -187,7 +187,7 @@ "DetectingDevices": "Qurylǵylardy tabýda", "DeviceAccessHelp": "Bul tek qana biregeı anyqtalýy múmkin qurylǵylar úshin qoldanylady jáne sholǵyshpen qantynaýǵa tyıym salmaıdy. Paıdalanýshy qurylǵysynan qatynaýdy súzgileýi jańa qurylǵylardy munda bekitilgenshe deıin paıdalanýǵa tyıym salady.", "DirectPlaying": "Tikeleı oınatýda", - "DirectStreamHelp1": "Ajyratymdylyq pen tasyǵyshderekter túrine (H.264, AC3, t.b.) qatysty tasyǵyshderekter qurylǵyǵa sáıkes keledi, biraq syıyspaıtyn faıl konteınerinde (.mkv, .avi, .wmv jáne t.b.) bolyp tur. Qurylǵyǵa taratpas buryn, beıne naqty ýaqytta qaıta jınaqtalady.", + "DirectStreamHelp1": "Ajyratymdylyq pen tasyǵyshderekter túrine (H.264, AC3, t.b.) qatysty tasyǵyshderekter qurylǵyǵa sáıkes keledi, biraq syıyspaıtyn faıl konteınerinde (mkv, avi, wmv jáne t.b.) bolyp tur. Qurylǵyǵa taratpas buryn, beıne naqty ýaqytta qaıta jınaqtalady.", "DirectStreamHelp2": "Faıldy tikeleı taratý beıne sapasyn joǵaltpaı óte az esepteý qýatyn paıdalanady.", "DirectStreaming": "Tikeleı tasymaldanýda", "Director": "Rejısór", @@ -201,7 +201,7 @@ "DisplayInMyMedia": "Basqy ekranda beınelenedi", "DisplayInOtherHomeScreenSections": "Basqy ekran bólimderinde beıneleý (mys. Eń sońǵy tasyǵyshderekter jáne Kórýdi jalǵastyrý)", "DisplayMissingEpisodesWithinSeasons": "Joq bólimderdi maýsym ishinde beıneleý", - "DisplayMissingEpisodesWithinSeasonsHelp": "Bul sondaı-aq Jellyfin Server ornatýyndaǵy TD tasyǵyshhanalary úshin qosýly bolýy kerek.", + "DisplayMissingEpisodesWithinSeasonsHelp": "Bul sondaı-aq server konfıgýrasýasyndaǵy TD tasyǵyshhanalary úshin qosýlýy qajet.", "DisplayModeHelp": "Jellyfin iske qosylǵanda ekran túrin tańdańyz.", "DoNotRecord": "Jazýǵa bolmaıdy", "Down": "Tómenge", @@ -209,29 +209,29 @@ "DownloadsValue": "{0} júkteý", "DrmChannelsNotImported": "DRM bar arnalar shetten ákelinbeıdi.", "DropShadow": "Kóleńkeli", - "EasyPasswordHelp": "Ońaıtylǵan PIN-kodyńyz qoldaýdaǵy Jellyfin qoldanbalarynan derbes qatynaý úshin paıdalanylady, jáne jeli ishinde ońaıtylyp kirý úshin paıdalanylýy múmkin.", + "EasyPasswordHelp": "Ońaıtylǵan PIN-kodyńyz qoldaýdaǵy klıenterden derbes qatynaý úshin paıdalanylady, jáne jeli ishinde ońaıtylyp kirý úshin paıdalanylýy múmkin.", "Edit": "Óńdeý", "EditImages": "Sýretterdi óńdeý", "EditMetadata": "Metaderekterdi óńdeý", "EditSubtitles": "Sýbtıtrlerdi óńdeý", - "EnableBackdrops": "Artqy sýretterdi qosý", - "EnableBackdropsHelp": "Qosylǵanda, artqy sýretter tasyǵyshhanany sholý kezinde keıbir betterde óńde beınelenedi.", - "EnableCinemaMode": "Kınoteatr rejimin qosý", - "EnableColorCodedBackgrounds": "Túspen belgilengen óńderdi qosý", - "EnableDisplayMirroring": "Beıneleýdiń telnusqasyn qosý", - "EnableExternalVideoPlayers": "Syrtqy oınatqyshtardy qosý", + "EnableBackdrops": "Artqy sýretter", + "EnableBackdropsHelp": "Artqy sýretter tasyǵyshhanany sholý kezinde keıbir betterde óńde beınelenedi.", + "EnableCinemaMode": "Kınoteatr rejimi", + "EnableColorCodedBackgrounds": "Túspen belgilengen óńder", + "EnableDisplayMirroring": "Beıneleýdiń telnusqasy", + "EnableExternalVideoPlayers": "Syrtqy oınatqyshtar", "EnableExternalVideoPlayersHelp": "Syrtqy oınatqysh máziri beıne oınatýdy bastaǵan kezde kórsetiledi.", "EnableHardwareEncoding": "Apparatyq kodtaýýdy qosý", - "EnableNextVideoInfoOverlay": "Oınatý kezinde kelesi beıne týraly aqparatty qosý", + "EnableNextVideoInfoOverlay": "Oınatý kezinde kelesi beıne týraly aqparatty kórsetý", "EnableNextVideoInfoOverlayHelp": "Beıne sońynda aǵymdaǵy oınatý tizimindegi kelesi beıne týraly aqparatty kórsetý.", - "EnablePhotos": "Fotosýretterdi qosý", - "EnablePhotosHelp": "Fotosýretter basqa tasyǵysh faıldarymen qatar anyqtalady jáne beınelenedi.", + "EnablePhotos": "Fotosýretter", + "EnablePhotosHelp": "Sýretter basqa tasyǵysh faıldarymen qatar anyqtalady jáne beınelenedi.", "EnableStreamLooping": "Taratýlardy avtomatty tuıyqtaý", "EnableStreamLoopingHelp": "Eger taratý derekterinde tek qana azyn-aýlaq sekýnd bar bolsa jáne ony úzdiksiz suratyp alý qajet bolsa, ony qosyńyz. Bul qajet bolmaǵan jaǵdaıda qosylsa, qıyndyqtar týdyrýy múmkin.", - "EnableThemeSongs": "Taqyryptyq áýenderdi qosý", - "EnableThemeSongsHelp": "Qosylǵanda, tasyǵyshhanany sholý kezinde taqyryptyq áýender óńde oınatylady.", - "EnableThemeVideos": "Taqyryptyq beınelerdi qosý", - "EnableThemeVideosHelp": "Qosylǵanda, tasyǵyshhanany sholý kezinde taqyryptyq beıneler óńde oınatylady.", + "EnableThemeSongs": "Taqyryptyq áýender", + "EnableThemeSongsHelp": "Taqyryptyq áýender tasyǵyshhanany sholý kezinde óńde oınatylady.", + "EnableThemeVideos": "Taqyryptyq beıneler", + "EnableThemeVideosHelp": "Taqyryptyq beıneler tasyǵyshhanany sholý kezinde óńde oınatylady.", "Ended": "Aıaqtaldy", "EndsAtValue": "Sońy: {0}", "Episodes": "Bólimder", @@ -247,7 +247,7 @@ "EveryNDays": "{0} kún saıyn", "ExitFullscreen": "Tolyq ekrandan shyǵý", "ExtraLarge": "Óte iri", - "ExtractChapterImagesHelp": "Sahna sýretterin shyǵaryp alý Jellyfin-qoldanbalaryna sahna bólekteýge arnalǵan syzbalyq mázirlerdi beıneleý úshin ruqsat etedi. Bul proses baıaý, OP kerek qylatyn jáne biraz gıgabaıt keńistikti qajet etetin bolýy múmkin. Ol beınefaıldary tabylǵanda, jáne túngi ýaqytyna josparlaǵan tapsyrma retinde jumys isteıdi. Oryndaý kestesi Josparlaýshy aımaǵynda teńsheledi. Bul tapsyrmany qarbalas saǵattarynda jumys istetkizý usynylmaıdy.", + "ExtractChapterImagesHelp": "Sahna sýretterin shyǵaryp alý klıentterine sahna bólekteýge arnalǵan syzbalyq mázirlerdi beıneleý úshin ruqsat etedi. Bul proses baıaý, qor kózin kóp talap etetin jáne biraz gıgabaıt keńistikti qajet etetin bolýy múmkin. Ol beınefaıldary tabylǵanda, jáne túngi ýaqytyna josparlaǵan tapsyrma retinde jumys isteıdi. Oryndaý kestesi Josparlaýshy aımaǵynda teńsheledi. Bul tapsyrmany qarbalas saǵattarynda jumys istetkizý usynylmaıdy.", "Extras": "Qosymshalar", "FFmpegSavePathNotFound": "Bizge siz engizgen FFmpeg jolyn paıdalanyp tabý múmkin bolmady. Sondaı-aq FFprobe talap etiledi jáne sol qaltada bolýy jón. Bul quramdastar ádette sol júkteýmen birge jetkiziledi. Joldy tekserip, qaıtalap kórińiz.", "FastForward": "Jyldam alǵa", @@ -539,7 +539,7 @@ "LabelAll": "Barlyq", "LabelAllowHWTranscoding": "Apparattyq qaıta kodtaýǵa ruqsat etý", "LabelAllowServerAutoRestart": "Jańartýlardy qoldaný úshin serverge qaıta iske qosylýdy ruqsat etý", - "LabelAllowServerAutoRestartHelp": "Tek qana eshqandaı paıdalýnshylar belsendi emes, áreketsiz mezgilderde server qaıta iske qosylady.", + "LabelAllowServerAutoRestartHelp": "Tek qana eshqandaı paıdalýnshylar belsendi emes áreketsiz mezgilderde server qaıta iske qosylady.", "LabelAllowedRemoteAddresses": "Qashyqtaǵy IP-mekenjaı súzgisi:", "LabelAllowedRemoteAddressesMode": "Qashyqtaǵy IP-mekenjaı súzgisiniń rejimi:", "LabelAppName": "Qoldanba aty", @@ -554,7 +554,7 @@ "LabelBirthDate": "Týǵan kúni:", "LabelBirthYear": "Týǵan jyly:", "LabelBlastMessageInterval": "Belsendilikti tekserý habarlar aralyǵy, s", - "LabelBlastMessageIntervalHelp": "Server belsendiligin tekserý habarlardyń ara uzaqtyǵyn sekýndtar arqyly anyqtaıdy.", + "LabelBlastMessageIntervalHelp": "Belsendilikti tekserý habarlaryn jaýdyrý ara uzaqtyǵyn sekýndtar arqyly anyqtaıdy.", "LabelBlockContentWithTags": "Myna tegteri bar mazmundy qursaýlaý:", "LabelBurnSubtitles": "Sýbtıtrlerdi jazý:", "LabelCache": "Kesh:", @@ -575,7 +575,7 @@ "LabelCustomCertificatePath": "Teńsheýli SSL-kýálik joly:", "LabelCustomCertificatePathHelp": "Teńsheletin domende TLS qoldaýyn qosý úshin sertıfıkaty jáne jeke kilti bar PKCS #12 faılyna jol.", "LabelCustomCss": "Teńsheýli CSS:", - "LabelCustomCssHelp": "Ózińizdiń teńsheýli CSS-kodyn ýeb-tildesýde qoldanyńyz.", + "LabelCustomCssHelp": "Ózińizdiń teńsheýli mánerleýdi ýeb-tildesýde qoldanyńyz.", "LabelCustomDeviceDisplayName": "Beınelený aty:", "LabelCustomDeviceDisplayNameHelp": "Beınelenetin teńshelgen atyn usynyńyz nemese qurylǵy arqyly baıandalǵan atyn paıdalaný úshin bos qaldyryńyz.", "LabelCustomRating": "Teńshelgen sanat:", @@ -602,7 +602,7 @@ "LabelDisplayOrder": "Beıneleý reti:", "LabelDisplaySpecialsWithinSeasons": "Arnaıy bólimderdi efırde bolǵan maýsym ishinde beıneleý", "LabelDownMixAudioScale": "Kemitilip mıksherlengende dybys ótemi:", - "LabelDownMixAudioScaleHelp": "Dybysty kemitilip mıksherlengende ótemdeý. Bastapqy deńgeı mánin ózgertpeý úshin 1 sanyn ornatyńyz..", + "LabelDownMixAudioScaleHelp": "Dybysty kemitilip mıksherlengende ótemdeý. 1 máni bastapqy deńgeıdi saqtaıdy.", "LabelDownloadLanguages": "Júktep alynatyn tilder:", "LabelDropImageHere": "Sýretti munda súıretińiz nemese sharlaý úshin nuqyńyz.", "LabelDropShadow": "Jıekter:", @@ -618,9 +618,9 @@ "LabelEnableDlnaDebugLogging": "DLNA kúıkeltirý jazbalaryn jurnalda qosý", "LabelEnableDlnaDebugLoggingHelp": "Óte aýqymdy jurnal faıldary jasalady jáne tek qana aqaýlyqtardy joıý úshin qajet bolǵan retinde paıdalanylady.", "LabelEnableDlnaPlayTo": "DLNA qurylǵysynda oınatýdy qosý", - "LabelEnableDlnaPlayToHelp": "Jellyfin jelidegi qurylǵylardy tabýy múmkin jáne bulardy qashyqtan basqarý qabiletin usynady.", + "LabelEnableDlnaPlayToHelp": "Jelidegi qurylǵylardy tabady jáne bulardy qashyqtan basqarý qabiletin usynady.", "LabelEnableDlnaServer": "DLNA-serverin qosý", - "LabelEnableDlnaServerHelp": "Jelidegi UPnP qurylǵylarǵa Jellyfin mazmunyn sholý men oınatý úshin ruqsat etý.", + "LabelEnableDlnaServerHelp": "Jelidegi UPnP qurylǵylarǵa mazmun sholý men oınatý úshin ruqsat etý.", "LabelEnableHardwareDecodingFor": "Apparatyq kodtaýdy mynaǵan qosý:", "LabelEnableRealtimeMonitor": "Naqty ýaqyttaǵy baqylaýdy qosý", "LabelEnableRealtimeMonitorHelp": "Qoldaýdaǵy faıldyq júıelerinde faıldar ózgeristeri dereý óńdeledi.", @@ -631,9 +631,9 @@ "LabelEvent": "Oqıǵa:", "LabelEveryXMinutes": "Ár:", "LabelExternalDDNS": "Syrtqy domen:", - "LabelExternalDDNSHelp": "Eger sizde dınamıkalyq DNS bolsa, ony osynda engizińiz. Ol Jellyfin qoldanbalary qashyqtan qosylý kezinde paıdalanylady. Teńsheletin SSL-kýálandyrýmen paıdalanǵan kezde bul óris mindetti bolady. Mysaly: mydomain.com.", + "LabelExternalDDNSHelp": "Eger sizde dınamıkalyq DNS bolsa, klıentter qashyqtan qosylǵanda paıdalaný úshin ony osynda engizińiz. Teńsheletin SSL-kýálikti paıdalanǵanda bul óris mindetti bolady. Mysaly: mydomain.com.", "LabelExtractChaptersDuringLibraryScan": "Sahna sýretterin tasyǵyshhanany skanerleý mezgilinde shyǵaryp alý", - "LabelExtractChaptersDuringLibraryScanHelp": "Qosylǵanda, sahna sýretteri tasyǵyshhanany skanerleý mezgilinde, beıneler sheten ákelingende, bólinip alynady. Ajyratylǵanda, bular sahna sýretterine josparlaǵan tapsyrmasy mezgilinde, turaqty tasyǵyshhanany skanerleýin jyldamyraq aıaqtalýy ushin ruqsat etip, bólinip alynady.", + "LabelExtractChaptersDuringLibraryScanHelp": "Tasyǵyshhanany skanerleý kezinde beıneler shetten ákelingen jaǵdaıda, sahna sýretteri jasalady. Keri jaǵdaıda, bular sahna sýretterine josparlaǵan tapsyrmasy mezgilinde, turaqty tasyǵyshhanany skanerleýin jyldamyraq aıaqtalýy ushin ruqsat etip, bólinip alynady.", "LabelFailed": "Sátsiz", "LabelFileOrUrl": "Faıl nemese URL:", "LabelFinish": "Aıaqtaý", @@ -641,16 +641,16 @@ "LabelForgotPasswordUsernameHelp": "Eske salsańyz, paıdalanýshy atyńyzdy engizińiz.", "LabelFormat": "Pishim:", "LabelFriendlyName": "Túsinikti ataý:", - "LabelServerNameHelp": "Bul ataý osy serverdi anyqtaý úshin paıdalanylady. Eger óris bos qaldyrylsa, kompúter aty paıdalanylady.", + "LabelServerNameHelp": "Bul ataý serverdi anyqtaý úshin paıdalanylady jáne serverdiń kompúter ataýyna ádepki bolady.", "LabelGroupMoviesIntoCollections": "Jıyntyqtar ishindegi fılmderdi toptastyrý", "LabelGroupMoviesIntoCollectionsHelp": "Fılm tizimderin beınelegen kezde jıyntyqqa kiretin fılmder toptalǵan biryńǵaı tarmaq bolyp kórsetiledi.", "LabelH264Crf": "H264 kodtaý CRF máni:", "LabelH264EncodingPreset": "H264 kodtaý daıyndamasy:", "LabelHardwareAccelerationType": "Apparatyq jedeldetý:", - "LabelHardwareAccelerationTypeHelp": "Tek qana qoldaýdaǵy júıelerde qoljetimdi.", + "LabelHardwareAccelerationTypeHelp": "Bul tájirıbelik múmkindik tek qoldaý kórsetiletin júıelerde qoljetimdi.", "LabelHomeNetworkQuality": "Úılik jeli sapasy:", "LabelHomeScreenSectionValue": "Basqy bet {0}-bólim:", - "LabelHttpsPort": "Jergilikti https-port nómiri:", + "LabelHttpsPort": "Jergilikti HTTPS-port nómiri:", "LabelHttpsPortHelp": "Jellyfin HTTPS-serveri baılastyrylýǵa tıisti TCP-port nómiri.", "LabelIconMaxHeight": "Belgisheniń eń joǵary bıigi:", "LabelIconMaxHeightHelp": "upnp:icon arqyly kórsetetin belgisheleriniń eń joǵary ajyratylymdyǵy.", @@ -661,37 +661,37 @@ "LabelImageType": "Sýret túri:", "LabelImportOnlyFavoriteChannels": "Tańdaýly retinde belgilengen arnalarmen shekteý", "LabelInNetworkSignInWithEasyPassword": "Ońaıtylǵan PIN-kod arqyly jeli ishinde ońaıtylyp kirýdi qosý", - "LabelInNetworkSignInWithEasyPasswordHelp": "Qosylǵanda, úı jelisi ishinen Jellyfin qoldanbalaryna kirý úshin ońaıtylǵan PIN-kodyńyzdy paıdalanýyńyz múmkin. Sizdiń qalypty parólińiz tek qana úı syrtynda qajet bolady. Eger PIN-kod bos qaldyrylsa, úılik jelisinde parólińiz qajet bolmaıdy.", + "LabelInNetworkSignInWithEasyPasswordHelp": "Jergilikti jelidegi klıentterge kirý úshin ońaıtylǵan PIN-kodyn qoldanyńyz. Sizdiń qalypty parólińiz tek qana úı syrtynda qajet bolady. Eger PIN-kody bos bolsa, sizge úılik jelisinde paról qajet emes.", "LabelInternetQuality": "Internettegi sapasy:", "LabelKeepUpTo": "Osyǵan deıin saqtap qalý:", "LabelKidsCategories": "Balalyq sanattary:", "LabelKodiMetadataDateFormat": "Shyǵarý kúniniń pishimi:", - "LabelKodiMetadataDateFormatHelp": "Osy pishimdi paıdalanyp nfo ishindegi barlyq kúnderi oqylady jáne jazylady.", - "LabelKodiMetadataEnableExtraThumbs": "Ádepki extrafanart derekterin extrathumbs ishine kóshirý", + "LabelKodiMetadataDateFormatHelp": "NFO-faıldaryndaǵy barlyq kúnder osy pishimniń kómegimen taldanady.", + "LabelKodiMetadataEnableExtraThumbs": "extrafanart derekterin extrathumbs órisine kóshirý", "LabelKodiMetadataEnableExtraThumbsHelp": "Sýretterdi júktegen kezde, olar Kodi qabyǵymen eń joǵary sıysymdyǵy úshin extrafanart jáne extrathumbs ekeýinde saqtalady.", "LabelKodiMetadataEnablePathSubstitution": "Jol almastyrýdy qosý", "LabelKodiMetadataEnablePathSubstitutionHelp": "Serverdiń jol almastyrý teńsheýin paıdalanyp sýretterdiń jol almastyrýyn qosady.", "LabelKodiMetadataSaveImagePaths": "Sýret joldaryn NFO-faıldarynda saqtaý", "LabelKodiMetadataSaveImagePathsHelp": "Eger sýretterdiń Kodi nusqaýlyq ustanymdaryna saı kelmegen ataýlary bolsa, bul usynylady.", "LabelKodiMetadataUser": "NFO-faıldarda myna paıdalanýshynyń qaralǵan derekterin saqtaý:", - "LabelKodiMetadataUserHelp": "Basqa qoldanbalarda paıdalaný úshin NFO-faıldarda qaralǵan derekterin saqtaýydy qosyńyz.", + "LabelKodiMetadataUserHelp": "Qaralý derekterin basqa qoldanbalar úshin NFO-faıldarda saqtaý.", "LabelLanNetworks": "Úıdegi jeliler:", "LabelLanguage": "Til:", "LabelLineup": "Tizbek:", - "LabelLocalHttpServerPortNumber": "Jergilikti http-port nómiri:", + "LabelLocalHttpServerPortNumber": "Jergilikti HTTP-port nómiri:", "LabelLocalHttpServerPortNumberHelp": "Jellyfin HTTP-serveri baılastyrylýǵa tıisti TCP-port nómiri.", "LabelLockItemToPreventChanges": "Osy tarmaqty keleshek ózgertýlerden qursaýlaý", "LabelLoginDisclaimer": "Kirgendegi eskertý:", - "LabelLoginDisclaimerHelp": "Bul kirý betiniń tómeninde beınelenedi.", + "LabelLoginDisclaimerHelp": "Kirý beti tómengi jaǵynda beınelenetin habar.", "LabelLogs": "Jurnaldar:", "LabelManufacturer": "Óndirýshi", - "LabelManufacturerUrl": "Óndirýshi url", + "LabelManufacturerUrl": "Óndirýshi URL mekenjaıy", "LabelMatchType": "Sáıkes túri:", "LabelMaxBackdropsPerItem": "Tarmaq boıynsha artqy sýretterdiń eń kóp sany:", "LabelMaxChromecastBitrate": "Chromecast tasymaldaný sapasy:", "LabelMaxParentalRating": "Eń joǵary uıǵaryndy jastas sanaty:", "LabelMaxResumePercentage": "Jalǵastyrý úshin eń kóp paıyzy:", - "LabelMaxResumePercentageHelp": "Bul kezden keıin toqtatylsa týyndylar tolyq oınatylǵan dep boljaldy", + "LabelMaxResumePercentageHelp": "Bul kezden keıin toqtatylsa týyndylar tolyq oınatylǵan dep boljaldy.", "LabelMaxScreenshotsPerItem": "Tarmaq boıynsha eń kóp skrınshot sany:", "LabelMaxStreamingBitrate": "Eń joǵary tasymaldaný sapasy:", "LabelMaxStreamingBitrateHelp": "Tasymaldaný kezinde eń joǵary qarqyndy anyqtańyz.", @@ -709,18 +709,18 @@ "LabelMethod": "Ádis:", "LabelMinBackdropDownloadWidth": "Artqy sýrettiń júktep alynatyn eń az eni:", "LabelMinResumeDuration": "Jalǵastyrý úshin eń az uzaqtyǵy:", - "LabelMinResumeDurationHelp": "Oınatý orny saqtalatyn jáne jalǵastyrýǵa múmkindik beretin sekýndtar arqyly eń qysqa beıne uzyndyǵy", + "LabelMinResumeDurationHelp": "Oınatý orny saqtalatyn jáne jalǵastyrýǵa múmkindik beretin sekýndtar arqyly eń qysqa beıne uzyndyǵy.", "LabelMinResumePercentage": "Jalǵastyrý úshin eń az paıyzy:", - "LabelMinResumePercentageHelp": "Bul kezden buryn toqtatylsa týyndylar oınatylmaǵan dep boljaldy", + "LabelMinResumePercentageHelp": "Bul kezden buryn toqtatylsa týyndylar oınatylmaǵan dep boljaldy.", "LabelMinScreenshotDownloadWidth": "Júktep alý úshin eń az skrınshot eni:", "LabelModelDescription": "Model sıpattamasy", "LabelModelName": "Model aty", "LabelModelNumber": "Model nómiri", - "LabelModelUrl": "Model url", + "LabelModelUrl": "Model URL mekenjaıy", "LabelMonitorUsers": "Mynanyń áreketterin baqylaý:", "LabelMovieCategories": "Fılmdik sanattar:", "LabelMoviePrefix": "Fılm prefıksi:", - "LabelMoviePrefixHelp": "Eger fılmderdiń ataýynda prefıks qoldanylsa, Jellyfin durys óńdeı alý úshin buny munda engizińiz.", + "LabelMoviePrefixHelp": "Eger fılmderdiń ataýynda prefıks qoldanylsa, server durys óńdeı alý úshin buny munda engizińiz.", "LabelMovieRecordingPath": "Fılm jazbalardyń joly (mindetti emes):", "LabelMusicStreamingTranscodingBitrate": "Mýzykany qaıta kodtaý qarqyny:", "LabelMusicStreamingTranscodingBitrateHelp": "Mýzyka tasymaldaný kezinde eń joǵary qarqyndy anyqtańyz", @@ -766,10 +766,10 @@ "LabelProtocol": "Protokol:", "LabelProtocolInfo": "Protoqol týraly:", "LabelProtocolInfoHelp": "Bul mán qurylǵynyń GetProtocolInfo suranystaryna jaýap bergende paıdalanylady.", - "LabelPublicHttpPort": "Jarıa http-port nómiri:", - "LabelPublicHttpPortHelp": "Jergilikti http-portyna salystyrylýy tıis jarıa port nómiri.", - "LabelPublicHttpsPort": "Jarıa https-port nómiri:", - "LabelPublicHttpsPortHelp": "Jergilikti https-portyna salystyrylýy tıis jarıa port nómiri.", + "LabelPublicHttpPort": "Jarıa HTTP-port nómiri:", + "LabelPublicHttpPortHelp": "Jergilikti HTTP-portyna salystyrylýy tıis jarıa port nómiri.", + "LabelPublicHttpsPort": "Jarıa HTTPS-port nómiri:", + "LabelPublicHttpsPortHelp": "Jergilikti HTTPS-portyna salystyrylýy tıis jarıa port nómiri.", "LabelReadHowYouCanContribute": "Qalaı úles qosý týraly bilý.", "LabelReasonForTranscoding": "Qaıta kodtaý sebebi:", "LabelRecord": "Jazý:", @@ -794,7 +794,7 @@ "LabelSerialNumber": "Serıalyq nómiri", "LabelSeriesRecordingPath": "Telehıkaıa jazbalardyń joly (mindetti emes):", "LabelServerHost": "Host:", - "LabelServerHostHelp": "192.168.1.100 nemese https://myserver.com", + "LabelServerHostHelp": "192.168.1.100:8096 nemese https://myserver.com", "LabelServerPort": "Port:", "LabelSimultaneousConnectionLimit": "Bir mezgildegi aǵyndardyń shegi:", "LabelSkin": "Muqaba:", @@ -835,7 +835,7 @@ "LabelTrackNumber": "Jolshyq nómiri:", "LabelTranscodingAudioCodec": "Dybystyq kodek:", "LabelTranscodingContainer": "Konteıner:", - "LabelTranscodingTempPathHelp": "Bul qalta quramynda qaıta kodtaý quraly paıdalanatyn jumys faıldary bar. Teńshelgen joldy anyqtańyz, nemese serverdiń derekter qaltasy ishindegi ádepkisin paıdalaný úshin bos qaldyryńyz.", + "LabelTranscodingTempPathHelp": "Klıentterge qyzmet etetin qaıta kodtaý faıldar úshin teńshelgen jolyn kórsetińiz. Server ádepkisin paıdalaný úshin bos qaldyryńyz.", "LabelTranscodingThreadCount": "Qaıta qodtaý tizbekterdiń sany:", "LabelTranscodingThreadCountHelp": "Qaıta kodtaý kezinde paıdalanatyn eń kóp tizbek sanyn tańdańyz. Tizbek sanyn azaıtý OP paıdalanýyn tómendetedi, biraq jatyq oınatý áseri úshin tez túrlendirýge jetkilikti bolmaýy múmkin.", "LabelTranscodingVideoCodec": "Beınelik kodek:", @@ -854,7 +854,7 @@ "LabelUserAgent": "Paıdalanýshy agenti:", "LabelUserLibrary": "Paıdalanýshy tasyǵyshhanasy:", "LabelUserLibraryHelp": "Qurylǵyda qaı paıdalanýshy tasyǵyshhanasyn beıneleýin bólekteńiz. Ádepki parametr murasyna ıelený úshin bos qaldyryńyz.", - "LabelUserRemoteClientBitrateLimitHelp": "Bul serverdi oınatý parametrlerinde ornatylǵan ádepki ǵalamdyq mándi qaıta anyqtaıdy.", + "LabelUserRemoteClientBitrateLimitHelp": "Serverdiń oınatý parametrlerinde ornatylǵan ádepki ǵalamdyq mándi qaıta anyqtaıdy.", "LabelUsername": "Paıdalanýshy aty:", "LabelVaapiDevice": "VA-API qurylǵysy:", "LabelVaapiDeviceHelp": "Bul apparattyq jedeldetý úshin qoldanylatyn kórsetý túıini bolyp tabylady.", @@ -863,9 +863,9 @@ "LabelVersionInstalled": "{0} ornatylǵan", "LabelVersionNumber": "Nýsqasy: {0}", "LabelVideo": "Beıne:", - "LabelXDlnaCap": "X-Dlna sıpattary:", + "LabelXDlnaCap": "X-DLNA sıpattary:", "LabelXDlnaCapHelp": "urn:schemas-dlna-org:device-1-0 ataýlar keńistigindegi X_DLNACAP elementi mazmunyn anyqtaıdy.", - "LabelXDlnaDoc": "X-Dlna tásimi:", + "LabelXDlnaDoc": "X-DLNA tásimi:", "LabelXDlnaDocHelp": "urn:schemas-dlna-org:device-1-0 ataýlar keńistigindegi X_DLNADOC elementi mazmunyn anyqtaıdy.", "LabelYear": "Jyl:", "LabelYourFirstName": "Atyńyz:", @@ -877,7 +877,7 @@ "Large": "Iri", "LatestFromLibrary": "Eń keıingi {0}", "LearnHowYouCanContribute": "Qalaı úles qosýynyńyz múmkin týraly úırenińiz.", - "LibraryAccessHelp": "Bul paıdalanýshymen ortaqtasý úshin tasyǵysh qaltalardy bólekteńiz. Metaderek retteýshini paıdalanyp ákimshiler barlyq qaltalardy óńdeýi múmkin.", + "LibraryAccessHelp": "Bul paıdalanýshymen ortaqtasý úshin tasyǵyshhanalardy bólekteńiz. Metaderek retteýshini paıdalanyp ákimshiler barlyq qaltalardy óńdeýi múmkin.", "Like": "Unaıdy", "LinksValue": "Siltemeler: {0}", "List": "Tizim", @@ -937,14 +937,14 @@ "MessageDeleteTaskTrigger": "Shynymen osy tapsyrma trıggerin joıý qajet pe?", "MessageDirectoryPickerBSDInstruction": "BSD ortasynda, Jellyfin qol jetkizý maqsatynda, sizdiń FreeNAS Jail ishindegi jınaqtaýyshty teńsheý qajet bolýy múmkin.", "MessageDirectoryPickerInstruction": "Jeli túımeshigi basylǵanda qurylǵylaryńyz orny tabylmasa, jelilik joldar qolmen engizilýi múmkin. Mysaly, {0} nemese {1}.", - "MessageDirectoryPickerLinuxInstruction": "Arch Linux, CentOS, Debian, Fedora, OpenSuse nemese Ubuntu júıelerindegi Linux úshin, Jellyfin júıelik paıdalanýshyǵa kem degende saqtaý jerlerińizge oqýǵa qatynas úshin ruqsat etýge tıissiz.", + "MessageDirectoryPickerLinuxInstruction": "Arch Linux, CentOS, Debian, Fedora, OpenSuse nemese Ubuntu júıelerindegi Linux úshin, Jqyzmet kórsetý paıdalanýshyǵa kem degende saqtaý jerlerińizge oqýǵa qatynas úshin ruqsat etýge tıissiz.", "MessageDownloadQueued": "Júktep alý kezekte.", "MessageEnablingOptionLongerScans": "Osy opsıa qoıylsa, tasyǵyshhana skanerleýleri edáýir uzyn bolýy múmkin.", "MessageFileReadError": "Faıl oqý kezinde qate oryn aldy. Áreketti keıin qaıtalańyz.", "MessageForgotPasswordFileCreated": "Kelesi faıl serverińizde jasaldy jáne qalaı kirisý týraly nusqaýlar ishinde bar:", "MessageForgotPasswordInNetworkRequired": "Paróldi ysyrý prosesi úshin áreketti úılik jelińizdiń ishinde qaıtalańyz.", "MessageInstallPluginFromApp": "Bul plagın qandaı qoldanbaǵa taǵaıyndalsa, sonyń ishinen ornatylýy tıisti.", - "MessageInvalidForgotPasswordPin": "Jaramsyz nemese merzimi aıaqtalǵan PIN engizildi. Áreketti qaıtalańyz.", + "MessageInvalidForgotPasswordPin": "Jaramsyz nemese merzimi aıaqtalǵan PIN-kod engizildi. Áreketti qaıtalańyz.", "MessageInvalidUser": "Jaramsyz paıdalanýshy aty nemese paról. Áreketti qaıtalańyz.", "MessageItemSaved": "Tarmaq saqtaldy.", "MessageItemsAdded": "Tarmaqtar ústelgen.", @@ -956,8 +956,8 @@ "MessageNoPluginsInstalled": "Ornatylǵan plagınder joq.", "MessageNoTrailersFound": "Treılerler tabylmady. Internet-treılerler tasyǵyshhanasyn ústep fılm áserin jaqsartý úshin Treıler arnasyn ornatyńyz.", "MessageNothingHere": "Osynda eshteme joq.", - "MessagePasswordResetForUsers": "Kelesi paıdalanýshylar ózderiniń parólderin ysyrddy. Endi ysyrýdyi oryndaý úshin paıdalanylǵan PIN kodtarymem kire alady.", - "MessagePlayAccessRestricted": "Osy mazmundyń oınatýy aǵymda shektelgen. Qosymsha aqparat alý úshin Jellyfin Server ákimshisine baılanysyńyz.", + "MessagePasswordResetForUsers": "Kelesi paıdalanýshylar ózderiniń parólderin ysyrddy. Endi ysyrýdyi oryndaý úshin paıdalanylǵan PIN-kodtarymem kire alady.", + "MessagePlayAccessRestricted": "Osy mazmundyń oınatýy aǵymda shektelgen. Qosymsha aqparat alý úshin server ákimshisine baılanysyńyz.", "MessagePleaseEnsureInternetMetadata": "Internetten metaderekti júktep alýy qosylǵanyna kóz jetkizińiz.", "MessagePleaseWait": "Kúte turyńyz. Bul mınót alýy múmkin.", "MessagePluginConfigurationRequiresLocalAccess": "Osy plagındi teńsheý úshin jergilikti serverińizge tikeleı kirińiz.", @@ -965,7 +965,7 @@ "MessageReenableUser": "Qaıta qosý úshin tómende qarańyz", "MessageServerConfigurationUpdated": "Server konfıgýrasıasy jańartyldy", "MessageSettingsSaved": "Parametrler saqtaldy.", - "MessageTheFollowingLocationWillBeRemovedFromLibrary": "Jellyfin tasyǵyshhanańyzdan kelesi tasyǵysh ornalasýlary alastalady:", + "MessageTheFollowingLocationWillBeRemovedFromLibrary": "Tasyǵyshhanańyzdan kelesi tasyǵysh ornalasýlary alastalady:", "MessageUnableToConnectToServer": "Tańdalǵan serverge qosylýymyz dál qazir múmkin emes. Bul iske qosylǵanyna kóz jetkizińiz jáne áreketti keıin qaıtalańyz.", "MessageUnsetContentHelp": "Mazmun kádimgi qaltalar retinde beınelenedi. Eń jaqsy nátıjeler alý úshin, ishki qaltalardyń mazmún túrlerin ornatyp Metaderek retteýshini paıdalanyńyz.", "MessageYouHaveVersionInstalled": "Aǵymda {0} nusqasy ornatylǵan.", @@ -974,10 +974,10 @@ "MetadataSettingChangeHelp": "Metaderekter parametrlerin ózgertý bolashaqtaǵy ústelgen jańa mazmunǵa áser etedi. Bar mazmundy jańartý úshin, tolyq málimetter ekranyn ashyńyz da jańartý túımeshigin basyńyz, nemese metaderekter retteýishini paıdalanyp qorymymen jańartýdy oryndańyz.", "MinutesAfter": "mınýt sońyńda", "MinutesBefore": "mınýt aldynda", - "Mobile": "Uıaly / Planshettik", + "Mobile": "Utqyr", "Monday": "dúısenbi", "MoreFromValue": "{0} arqyly kóbirek", - "MoreUsersCanBeAddedLater": "Kóbirek paıdalanýshylardy keıin Taqta arqyly ústeýińiz múmkin.", + "MoreUsersCanBeAddedLater": "Kóbirek paıdalanýshylardy keıin Taqta ishinde ústeýińiz múmkin.", "MoveLeft": "Solǵa jyljytý", "MoveRight": "Ońǵa jyljytý", "MovieLibraryHelp": "{0}Fılminiń atyn ózgertý Jellyfin-nusqaýlyǵyn{1} sholý.", @@ -1008,7 +1008,7 @@ "OneChannel": "Bir arnadan", "OnlyForcedSubtitles": "Tek qana májbúrli sýbtıtrler", "OnlyForcedSubtitlesHelp": "Tek qana májbúrli dep belgilengen sýbtıtrler júkteledi.", - "OnlyImageFormats": "Tek keskin pishimderi (VOBSUB, PGS, SUB/IDX jáne t.b. )", + "OnlyImageFormats": "Tek keskin pishimder (VOBSUB, PGS, SUB j.t.b.)", "Open": "Ashý", "OptionActor": "Aktór", "OptionActors": "Aktórler", @@ -1059,7 +1059,7 @@ "OptionDisableUserHelp": "Eger tyıym salynsa, server bul paıdalanýshydan eshqandaı baılanystarǵa ruqsat etpeıdi. Bar qosylymdar kenet úziledi.", "OptionDislikes": "Unatpaýlar", "OptionDisplayFolderView": "Kádimgi tasyǵysh qaltalaryn kórsetý úshin Qalta aspektin beıneleý", - "OptionDisplayFolderViewHelp": "Qosylǵanda, Jellyfin-qoldanbalarda Qaltalar sanaty tasyǵyshhanańyz janynda beınelenedi. Eger kádimgi qalta kórinisterin unatsańyz, bul paıdaly bolady.", + "OptionDisplayFolderViewHelp": "Basqa tasyǵyshhanalaryńyzben birge Qaltalar kórsetiledi. Bul qarapaıym qalta kórinisin alǵyńyz kelse paıdaly bolýy múmkin.", "OptionDownloadArtImage": "Oıý sýret", "OptionDownloadBackImage": "Artqy muqaba", "OptionDownloadBannerImage": "Baner", @@ -1078,7 +1078,7 @@ "OptionEnableAccessToAllLibraries": "Barlyq tasyǵyshhanalarǵa qatynaýdy qosý", "OptionEnableAutomaticServerUpdates": "Serverdiń avtomatty jańartylýyn qosý", "OptionEnableExternalContentInSuggestions": "Uynystarǵa syrtqy mazmundy qosý", - "OptionEnableExternalContentInSuggestionsHelp": "Internet-treılerler men efırlik TD kórsetimderge usynǵan mazmunǵa kirý úshin ruqsat etedi.", + "OptionEnableExternalContentInSuggestionsHelp": "Internet-treılerler men efırlik kórsetimderge usynǵan mazmunǵa kirý úshin ruqsat etedi.", "OptionEnableForAllTuners": "Barlyq túner qurylǵylary úshin qosý", "OptionEnableM2tsMode": "M2ts rejimin qosý", "OptionEnableM2tsModeHelp": "Mpegts úshin kodtaý kezinde m2ts rejimin qosý.", @@ -1098,7 +1098,7 @@ "OptionHideUser": "Bul paıdalanýshyny kirý ekrandarynan jasyrý", "OptionHideUserFromLoginHelp": "Jeke nemese jasyryn ákimshi tirkelgileri úshin paıdaly. Paıdalanýshy aty men paróldi engizý arqyly paıdalanýshyǵa qolmen kirý qajet bolady.", "OptionHlsSegmentedSubtitles": "HLS bólshektelgen sýbtıtrler", - "OptionHomeVideos": "Úı beıneleri men fotosýretter", + "OptionHomeVideos": "Fotosýretter", "OptionIgnoreTranscodeByteRangeRequests": "Qaıta kodtaý baıt aýqymy suranystaryn elemeý", "OptionIgnoreTranscodeByteRangeRequestsHelp": "Qosylǵanda, osy suranystarmen sanasý bolady, biraq baıt aýqymynyń bas derektemesi elep eskerilmeıdi.", "OptionImdbRating": "IMDb baǵalaýy", @@ -1283,7 +1283,7 @@ "Studios": "Stýdıalar", "Subscriptions": "Jazylymdar", "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Bul parametrler osy qurylǵy arqyly iske qosylǵan kezkelgen Chromecast oınatýyna qoldanylady.", - "SubtitleAppearanceSettingsDisclaimer": "Bul parametrler grafıkalyq sýbtıtrlerge (PGS, DVD j.t.b.) nemese óz máneri bar endirilgen sýbtıtrlerge (ASS/SSA) qoldanylmaıdy.", + "SubtitleAppearanceSettingsDisclaimer": "Bul parametrler grafıkalyq sýbtıtrlerge (PGS, DVD j.t.b.) nemese óz máneri bar endirilgen ASS/SSA sýbtıtrlerine qoldanylmaıdy.", "SubtitleDownloadersHelp": "Teńshelgen sýbtıtrler júkteýshilerin qosyńyz jáne basymdylyq reti boıynsha dáreje berińiz.", "Subtitles": "Sýbtıtrler", "Suggestions": "Usynystar", @@ -1420,11 +1420,11 @@ "ChangingMetadataImageSettingsNewContent": "Metaderekterdi nemese sýretterdi júkteý parametrlerin ózgertýi tek tasyǵyshhanaǵa ústelgen jańa mazmunǵa qoldanylady. Ózgeristerdi qoldanystaǵy ataýlarǵa qoldaný úshin olardyń metaderekterin qolmen jańǵyrtý qajet.", "HeaderAudioLanguages": "Dybys tilderi", "LabelDynamicExternalId": "{0} Id:", - "LeaveBlankToNotSetAPassword": "Mindetti emes - bos qaldyrsańyz, paról paıdalanylmaıdy", + "LeaveBlankToNotSetAPassword": "Paróldi ornatpaý úshin bul óristi bos qaldyrýǵa bolady.", "MessageImageFileTypeAllowed": "Tek qana JPEG jáne PNG faıldary qoldaýda.", "MessageImageTypeNotSelected": "Sýret túrin ashylmaly mázirden tandańyz.", "OptionResElement": "res elementi", - "AuthProviderHelp": "Osy paıdalanýshynyń parólin rastaý úshin paıdalanylatyn túpnusqalyq rastama jetkizýshisin bólekteńiz", + "AuthProviderHelp": "Osy paıdalanýshynyń parólin rastaý úshin paıdalanylatyn túpnusqalyq rastama jetkizýshisin bólekteńiz.", "HeaderFavoriteMovies": "Tańdaýly fılmder", "HeaderFavoriteShows": "Tańdaýly kórsetimder", "HeaderFavoriteEpisodes": "Tańdaýly bólimder", @@ -1446,8 +1446,8 @@ "DashboardOperatingSystem": "Operasıalyq júıe: {0}", "DashboardArchitecture": "Arhıtektýrasy: {0}", "LabelWeb": "Ýeb: ", - "LaunchWebAppOnStartup": "Jellyfin serveri iske qosylǵan kezde ýeb-sholǵyshta Jellyfin veb-qoldanbasyn iske qosý", - "LaunchWebAppOnStartupHelp": "Jellyfin serveri bastapqyda iske qosylǵan kezde, ol ýeb-qoldanbany ádepki ýeb-sholǵyshta ashady. Bul serverdi qaıta iske qosý fýnksıasyn qoldanǵanda oryn almaıdy.", + "LaunchWebAppOnStartup": "Serverdi iske qosqan kezde ýeb-ınterfeısti iske qosý", + "LaunchWebAppOnStartupHelp": "Server bastapqyda iske qosylǵan kezde, ýeb-klıent ádepki sholǵyshta ashylady. Bul serverdi qaıta iske qosý fýnksıasyn qoldanǵanda oryn almaıdy.", "MediaInfoSoftware": "Baǵdarlamalyq jasaqtama", "MediaInfoStreamTypeAudio": "Dybys", "MediaInfoStreamTypeData": "Derekter", @@ -1466,7 +1466,7 @@ "OptionIsSD": "SD", "OptionList": "Tizim", "OptionLoginAttemptsBeforeLockout": "Qulyptalǵansha deıin qansha durys emes kirý áreketi jasalýy múmkin ekendigin anyqtaıdy.", - "OptionLoginAttemptsBeforeLockoutHelp": "0 ádepkini ıelenýdi bildiredi, 3 ákimshi emes úshin, jáne 5 ákimshi úshin, -1 qulyptaýdy óshiredi", + "OptionLoginAttemptsBeforeLockoutHelp": "0 máni qarapaıym paıdalanýshylar úshin úsh jáne ákimshiler úshin bes árekettiń ádepki mánin bildiredi. Osyny -1 etip ornatý múmkindikti ajyratady.", "OptionPoster": "Póster", "OptionPosterCard": "Poster-karta", "OptionThumb": "Nobaı", From e4f7e95f46c701de9e01aec9a228e81bf9fc820e Mon Sep 17 00:00:00 2001 From: WWWesten Date: Tue, 17 Sep 2019 06:43:27 +0000 Subject: [PATCH 75/80] Translated using Weblate (Russian) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/ru/ --- src/strings/ru.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strings/ru.json b/src/strings/ru.json index 078cf6055f..d07e5811d1 100644 --- a/src/strings/ru.json +++ b/src/strings/ru.json @@ -543,7 +543,7 @@ "LabelBirthDate": "Дата рождения:", "LabelBirthYear": "Год рождения:", "LabelBlastMessageInterval": "Интервал сообщений проверки активности, с", - "LabelBlastMessageIntervalHelp": "Определяет длительность в секундах между сообщениями проверки активности.", + "LabelBlastMessageIntervalHelp": "Определяет длительность в секундах между бомбардированием сообщениями проверки активности.", "LabelBlockContentWithTags": "Блокирование элементов с тегами:", "LabelBurnSubtitles": "Внедрение субтитров:", "LabelCache": "Кэш:", @@ -779,7 +779,7 @@ "LabelSerialNumber": "Серийный номер", "LabelSeriesRecordingPath": "Путь к записываемым сериалам (необязательно):", "LabelServerHost": "Узел:", - "LabelServerHostHelp": "192.168.1.100 или https://myserver.com", + "LabelServerHostHelp": "192.168.1.100:8096 или https://myserver.com", "LabelServerPort": "Порт:", "LabelSimultaneousConnectionLimit": "Лимит одновременных потоков:", "LabelSkin": "Оболочка:", From 110b148c559e52ba527f7960ec6ff6f3f1eeb22a Mon Sep 17 00:00:00 2001 From: Jonas Lundberg Date: Mon, 16 Sep 2019 18:13:09 +0000 Subject: [PATCH 76/80] Translated using Weblate (Swedish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/sv/ --- src/strings/sv.json | 53 ++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/src/strings/sv.json b/src/strings/sv.json index 3a8ecaffc1..4fcfb7abde 100644 --- a/src/strings/sv.json +++ b/src/strings/sv.json @@ -162,7 +162,7 @@ "DetectingDevices": "Söker efter enheter", "DeviceAccessHelp": "Detta tillämpas endast för enheter som kan bli unikt identifierade och som inte förhindrar åtkomst till browsern. Filtering av användarenheter kommer att blockera dom från att använda nya enheter tills dom har blivit godkända här.", "DirectPlaying": "Direktuppspelning", - "DirectStreamHelp1": "Innehållet är kompatibelt med enheten vad gäller upplösning och mediatyp (H.264, AC3, etc.) men det är en inkompatibel filkontainer (.mkv, .avi, .wmv etc.). Video-filen kommer att packas om live innan strömningen startar till enheten.", + "DirectStreamHelp1": "Innehållet är kompatibelt med enheten vad gäller upplösning och mediatyp (H.264, AC3, etc) men det är en inkompatibel filkontainer (mkv, avi, wmv etc). Video-filen kommer att packas om live innan strömningen startar till enheten.", "DirectStreamHelp2": "Direktströmning av en fil använder väldigt lite resurser av CPU'n utan att bildkvaliten försämras.", "DirectStreaming": "Direktströmning", "Director": "Regissör", @@ -176,7 +176,7 @@ "DisplayInMyMedia": "Visa på hemskärmen", "DisplayInOtherHomeScreenSections": "Visa sektioner på hemskärmen som till exempel senast media och fortsätt kolla på", "DisplayMissingEpisodesWithinSeasons": "Visa saknade avsnitt i säsonger", - "DisplayMissingEpisodesWithinSeasonsHelp": "Detta måste också vara aktiverat för TV-bibliotek på Jellyfin-servern.", + "DisplayMissingEpisodesWithinSeasonsHelp": "Detta måste också vara aktiverat för TV-bibliotek i serverkonfigurationen.", "DisplayModeHelp": "Välj vilken typ av skärm som du kör Jellyfin på.", "DoNotRecord": "Spela inte in", "Down": "Ner", @@ -184,27 +184,27 @@ "DownloadsValue": "Nedladdningar: {0}", "DrmChannelsNotImported": "Kanaler med DRM kommer inte att importeras", "DropShadow": "Visa skugga", - "EasyPasswordHelp": "Din enkla pin-kod används för att logga in offline på Jellyfin-appar som stödjer det, och kan också användas för enkel inloggning från ditt nätverk.", + "EasyPasswordHelp": "Din enkla pin-kod används för att logga in offline på klienter som stödjer det, och kan också användas för enkel inloggning från ditt nätverk.", "Edit": "Ändra", "EditImages": "Ändra bilder", "EditMetadata": "Redigera metadata", "EditSubtitles": "Ändra undertexter", "EnableBackdrops": "Aktivera fondbilder", - "EnableBackdropsHelp": "Om aktiverat visas fondbilder i bakgrunden av vissa sidor vid bläddring i biblioteket.", - "EnableCinemaMode": "Aktivera bioläge", - "EnableColorCodedBackgrounds": "Aktivera färgkodade bakgrundsbilder", - "EnableDisplayMirroring": "Aktivera skärmspegling", - "EnableExternalVideoPlayers": "Aktivera externa videospelare", + "EnableBackdropsHelp": "Visar fondbilder i bakgrunden av vissa sidor vid bläddring i biblioteket.", + "EnableCinemaMode": "Bioläge", + "EnableColorCodedBackgrounds": "Färgkodade bakgrundsbilder", + "EnableDisplayMirroring": "Skärmspegling", + "EnableExternalVideoPlayers": "Externa videospelare", "EnableExternalVideoPlayersHelp": "En extern uppspelningsmeny kommer att visas när man startar en videouppspelning.", "EnableHardwareEncoding": "Aktivera hårdvaruomkodning", "EnableNextVideoInfoOverlay": "Visa info om nästa video under uppspelning", "EnableNextVideoInfoOverlayHelp": "Vid slutet av en video, visa information om nästföljande video i spellistan.", - "EnablePhotos": "Aktivera foton", - "EnablePhotosHelp": "Foton kommer upptäckas och visas tillsammans med andra mediefiler.", + "EnablePhotos": "Visa foton", + "EnablePhotosHelp": "Bilder kommer upptäckas och visas tillsammans med andra mediefiler.", "EnableThemeSongs": "Aktivera ledmotiv", - "EnableThemeSongsHelp": "Om aktiverat spelas ledmotiv upp vid bläddring i biblioteket.", + "EnableThemeSongsHelp": "Spela ledmotiv i bakgrunden vid bläddring i biblioteket.", "EnableThemeVideos": "Aktivera tema-videos", - "EnableThemeVideosHelp": "Visar tema-videos i bakgrunden när man bläddrar i biblioteket.", + "EnableThemeVideosHelp": "Spela tema-videos i bakgrunden vid bläddring i biblioteket.", "Ended": "Avslutad", "EndsAtValue": "Slutar vid: {0}", "Episodes": "Avsnitt", @@ -218,7 +218,7 @@ "EveryNDays": "Var {0}:e dag", "ExitFullscreen": "Avsluta fullskärm", "ExtraLarge": "Extra stor", - "ExtractChapterImagesHelp": "Att extrahera kapitelrutor möjliggör för vissa klienter att visa grafiska menyer för kapitelval. Aktiviteten kan vara långsam, cpu-intensiv och kan kräva flera gigabyte hårddiskutrymme på din Jellyfin Server. Aktiviteten körs när nya videofiler upptäcks och är även schemalagd under nattetid, men det går att ändra under schemalagda aktiviteter. Det är inte rekommenderat att köra den här aktiviteten vid tider med hög belastning.", + "ExtractChapterImagesHelp": "Att extrahera kapitelrutor möjliggör för klienter att visa grafiska menyer för kapitelval. Aktiviteten kan vara långsam, resurs-intensiv och kan kräva flera gigabyte i utrymme. Aktiviteten körs när nya videofiler upptäcks, och är även schemalagd under nattetid. Schemat går att konfigurera under schemalagda aktiviteter. Det är inte rekommenderat att köra den här aktiviteten vid tider med hög belastning.", "FFmpegSavePathNotFound": "Det gick inte att hitta FFmpeg med den angivna sökvägen. FFprobe måste även finnas i samma mapp. Dessa komponenter inkluderas normalt i samma nedladdning. Var god undersök sökvägen och försök igen.", "Favorite": "Favorit", "Favorites": "Favoriter", @@ -232,8 +232,8 @@ "FolderTypeMovies": "Filmer", "FolderTypeMusic": "Musik", "FolderTypeMusicVideos": "Musikvideor", - "FolderTypeTvShows": "TV-serier", - "FolderTypeUnset": "Blandat innehåll", + "FolderTypeTvShows": "Serier", + "FolderTypeUnset": "Blandat Innehåll", "Folders": "Mappar", "Friday": "Fredag", "Fullscreen": "Fullskärm", @@ -1280,16 +1280,16 @@ "HeaderFavoriteMovies": "Favoritfilmer", "HeaderAudioLanguages": "Ljudspråk", "HeaderAppearsOn": "Medverkar i", - "HeaderApp": "Appar", + "HeaderApp": "App", "HeaderAdmin": "Administratör", - "Guide": "Hjälp", + "Guide": "Guide", "GenreValue": "Genre: {0}", "General": "Allmänt", "ForAdditionalLiveTvOptions": "Klicka på \"Tjänster\" fliken för ytterligare Live TV leverantörer.", "FastForward": "Snabbspola", "Extras": "Mer", "ErrorAddingXmlTvFile": "Det uppstod ett problem vid läsningen av XmlTV filen. Kontrollera att filen är tillgänglig och försök igen.", - "ErrorAddingListingsToSchedulesDirect": "Det uppstod ett problem när din lista skulle läggas till på ditt Schedules Direct konto. Schedules Direct tillåter bara ett begränsat antal listor per konto. Du kanske behöver logga in på Schedules Direct hemsidan och ta bort dina andra listor innan du kan fortsätta.", + "ErrorAddingListingsToSchedulesDirect": "Det uppstod ett problem när din lista skulle läggas till på ditt Schedules Direct konto. Schedules Direct tillåter bara ett begränsat antal listor per konto. Du kanske behöver logga in på Schedules Direct hemsidan och ta bort andras listningar från ditt konto innan du fortsätter.", "EnableStreamLoopingHelp": "Aktivera enbart detta om direktsändningen enbart innehåller några sekunders data och behöver bli kontinuerligt uppdaterad. Att aktivera denna funktion i onödan kan skapa problem.", "EnableStreamLooping": "Loopa direktsändningar", "Descending": "Fallande", @@ -1302,7 +1302,7 @@ "ButtonTrailer": "Trailer", "ButtonStart": "Börja", "ButtonInfo": "Information", - "ButtonGuide": "Hjälp", + "ButtonGuide": "Guide", "Blacklist": "Svartlista", "Auto": "Automatisk", "AuthProviderHelp": "Välj en autentiserings leverantör som ska användas för att autentisera denna användarens lösenord", @@ -1310,5 +1310,18 @@ "AllowedRemoteAddressesHelp": "Kommaavgränsad lista av IP-adresser eller IP/nätmask poster för nätverk som kommer bli tillåtna att ansluta avlägset. Om fältet lämnas tomt så kommer alla avlägsna adresser tillåtas.", "AllowMediaConversionHelp": "Tillåt eller neka tillgång till media konvertings funktionen.", "AllowMediaConversion": "Tillåt media konvertering", - "Alerts": "Notiser" + "Alerts": "Notiser", + "HeaderMedia": "Media", + "HeaderHomeSettings": "Hem Inställningar", + "HeaderHome": "Hem", + "HeaderFavoriteVideos": "Favoritvideor", + "HeaderFavoriteSongs": "Favoritlåtar", + "HeaderFavoriteArtists": "Favoritartister", + "HeaderFavoriteAlbums": "Favoritalbum", + "HeaderFavoriteEpisodes": "Favoritavsnitt", + "HeaderFavoriteShows": "Favoritserier", + "HeaderFavoriteBooks": "Favoritböcker", + "FormatValue": "Format: {0}", + "CopyStreamURLSuccess": "URL har kopierats.", + "CopyStreamURL": "Kopiera Stream URL" } From 98e83600dc349f3e20b7de06e21b6c4fc35551a2 Mon Sep 17 00:00:00 2001 From: Will Chen Date: Mon, 16 Sep 2019 18:51:34 +0000 Subject: [PATCH 77/80] 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 | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/strings/zh-cn.json b/src/strings/zh-cn.json index 536887372e..ea07eee2d8 100644 --- a/src/strings/zh-cn.json +++ b/src/strings/zh-cn.json @@ -1444,5 +1444,20 @@ "SmallCaps": "小型大写字母", "SubtitleOffset": "字幕偏移", "MessageNoServersAvailable": "未能自动发现服务器。", - "TabNetworking": "联网" + "TabNetworking": "联网", + "HeaderFavoriteBooks": "最爱的书籍", + "LabelVideoCodec": "视频编码:", + "LabelVideoBitrate": "视频码率:", + "LabelTranscodingProgress": "转码进度:", + "LabelTranscodingFramerate": "转码帧率:", + "LabelSize": "大小:", + "LabelPleaseRestart": "改动将在手动重启客户端后生效。", + "LabelPlayMethod": "播放方式:", + "LabelFolder": "文件夹:", + "LabelBitrate": "比特率:", + "LabelAudioSampleRate": "采样率:", + "LabelAudioCodec": "编码:", + "LabelAudioChannels": "声道:", + "LabelAudioBitrate": "比特率:", + "LabelAudioBitDepth": "采样位宽:" } From 5cb4c195d79525714115a942b6c16730b292fa23 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Thu, 19 Sep 2019 14:35:30 -0400 Subject: [PATCH 78/80] Azure pipelines (#470) * Set up CI with Azure Pipelines [skip ci] * Update azure-pipelines.yml for Azure Pipelines * Update .npmignore * Add linting to Azure Pipelines * Move linting to separate job * Move Azure config to .ci * Publish pipeline artifact * Fix yaml * Only run build if lint succeeds * Remove version variable * Update npmignore * Exclude version from package filename * Update CI triggers --- .ci/azure-pipelines.yml | 60 +++++++++++++++++++++++++++++++++++++++++ .drone.yml | 9 ------- .npmignore | 3 ++- package.json | 2 +- run-eslint.sh | 18 ------------- 5 files changed, 63 insertions(+), 29 deletions(-) create mode 100644 .ci/azure-pipelines.yml delete mode 100644 .drone.yml delete mode 100755 run-eslint.sh diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml new file mode 100644 index 0000000000..483d367b64 --- /dev/null +++ b/.ci/azure-pipelines.yml @@ -0,0 +1,60 @@ +trigger: + batch: true + branches: + include: + - master + - release-* + tags: + include: + - '*' + +jobs: + - job: main_build + displayName: 'Main Build' + + dependsOn: lint + condition: succeeded() + + pool: + vmImage: 'ubuntu-latest' + + steps: + - task: NodeTool@0 + displayName: 'Install Node.js' + inputs: + versionSpec: '10.x' + + - script: | + yarn install + displayName: 'Install dependencies' + + - script: | + yarn pack --filename jellyfin-web.tgz + displayName: 'Build package' + + - task: PublishPipelineArtifact@1 + displayName: 'Publish package' + condition: succeeded() + inputs: + targetPath: '$(Build.SourcesDirectory)/jellyfin-web.tgz' + artifactName: 'jellyfin-web' + + - job: lint + displayName: 'Lint' + + pool: + vmImage: 'ubuntu-latest' + + steps: + - task: NodeTool@0 + displayName: 'Install Node.js' + inputs: + versionSpec: '10.x' + + - script: | + yarn install + displayName: 'Install dependencies' + + - script: | + yarn run lint + displayName: 'Run ESLint' diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index d1a67db6e8..0000000000 --- a/.drone.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -kind: pipeline -name: eslint - -steps: -- name: run - image: nextcloudci/eslint:eslint-1 - commands: - - ./run-eslint.sh diff --git a/.npmignore b/.npmignore index 968748d69b..f5aa5a5219 100644 --- a/.npmignore +++ b/.npmignore @@ -1,6 +1,7 @@ +.editorconfig +.ci .gitattributes .github -.drone.yml .eslintrc.yml run-eslint.sh webpack.config.js diff --git a/package.json b/package.json index 0e1922a7e1..6f8ad1f0b1 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "scripts": { "dev": "webpack --mode development", "build": "webpack --mode production", - "lint": "eslint src", + "lint": "eslint \"src\"", "prepare": "webpack --mode production" } } diff --git a/run-eslint.sh b/run-eslint.sh deleted file mode 100755 index 46b74c1a7e..0000000000 --- a/run-eslint.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -set -e - -# used this pull request for reference -# https://github.com/nextcloud/spreed/pull/48 -ESLINT=$(which eslint || true) -if [ -z "$ESLINT" ] -then - echo "could not find eslint in $PATH" - exit 1 -fi - -echo checking scripts with $ESLINT -find -name "*.js" -print0 | xargs -0 $ESLINT - -# use this line to test changes locally -#find src -name "*.js" -exec sh -c 'npx eslint $1' -- {} \; From 2c9fe360a6e68fdb0b6576dc384acbdd469207c9 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Wed, 18 Sep 2019 09:31:31 +0000 Subject: [PATCH 79/80] Translated using Weblate (Kazakh) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/kk/ --- src/strings/kk.json | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/strings/kk.json b/src/strings/kk.json index 0528ae0075..030b2be102 100644 --- a/src/strings/kk.json +++ b/src/strings/kk.json @@ -1475,5 +1475,25 @@ "PlaybackData": "Oınatý derekteri", "SubtitleOffset": "Sýbtıtrler yǵysýy", "TabNetworking": "Jelilik jumys", - "HeaderFavoriteBooks": "Tańdaýly kitaptar" + "HeaderFavoriteBooks": "Tańdaýly kitaptar", + "LabelBaseUrlHelp": "Serverge neǵurlym erekshe URL mekenjaıynan kirý úshin osynda jeke ishki katalogty qosýǵa bolady.", + "MoreMediaInfo": "Tasyǵyshderekter týraly", + "LabelVideoCodec": "Beınelik kodek:", + "LabelVideoBitrate": "Beıne qarqyny:", + "LabelTranscodingProgress": "Qaıta kodtaýdyń barysy:", + "LabelTranscodingFramerate": "Qaıta kodtaýdyń kadr jıiligi:", + "LabelSize": "Ólshemi:", + "LabelPleaseRestart": "Ózgerister ýeb-klıentti qolmen qaıta júktegennen keıin kúshine enedi.", + "LabelPlayMethod": "Oınatý tásli:", + "LabelPlayer": "Oınatqysh:", + "LabelFolder": "Qalta:", + "LabelBaseUrl": "Negizgi URL:", + "LabelBitrate": "Qarqyn:", + "LabelAudioSampleRate": "Dybystyq úlgi jıiligi:", + "LabelAudioCodec": "Dybystyq kodek:", + "LabelAudioChannels": "Dybys arnalary:", + "LabelAudioBitrate": "Dybys qarqyny:", + "LabelAudioBitDepth": "Dybystyń bıttik tereńdigi:", + "CopyStreamURLSuccess": "URL sátti kóshirildi.", + "CopyStreamURL": "Aǵyn URL mekenjaıyn kóshirý" } From 3b3f230eff78bbdc76e2f93e31a51bdd76049d5b Mon Sep 17 00:00:00 2001 From: Mark Bai Date: Thu, 19 Sep 2019 06:20:58 +0000 Subject: [PATCH 80/80] Translated using Weblate (Chinese (Simplified)) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/zh_Hans/ --- src/strings/zh-cn.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strings/zh-cn.json b/src/strings/zh-cn.json index ea07eee2d8..691aea562b 100644 --- a/src/strings/zh-cn.json +++ b/src/strings/zh-cn.json @@ -137,7 +137,7 @@ "ChannelNameOnly": "只在频道 {0}", "Channels": "频道", "CinemaModeConfigurationHelp": "影院模式直接为您的客厅带来剧场级体验,同时还可以播放预告片和自定义介绍。", - "Collections": "收藏", + "Collections": "合集", "CommunityRating": "公众评分", "Composer": "作曲家", "ConfirmDeleteImage": "删除图片?", @@ -264,7 +264,7 @@ "HeaderAddUser": "添加用户", "HeaderAdditionalParts": "附加部分", "HeaderAdmin": "管理", - "HeaderAlbumArtists": "专辑艺术家", + "HeaderAlbumArtists": "专辑作家", "HeaderAlbums": "专辑", "HeaderAlert": "警报", "HeaderAllowMediaDeletionFrom": "允许从中删除媒体", @@ -365,7 +365,7 @@ "HeaderMyMediaSmall": "我的媒体 (小)", "HeaderNewApiKey": "新 API 密钥", "HeaderNewDevices": "新设备", - "HeaderNextUp": "下一个", + "HeaderNextUp": "接下来", "HeaderOnNow": "现在", "HeaderOtherItems": "其他项目", "HeaderParentalRatings": "家长分级",