diff --git a/package.json b/package.json index ec1a173f33..8014caa22f 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ "license": "GPL-2.0-or-later", "devDependencies": { "@babel/core": "^7.11.1", - "@babel/eslint-parser": "^7.11.0", - "@babel/eslint-plugin": "^7.11.0", + "@babel/eslint-parser": "^7.11.3", + "@babel/eslint-plugin": "^7.11.3", "@babel/plugin-proposal-class-properties": "^7.10.1", "@babel/plugin-proposal-private-methods": "^7.10.1", "@babel/plugin-transform-modules-amd": "^7.10.5", @@ -113,6 +113,8 @@ "src/components/filterdialog/filterdialog.js", "src/components/focusManager.js", "src/components/groupedcards.js", + "src/components/guide/guide.js", + "src/components/guide/guide-settings.js", "src/components/homeScreenSettings/homeScreenSettings.js", "src/components/homesections/homesections.js", "src/components/htmlMediaHelper.js", @@ -156,12 +158,17 @@ "src/components/playlisteditor/playlisteditor.js", "src/components/playmenu.js", "src/components/prompt/prompt.js", + "src/components/recordingcreator/recordingbutton.js", + "src/components/recordingcreator/recordingcreator.js", "src/components/recordingcreator/seriesrecordingeditor.js", "src/components/recordingcreator/recordinghelper.js", "src/components/refreshdialog/refreshdialog.js", "src/components/qualityOptions.js", + "src/components/remotecontrol/remotecontrol.js", "src/components/sanatizefilename.js", "src/components/scrollManager.js", + "src/plugins/htmlAudioPlayer/plugin.js", + "src/plugins/chromecastPlayer/plugin.js", "src/components/slideshow/slideshow.js", "src/components/sortmenu/sortmenu.js", "src/plugins/htmlVideoPlayer/plugin.js", @@ -179,6 +186,7 @@ "src/components/syncPlay/playbackPermissionManager.js", "src/components/syncPlay/syncPlayManager.js", "src/components/syncPlay/timeSyncManager.js", + "src/components/tabbedview/tabbedview.js", "src/components/viewManager/viewManager.js", "src/components/tvproviders/schedulesdirect.js", "src/components/tvproviders/xmltv.js", @@ -208,7 +216,7 @@ "src/controllers/music/musicplaylists.js", "src/controllers/music/musicrecommended.js", "src/controllers/music/songs.js", - "src/controllers/dashboard/mediaLibrary.js", + "src/controllers/dashboard/library.js", "src/controllers/dashboard/metadataImages.js", "src/controllers/dashboard/metadatanfo.js", "src/controllers/dashboard/networking.js", @@ -229,6 +237,7 @@ "src/controllers/dashboard/users/userparentalcontrol.js", "src/controllers/dashboard/users/userpasswordpage.js", "src/controllers/dashboard/users/userprofilespage.js", + "src/controllers/home.js", "src/controllers/list.js", "src/controllers/edititemmetadata.js", "src/controllers/favorites.js", @@ -244,6 +253,7 @@ "src/controllers/playback/queue/index.js", "src/controllers/playback/video/index.js", "src/controllers/searchpage.js", + "src/controllers/livetv/livetvguide.js", "src/controllers/livetvtuner.js", "src/controllers/livetvstatus.js", "src/controllers/livetvguideprovider.js", @@ -310,11 +320,14 @@ "src/scripts/filesystem.js", "src/scripts/globalize.js", "src/scripts/imagehelper.js", + "src/scripts/itembynamedetailpage.js", "src/scripts/inputManager.js", "src/scripts/autoThemes.js", "src/scripts/themeManager.js", "src/scripts/keyboardNavigation.js", + "src/scripts/libraryMenu.js", "src/scripts/libraryBrowser.js", + "src/scripts/livetvcomponents.js", "src/scripts/mouseManager.js", "src/scripts/multiDownload.js", "src/scripts/playlists.js", diff --git a/src/components/guide/guide-settings.js b/src/components/guide/guide-settings.js index b3133ec272..35f0d3e06e 100644 --- a/src/components/guide/guide-settings.js +++ b/src/components/guide/guide-settings.js @@ -1,150 +1,149 @@ -define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectionManager', 'require', 'loading', 'scrollHelper', 'emby-checkbox', 'emby-radio', 'css!./../formdialog', 'material-icons'], function (dialogHelper, globalize, userSettings, layoutManager, connectionManager, require, loading, scrollHelper) { - 'use strict'; +import dialogHelper from 'dialogHelper'; +import globalize from 'globalize'; +import * as userSettings from 'userSettings'; +import layoutManager from 'layoutManager'; +import scrollHelper from 'scrollHelper'; +import 'emby-checkbox'; +import 'emby-radio'; +import 'css!./../formdialog'; +import 'material-icons'; - layoutManager = layoutManager.default || layoutManager; - scrollHelper = scrollHelper.default || scrollHelper; +function saveCategories(context, options) { + const categories = []; - function saveCategories(context, options) { - var categories = []; + const chkCategorys = context.querySelectorAll('.chkCategory'); + for (const chkCategory of chkCategorys) { + const type = chkCategory.getAttribute('data-type'); - var chkCategorys = context.querySelectorAll('.chkCategory'); - for (var i = 0, length = chkCategorys.length; i < length; i++) { - var type = chkCategorys[i].getAttribute('data-type'); - - if (chkCategorys[i].checked) { - categories.push(type); - } - } - - if (categories.length >= 4) { - categories.push('series'); - } - - // differentiate between none and all - categories.push('all'); - options.categories = categories; - } - - function loadCategories(context, options) { - var selectedCategories = options.categories || []; - - var chkCategorys = context.querySelectorAll('.chkCategory'); - for (var i = 0, length = chkCategorys.length; i < length; i++) { - var type = chkCategorys[i].getAttribute('data-type'); - - chkCategorys[i].checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1; + if (chkCategory.checked) { + categories.push(type); } } - function save(context) { - var i; - var length; + if (categories.length >= 4) { + categories.push('series'); + } - var chkIndicators = context.querySelectorAll('.chkIndicator'); - for (i = 0, length = chkIndicators.length; i < length; i++) { - var type = chkIndicators[i].getAttribute('data-type'); - userSettings.set('guide-indicator-' + type, chkIndicators[i].checked); + // differentiate between none and all + categories.push('all'); + options.categories = categories; +} + +function loadCategories(context, options) { + const selectedCategories = options.categories || []; + + const chkCategorys = context.querySelectorAll('.chkCategory'); + for (const chkCategory of chkCategorys) { + const type = chkCategory.getAttribute('data-type'); + + chkCategory.checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1; + } +} + +function save(context) { + const chkIndicators = context.querySelectorAll('.chkIndicator'); + + for (const chkIndicator of chkIndicators) { + const type = chkIndicator.getAttribute('data-type'); + userSettings.set('guide-indicator-' + type, chkIndicator.checked); + } + + userSettings.set('guide-colorcodedbackgrounds', context.querySelector('.chkColorCodedBackgrounds').checked); + userSettings.set('livetv-favoritechannelsattop', context.querySelector('.chkFavoriteChannelsAtTop').checked); + + const sortBys = context.querySelectorAll('.chkSortOrder'); + for (const sortBy of sortBys) { + if (sortBy.checked) { + userSettings.set('livetv-channelorder', sortBy.value); + break; } + } +} - userSettings.set('guide-colorcodedbackgrounds', context.querySelector('.chkColorCodedBackgrounds').checked); - userSettings.set('livetv-favoritechannelsattop', context.querySelector('.chkFavoriteChannelsAtTop').checked); +function load(context) { + const chkIndicators = context.querySelectorAll('.chkIndicator'); - var sortBys = context.querySelectorAll('.chkSortOrder'); - for (i = 0, length = sortBys.length; i < length; i++) { - if (sortBys[i].checked) { - userSettings.set('livetv-channelorder', sortBys[i].value); - break; - } + for (const chkIndicator of chkIndicators) { + const type = chkIndicator.getAttribute('data-type'); + + if (chkIndicator.getAttribute('data-default') === 'true') { + chkIndicator.checked = userSettings.get('guide-indicator-' + type) !== 'false'; + } else { + chkIndicator.checked = userSettings.get('guide-indicator-' + type) === 'true'; } } - function load(context) { - var i; - var length; + context.querySelector('.chkColorCodedBackgrounds').checked = userSettings.get('guide-colorcodedbackgrounds') === 'true'; + context.querySelector('.chkFavoriteChannelsAtTop').checked = userSettings.get('livetv-favoritechannelsattop') !== 'false'; - var chkIndicators = context.querySelectorAll('.chkIndicator'); - for (i = 0, length = chkIndicators.length; i < length; i++) { - var type = chkIndicators[i].getAttribute('data-type'); + const sortByValue = userSettings.get('livetv-channelorder') || 'Number'; - if (chkIndicators[i].getAttribute('data-default') === 'true') { - chkIndicators[i].checked = userSettings.get('guide-indicator-' + type) !== 'false'; + const sortBys = context.querySelectorAll('.chkSortOrder'); + for (const sortBy of sortBys) { + sortBy.checked = sortBy.value === sortByValue; + } +} + +function showEditor(options) { + return new Promise(function (resolve, reject) { + let settingsChanged = false; + + import('text!./guide-settings.template.html').then(({ default: template }) => { + const dialogOptions = { + removeOnClose: true, + scrollY: false + }; + + if (layoutManager.tv) { + dialogOptions.size = 'fullscreen'; } else { - chkIndicators[i].checked = userSettings.get('guide-indicator-' + type) === 'true'; + dialogOptions.size = 'small'; } - } - context.querySelector('.chkColorCodedBackgrounds').checked = userSettings.get('guide-colorcodedbackgrounds') === 'true'; - context.querySelector('.chkFavoriteChannelsAtTop').checked = userSettings.get('livetv-favoritechannelsattop') !== 'false'; + const dlg = dialogHelper.createDialog(dialogOptions); - var sortByValue = userSettings.get('livetv-channelorder') || 'Number'; + dlg.classList.add('formDialog'); - var sortBys = context.querySelectorAll('.chkSortOrder'); - for (i = 0, length = sortBys.length; i < length; i++) { - sortBys[i].checked = sortBys[i].value === sortByValue; - } - } + let html = ''; - function showEditor(options) { - return new Promise(function (resolve, reject) { - var settingsChanged = false; + html += globalize.translateHtml(template, 'core'); - require(['text!./guide-settings.template.html'], function (template) { - var dialogOptions = { - removeOnClose: true, - scrollY: false - }; + dlg.innerHTML = html; - if (layoutManager.tv) { - dialogOptions.size = 'fullscreen'; - } else { - dialogOptions.size = 'small'; - } - - var dlg = dialogHelper.createDialog(dialogOptions); - - dlg.classList.add('formDialog'); - - var html = ''; - - html += globalize.translateHtml(template, 'core'); - - dlg.innerHTML = html; - - dlg.addEventListener('change', function () { - settingsChanged = true; - }); - - dlg.addEventListener('close', function () { - if (layoutManager.tv) { - scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false); - } - - save(dlg); - saveCategories(dlg, options); - - if (settingsChanged) { - resolve(); - } else { - reject(); - } - }); - - dlg.querySelector('.btnCancel').addEventListener('click', function () { - dialogHelper.close(dlg); - }); - - if (layoutManager.tv) { - scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false); - } - - load(dlg); - loadCategories(dlg, options); - dialogHelper.open(dlg); + dlg.addEventListener('change', function () { + settingsChanged = true; }); - }); - } - return { - show: showEditor - }; -}); + dlg.addEventListener('close', function () { + if (layoutManager.tv) { + scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false); + } + + save(dlg); + saveCategories(dlg, options); + + if (settingsChanged) { + resolve(); + } else { + reject(); + } + }); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + dialogHelper.close(dlg); + }); + + if (layoutManager.tv) { + scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false); + } + + load(dlg); + loadCategories(dlg, options); + dialogHelper.open(dlg); + }); + }); +} + +export default { + show: showEditor +}; diff --git a/src/components/guide/guide.js b/src/components/guide/guide.js index c8fd8021e3..a7b32d887d 100644 --- a/src/components/guide/guide.js +++ b/src/components/guide/guide.js @@ -1,1182 +1,1198 @@ -define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', 'scrollHelper', 'serverNotifications', 'loading', 'datetime', 'focusManager', 'playbackManager', 'userSettings', 'imageLoader', 'events', 'layoutManager', 'itemShortcuts', 'dom', 'css!./guide.css', 'programStyles', 'material-icons', 'scrollStyles', 'emby-programcell', 'emby-button', 'paper-icon-button-light', 'emby-tabs', 'emby-scroller', 'flexStyles', 'webcomponents'], function (require, inputManager, browser, globalize, connectionManager, scrollHelper, serverNotifications, loading, datetime, focusManager, playbackManager, userSettings, imageLoader, events, layoutManager, itemShortcuts, dom) { - 'use strict'; +import inputManager from 'inputManager'; +import browser from 'browser'; +import globalize from 'globalize'; +import connectionManager from 'connectionManager'; +import scrollHelper from 'scrollHelper'; +import serverNotifications from 'serverNotifications'; +import loading from 'loading'; +import datetime from 'datetime'; +import focusManager from 'focusManager'; +import playbackManager from 'playbackManager'; +import * as userSettings from 'userSettings'; +import imageLoader from 'imageLoader'; +import events from 'events'; +import layoutManager from 'layoutManager'; +import itemShortcuts from 'itemShortcuts'; +import dom from 'dom'; +import 'css!./guide.css'; +import 'programStyles'; +import 'material-icons'; +import 'scrollStyles'; +import 'emby-programcell'; +import 'emby-button'; +import 'paper-icon-button-light'; +import 'emby-tabs'; +import 'emby-scroller'; +import 'flexStyles'; +import 'webcomponents'; - playbackManager = playbackManager.default || playbackManager; - browser = browser.default || browser; - loading = loading.default || loading; - layoutManager = layoutManager.default || layoutManager; - focusManager = focusManager.default || focusManager; - scrollHelper = scrollHelper.default || scrollHelper; - serverNotifications = serverNotifications.default || serverNotifications; - - function showViewSettings(instance) { - require(['guide-settings-dialog'], function (guideSettingsDialog) { - guideSettingsDialog.show(instance.categoryOptions).then(function () { - instance.refresh(); - }); +function showViewSettings(instance) { + import('guide-settings-dialog').then(({default: guideSettingsDialog}) => { + guideSettingsDialog.show(instance.categoryOptions).then(function () { + instance.refresh(); }); + }); +} + +function updateProgramCellOnScroll(cell, scrollPct) { + let left = cell.posLeft; + if (!left) { + left = parseFloat(cell.style.left.replace('%', '')); + cell.posLeft = left; + } + let width = cell.posWidth; + if (!width) { + width = parseFloat(cell.style.width.replace('%', '')); + cell.posWidth = width; } - function updateProgramCellOnScroll(cell, scrollPct) { - var left = cell.posLeft; - if (!left) { - left = parseFloat(cell.style.left.replace('%', '')); - cell.posLeft = left; - } - var width = cell.posWidth; - if (!width) { - width = parseFloat(cell.style.width.replace('%', '')); - cell.posWidth = width; - } + const right = left + width; + const newPct = Math.max(Math.min(scrollPct, right), left); - var right = left + width; - var newPct = Math.max(Math.min(scrollPct, right), left); + const offset = newPct - left; + const pctOfWidth = (offset / width) * 100; - var offset = newPct - left; - var pctOfWidth = (offset / width) * 100; - - var guideProgramName = cell.guideProgramName; - if (!guideProgramName) { - guideProgramName = cell.querySelector('.guideProgramName'); - cell.guideProgramName = guideProgramName; - } - - var caret = cell.caret; - if (!caret) { - caret = cell.querySelector('.guide-programNameCaret'); - cell.caret = caret; - } - - if (guideProgramName) { - if (pctOfWidth > 0 && pctOfWidth <= 100) { - guideProgramName.style.transform = 'translateX(' + pctOfWidth + '%)'; - caret.classList.remove('hide'); - } else { - guideProgramName.style.transform = 'none'; - caret.classList.add('hide'); - } - } + let guideProgramName = cell.guideProgramName; + if (!guideProgramName) { + guideProgramName = cell.querySelector('.guideProgramName'); + cell.guideProgramName = guideProgramName; } - var isUpdatingProgramCellScroll = false; - function updateProgramCellsOnScroll(programGrid, programCells) { - if (isUpdatingProgramCellScroll) { - return; - } - - isUpdatingProgramCellScroll = true; - - requestAnimationFrame(function () { - var scrollLeft = programGrid.scrollLeft; - - var scrollPct = scrollLeft ? (scrollLeft / programGrid.scrollWidth) * 100 : 0; - - for (var i = 0, length = programCells.length; i < length; i++) { - updateProgramCellOnScroll(programCells[i], scrollPct); - } - - isUpdatingProgramCellScroll = false; - }); + let caret = cell.caret; + if (!caret) { + caret = cell.querySelector('.guide-programNameCaret'); + cell.caret = caret; } - function onProgramGridClick(e) { - if (!layoutManager.tv) { - return; - } - - var programCell = dom.parentWithClass(e.target, 'programCell'); - if (programCell) { - var startDate = programCell.getAttribute('data-startdate'); - var endDate = programCell.getAttribute('data-enddate'); - startDate = datetime.parseISO8601Date(startDate, { toLocal: true }).getTime(); - endDate = datetime.parseISO8601Date(endDate, { toLocal: true }).getTime(); - - var now = new Date().getTime(); - if (now >= startDate && now < endDate) { - var channelId = programCell.getAttribute('data-channelid'); - var serverId = programCell.getAttribute('data-serverid'); - - e.preventDefault(); - e.stopPropagation(); - - playbackManager.play({ - ids: [channelId], - serverId: serverId - }); - } + if (guideProgramName) { + if (pctOfWidth > 0 && pctOfWidth <= 100) { + guideProgramName.style.transform = 'translateX(' + pctOfWidth + '%)'; + caret.classList.remove('hide'); + } else { + guideProgramName.style.transform = 'none'; + caret.classList.add('hide'); } } +} - function Guide(options) { - var self = this; - var items = {}; +let isUpdatingProgramCellScroll = false; +function updateProgramCellsOnScroll(programGrid, programCells) { + if (isUpdatingProgramCellScroll) { + return; + } - self.options = options; - self.categoryOptions = { categories: [] }; + isUpdatingProgramCellScroll = true; - // 30 mins - var cellCurationMinutes = 30; - var cellDurationMs = cellCurationMinutes * 60 * 1000; - var msPerDay = 86400000; + requestAnimationFrame(function () { + const scrollLeft = programGrid.scrollLeft; - var currentDate; - var currentStartIndex = 0; - var currentChannelLimit = 0; - var autoRefreshInterval; - var programCells; - var lastFocusDirection; - var programGrid; + const scrollPct = scrollLeft ? (scrollLeft / programGrid.scrollWidth) * 100 : 0; - self.refresh = function () { - currentDate = null; - reloadPage(options.element); - restartAutoRefresh(); - }; - - self.pause = function () { - stopAutoRefresh(); - }; - - self.resume = function (refreshData) { - if (refreshData) { - self.refresh(); - } else { - restartAutoRefresh(); - } - }; - - self.destroy = function () { - stopAutoRefresh(); - - events.off(serverNotifications, 'TimerCreated', onTimerCreated); - events.off(serverNotifications, 'SeriesTimerCreated', onSeriesTimerCreated); - events.off(serverNotifications, 'TimerCancelled', onTimerCancelled); - events.off(serverNotifications, 'SeriesTimerCancelled', onSeriesTimerCancelled); - - setScrollEvents(options.element, false); - itemShortcuts.off(options.element); - items = {}; - }; - - function restartAutoRefresh() { - stopAutoRefresh(); - - var intervalMs = 60000 * 15; // (minutes) - - autoRefreshInterval = setInterval(function () { - self.refresh(); - }, intervalMs); + for (const programCell of programCells) { + updateProgramCellOnScroll(programCell, scrollPct); } - function stopAutoRefresh() { - if (autoRefreshInterval) { - clearInterval(autoRefreshInterval); - autoRefreshInterval = null; - } - } - - function normalizeDateToTimeslot(date) { - var minutesOffset = date.getMinutes() - cellCurationMinutes; - - if (minutesOffset >= 0) { - date.setHours(date.getHours(), cellCurationMinutes, 0, 0); - } else { - date.setHours(date.getHours(), 0, 0, 0); - } - - return date; - } - - function showLoading() { - loading.show(); - } - - function hideLoading() { - loading.hide(); - } - - function reloadGuide(context, newStartDate, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) { - var apiClient = connectionManager.getApiClient(options.serverId); - - var channelQuery = { - - StartIndex: 0, - EnableFavoriteSorting: userSettings.get('livetv-favoritechannelsattop') !== 'false' - }; - - channelQuery.UserId = apiClient.getCurrentUserId(); - - var channelLimit = 500; - currentChannelLimit = channelLimit; - - showLoading(); - - channelQuery.StartIndex = currentStartIndex; - channelQuery.Limit = channelLimit; - channelQuery.AddCurrentProgram = false; - channelQuery.EnableUserData = false; - channelQuery.EnableImageTypes = 'Primary'; - - var categories = self.categoryOptions.categories || []; - var displayMovieContent = !categories.length || categories.indexOf('movies') !== -1; - var displaySportsContent = !categories.length || categories.indexOf('sports') !== -1; - var displayNewsContent = !categories.length || categories.indexOf('news') !== -1; - var displayKidsContent = !categories.length || categories.indexOf('kids') !== -1; - var displaySeriesContent = !categories.length || categories.indexOf('series') !== -1; - - if (displayMovieContent && displaySportsContent && displayNewsContent && displayKidsContent) { - channelQuery.IsMovie = null; - channelQuery.IsSports = null; - channelQuery.IsKids = null; - channelQuery.IsNews = null; - channelQuery.IsSeries = null; - } else { - if (displayNewsContent) { - channelQuery.IsNews = true; - } - if (displaySportsContent) { - channelQuery.IsSports = true; - } - if (displayKidsContent) { - channelQuery.IsKids = true; - } - if (displayMovieContent) { - channelQuery.IsMovie = true; - } - if (displaySeriesContent) { - channelQuery.IsSeries = true; - } - } - - if (userSettings.get('livetv-channelorder') === 'DatePlayed') { - channelQuery.SortBy = 'DatePlayed'; - channelQuery.SortOrder = 'Descending'; - } else { - channelQuery.SortBy = null; - channelQuery.SortOrder = null; - } - - var date = newStartDate; - // Add one second to avoid getting programs that are just ending - date = new Date(date.getTime() + 1000); - - // Subtract to avoid getting programs that are starting when the grid ends - var nextDay = new Date(date.getTime() + msPerDay - 2000); - - // Normally we'd want to just let responsive css handle this, - // but since mobile browsers are often underpowered, - // it can help performance to get them out of the markup - var allowIndicators = dom.getWindowSize().innerWidth >= 600; - - var renderOptions = { - showHdIcon: allowIndicators && userSettings.get('guide-indicator-hd') === 'true', - showLiveIndicator: allowIndicators && userSettings.get('guide-indicator-live') !== 'false', - showPremiereIndicator: allowIndicators && userSettings.get('guide-indicator-premiere') !== 'false', - showNewIndicator: allowIndicators && userSettings.get('guide-indicator-new') !== 'false', - showRepeatIndicator: allowIndicators && userSettings.get('guide-indicator-repeat') === 'true', - showEpisodeTitle: layoutManager.tv ? false : true - }; - - apiClient.getLiveTvChannels(channelQuery).then(function (channelsResult) { - var btnPreviousPage = context.querySelector('.btnPreviousPage'); - var btnNextPage = context.querySelector('.btnNextPage'); - - if (channelsResult.TotalRecordCount > channelLimit) { - context.querySelector('.guideOptions').classList.remove('hide'); - - btnPreviousPage.classList.remove('hide'); - btnNextPage.classList.remove('hide'); - - if (channelQuery.StartIndex) { - context.querySelector('.btnPreviousPage').disabled = false; - } else { - context.querySelector('.btnPreviousPage').disabled = true; - } - - if ((channelQuery.StartIndex + channelLimit) < channelsResult.TotalRecordCount) { - btnNextPage.disabled = false; - } else { - btnNextPage.disabled = true; - } - } else { - context.querySelector('.guideOptions').classList.add('hide'); - } - - var programFields = []; - - var programQuery = { - UserId: apiClient.getCurrentUserId(), - MaxStartDate: nextDay.toISOString(), - MinEndDate: date.toISOString(), - channelIds: channelsResult.Items.map(function (c) { - return c.Id; - }).join(','), - ImageTypeLimit: 1, - EnableImages: false, - //EnableImageTypes: layoutManager.tv ? "Primary,Backdrop" : "Primary", - SortBy: 'StartDate', - EnableTotalRecordCount: false, - EnableUserData: false - }; - - if (renderOptions.showHdIcon) { - programFields.push('IsHD'); - } - - if (programFields.length) { - programQuery.Fields = programFields.join(''); - } - - apiClient.getLiveTvPrograms(programQuery).then(function (programsResult) { - renderGuide(context, date, channelsResult.Items, programsResult.Items, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender); - - hideLoading(); - }); - }); - } - - function getDisplayTime(date) { - if ((typeof date).toString().toLowerCase() === 'string') { - try { - date = datetime.parseISO8601Date(date, { toLocal: true }); - } catch (err) { - return date; - } - } - - return datetime.getDisplayTime(date).toLowerCase(); - } - - function getTimeslotHeadersHtml(startDate, endDateTime) { - var html = ''; - - // clone - startDate = new Date(startDate.getTime()); - - html += '
http://priklad.sk/<vlastnyretazec>
",
+ "LabelBaseUrlHelp": "Pridá vlastný reťazec na URL adresu serveru, napr: http://priklad.sk/<vlastny-retazec>
",
"LabelBaseUrl": "Východzia URL:",
"LabelEveryXMinutes": "Každý:",
"LabelEnableSingleImageInDidlLimitHelp": "Niektoré zariadenia nebudú zobrazovať správne pokiaľ je viacero obrázkov uložených v Didl.",
@@ -1410,11 +1410,11 @@
"LabelEnableDlnaDebugLoggingHelp": "Vytvára veľké súbory s logami a mal by sa použiť len v prípade potreby odstraňovania problémov.",
"LabelEnableDlnaDebugLogging": "Povoliť loggovanie DLNA debugu",
"LabelEnableDlnaClientDiscoveryIntervalHelp": "Určuje dobu trvania v sekundách medzi SSDP vyhľadávaniami vykonanými Jellyfinom.",
- "LabelEnableDlnaClientDiscoveryInterval": "Interval pre objavenie klienta (sekundy)",
+ "LabelEnableDlnaClientDiscoveryInterval": "Interval pre objavenie klienta",
"LabelEnableAutomaticPortMapHelp": "Automatické namapovanie vejerného portu na lokálny port serveru cez UPnP. Toto nemusí fungovať so všetkými modelmi routerov alebo sieťových konfigurácií. Zmeny sa vykonajú až po reštarte servera.",
"LabelEmbedAlbumArtDidlHelp": "Niektoré zariadenia preferujú túto metódu pre získavanie obrázku albumu. Ostatným môže zlyhať prehrávanie pokiaľ je táto možnosť povolená.",
"LabelBlastMessageIntervalHelp": "Určuje dobu v sekundách medzi vysielaniami správ o serveri.",
- "LabelBindToLocalNetworkAddressHelp": "Voliteľné. Prepísať lokálnu IP adresu viazanú na http server. Pokiaľ zostane prázdna, server sa naviaže na všetky dostupné adresy. Pri zmene tejto hodnoty sa vyžaduje reštart Jellyfin Servera.",
+ "LabelBindToLocalNetworkAddressHelp": "Prepísať lokálnu IP adresu http serveru. Pokiaľ zostane prázdna, server sa naviaže na všetky dostupné adresy. Pri zmene tejto hodnoty sa vyžaduje reštart Jellyfin Servera.",
"LabelAlbumArtPN": "Obrázok albumu PN:",
"LabelAlbumArtMaxWidthHelp": "Maximálne rozlíšenie obrázku albumu prostredníctvom upnp:albumArtURI.",
"LabelAlbumArtMaxHeightHelp": "Maximálne rozlíšenie obrázku albumu prostredníctvom upnp:albumArtURI.",
@@ -1477,7 +1477,7 @@
"TabDVR": "DVR",
"LabelRequireHttpsHelp": "Pokiaľ je zaškrtnutý, server bude automaticky presmerovávať všetky HTTP požiadavky cez HTTPS. Toto nastavenie nemá žiadny efekt, pokiaľ server nepočúva na HTTPS.",
"LabelRequireHttps": "Vyžadovať HTTPS",
- "LabelEnableHttpsHelp": "Umožní serveru počúvať na nastavenom HTTPS porte. K správnemu fungovaniu je nutné nakonfigurovať aj platný certifikát.",
+ "LabelEnableHttpsHelp": "Počúvanie na nastavenom HTTPS porte. K správnemu fungovaniu je nutné nakonfigurovať aj platný certifikát.",
"LabelEnableHttps": "Povoliť HTTPS",
"HeaderServerAddressSettings": "Nastavenie adresy servera",
"HeaderRemoteAccessSettings": "Nastavenie vzdialeného prístupu",
@@ -1539,5 +1539,13 @@
"Writers": "Scenáristi",
"ClearQueue": "Vymazať frontu",
"StopPlayback": "Zastaviť prehrávanie",
- "ViewAlbumArtist": "Zobraziť interpreta albumu"
+ "ViewAlbumArtist": "Zobraziť interpreta albumu",
+ "Preview": "Náhľad",
+ "SubtitleVerticalPositionHelp": "Číslo riadku, na ktorom sa zobrazí text. Kladné čísla znamenajú smer zhora dole. Záporné čísla zdola hore.",
+ "LabelSubtitleVerticalPosition": "Vertikálne umiestnenie:",
+ "PreviousTrack": "Predchádzajúca",
+ "MessageGetInstalledPluginsError": "Pri načítaní zoznamu nainštalovaných zásuvných modulov došlo k chybe.",
+ "MessagePluginInstallError": "Pri inštalácií zásuvného modulu došlo k chybe.",
+ "NextTrack": "Ďalšia",
+ "LabelUnstable": "Nestabilný"
}
diff --git a/src/strings/zh-cn.json b/src/strings/zh-cn.json
index 553445404a..eed9f95599 100644
--- a/src/strings/zh-cn.json
+++ b/src/strings/zh-cn.json
@@ -159,7 +159,7 @@
"DetectingDevices": "正在侦测设备",
"DeviceAccessHelp": "这仅适用于可以唯一标识的设备,而不会阻止浏览器访问。限制用户设备访问会阻止使用未在此被批准的新增设备。",
"DirectPlaying": "直接播放",
- "DirectStreamHelp2": "直接串流只占用占用很少的CPU并且视频的品质不会有任何损失。",
+ "DirectStreamHelp2": "直接串流只占用占用很少的CPU并且视频的品质只会有极小程度的损失。",
"DirectStreaming": "直接串流",
"Director": "导演",
"Disabled": "已禁用",
@@ -261,7 +261,7 @@
"HeaderAllowMediaDeletionFrom": "允许从中删除媒体",
"HeaderApiKey": "API 密钥",
"HeaderApiKeys": "API 密钥",
- "HeaderApiKeysHelp": "外部应用程序需要 API 密钥才能与 Jellyfin Server 进行通信。使用 Jellyfin 账户进行登录时密钥将会自动生成,您也可以手动为某个应用程序分配一个密钥。",
+ "HeaderApiKeysHelp": "外部应用程序需要 API 密钥才能与服务器进行通信。密钥会在使用普通账户登录时自动生成,或是手动为应用分配。",
"HeaderAudioBooks": "有声读物",
"HeaderAudioSettings": "声音设置",
"HeaderBlockItemsWithNoRating": "通过没有评级和设置不允许的评级锁定内容:",
@@ -327,7 +327,7 @@
"HeaderInstall": "安装",
"HeaderInstantMix": "速成合辑",
"HeaderItems": "项目",
- "HeaderKodiMetadataHelp": "要启用或禁用 NFO 元数据, 请在 Jellyfin 库安装程序中编辑库, 然后找到“元数据储户”部分。",
+ "HeaderKodiMetadataHelp": "要启用或禁用 NFO 元数据, 请编辑库, 然后找到“元数据储户”部分。",
"HeaderLatestEpisodes": "最新剧集",
"HeaderLatestMedia": "最新媒体",
"HeaderLatestMovies": "最新电影",
@@ -372,7 +372,7 @@
"HeaderPreferredMetadataLanguage": "首选元数据语言",
"HeaderProfile": "配置",
"HeaderProfileInformation": "配置信息",
- "HeaderProfileServerSettingsHelp": "这些参数将控制 Jellyfin 媒体服务器如何呈现给设备。",
+ "HeaderProfileServerSettingsHelp": "这些参数将控制服务器如何将自己呈现给客户端。",
"HeaderRecentlyPlayed": "最近播放",
"HeaderRecordingOptions": "录制选项",
"HeaderRecordingPostProcessing": "记录后处理",
@@ -396,7 +396,7 @@
"HeaderSelectServerCachePath": "选择服务器缓存路径",
"HeaderSelectServerCachePathHelp": "浏览或输入一个路径用于服务器缓存文件,此文件夹必须可写。",
"HeaderSelectTranscodingPath": "选择临时解码路径",
- "HeaderSelectTranscodingPathHelp": "浏览或输入一个路径用于临时转码,此文件夹必须可写。",
+ "HeaderSelectTranscodingPathHelp": "浏览或输入一个路径用于转码文件,此文件夹必须可写。",
"HeaderSendMessage": "发送消息",
"HeaderSeries": "电视剧",
"HeaderSeriesOptions": "系列选项",
@@ -445,8 +445,8 @@
"HttpsRequiresCert": "要启用安全连接, 您需要提供一个受信任的 SSL 证书, 例如 Let's Encrypt 。请提供证书或禁用安全连接。",
"Identify": "识别",
"Images": "图片",
- "ImportFavoriteChannelsHelp": "如果启用,只有在协调器设备中被标记为我的最爱的频道才会被导入。",
- "ImportMissingEpisodesHelp": "如果启用,会将缺少的剧集信息导入到你的 Jellyfin 数据库并分季分剧显示。可能会大大延长媒体库扫描时间。",
+ "ImportFavoriteChannelsHelp": "只有在协调器设备中被标记为我的最爱的频道才会被导入。",
+ "ImportMissingEpisodesHelp": "缺少的剧集信息将被导入到你的数据库并分季分剧显示。可能会大大延长媒体库扫描时间。",
"InstallingPackage": "正在安装 {0}(版本 {1})",
"InstantMix": "即时混音",
"ItemCount": "{0} 项",
@@ -476,14 +476,14 @@
"LabelAppName": "APP名称",
"LabelAppNameExample": "例如:Sickbeard, Sonarr",
"LabelArtists": "艺术家:",
- "LabelArtistsHelp": "独立多功能 ;",
+ "LabelArtistsHelp": "将多个艺术家用分号分隔",
"LabelAudioLanguagePreference": "首选音频语言:",
"LabelAutomaticallyRefreshInternetMetadataEvery": "自动从互联网获取元数据并刷新:",
"LabelBindToLocalNetworkAddress": "监听的本地网络地址:",
- "LabelBindToLocalNetworkAddressHelp": "(可选的)覆盖 HTTP 服务器绑定的本地 IP 地址。如果留空,服务器将会监听所有可用的地址。改变这个值需要重启 Jellyfin 服务器。",
+ "LabelBindToLocalNetworkAddressHelp": "覆盖 HTTP 服务器绑定的本地 IP 地址。如果留空,服务器将会监听所有可用的地址。改变这个值需要重启 Jellyfin 服务器。",
"LabelBirthDate": "出生日期:",
"LabelBirthYear": "出生年份:",
- "LabelBlastMessageInterval": "活动信号的时间间隔(秒)",
+ "LabelBlastMessageInterval": "活动信号的时间间隔",
"LabelBlastMessageIntervalHelp": "确定爆炸活动消息之间的持续时间(以秒为单位)。",
"LabelBlockContentWithTags": "通过标签锁定内容:",
"LabelBurnSubtitles": "烧录字幕:",
@@ -541,7 +541,7 @@
"LabelEnableAutomaticPortMapHelp": "通过UPnP将路由器端口自动转发到服务器端口。这可能不适用于某些型号的路由器和网络配置。需要服务器重新启动后才会应用更改。",
"LabelEnableBlastAliveMessages": "爆发活动信号",
"LabelEnableBlastAliveMessagesHelp": "如果该服务器不能被网络中的其他UPnP设备检测到,请启用此选项。",
- "LabelEnableDlnaClientDiscoveryInterval": "客户端搜寻时间间隔(秒)",
+ "LabelEnableDlnaClientDiscoveryInterval": "客户端搜寻时间间隔",
"LabelEnableDlnaClientDiscoveryIntervalHelp": "确定由 Jellyfin 执行的 SSDP 搜索之间的持续时间 (以秒为单位)。",
"LabelEnableDlnaDebugLogging": "启用 DLNA 调试日志",
"LabelEnableDlnaDebugLoggingHelp": "创建一个很大的日志文件,仅应在排除故障时使用。",
@@ -567,9 +567,9 @@
"LabelForgotPasswordUsernameHelp": "输入你的用户名,如果你还记得。",
"LabelFormat": "格式:",
"LabelFriendlyName": "好记的名称:",
- "LabelServerNameHelp": "此名称将用做服务器名,如果留空,将使用计算机名。",
+ "LabelServerNameHelp": "此名称将用做服务器名,默认使用服务器的主机名。",
"LabelGroupMoviesIntoCollections": "批量添加电影到收藏",
- "LabelGroupMoviesIntoCollectionsHelp": "显示电影列表时,属于一个收藏的电影将显示为一个分组。",
+ "LabelGroupMoviesIntoCollectionsHelp": "显示电影列表时,同一收藏的电影将显示为一个分组。",
"LabelH264Crf": "H264 CRF 编码质量等级:",
"LabelEncoderPreset": "H264 和 H265 编码预设:",
"LabelHardwareAccelerationType": "硬件加速:",
@@ -577,7 +577,7 @@
"LabelHomeNetworkQuality": "家庭网络质量:",
"LabelHomeScreenSectionValue": "主屏幕模块{0}:",
"LabelHttpsPort": "本地 HTTPS 端口号:",
- "LabelHttpsPortHelp": "Jellyfin HTTPS 服务器监听端口。",
+ "LabelHttpsPortHelp": "HTTPS 服务器监听的 TCP 端口号。",
"LabelIconMaxHeight": "图标最大高度:",
"LabelIconMaxHeightHelp": "通过UPnP显示的图标最大分辨率。",
"LabelIconMaxWidth": "图标最大宽度:",
@@ -604,7 +604,7 @@
"LabelLanguage": "语言:",
"LabelLineup": "排队:",
"LabelLocalHttpServerPortNumber": "本地 HTTP 端口号:",
- "LabelLocalHttpServerPortNumberHelp": "Jellyfin HTTP 服务器监听的 TCP 端口。",
+ "LabelLocalHttpServerPortNumberHelp": "HTTP 服务器监听的 TCP 端口号。",
"LabelLockItemToPreventChanges": "锁定此项目防止改动",
"LabelLoginDisclaimer": "登录声明:",
"LabelLoginDisclaimerHelp": "将在登录页面底部显示的信息。",
@@ -646,9 +646,9 @@
"LabelMovieCategories": "电影分类:",
"LabelMoviePrefix": "电影前缀:",
"LabelMoviePrefixHelp": "如果将前缀应用于影片标题, 请在此处输入它, 以便服务器可以正确处理它。",
- "LabelMovieRecordingPath": "电影录制路径 (可选的):",
+ "LabelMovieRecordingPath": "电影录制路径:",
"LabelMusicStreamingTranscodingBitrate": "音乐转码的比特率:",
- "LabelMusicStreamingTranscodingBitrateHelp": "请指定一个音乐媒体串流时的最大比特率。",
+ "LabelMusicStreamingTranscodingBitrateHelp": "请指定音乐媒体串流时的最大比特率。",
"LabelName": "名字:",
"LabelNewName": "新名字:",
"LabelNewPassword": "新密码:",
@@ -659,7 +659,7 @@
"LabelNumber": "编号:",
"LabelNumberOfGuideDays": "下载几天的节目指南:",
"LabelNumberOfGuideDaysHelp": "下载更多天的节目指南可以帮你进一步查看节目列表并做出提前安排,但下载过程也将耗时更久。它将基于频道数量自动选择。",
- "LabelOptionalNetworkPath": "(可选的)共享的网络文件夹:",
+ "LabelOptionalNetworkPath": "共享的网络文件夹:",
"LabelOptionalNetworkPathHelp": "如果这个文件夹在你的网络上是共享的,提供这个网络共享地址能够允许其他设备上的 Jellyfin 应用程序直接访问媒体文件,例如 {0} 或者 {1}。",
"LabelOriginalAspectRatio": "原始长宽比:",
"LabelOriginalTitle": "原标题:",
@@ -704,7 +704,7 @@
"LabelReleaseDate": "发行日期:",
"LabelRemoteClientBitrateLimit": "互联网流媒体传输比特率限制(Mbps):",
"LabelRemoteClientBitrateLimitHelp": "所有网络设备都有一个可选的每流比特率限制。这对于防止设备请求比 internet 连接所能处理的更高的比特率非常有用。这可能会导致服务器上的 CPU 负载增加, 以便将视频转码到较低的比特率。",
- "LabelRuntimeMinutes": "播放时长(分钟):",
+ "LabelRuntimeMinutes": "播放时长:",
"LabelSaveLocalMetadata": "将媒体图像保存到媒体所在文件夹",
"LabelSaveLocalMetadataHelp": "直接将媒体图像保存到媒体所在文件夹以方便编辑。",
"LabelScheduledTaskLastRan": "最后运行 {0}, 花费时间 {1}.",
@@ -714,7 +714,7 @@
"LabelSelectVersionToInstall": "选择安装版本:",
"LabelSendNotificationToUsers": "发送通知至:",
"LabelSerialNumber": "序列号",
- "LabelSeriesRecordingPath": "电视剧录制路径 (可选的):",
+ "LabelSeriesRecordingPath": "电视剧录制路径:",
"LabelServerHost": "主机:",
"LabelServerHostHelp": "192.168.1.100:8096 或 https://myserver.com",
"LabelSimultaneousConnectionLimit": "并发流限制:",
@@ -786,7 +786,7 @@
"LabelYoureDone": "完成!",
"LabelZipCode": "邮编:",
"LabelffmpegPath": "FFmpeg 路径:",
- "LabelffmpegPathHelp": "FFmpeg 应用程序的文件,或者包含了 FFmpeg 的文件夹的路径。",
+ "LabelffmpegPathHelp": "FFmpeg 应用文件或包含 FFmpeg 的文件夹的路径。",
"LanNetworksHelp": "在强制带宽限制时,认作本地网络上的 IP 地址或 IP/网络掩码条目的逗号分隔列表。如果设置此项,所有其它 IP 地址将被视为在外部网络上,并且将受到外部带宽限制。如果保留为空,则只将服务器的子网视为本地网络。",
"Large": "大",
"LatestFromLibrary": "最新的{0}",
@@ -918,7 +918,7 @@
"OptionAllowLinkSharingHelp": "只有网页包含的媒体信息会被共享。媒体文件不会被公开共享。共享是有时间限制的并且会在 {0} 天后到期。",
"OptionAllowManageLiveTv": "允许电视直播录制管理",
"OptionAllowMediaPlayback": "允许播放媒体",
- "OptionAllowMediaPlaybackTranscodingHelp": "由于不支持的媒体格式, 限制对代码转换的访问可能会导致 Jellyfin 应用程序中的播放失败。",
+ "OptionAllowMediaPlaybackTranscodingHelp": "限制对转码的访问可能会由于不支持的媒体格式导致客户端中播放失败。",
"OptionAllowRemoteControlOthers": "允许其他用户全程控制",
"OptionAllowRemoteSharedDevices": "允许远程控制共享的设备",
"OptionAllowRemoteSharedDevicesHelp": "DLNA 设备在用户对他们进行控制前都被视为是共享的。",
@@ -931,7 +931,7 @@
"OptionAuto": "自动",
"OptionAutomatic": "自动",
"OptionAutomaticallyGroupSeries": "自动合并分布在不同文件夹的电视剧",
- "OptionAutomaticallyGroupSeriesHelp": "如果启用,分布在这个媒体库的多个文件夹中的同一部电视剧将会自动整合成一部电视剧。",
+ "OptionAutomaticallyGroupSeriesHelp": "在这个媒体库的多个文件夹中的同一部电视剧将会自动整合成一部电视剧。",
"OptionBlockBooks": "书籍",
"OptionBlockChannelContent": "互联网频道内容",
"OptionBlockLiveTvChannels": "电视直播频道",
@@ -952,7 +952,7 @@
"OptionDatePlayed": "播放日期",
"OptionDescending": "降序",
"OptionDisableUser": "禁用此用户",
- "OptionDisableUserHelp": "如果禁用该用户,服务器将不允许该用户连接。现有的连接将被终止。",
+ "OptionDisableUserHelp": "服务器将不允许来自该用户的任何连接。现有的连接将立即被终止。",
"OptionDislikes": "不喜欢",
"OptionDisplayFolderView": "显示一个“文件夹”类别用于按文件夹分类浏览你的媒体文件夹",
"OptionDisplayFolderViewHelp": "在你的媒体库列表中显示文件夹。如果你有按文件夹分类进行浏览的需求,这会非常有用。",
@@ -962,7 +962,7 @@
"OptionDownloadBoxImage": "包装",
"OptionDownloadDiscImage": "光盘",
"OptionDownloadImagesInAdvance": "提前下载图片",
- "OptionDownloadImagesInAdvanceHelp": "默认下,大部分图片只有在 Jellyfin 应用程序请求时下载。开启此选项将随着媒体导入时下载所有图片。这可能需要更久媒体库扫描时间。",
+ "OptionDownloadImagesInAdvanceHelp": "默认大多数图片只在客户端请求时下载。开启此选项将在新媒体导入时预先下载所有图片。这可能大大延长媒体库扫描时间。",
"OptionDownloadMenuImage": "菜单",
"OptionDownloadPrimaryImage": "封面图",
"OptionDownloadThumbImage": "缩略图",
@@ -994,7 +994,7 @@
"OptionHlsSegmentedSubtitles": "HLS分段字幕",
"OptionHomeVideos": "照片",
"OptionIgnoreTranscodeByteRangeRequests": "忽略转码字节范围请求",
- "OptionIgnoreTranscodeByteRangeRequestsHelp": "如果启用,这些请求会被兑现,但会忽略的字节范围标头。",
+ "OptionIgnoreTranscodeByteRangeRequestsHelp": "这些请求会被兑现,但会忽略的字节范围标头。",
"OptionImdbRating": "IMDb 评分",
"OptionIsHD": "HD高清",
"OptionIsSD": "SD标清",
@@ -1009,9 +1009,9 @@
"OptionOnInterval": "在一个期间",
"OptionParentalRating": "家长分级",
"OptionPlainStorageFolders": "显示所有文件夹作为一般存储文件夹",
- "OptionPlainStorageFoldersHelp": "如果启用,所有文件夹在DIDL中显示为“ object.container.storageFolder ”,而不是一个更具体的类型,如“ object.container.person.musicArtist ” 。",
+ "OptionPlainStorageFoldersHelp": "所有文件夹在DIDL中显示为 \"object.container.storageFolder\" ,而不是一个更具体的类型,如 \"object.container.person.musicArtist\" 。",
"OptionPlainVideoItems": "显示所有视频为一般视频项目",
- "OptionPlainVideoItemsHelp": "如果启用,所有视频在DIDL中显示为“object.item.videoItem”,而不是一个更具体的类型,如“object.item.videoItem.movie ” 。",
+ "OptionPlainVideoItemsHelp": "所有视频在DIDL中显示为 \"object.item.videoItem\" ,而不是一个更具体的类型,如 \"object.item.videoItem.movie\" 。",
"OptionPlayCount": "播放次数",
"OptionPlayed": "已播放",
"OptionPremiereDate": "首映日期",
@@ -1316,7 +1316,7 @@
"ErrorDeletingItem": "从 Jellyfin Server 删除项目时出错。请确认 Jellyfin Server 是否拥有对媒体目录的写权限,然后重试。",
"GroupBySeries": "按系列分组",
"HeaderApp": "应用程序",
- "DirectStreamHelp1": "该媒体文件的分辨率和编码(H.264、AC3 等)与您的设备兼容,但容器格式(.mkv、.avi、.wmv 等)不受支持。因此,视频在串流至您的设备之前将会被即时封装为另一种格式。",
+ "DirectStreamHelp1": "该媒体文件的分辨率和编码(H.264、AC3 等)与您的设备兼容,但文件格式(.mkv、.avi、.wmv 等)不受支持。因此,视频在串流至您的设备之前将会被即时封装为另一种格式。",
"HeaderAppearsOn": "同时出现于",
"HeaderCancelSeries": "取消系列",
"HeaderFavoriteEpisodes": "最爱的剧集",
@@ -1361,14 +1361,14 @@
"OptionDownloadLogoImage": "标志",
"OptionLoginAttemptsBeforeLockout": "确定在锁定之前可以进行多少次不正确的登录尝试。",
"OptionLoginAttemptsBeforeLockoutHelp": "如果值为0,则表示将允许普通用户尝试三次、管理员尝试五次的默认值。将此设置为-1将禁用此功能。",
- "PasswordResetProviderHelp": "选择一个密码重置提供者用于密码重置",
+ "PasswordResetProviderHelp": "选择一个密码重置提供者用于此用户申请重置密码",
"PlaceFavoriteChannelsAtBeginning": "将最喜爱的频道置顶",
"PlayNext": "播放下一个",
"PlayNextEpisodeAutomatically": "自动播放下一集",
"Premieres": "首映",
"Raised": "提高",
"Recordings": "录音",
- "RefreshDialogHelp": "元数据根据设置和Jellyfin服务器中启用的网络服务进行刷新。",
+ "RefreshDialogHelp": "元数据根据设置和仪表盘中启用的网络服务进行刷新。",
"RepeatEpisodes": "重复剧集",
"Schedule": "日程",
"Screenshot": "屏幕截图",
@@ -1421,7 +1421,7 @@
"ButtonAddImage": "添加图片",
"LabelPlayer": "播放器:",
"LabelBaseUrl": "基础 URL:",
- "LabelBaseUrlHelp": "为服务器 URL添加自定义子目录,例如:http://example.com/<baseurl>
。",
+ "LabelBaseUrlHelp": "为服务器 URL添加自定义子目录,例如:http://example.com/<baseurl>
",
"MusicLibraryHelp": "重播 {0}音乐命名指南{1}。",
"HeaderFavoritePeople": "最喜欢的人物",
"OptionRandom": "随机",
@@ -1480,7 +1480,7 @@
"LabelRequireHttpsHelp": "开启后服务器将自动将所有 HTTP 请求重定向到 HTTPS。如果服务器没有启用 HTTPS 则不生效。",
"LabelRequireHttps": "强制 HTTPS",
"LabelStable": "稳定版",
- "LabelEnableHttpsHelp": "开启服务器对所配置 HTTPS 端口的监听。必须配置有效的证书才会生效。",
+ "LabelEnableHttpsHelp": "监听已配置的 HTTPS 端口。必须配置有效的证书才会生效。",
"LabelEnableHttps": "启用 HTTPS",
"LabelChromecastVersion": "Chromecast版本",
"HeaderDVR": "DVR",
@@ -1539,5 +1539,13 @@
"ClearQueue": "清空队列",
"StopPlayback": "停止播放",
"Writers": "作者",
- "ViewAlbumArtist": "查看专辑艺术家"
+ "ViewAlbumArtist": "查看专辑艺术家",
+ "Preview": "预览",
+ "SubtitleVerticalPositionHelp": "文字出现的行号。正数表示由上到下,负数表示由下到上。",
+ "LabelSubtitleVerticalPosition": "垂直位置:",
+ "PreviousTrack": "上一曲",
+ "MessageGetInstalledPluginsError": "获取已安装插件列表时出现错误。",
+ "MessagePluginInstallError": "安装插件时出现错误。",
+ "NextTrack": "下一曲",
+ "LabelUnstable": "不稳定"
}
diff --git a/yarn.lock b/yarn.lock
index 758ded53fc..269b3b93cd 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -40,19 +40,19 @@
semver "^5.4.1"
source-map "^0.5.0"
-"@babel/eslint-parser@^7.11.0":
- version "7.11.0"
- resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.11.0.tgz#b123924edd44508782c030066c926f1b807151cd"
- integrity sha512-dJDM2Pc01D9TwKL3Mmz2xgVF9X953RBHq9H4gywbN1q8MrfvXmNHfsCt06vvByBVQqm+9WxMs+doEH/R09TwWQ==
+"@babel/eslint-parser@^7.11.3":
+ version "7.11.3"
+ resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.11.3.tgz#ceb94cb6e2457c4a4d2d87db29925e6b48d20786"
+ integrity sha512-OdCt/CVXdR/eTNTYDEobf4e55m/AAc04ki+/Oe2/GE8ivh2FxX4yDab48lA6t7ysP4M7luap6Fxx3hUVNTwzFQ==
dependencies:
eslint-scope "5.1.0"
eslint-visitor-keys "^1.3.0"
semver "^6.3.0"
-"@babel/eslint-plugin@^7.11.0":
- version "7.11.0"
- resolved "https://registry.yarnpkg.com/@babel/eslint-plugin/-/eslint-plugin-7.11.0.tgz#55d5b6bd29859cabce152f16d01b3a8150d5b295"
- integrity sha512-+gfPM0/T6d25jKBgmxWp38W0jqRs16Vt7DPBxGOcnN/7nS2A/6QoaXOYEaccvWS5a9UpWlMIAylivp6UtH8/sQ==
+"@babel/eslint-plugin@^7.11.3":
+ version "7.11.3"
+ resolved "https://registry.yarnpkg.com/@babel/eslint-plugin/-/eslint-plugin-7.11.3.tgz#66b531f90592f8f0621d072b59ea2c37c91e8d0d"
+ integrity sha512-gmi3lgaWlYpNb+h7qPfv5GVz2ZVwzCDyV+kAGj+3il+Mv5uan5Yccvdw7m14UAAY2tdTbB0VgRF6ZLjUbrUm0g==
dependencies:
eslint-rule-composer "^0.3.0"