diff --git a/.eslintrc.js b/.eslintrc.js index 27b5c2a23..ab53f0f03 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -132,6 +132,7 @@ module.exports = { 'Object.getOwnPropertyDescriptor', 'Object.getPrototypeOf', 'Object.keys', + 'Object.entries', 'Object.getOwnPropertyNames', 'Function.name', 'Function.hasInstance', diff --git a/.gitignore b/.gitignore index 9bccd32fb..36b843f02 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -# config -config.json - # npm dist web @@ -10,5 +7,5 @@ node_modules .idea .vscode -#log +# log yarn-error.log diff --git a/package.json b/package.json index a06fad3ae..e24612f62 100644 --- a/package.json +++ b/package.json @@ -5,12 +5,12 @@ "repository": "https://github.com/jellyfin/jellyfin-web", "license": "GPL-2.0-or-later", "devDependencies": { - "@babel/core": "^7.9.6", + "@babel/core": "^7.10.2", "@babel/plugin-proposal-class-properties": "^7.10.1", "@babel/plugin-proposal-private-methods": "^7.10.1", "@babel/plugin-transform-modules-amd": "^7.9.6", "@babel/polyfill": "^7.8.7", - "@babel/preset-env": "^7.8.6", + "@babel/preset-env": "^7.10.2", "autoprefixer": "^9.8.0", "babel-eslint": "^11.0.0-beta.2", "babel-loader": "^8.0.6", @@ -21,13 +21,13 @@ "del": "^5.1.0", "eslint": "^6.8.0", "eslint-plugin-compat": "^3.5.1", - "eslint-plugin-eslint-comments": "^3.1.2", - "eslint-plugin-import": "^2.20.2", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-import": "^2.21.1", "eslint-plugin-promise": "^4.2.1", "file-loader": "^6.0.0", "gulp": "^4.0.2", "gulp-babel": "^8.0.0", - "gulp-cli": "^2.2.1", + "gulp-cli": "^2.3.0", "gulp-concat": "^2.6.1", "gulp-htmlmin": "^5.0.1", "gulp-if": "^3.0.0", @@ -44,16 +44,17 @@ "postcss-loader": "^3.0.0", "postcss-preset-env": "^6.7.0", "style-loader": "^1.1.3", - "stylelint": "^13.5.0", + "stylelint": "^13.6.0", "stylelint-config-rational-order": "^0.1.2", "stylelint-no-browser-hacks": "^1.2.1", - "stylelint-order": "^4.0.0", + "stylelint-order": "^4.1.0", "webpack": "^4.41.5", "webpack-merge": "^4.2.2", "webpack-stream": "^5.2.1" }, "dependencies": { "alameda": "^1.4.0", + "blurhash": "^1.1.3", "classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz", "core-js": "^3.6.5", "date-fns": "^2.14.0", @@ -65,7 +66,7 @@ "hls.js": "^0.13.1", "howler": "^2.2.0", "intersection-observer": "^0.10.0", - "jellyfin-apiclient": "^1.2.0", + "jellyfin-apiclient": "^1.2.2", "jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto", "jquery": "^3.5.1", "jstree": "^3.3.7", @@ -73,12 +74,12 @@ "material-design-icons-iconfont": "^5.0.1", "native-promise-only": "^0.8.0-a", "page": "^1.11.6", - "query-string": "^6.11.1", + "query-string": "^6.13.0", "resize-observer-polyfill": "^1.5.1", "screenfull": "^5.0.2", - "shaka-player": "^2.5.11", + "shaka-player": "^2.5.12", "sortablejs": "^1.10.2", - "swiper": "^5.4.1", + "swiper": "^5.4.2", "webcomponents.js": "^0.7.24", "whatwg-fetch": "^3.0.0" }, @@ -89,30 +90,44 @@ "overrides": [ { "test": [ + "src/components/accessSchedule/accessSchedule.js", + "src/components/actionSheet/actionSheet.js", "src/components/autoFocuser.js", "src/components/cardbuilder/cardBuilder.js", - "src/scripts/fileDownloader.js", + "src/components/cardbuilder/chaptercardbuilder.js", + "src/components/cardbuilder/peoplecardbuilder.js", "src/components/images/imageLoader.js", + "src/components/indicators/indicators.js", "src/components/lazyLoader/lazyLoaderIntersectionObserver.js", + "src/components/playback/brightnessosd.js", "src/components/playback/mediasession.js", + "src/components/playback/nowplayinghelper.js", + "src/components/playback/playbackorientation.js", + "src/components/playback/playerSelectionMenu.js", + "src/components/playback/playersettingsmenu.js", + "src/components/playback/playmethodhelper.js", + "src/components/playback/remotecontrolautoplay.js", + "src/components/playback/volumeosd.js", + "src/components/playmenu.js", "src/components/sanatizefilename.js", "src/components/scrollManager.js", - "src/components/bookPlayer/plugin.js", - "src/components/bookPlayer/tableOfContent.js", - "src/components/syncplay/playbackPermissionManager.js", - "src/components/syncplay/groupSelectionMenu.js", - "src/components/syncplay/timeSyncManager.js", - "src/components/syncplay/syncPlayManager.js", + "src/components/syncPlay/groupSelectionMenu.js", + "src/components/syncPlay/playbackPermissionManager.js", + "src/components/syncPlay/syncPlayManager.js", + "src/components/syncPlay/timeSyncManager.js", + "src/plugins/bookPlayer/plugin.js", + "src/plugins/bookPlayer/tableOfContent.js", + "src/plugins/photoPlayer/plugin.js", + "src/scripts/deleteHelper.js", "src/scripts/dfnshelper.js", "src/scripts/dom.js", + "src/scripts/fileDownloader.js", "src/scripts/filesystem.js", "src/scripts/imagehelper.js", "src/scripts/inputManager.js", - "src/scripts/deleteHelper.js", - "src/components/actionSheet/actionSheet.js", - "src/components/playmenu.js", - "src/components/indicators/indicators.js", - "src/components/photoPlayer/plugin.js", + "src/plugins/backdropScreensaver/plugin.js", + "src/components/filterdialog/filterdialog.js", + "src/components/fetchhelper.js", "src/scripts/keyboardNavigation.js", "src/scripts/settings/appSettings.js", "src/scripts/settings/userSettings.js", diff --git a/src/assets/css/librarybrowser.css b/src/assets/css/librarybrowser.css index 82e704f07..baea885a0 100644 --- a/src/assets/css/librarybrowser.css +++ b/src/assets/css/librarybrowser.css @@ -597,6 +597,7 @@ .detailImageContainer { position: relative; margin-top: -25vh; + margin-bottom: 10vh; float: left; width: 25vw; z-index: 3; @@ -641,7 +642,8 @@ div.itemDetailGalleryLink.defaultCardBackground { } .itemDetailGalleryLink.defaultCardBackground { - height: 23vw; /* Dirty hack to get it to look somewhat square. Less than ideal. */ + /* Dirty hack to get it to look somewhat square. Less than ideal. */ + height: 23vw; } .itemDetailGalleryLink.defaultCardBackground > .material-icons { @@ -1144,3 +1146,21 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards { margin-top: 0; font-size: 1.4em; } + +.overview-controls { + display: flex; + justify-content: flex-end; +} + +.detail-clamp-text { + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 12; + -webkit-box-orient: vertical; +} + +@media all and (min-width: 40em) { + .detail-clamp-text { + -webkit-line-clamp: 6; + } +} diff --git a/src/bundle.js b/src/bundle.js index d4a97247f..41648f7c4 100644 --- a/src/bundle.js +++ b/src/bundle.js @@ -16,6 +16,12 @@ _define('fetch', function() { return fetch; }); +// Blurhash +var blurhash = require('blurhash'); +_define('blurhash', function() { + return blurhash; +}); + // query-string var query = require('query-string'); _define('queryString', function() { diff --git a/src/components/accessSchedule/accessSchedule.js b/src/components/accessSchedule/accessSchedule.js index 2209f5761..166460a02 100644 --- a/src/components/accessSchedule/accessSchedule.js +++ b/src/components/accessSchedule/accessSchedule.js @@ -1,9 +1,20 @@ -define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-button-light', 'formDialogStyle'], function (dialogHelper, datetime, globalize) { - 'use strict'; +/* eslint-disable indent */ + +/** + * Module for controlling user parental control from. + * @module components/accessSchedule/accessSchedule + */ + +import dialogHelper from 'dialogHelper'; +import datetime from 'datetime'; +import globalize from 'globalize'; +import 'emby-select'; +import 'paper-icon-button-light'; +import 'formDialogStyle'; function getDisplayTime(hours) { - var minutes = 0; - var pct = hours % 1; + let minutes = 0; + const pct = hours % 1; if (pct) { minutes = parseInt(60 * pct); @@ -13,25 +24,25 @@ define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-butt } function populateHours(context) { - var html = ''; + let html = ''; - for (var i = 0; i < 24; i++) { - html += ''; + for (let i = 0; i < 24; i++) { + html += ``; } - html += ''; + html += ``; context.querySelector('#selectStart').innerHTML = html; context.querySelector('#selectEnd').innerHTML = html; } - function loadSchedule(context, schedule) { - context.querySelector('#selectDay').value = schedule.DayOfWeek || 'Sunday'; - context.querySelector('#selectStart').value = schedule.StartHour || 0; - context.querySelector('#selectEnd').value = schedule.EndHour || 0; + function loadSchedule(context, {DayOfWeek, StartHour, EndHour}) { + context.querySelector('#selectDay').value = DayOfWeek || 'Sunday'; + context.querySelector('#selectStart').value = StartHour || 0; + context.querySelector('#selectEnd').value = EndHour || 0; } function submitSchedule(context, options) { - var updatedSchedule = { + const updatedSchedule = { DayOfWeek: context.querySelector('#selectDay').value, StartHour: context.querySelector('#selectStart').value, EndHour: context.querySelector('#selectEnd').value @@ -46,44 +57,42 @@ define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-butt dialogHelper.close(context); } - return { - show: function (options) { - return new Promise(function (resolve, reject) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', 'components/accessSchedule/accessSchedule.template.html', true); - - xhr.onload = function (e) { - var template = this.response; - var dlg = dialogHelper.createDialog({ - removeOnClose: true, - size: 'small' - }); - dlg.classList.add('formDialog'); - var html = ''; - html += globalize.translateDocument(template); - dlg.innerHTML = html; - populateHours(dlg); - loadSchedule(dlg, options.schedule); - dialogHelper.open(dlg); - dlg.addEventListener('close', function () { - if (dlg.submitted) { - resolve(options.schedule); - } else { - reject(); - } - }); - dlg.querySelector('.btnCancel').addEventListener('click', function (e) { - dialogHelper.close(dlg); - }); - dlg.querySelector('form').addEventListener('submit', function (e) { - submitSchedule(dlg, options); - e.preventDefault(); - return false; - }); - }; - - xhr.send(); + export function show(options) { + return new Promise((resolve, reject) => { + // TODO: remove require + require(['text!./components/accessSchedule/accessSchedule.template.html'], template => { + const dlg = dialogHelper.createDialog({ + removeOnClose: true, + size: 'small' + }); + dlg.classList.add('formDialog'); + let html = ''; + html += globalize.translateDocument(template); + dlg.innerHTML = html; + populateHours(dlg); + loadSchedule(dlg, options.schedule); + dialogHelper.open(dlg); + dlg.addEventListener('close', () => { + if (dlg.submitted) { + resolve(options.schedule); + } else { + reject(); + } + }); + dlg.querySelector('.btnCancel').addEventListener('click', () => { + dialogHelper.close(dlg); + }); + dlg.querySelector('form').addEventListener('submit', event => { + submitSchedule(dlg, options); + event.preventDefault(); + return false; + }); }); - } - }; -}); + }); + } + +/* eslint-enable indent */ + +export default { + show: show +}; diff --git a/src/components/actionSheet/actionSheet.js b/src/components/actionSheet/actionSheet.js index 9f916d097..c56f42a9d 100644 --- a/src/components/actionSheet/actionSheet.js +++ b/src/components/actionSheet/actionSheet.js @@ -16,15 +16,8 @@ function getOffsets(elems) { return results; } - let box; for (let elem of elems) { - // Support: BlackBerry 5, iOS 3 (original iPhone) - // If we don't have gBCR, just use 0,0 rather than error - if (elem.getBoundingClientRect) { - box = elem.getBoundingClientRect(); - } else { - box = { top: 0, left: 0 }; - } + let box = elem.getBoundingClientRect(); results.push({ top: box.top, @@ -153,7 +146,9 @@ export function show(options) { } if (layoutManager.tv) { - html += ''; + html += ``; } // If any items have an icon, give them all an icon just to make sure they're all lined up evenly @@ -216,7 +211,7 @@ export function show(options) { itemIcon = icons[i]; if (itemIcon) { - html += ''; + html += ``; } else if (renderIcon && !center) { html += ''; } @@ -228,13 +223,13 @@ export function show(options) { html += ''; if (item.secondaryText) { - html += '
' + item.secondaryText + '
'; + html += `
${item.secondaryText}
`; } html += ''; if (item.asideText) { - html += '
' + item.asideText + '
'; + html += `
${item.asideText}
`; } html += ''; @@ -242,7 +237,7 @@ export function show(options) { if (options.showCancel) { html += '
'; - html += ''; + html += ``; html += '
'; } html += ''; diff --git a/src/components/activitylog.js b/src/components/activitylog.js index a7b3f48bc..bbb099506 100644 --- a/src/components/activitylog.js +++ b/src/components/activitylog.js @@ -34,10 +34,14 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings', html += ''; if (entry.Overview) { - html += ''; + html += ``; } - return html += ''; + html += ''; + + return html; } function renderList(elem, apiClient, result, startIndex, limit) { diff --git a/src/components/appRouter.js b/src/components/appRouter.js index a7496b275..0861cf7e0 100644 --- a/src/components/appRouter.js +++ b/src/components/appRouter.js @@ -26,11 +26,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro connectionManager.connect({ enableAutoLogin: appSettings.enableAutoLogin() }).then(function (result) { - handleConnectionResult(result, loading); + handleConnectionResult(result); }); } - function handleConnectionResult(result, loading) { + function handleConnectionResult(result) { switch (result.State) { case 'SignedIn': loading.hide(); @@ -246,13 +246,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro } if (setQuality) { - - var quality = 100; - + var quality; var type = options.type || 'Primary'; if (browser.tv || browser.slow) { - + // TODO: wtf if (browser.chrome) { // webp support quality = type === 'Primary' ? 40 : 50; @@ -384,7 +382,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro if (firstResult.State !== 'SignedIn' && !route.anonymous) { - handleConnectionResult(firstResult, loading); + handleConnectionResult(firstResult); return; } } @@ -463,7 +461,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro return Promise.resolve(); } - var isHandlingBackToDefault; var isDummyBackToHome; function loadContent(ctx, route, html, request) { @@ -589,8 +586,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro path = '/' + path; } - var baseRoute = baseUrl(); - path = path.replace(baseRoute, ''); + path = path.replace(baseUrl(), ''); if (currentRouteInfo && currentRouteInfo.path === path) { // can't use this with home right now due to the back menu @@ -621,10 +617,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro } function showItem(item, serverId, options) { + // TODO: Refactor this so it only gets items, not strings. if (typeof (item) === 'string') { var apiClient = serverId ? connectionManager.getApiClient(serverId) : connectionManager.currentApiClient(); - apiClient.getItem(apiClient.getCurrentUserId(), item).then(function (item) { - appRouter.showItem(item, options); + apiClient.getItem(apiClient.getCurrentUserId(), item).then(function (itemObject) { + appRouter.showItem(itemObject, options); }); } else { if (arguments.length === 2) { diff --git a/src/components/apphost.js b/src/components/apphost.js index 7b044d5d3..f200b9a64 100644 --- a/src/components/apphost.js +++ b/src/components/apphost.js @@ -5,7 +5,7 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g var disableHlsVideoAudioCodecs = []; if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) { - if (browser.edge || browser.msie) { + if (browser.edge) { disableHlsVideoAudioCodecs.push('mp3'); } @@ -93,18 +93,36 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g function getDeviceName() { var deviceName; - deviceName = browser.tizen ? 'Samsung Smart TV' : browser.web0s ? 'LG Smart TV' : browser.operaTv ? 'Opera TV' : browser.xboxOne ? 'Xbox One' : browser.ps4 ? 'Sony PS4' : browser.chrome ? 'Chrome' : browser.edge ? 'Edge' : browser.firefox ? 'Firefox' : browser.msie ? 'Internet Explorer' : browser.opera ? 'Opera' : browser.safari ? 'Safari' : 'Web Browser'; + if (browser.tizen) { + deviceName = 'Samsung Smart TV'; + } else if (browser.web0s) { + deviceName = 'LG Smart TV'; + } else if (browser.operaTv) { + deviceName = 'Opera TV'; + } else if (browser.xboxOne) { + deviceName = 'Xbox One'; + } else if (browser.ps4) { + deviceName = 'Sony PS4'; + } else if (browser.chrome) { + deviceName = 'Chrome'; + } else if (browser.edge) { + deviceName = 'Edge'; + } else if (browser.firefox) { + deviceName = 'Firefox'; + } else if (browser.opera) { + deviceName = 'Opera'; + } else if (browser.safari) { + deviceName = 'Safari'; + } else { + deviceName = 'Web Browser'; + } if (browser.ipad) { deviceName += ' iPad'; - } else { - if (browser.iphone) { - deviceName += ' iPhone'; - } else { - if (browser.android) { - deviceName += ' Android'; - } - } + } else if (browser.iphone) { + deviceName += ' iPhone'; + } else if (browser.android) { + deviceName += ' Android'; } return deviceName; @@ -267,7 +285,7 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g if (enabled) features.push('multiserver'); }); - if (!browser.orsay && !browser.msie && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) { + if (!browser.orsay && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) { features.push('subtitleappearancesettings'); } diff --git a/src/components/backdropScreensaver/plugin.js b/src/components/backdropScreensaver/plugin.js deleted file mode 100644 index dc0a906dd..000000000 --- a/src/components/backdropScreensaver/plugin.js +++ /dev/null @@ -1,56 +0,0 @@ -define(['connectionManager'], function (connectionManager) { - - return function () { - - var self = this; - - self.name = 'Backdrop ScreenSaver'; - self.type = 'screensaver'; - self.id = 'backdropscreensaver'; - self.supportsAnonymous = false; - - var currentSlideshow; - - self.show = function () { - - var query = { - ImageTypes: 'Backdrop', - EnableImageTypes: 'Backdrop', - IncludeItemTypes: 'Movie,Series,MusicArtist', - SortBy: 'Random', - Recursive: true, - Fields: 'Taglines', - ImageTypeLimit: 1, - StartIndex: 0, - Limit: 200 - }; - - var apiClient = connectionManager.currentApiClient(); - apiClient.getItems(apiClient.getCurrentUserId(), query).then(function (result) { - - if (result.Items.length) { - - require(['slideshow'], function (slideshow) { - - var newSlideShow = new slideshow({ - showTitle: true, - cover: true, - items: result.Items - }); - - newSlideShow.show(); - currentSlideshow = newSlideShow; - }); - } - }); - }; - - self.hide = function () { - - if (currentSlideshow) { - currentSlideshow.hide(); - currentSlideshow = null; - } - }; - }; -}); diff --git a/src/components/cardbuilder/cardBuilder.js b/src/components/cardbuilder/cardBuilder.js index d4d4d7f73..e540a4021 100644 --- a/src/components/cardbuilder/cardBuilder.js +++ b/src/components/cardbuilder/cardBuilder.js @@ -503,94 +503,49 @@ import 'programStyles'; const primaryImageAspectRatio = item.PrimaryImageAspectRatio; let forceName = false; let imgUrl = null; + let imgTag = null; let coverImage = false; let uiAspect = null; + let imgType = null; + let itemId = null; if (options.preferThumb && item.ImageTags && item.ImageTags.Thumb) { - - imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: 'Thumb', - maxWidth: width, - tag: item.ImageTags.Thumb - }); - + imgType = 'Thumb'; + imgTag = item.ImageTags.Thumb; } else if ((options.preferBanner || shape === 'banner') && item.ImageTags && item.ImageTags.Banner) { - - imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: 'Banner', - maxWidth: width, - tag: item.ImageTags.Banner - }); - + imgType = 'Banner'; + imgTag = item.ImageTags.Banner; } else if (options.preferDisc && item.ImageTags && item.ImageTags.Disc) { - - imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: 'Disc', - maxWidth: width, - tag: item.ImageTags.Disc - }); - + imgType = 'Disc'; + imgTag = item.ImageTags.Disc; } else if (options.preferLogo && item.ImageTags && item.ImageTags.Logo) { - - imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: 'Logo', - maxWidth: width, - tag: item.ImageTags.Logo - }); - + imgType = 'Logo'; + imgTag = item.ImageTags.Logo; } else if (options.preferLogo && item.ParentLogoImageTag && item.ParentLogoItemId) { - - imgUrl = apiClient.getScaledImageUrl(item.ParentLogoItemId, { - type: 'Logo', - maxWidth: width, - tag: item.ParentLogoImageTag - }); - + imgType = 'Logo'; + imgTag = item.ParentLogoImageTag; + itemId = item.ParentLogoItemId; } else if (options.preferThumb && item.SeriesThumbImageTag && options.inheritThumb !== false) { - - imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { - type: 'Thumb', - maxWidth: width, - tag: item.SeriesThumbImageTag - }); - + imgType = 'Thumb'; + imgTag = item.SeriesThumbImageTag; + itemId = item.SeriesId; } else if (options.preferThumb && item.ParentThumbItemId && options.inheritThumb !== false && item.MediaType !== 'Photo') { - - imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, { - type: 'Thumb', - maxWidth: width, - tag: item.ParentThumbImageTag - }); - + imgType = 'Thumb'; + imgTag = item.ParentThumbImageTag; + itemId = item.ParentThumbItemId; } else if (options.preferThumb && item.BackdropImageTags && item.BackdropImageTags.length) { - - imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: 'Backdrop', - maxWidth: width, - tag: item.BackdropImageTags[0] - }); - + imgType = 'Backdrop'; + imgTag = item.BackdropImageTags[0]; forceName = true; - } else if (options.preferThumb && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false && item.Type === 'Episode') { - - imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { - type: 'Backdrop', - maxWidth: width, - tag: item.ParentBackdropImageTags[0] - }); - + imgType = 'Backdrop'; + imgTag = item.ParentBackdropImageTags[0]; + itemId = item.ParentBackdropItemId; } else if (item.ImageTags && item.ImageTags.Primary) { - + imgType = 'Primary'; + imgTag = item.ImageTags.Primary; height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; - imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: 'Primary', - maxHeight: height, - maxWidth: width, - tag: item.ImageTags.Primary - }); - if (options.preferThumb && options.showTitle !== false) { forceName = true; } @@ -603,16 +558,11 @@ import 'programStyles'; } } else if (item.PrimaryImageTag) { - + imgType = 'Primary'; + imgTag = item.PrimaryImageTag; + itemId = item.PrimaryImageItemId; height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; - imgUrl = apiClient.getScaledImageUrl(item.PrimaryImageItemId || item.Id || item.ItemId, { - type: 'Primary', - maxHeight: height, - maxWidth: width, - tag: item.PrimaryImageTag - }); - if (options.preferThumb && options.showTitle !== false) { forceName = true; } @@ -624,30 +574,19 @@ import 'programStyles'; } } } else if (item.ParentPrimaryImageTag) { - - imgUrl = apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, { - type: 'Primary', - maxWidth: width, - tag: item.ParentPrimaryImageTag - }); + imgType = 'Primary'; + imgTag = item.ParentPrimaryImageTag; + itemId = item.ParentPrimaryImageItemId; } else if (item.SeriesPrimaryImageTag) { - - imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { - type: 'Primary', - maxWidth: width, - tag: item.SeriesPrimaryImageTag - }); + imgType = 'Primary'; + imgTag = item.SeriesPrimaryImageTag; + itemId = item.SeriesId; } else if (item.AlbumId && item.AlbumPrimaryImageTag) { - + imgType = 'Primary'; + imgTag = item.AlbumPrimaryImageTag; + itemId = item.AlbumId; height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; - imgUrl = apiClient.getScaledImageUrl(item.AlbumId, { - type: 'Primary', - maxHeight: height, - maxWidth: width, - tag: item.AlbumPrimaryImageTag - }); - if (primaryImageAspectRatio) { uiAspect = getDesiredAspect(shape); if (uiAspect) { @@ -655,57 +594,46 @@ import 'programStyles'; } } } else if (item.Type === 'Season' && item.ImageTags && item.ImageTags.Thumb) { - - imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: 'Thumb', - maxWidth: width, - tag: item.ImageTags.Thumb - }); - + imgType = 'Thumb'; + imgTag = item.ImageTags.Thumb; } else if (item.BackdropImageTags && item.BackdropImageTags.length) { - - imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: 'Backdrop', - maxWidth: width, - tag: item.BackdropImageTags[0] - }); - + imgType = 'Backdrop'; + imgTag = item.BackdropImageTags[0]; } else if (item.ImageTags && item.ImageTags.Thumb) { - - imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: 'Thumb', - maxWidth: width, - tag: item.ImageTags.Thumb - }); - + imgType = 'Thumb'; + imgTag = item.ImageTags.Thumb; } else if (item.SeriesThumbImageTag && options.inheritThumb !== false) { - - imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { - type: 'Thumb', - maxWidth: width, - tag: item.SeriesThumbImageTag - }); - + imgType = 'Thumb'; + imgTag = item.SeriesThumbImageTag; + itemId = item.SeriesId; } else if (item.ParentThumbItemId && options.inheritThumb !== false) { - - imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, { - type: 'Thumb', - maxWidth: width, - tag: item.ParentThumbImageTag - }); - + imgType = 'Thumb'; + imgTag = item.ParentThumbImageTag; + itemId = item.ParentThumbItemId; } else if (item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false) { - - imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { - type: 'Backdrop', - maxWidth: width, - tag: item.ParentBackdropImageTags[0] - }); - + imgType = 'Backdrop'; + imgTag = item.ParentBackdropImageTags[0]; + itemId = item.ParentBackdropItemId; } + if (!itemId) { + itemId = item.Id; + } + + if (imgTag && imgType) { + imgUrl = apiClient.getScaledImageUrl(itemId, { + type: imgType, + maxHeight: height, + maxWidth: width, + tag: imgTag + }); + } + + let blurHashes = options.imageBlurhashes || item.ImageBlurHashes || {}; + return { imgUrl: imgUrl, + blurhash: (blurHashes[imgType] || {})[imgTag], forceName: forceName, coverImage: coverImage }; @@ -1321,6 +1249,7 @@ import 'programStyles'; const imgInfo = getCardImageUrl(item, apiClient, options, shape); const imgUrl = imgInfo.imgUrl; + const blurhash = imgInfo.blurhash; const forceName = imgInfo.forceName; @@ -1445,15 +1374,20 @@ import 'programStyles'; cardContentClass += ' cardContent-shadow'; } + let blurhashAttrib = ''; + if (blurhash && blurhash.length > 0) { + blurhashAttrib = 'data-blurhash="' + blurhash + '"'; + } + if (layoutManager.tv) { // Don't use the IMG tag with safari because it puts a white border around it - cardImageContainerOpen = imgUrl ? ('
') : ('
'); + cardImageContainerOpen = imgUrl ? ('
') : ('
'); cardImageContainerClose = '
'; } else { // Don't use the IMG tag with safari because it puts a white border around it - cardImageContainerOpen = imgUrl ? (''; } diff --git a/src/components/cardbuilder/chaptercardbuilder.js b/src/components/cardbuilder/chaptercardbuilder.js index eae60574b..c6ee9ba3c 100644 --- a/src/components/cardbuilder/chaptercardbuilder.js +++ b/src/components/cardbuilder/chaptercardbuilder.js @@ -1,13 +1,23 @@ -define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browser'], function (datetime, imageLoader, connectionManager, layoutManager, browser) { - 'use strict'; +/* eslint-disable indent */ - var enableFocusTransform = !browser.slow && !browser.edge; +/** + * Module for building cards from item data. + * @module components/cardBuilder/chaptercardbuilder + */ - function buildChapterCardsHtml(item, chapters, options) { +import datetime from 'datetime'; +import imageLoader from 'imageLoader'; +import connectionManager from 'connectionManager'; +import layoutManager from 'layoutManager'; +import browser from 'browser'; + + const enableFocusTransform = !browser.slow && !browser.edge; + + function buildChapterCardsHtml(item, chapters, options) { // TODO move card creation code to Card component - var className = 'card itemAction chapterCard'; + let className = 'card itemAction chapterCard'; if (layoutManager.tv) { className += ' show-focus'; @@ -17,12 +27,12 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse } } - var mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || []; - var videoStream = mediaStreams.filter(function (i) { - return i.Type === 'Video'; + const mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || []; + const videoStream = mediaStreams.filter(({Type}) => { + return Type === 'Video'; })[0] || {}; - var shape = (options.backdropShape || 'backdrop'); + let shape = (options.backdropShape || 'backdrop'); if (videoStream.Width && videoStream.Height) { @@ -31,24 +41,24 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse } } - className += ' ' + shape + 'Card'; + className += ` ${shape}Card`; if (options.block || options.rows) { className += ' block'; } - var html = ''; - var itemsInRow = 0; + let html = ''; + let itemsInRow = 0; - var apiClient = connectionManager.getApiClient(item.ServerId); + const apiClient = connectionManager.getApiClient(item.ServerId); - for (var i = 0, length = chapters.length; i < length; i++) { + for (let i = 0, length = chapters.length; i < length; i++) { if (options.rows && itemsInRow === 0) { html += '
'; } - var chapter = chapters[i]; + const chapter = chapters[i]; html += buildChapterCard(item, apiClient, chapter, i, options, className, shape); itemsInRow++; @@ -62,50 +72,50 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse return html; } - function getImgUrl(item, chapter, index, maxWidth, apiClient) { + function getImgUrl({Id}, {ImageTag}, index, maxWidth, apiClient) { - if (chapter.ImageTag) { + if (ImageTag) { - return apiClient.getScaledImageUrl(item.Id, { + return apiClient.getScaledImageUrl(Id, { maxWidth: maxWidth * 2, - tag: chapter.ImageTag, + tag: ImageTag, type: 'Chapter', - index: index + index }); } return null; } - function buildChapterCard(item, apiClient, chapter, index, options, className, shape) { + function buildChapterCard(item, apiClient, chapter, index, {width, coverImage}, className, shape) { - var imgUrl = getImgUrl(item, chapter, index, options.width || 400, apiClient); + const imgUrl = getImgUrl(item, chapter, index, width || 400, apiClient); - var cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer'; - if (options.coverImage) { + let cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer'; + if (coverImage) { cardImageContainerClass += ' coveredImage'; } - var dataAttributes = ' data-action="play" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-positionticks="' + chapter.StartPositionTicks + '"'; - var cardImageContainer = imgUrl ? ('
') : ('
'); + const dataAttributes = ` data-action="play" data-isfolder="${item.IsFolder}" data-id="${item.Id}" data-serverid="${item.ServerId}" data-type="${item.Type}" data-mediatype="${item.MediaType}" data-positionticks="${chapter.StartPositionTicks}"`; + let cardImageContainer = imgUrl ? (`
`) : (`
`); if (!imgUrl) { cardImageContainer += ''; } - var nameHtml = ''; - nameHtml += '
' + chapter.Name + '
'; - nameHtml += '
' + datetime.getDisplayRunningTime(chapter.StartPositionTicks) + '
'; + let nameHtml = ''; + nameHtml += `
${chapter.Name}
`; + nameHtml += `
${datetime.getDisplayRunningTime(chapter.StartPositionTicks)}
`; - var cardBoxCssClass = 'cardBox'; - var cardScalableClass = 'cardScalable'; + const cardBoxCssClass = 'cardBox'; + const cardScalableClass = 'cardScalable'; - var html = '
'; + const html = `
`; return html; } - function buildChapterCards(item, chapters, options) { + export function buildChapterCards(item, chapters, options) { if (options.parentContainer) { // Abort if the container has been disposed @@ -121,15 +131,16 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse } } - var html = buildChapterCardsHtml(item, chapters, options); + const html = buildChapterCardsHtml(item, chapters, options); options.itemsContainer.innerHTML = html; imageLoader.lazyChildren(options.itemsContainer); } - return { - buildChapterCards: buildChapterCards - }; +/* eslint-enable indent */ + +export default { + buildChapterCards: buildChapterCards +}; -}); diff --git a/src/components/cardbuilder/peoplecardbuilder.js b/src/components/cardbuilder/peoplecardbuilder.js index 5d34d29e6..3b9a26a70 100644 --- a/src/components/cardbuilder/peoplecardbuilder.js +++ b/src/components/cardbuilder/peoplecardbuilder.js @@ -1,7 +1,13 @@ -define(['cardBuilder'], function (cardBuilder) { - 'use strict'; +/* eslint-disable indent */ - function buildPeopleCards(items, options) { +/** + * Module for building cards from item data. + * @module components/cardBuilder/peoplecardbuilder + */ + +import cardBuilder from 'cardBuilder'; + + export function buildPeopleCards(items, options) { options = Object.assign(options || {}, { cardLayout: false, @@ -15,8 +21,8 @@ define(['cardBuilder'], function (cardBuilder) { cardBuilder.buildCards(items, options); } - return { - buildPeopleCards: buildPeopleCards - }; + /* eslint-enable indent */ -}); +export default { + buildPeopleCards: buildPeopleCards +}; diff --git a/src/components/displaySettings/displaySettings.js b/src/components/displaySettings/displaySettings.js index 4e068960a..c4eb35f49 100644 --- a/src/components/displaySettings/displaySettings.js +++ b/src/components/displaySettings/displaySettings.js @@ -181,6 +181,7 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', ' context.querySelector('#chkThemeSong').checked = userSettings.enableThemeSongs(); context.querySelector('#chkThemeVideo').checked = userSettings.enableThemeVideos(); context.querySelector('#chkFadein').checked = userSettings.enableFastFadein(); + context.querySelector('#chkBlurhash').checked = userSettings.enableBlurhash(); context.querySelector('#chkBackdrops').checked = userSettings.enableBackdrops(); context.querySelector('#chkDetailsBanner').checked = userSettings.detailsBanner(); @@ -223,6 +224,7 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', ' userSettingsInstance.skin(context.querySelector('.selectSkin').value); userSettingsInstance.enableFastFadein(context.querySelector('#chkFadein').checked); + userSettingsInstance.enableBlurhash(context.querySelector('#chkBlurhash').checked); userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked); userSettingsInstance.detailsBanner(context.querySelector('#chkDetailsBanner').checked); diff --git a/src/components/displaySettings/displaySettings.template.html b/src/components/displaySettings/displaySettings.template.html index d37c24b49..ab01b4b6a 100644 --- a/src/components/displaySettings/displaySettings.template.html +++ b/src/components/displaySettings/displaySettings.template.html @@ -143,20 +143,28 @@
-
+
${LabelLibraryPageSizeHelp}
-
+
-
${EnableFastImageFadeInHelp}
+
${EnableFasterAnimationsHelp}
-
+
+ +
${EnableBlurhashHelp}
+
+ +
'; + if (index > 0) { + html += ''; + } else if (plugins.length > 1) { + html += ''; + } + html += '
'; }); html += '
'; diff --git a/src/components/libraryoptionseditor/libraryoptionseditor.template.html b/src/components/libraryoptionseditor/libraryoptionseditor.template.html index caa177108..92cebc9da 100644 --- a/src/components/libraryoptionseditor/libraryoptionseditor.template.html +++ b/src/components/libraryoptionseditor/libraryoptionseditor.template.html @@ -79,7 +79,7 @@
${OptionAutomaticallyGroupSeriesHelp}
diff --git a/src/components/listview/listview.js b/src/components/listview/listview.js index 587355b35..7bafc925b 100644 --- a/src/components/listview/listview.js +++ b/src/components/listview/listview.js @@ -70,6 +70,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan function getImageUrl(item, width) { var apiClient = connectionManager.getApiClient(item.ServerId); + let itemId; var options = { maxWidth: width * 2, @@ -77,45 +78,45 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan }; if (item.ImageTags && item.ImageTags.Primary) { - options.tag = item.ImageTags.Primary; - return apiClient.getScaledImageUrl(item.Id, options); + itemId = item.Id; } if (item.AlbumId && item.AlbumPrimaryImageTag) { - options.tag = item.AlbumPrimaryImageTag; - return apiClient.getScaledImageUrl(item.AlbumId, options); + itemId = item.AlbumId; } else if (item.SeriesId && item.SeriesPrimaryImageTag) { - options.tag = item.SeriesPrimaryImageTag; - return apiClient.getScaledImageUrl(item.SeriesId, options); - + itemId = item.SeriesId; } else if (item.ParentPrimaryImageTag) { - options.tag = item.ParentPrimaryImageTag; - return apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, options); + itemId = item.ParentPrimaryImageItemId; } + let blurHashes = item.ImageBlurHashes || {}; + let blurhashstr = (blurHashes[options.type] || {})[options.tag]; - return null; + if (itemId) { + return { url: apiClient.getScaledImageUrl(itemId, options), blurhash: blurhashstr }; + } } function getChannelImageUrl(item, width) { var apiClient = connectionManager.getApiClient(item.ServerId); - var options = { maxWidth: width * 2, type: 'Primary' }; if (item.ChannelId && item.ChannelPrimaryImageTag) { - options.tag = item.ChannelPrimaryImageTag; - return apiClient.getScaledImageUrl(item.ChannelId, options); } + let blurHashes = item.ImageBlurHashes || {}; + let blurhashstr = (blurHashes[options.type])[options.tag]; - return null; + if (item.ChannelId) { + return { url: apiClient.getScaledImageUrl(item.ChannelId, options), blurhash: blurhashstr }; + } } function getTextLinesHtml(textlines, isLargeStyle) { @@ -268,8 +269,10 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan } if (options.image !== false) { - var imgUrl = options.imageSource === 'channel' ? getChannelImageUrl(item, downloadWidth) : getImageUrl(item, downloadWidth); - var imageClass = isLargeStyle ? 'listItemImage listItemImage-large' : 'listItemImage'; + let imgData = options.imageSource === 'channel' ? getChannelImageUrl(item, downloadWidth) : getImageUrl(item, downloadWidth); + let imgUrl = imgData.url; + let blurhash = imgData.blurhash; + let imageClass = isLargeStyle ? 'listItemImage listItemImage-large' : 'listItemImage'; if (isLargeStyle && layoutManager.tv) { imageClass += ' listItemImage-large-tv'; @@ -283,8 +286,13 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan var imageAction = playOnImageClick ? 'resume' : action; + let blurhashAttrib = ''; + if (blurhash && blurhash.length > 0) { + blurhashAttrib = 'data-blurhash="' + blurhash + '"'; + } + if (imgUrl) { - html += '
'; + html += '
'; } else { html += '
'; } diff --git a/src/components/mediainfo/mediainfo.js b/src/components/mediainfo/mediainfo.js index c569a7c78..7de11c42f 100644 --- a/src/components/mediainfo/mediainfo.js +++ b/src/components/mediainfo/mediainfo.js @@ -273,7 +273,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater } } - if (item.RunTimeTicks && item.Type !== 'Series' && item.Type !== 'Program' && !showFolderRuntime && options.runtime !== false) { + if (item.RunTimeTicks && item.Type !== 'Series' && item.Type !== 'Program' && item.Type !== 'Book' && !showFolderRuntime && options.runtime !== false) { if (item.Type === 'Audio') { diff --git a/src/components/packagemanager.js b/src/components/packageManager.js similarity index 100% rename from src/components/packagemanager.js rename to src/components/packageManager.js diff --git a/src/components/playback/brightnessosd.js b/src/components/playback/brightnessosd.js index 5ed2b8f81..5f3becd64 100644 --- a/src/components/playback/brightnessosd.js +++ b/src/components/playback/brightnessosd.js @@ -1,171 +1,171 @@ -define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'material-icons'], function (events, playbackManager, dom, browser) { - 'use strict'; +import events from 'events'; +import playbackManager from 'playbackManager'; +import dom from 'dom'; +import browser from 'browser'; +import 'css!./iconosd'; +import 'material-icons'; - var currentPlayer; - var osdElement; - var iconElement; - var progressElement; +var currentPlayer; +var osdElement; +var iconElement; +var progressElement; - var enableAnimation; +var enableAnimation; - function getOsdElementHtml() { - var html = ''; +function getOsdElementHtml() { + var html = ''; - html += ''; + html += ''; - html += '
'; + html += '
'; - return html; + return html; +} + +function ensureOsdElement() { + + var elem = osdElement; + if (!elem) { + + enableAnimation = browser.supportsCssAnimation(); + + elem = document.createElement('div'); + elem.classList.add('hide'); + elem.classList.add('iconOsd'); + elem.classList.add('iconOsd-hidden'); + elem.classList.add('brightnessOsd'); + elem.innerHTML = getOsdElementHtml(); + + iconElement = elem.querySelector('.material-icons'); + progressElement = elem.querySelector('.iconOsdProgressInner'); + + document.body.appendChild(elem); + osdElement = elem; } +} - function ensureOsdElement() { +function onHideComplete() { + this.classList.add('hide'); +} - var elem = osdElement; - if (!elem) { +var hideTimeout; +function showOsd() { - enableAnimation = browser.supportsCssAnimation(); + clearHideTimeout(); - elem = document.createElement('div'); - elem.classList.add('hide'); - elem.classList.add('iconOsd'); - elem.classList.add('iconOsd-hidden'); - elem.classList.add('brightnessOsd'); - elem.innerHTML = getOsdElementHtml(); + var elem = osdElement; - iconElement = elem.querySelector('.material-icons'); - progressElement = elem.querySelector('.iconOsdProgressInner'); - - document.body.appendChild(elem); - osdElement = elem; - } - } - - function onHideComplete() { - this.classList.add('hide'); - } - - var hideTimeout; - function showOsd() { - - clearHideTimeout(); - - var elem = osdElement; - - dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { - once: true - }); - - elem.classList.remove('hide'); - - // trigger reflow - void elem.offsetWidth; - - requestAnimationFrame(function () { - elem.classList.remove('iconOsd-hidden'); - - hideTimeout = setTimeout(hideOsd, 3000); - }); - } - - function clearHideTimeout() { - if (hideTimeout) { - clearTimeout(hideTimeout); - hideTimeout = null; - } - } - - function hideOsd() { - - clearHideTimeout(); - - var elem = osdElement; - if (elem) { - - if (enableAnimation) { - // trigger reflow - void elem.offsetWidth; - - requestAnimationFrame(function () { - elem.classList.add('iconOsd-hidden'); - - dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { - once: true - }); - }); - } else { - onHideComplete.call(elem); - } - } - } - - function setIcon(iconElement, icon) { - iconElement.classList.remove('brightness_high'); - iconElement.classList.remove('brightness_medium'); - iconElement.classList.remove('brightness_low'); - iconElement.classList.add(icon); - } - - function updateElementsFromPlayer(brightness) { - - if (iconElement) { - if (brightness >= 80) { - setIcon(iconElement, 'brightness_high'); - } else if (brightness >= 20) { - setIcon(iconElement, 'brightness_medium'); - } else { - setIcon(iconElement, 'brightness_low'); - } - } - if (progressElement) { - progressElement.style.width = (brightness || 0) + '%'; - } - } - - function releaseCurrentPlayer() { - - var player = currentPlayer; - - if (player) { - events.off(player, 'brightnesschange', onBrightnessChanged); - events.off(player, 'playbackstop', hideOsd); - currentPlayer = null; - } - } - - function onBrightnessChanged(e) { - - var player = this; - - ensureOsdElement(); - - updateElementsFromPlayer(playbackManager.getBrightness(player)); - - showOsd(); - } - - function bindToPlayer(player) { - - if (player === currentPlayer) { - return; - } - - releaseCurrentPlayer(); - - currentPlayer = player; - - if (!player) { - return; - } - - hideOsd(); - events.on(player, 'brightnesschange', onBrightnessChanged); - events.on(player, 'playbackstop', hideOsd); - } - - events.on(playbackManager, 'playerchange', function () { - bindToPlayer(playbackManager.getCurrentPlayer()); + dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { + once: true }); - bindToPlayer(playbackManager.getCurrentPlayer()); + elem.classList.remove('hide'); + // trigger reflow + void elem.offsetWidth; + + requestAnimationFrame(function () { + elem.classList.remove('iconOsd-hidden'); + + hideTimeout = setTimeout(hideOsd, 3000); + }); +} + +function clearHideTimeout() { + if (hideTimeout) { + clearTimeout(hideTimeout); + hideTimeout = null; + } +} + +function hideOsd() { + + clearHideTimeout(); + + var elem = osdElement; + if (elem) { + + if (enableAnimation) { + // trigger reflow + void elem.offsetWidth; + + requestAnimationFrame(function () { + elem.classList.add('iconOsd-hidden'); + + dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { + once: true + }); + }); + } else { + onHideComplete.call(elem); + } + } +} + +function setIcon(iconElement, icon) { + iconElement.classList.remove('brightness_high', 'brightness_medium', 'brightness_low'); + iconElement.classList.add(icon); +} + +function updateElementsFromPlayer(brightness) { + + if (iconElement) { + if (brightness >= 80) { + setIcon(iconElement, 'brightness_high'); + } else if (brightness >= 20) { + setIcon(iconElement, 'brightness_medium'); + } else { + setIcon(iconElement, 'brightness_low'); + } + } + if (progressElement) { + progressElement.style.width = (brightness || 0) + '%'; + } +} + +function releaseCurrentPlayer() { + + var player = currentPlayer; + + if (player) { + events.off(player, 'brightnesschange', onBrightnessChanged); + events.off(player, 'playbackstop', hideOsd); + currentPlayer = null; + } +} + +function onBrightnessChanged(e) { + + var player = this; + + ensureOsdElement(); + + updateElementsFromPlayer(playbackManager.getBrightness(player)); + + showOsd(); +} + +function bindToPlayer(player) { + + if (player === currentPlayer) { + return; + } + + releaseCurrentPlayer(); + + currentPlayer = player; + + if (!player) { + return; + } + + hideOsd(); + events.on(player, 'brightnesschange', onBrightnessChanged); + events.on(player, 'playbackstop', hideOsd); +} + +events.on(playbackManager, 'playerchange', function () { + bindToPlayer(playbackManager.getCurrentPlayer()); }); + +bindToPlayer(playbackManager.getCurrentPlayer()); diff --git a/src/components/playback/nowplayinghelper.js b/src/components/playback/nowplayinghelper.js index 9bba23c29..310edc03c 100644 --- a/src/components/playback/nowplayinghelper.js +++ b/src/components/playback/nowplayinghelper.js @@ -1,86 +1,82 @@ -define([], function () { - 'use strict'; +export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) { - function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) { + var topItem = nowPlayingItem; + var bottomItem = null; + var topText = nowPlayingItem.Name; - var topItem = nowPlayingItem; - var bottomItem = null; - var topText = nowPlayingItem.Name; - - if (nowPlayingItem.AlbumId && nowPlayingItem.MediaType === 'Audio') { - topItem = { - Id: nowPlayingItem.AlbumId, - Name: nowPlayingItem.Album, - Type: 'MusicAlbum', - IsFolder: true - }; - } - - if (nowPlayingItem.MediaType === 'Video') { - if (nowPlayingItem.IndexNumber != null) { - topText = nowPlayingItem.IndexNumber + ' - ' + topText; - } - if (nowPlayingItem.ParentIndexNumber != null) { - topText = nowPlayingItem.ParentIndexNumber + '.' + topText; - } - } - - var bottomText = ''; - - if (nowPlayingItem.ArtistItems && nowPlayingItem.ArtistItems.length) { - - bottomItem = { - Id: nowPlayingItem.ArtistItems[0].Id, - Name: nowPlayingItem.ArtistItems[0].Name, - Type: 'MusicArtist', - IsFolder: true - }; - - bottomText = nowPlayingItem.ArtistItems.map(function (a) { - return a.Name; - }).join(', '); - - } else if (nowPlayingItem.Artists && nowPlayingItem.Artists.length) { - - bottomText = nowPlayingItem.Artists.join(', '); - } else if (nowPlayingItem.SeriesName || nowPlayingItem.Album) { - bottomText = topText; - topText = nowPlayingItem.SeriesName || nowPlayingItem.Album; - - bottomItem = topItem; - - if (nowPlayingItem.SeriesId) { - topItem = { - Id: nowPlayingItem.SeriesId, - Name: nowPlayingItem.SeriesName, - Type: 'Series', - IsFolder: true - }; - } else { - topItem = null; - } - } else if (nowPlayingItem.ProductionYear && includeNonNameInfo !== false) { - bottomText = nowPlayingItem.ProductionYear; - } - - var list = []; - - list.push({ - text: topText, - item: topItem - }); - - if (bottomText) { - list.push({ - text: bottomText, - item: bottomItem - }); - } - - return list; + if (nowPlayingItem.AlbumId && nowPlayingItem.MediaType === 'Audio') { + topItem = { + Id: nowPlayingItem.AlbumId, + Name: nowPlayingItem.Album, + Type: 'MusicAlbum', + IsFolder: true + }; } - return { - getNowPlayingNames: getNowPlayingNames - }; -}); + if (nowPlayingItem.MediaType === 'Video') { + if (nowPlayingItem.IndexNumber != null) { + topText = nowPlayingItem.IndexNumber + ' - ' + topText; + } + if (nowPlayingItem.ParentIndexNumber != null) { + topText = nowPlayingItem.ParentIndexNumber + '.' + topText; + } + } + + var bottomText = ''; + + if (nowPlayingItem.ArtistItems && nowPlayingItem.ArtistItems.length) { + + bottomItem = { + Id: nowPlayingItem.ArtistItems[0].Id, + Name: nowPlayingItem.ArtistItems[0].Name, + Type: 'MusicArtist', + IsFolder: true + }; + + bottomText = nowPlayingItem.ArtistItems.map(function (a) { + return a.Name; + }).join(', '); + + } else if (nowPlayingItem.Artists && nowPlayingItem.Artists.length) { + + bottomText = nowPlayingItem.Artists.join(', '); + } else if (nowPlayingItem.SeriesName || nowPlayingItem.Album) { + bottomText = topText; + topText = nowPlayingItem.SeriesName || nowPlayingItem.Album; + + bottomItem = topItem; + + if (nowPlayingItem.SeriesId) { + topItem = { + Id: nowPlayingItem.SeriesId, + Name: nowPlayingItem.SeriesName, + Type: 'Series', + IsFolder: true + }; + } else { + topItem = null; + } + } else if (nowPlayingItem.ProductionYear && includeNonNameInfo !== false) { + bottomText = nowPlayingItem.ProductionYear; + } + + var list = []; + + list.push({ + text: topText, + item: topItem + }); + + if (bottomText) { + list.push({ + text: bottomText, + item: bottomItem + }); + } + + return list; +} + +export default { + getNowPlayingNames: getNowPlayingNames +}; diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 88d4e0d59..73f07a05f 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1907,11 +1907,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla // Setting this to true may cause some incorrect sorting Recursive: false, SortBy: options.shuffle ? 'Random' : 'SortName', - MediaTypes: 'Photo,Video', - Limit: 500 - + MediaTypes: 'Photo,Video' }).then(function (result) { - var items = result.Items; var index = items.map(function (i) { diff --git a/src/components/playback/playbackorientation.js b/src/components/playback/playbackorientation.js index 654ac2984..2078c6f6a 100644 --- a/src/components/playback/playbackorientation.js +++ b/src/components/playback/playbackorientation.js @@ -1,57 +1,57 @@ -define(['playbackManager', 'layoutManager', 'events'], function (playbackManager, layoutManager, events) { - 'use strict'; +import playbackManager from 'playbackManager'; +import layoutManager from 'layoutManager'; +import events from 'events'; - var orientationLocked; +var orientationLocked; - function onOrientationChangeSuccess() { - orientationLocked = true; - } +function onOrientationChangeSuccess() { + orientationLocked = true; +} - function onOrientationChangeError(err) { - orientationLocked = false; - console.error('error locking orientation: ' + err); - } +function onOrientationChangeError(err) { + orientationLocked = false; + console.error('error locking orientation: ' + err); +} - events.on(playbackManager, 'playbackstart', function (e, player, state) { +events.on(playbackManager, 'playbackstart', function (e, player, state) { - var isLocalVideo = player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player); + var isLocalVideo = player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player); - if (isLocalVideo && layoutManager.mobile) { - /* eslint-disable-next-line compat/compat */ - var lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation || (screen.orientation && screen.orientation.lock); + if (isLocalVideo && layoutManager.mobile) { + /* eslint-disable-next-line compat/compat */ + var lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation || (screen.orientation && screen.orientation.lock); - if (lockOrientation) { + if (lockOrientation) { - try { - var promise = lockOrientation('landscape'); - if (promise.then) { - promise.then(onOrientationChangeSuccess, onOrientationChangeError); - } else { - // returns a boolean - orientationLocked = promise; - } - } catch (err) { - onOrientationChangeError(err); + try { + var promise = lockOrientation('landscape'); + if (promise.then) { + promise.then(onOrientationChangeSuccess, onOrientationChangeError); + } else { + // returns a boolean + orientationLocked = promise; } + } catch (err) { + onOrientationChangeError(err); } } - }); - - events.on(playbackManager, 'playbackstop', function (e, playbackStopInfo) { - - if (orientationLocked && !playbackStopInfo.nextMediaType) { - - /* eslint-disable-next-line compat/compat */ - var unlockOrientation = screen.unlockOrientation || screen.mozUnlockOrientation || screen.msUnlockOrientation || (screen.orientation && screen.orientation.unlock); - - if (unlockOrientation) { - try { - unlockOrientation(); - } catch (err) { - console.error('error unlocking orientation: ' + err); - } - orientationLocked = false; - } - } - }); + } +}); + +events.on(playbackManager, 'playbackstop', function (e, playbackStopInfo) { + + if (orientationLocked && !playbackStopInfo.nextMediaType) { + + /* eslint-disable-next-line compat/compat */ + var unlockOrientation = screen.unlockOrientation || screen.mozUnlockOrientation || screen.msUnlockOrientation || (screen.orientation && screen.orientation.unlock); + + if (unlockOrientation) { + try { + unlockOrientation(); + } catch (err) { + console.error('error unlocking orientation: ' + err); + } + orientationLocked = false; + } + } }); diff --git a/src/components/playback/playerSelectionMenu.js b/src/components/playback/playerSelectionMenu.js index 329cc11f9..91b1ddc20 100644 --- a/src/components/playback/playerSelectionMenu.js +++ b/src/components/playback/playerSelectionMenu.js @@ -1,320 +1,325 @@ -define(['appSettings', 'events', 'browser', 'loading', 'playbackManager', 'appRouter', 'globalize', 'apphost'], function (appSettings, events, browser, loading, playbackManager, appRouter, globalize, appHost) { - 'use strict'; +import appSettings from 'appSettings'; +import events from 'events'; +import browser from 'browser'; +import loading from 'loading'; +import playbackManager from 'playbackManager'; +import appRouter from 'appRouter'; +import globalize from 'globalize'; +import appHost from 'apphost'; - function mirrorItem(info, player) { +function mirrorItem(info, player) { - var item = info.item; + var item = info.item; - playbackManager.displayContent({ + playbackManager.displayContent({ - ItemName: item.Name, - ItemId: item.Id, - ItemType: item.Type, - Context: info.context - }, player); - } + ItemName: item.Name, + ItemId: item.Id, + ItemType: item.Type, + Context: info.context + }, player); +} - function mirrorIfEnabled(info) { +function mirrorIfEnabled(info) { - if (info && playbackManager.enableDisplayMirroring()) { + if (info && playbackManager.enableDisplayMirroring()) { - var getPlayerInfo = playbackManager.getPlayerInfo(); + var getPlayerInfo = playbackManager.getPlayerInfo(); - if (getPlayerInfo) { - if (!getPlayerInfo.isLocalPlayer && getPlayerInfo.supportedCommands.indexOf('DisplayContent') !== -1) { - mirrorItem(info, playbackManager.getCurrentPlayer()); - } + if (getPlayerInfo) { + if (!getPlayerInfo.isLocalPlayer && getPlayerInfo.supportedCommands.indexOf('DisplayContent') !== -1) { + mirrorItem(info, playbackManager.getCurrentPlayer()); } } } +} - function emptyCallback() { - // avoid console logs about uncaught promises +function emptyCallback() { + // avoid console logs about uncaught promises +} + +function getTargetSecondaryText(target) { + + if (target.user) { + + return target.user.Name; } - function getTargetSecondaryText(target) { + return null; +} - if (target.user) { +function getIcon(target) { - return target.user.Name; - } + var deviceType = target.deviceType; - return null; - } - - function getIcon(target) { - - var deviceType = target.deviceType; - - if (!deviceType && target.isLocalPlayer) { - if (browser.tv) { - deviceType = 'tv'; - } else if (browser.mobile) { - deviceType = 'smartphone'; - } else { - deviceType = 'desktop'; - } - } - - if (!deviceType) { + if (!deviceType && target.isLocalPlayer) { + if (browser.tv) { deviceType = 'tv'; - } - - switch (deviceType) { - - case 'smartphone': - return 'smartphone'; - case 'tablet': - return 'tablet'; - case 'tv': - return 'tv'; - case 'cast': - return 'cast'; - case 'desktop': - return 'computer'; - default: - return 'tv'; - } - } - - function showPlayerSelection(button) { - - var currentPlayerInfo = playbackManager.getPlayerInfo(); - - if (currentPlayerInfo) { - if (!currentPlayerInfo.isLocalPlayer) { - showActivePlayerMenu(currentPlayerInfo); - return; - } - } - - var currentPlayerId = currentPlayerInfo ? currentPlayerInfo.id : null; - - loading.show(); - - playbackManager.getTargets().then(function (targets) { - - var menuItems = targets.map(function (t) { - - var name = t.name; - - if (t.appName && t.appName !== t.name) { - name += ' - ' + t.appName; - } - - return { - name: name, - id: t.id, - selected: currentPlayerId === t.id, - secondaryText: getTargetSecondaryText(t), - icon: getIcon(t) - }; - - }); - - require(['actionsheet'], function (actionsheet) { - - loading.hide(); - - var menuOptions = { - title: globalize.translate('HeaderPlayOn'), - items: menuItems, - positionTo: button, - - resolveOnClick: true, - border: true - }; - - // Unfortunately we can't allow the url to change or chromecast will throw a security error - // Might be able to solve this in the future by moving the dialogs to hashbangs - if (!(!browser.chrome || appHost.supports('castmenuhashchange'))) { - menuOptions.enableHistory = false; - } - - actionsheet.show(menuOptions).then(function (id) { - - var target = targets.filter(function (t) { - return t.id === id; - })[0]; - - playbackManager.trySetActivePlayer(target.playerName, target); - - mirrorIfEnabled(); - - }, emptyCallback); - }); - }); - } - - function showActivePlayerMenu(playerInfo) { - - require(['dialogHelper', 'dialog', 'emby-checkbox', 'emby-button'], function (dialogHelper) { - showActivePlayerMenuInternal(dialogHelper, playerInfo); - }); - } - - function disconnectFromPlayer(currentDeviceName) { - - if (playbackManager.getSupportedCommands().indexOf('EndSession') !== -1) { - - require(['dialog'], function (dialog) { - - var menuItems = []; - - menuItems.push({ - name: globalize.translate('Yes'), - id: 'yes' - }); - menuItems.push({ - name: globalize.translate('No'), - id: 'no' - }); - - dialog({ - buttons: menuItems, - //positionTo: positionTo, - text: globalize.translate('ConfirmEndPlayerSession', currentDeviceName) - - }).then(function (id) { - switch (id) { - - case 'yes': - playbackManager.getCurrentPlayer().endSession(); - playbackManager.setDefaultPlayerActive(); - break; - case 'no': - playbackManager.setDefaultPlayerActive(); - break; - default: - break; - } - }); - - }); - + } else if (browser.mobile) { + deviceType = 'smartphone'; } else { - - playbackManager.setDefaultPlayerActive(); + deviceType = 'desktop'; } } - function showActivePlayerMenuInternal(dialogHelper, playerInfo) { - - var html = ''; - - var dialogOptions = { - removeOnClose: true - }; - - dialogOptions.modal = false; - dialogOptions.entryAnimationDuration = 160; - dialogOptions.exitAnimationDuration = 160; - dialogOptions.autoFocus = false; - - var dlg = dialogHelper.createDialog(dialogOptions); - - dlg.classList.add('promptDialog'); - - var currentDeviceName = (playerInfo.deviceName || playerInfo.name); - - html += '
'; - html += '

'; - html += currentDeviceName; - html += '

'; - - html += '
'; - - if (playerInfo.supportedCommands.indexOf('DisplayContent') !== -1) { - - html += ''; - } - - html += '
'; - - html += '
'; - - html += ''; - html += ''; - html += ''; - html += '
'; - - html += '
'; - dlg.innerHTML = html; - - var chkMirror = dlg.querySelector('.chkMirror'); - - if (chkMirror) { - chkMirror.addEventListener('change', onMirrorChange); - } - - var destination = ''; - - var btnRemoteControl = dlg.querySelector('.btnRemoteControl'); - if (btnRemoteControl) { - btnRemoteControl.addEventListener('click', function () { - destination = 'nowplaying'; - dialogHelper.close(dlg); - }); - } - - dlg.querySelector('.btnDisconnect').addEventListener('click', function () { - destination = 'disconnectFromPlayer'; - dialogHelper.close(dlg); - }); - - dlg.querySelector('.btnCancel').addEventListener('click', function () { - dialogHelper.close(dlg); - }); - - dialogHelper.open(dlg).then(function () { - if (destination === 'nowplaying') { - appRouter.showNowPlaying(); - } else if (destination === 'disconnectFromPlayer') { - disconnectFromPlayer(currentDeviceName); - } - }, emptyCallback); + if (!deviceType) { + deviceType = 'tv'; } - function onMirrorChange() { - playbackManager.enableDisplayMirroring(this.checked); + switch (deviceType) { + + case 'smartphone': + return 'smartphone'; + case 'tablet': + return 'tablet'; + case 'tv': + return 'tv'; + case 'cast': + return 'cast'; + case 'desktop': + return 'computer'; + default: + return 'tv'; } +} - document.addEventListener('viewshow', function (e) { +export function show(button) { - var state = e.detail.state || {}; - var item = state.item; + var currentPlayerInfo = playbackManager.getPlayerInfo(); - if (item && item.ServerId) { - mirrorIfEnabled({ - item: item - }); + if (currentPlayerInfo) { + if (!currentPlayerInfo.isLocalPlayer) { + showActivePlayerMenu(currentPlayerInfo); return; } - }); + } - events.on(appSettings, 'change', function (e, name) { - if (name === 'displaymirror') { - mirrorIfEnabled(); - } - }); + var currentPlayerId = currentPlayerInfo ? currentPlayerInfo.id : null; - events.on(playbackManager, 'pairing', function (e) { - loading.show(); - }); + loading.show(); - events.on(playbackManager, 'paired', function (e) { - loading.hide(); - }); + playbackManager.getTargets().then(function (targets) { - events.on(playbackManager, 'pairerror', function (e) { - loading.hide(); - }); + var menuItems = targets.map(function (t) { - return { - show: showPlayerSelection + var name = t.name; + + if (t.appName && t.appName !== t.name) { + name += ' - ' + t.appName; + } + + return { + name: name, + id: t.id, + selected: currentPlayerId === t.id, + secondaryText: getTargetSecondaryText(t), + icon: getIcon(t) + }; + + }); + + require(['actionsheet'], function (actionsheet) { + + loading.hide(); + + var menuOptions = { + title: globalize.translate('HeaderPlayOn'), + items: menuItems, + positionTo: button, + + resolveOnClick: true, + border: true + }; + + // Unfortunately we can't allow the url to change or chromecast will throw a security error + // Might be able to solve this in the future by moving the dialogs to hashbangs + if (!(!browser.chrome || appHost.supports('castmenuhashchange'))) { + menuOptions.enableHistory = false; + } + + actionsheet.show(menuOptions).then(function (id) { + + var target = targets.filter(function (t) { + return t.id === id; + })[0]; + + playbackManager.trySetActivePlayer(target.playerName, target); + + mirrorIfEnabled(); + + }, emptyCallback); + }); + }); +} + +function showActivePlayerMenu(playerInfo) { + + require(['dialogHelper', 'dialog', 'emby-checkbox', 'emby-button'], function (dialogHelper) { + showActivePlayerMenuInternal(dialogHelper, playerInfo); + }); +} + +function disconnectFromPlayer(currentDeviceName) { + + if (playbackManager.getSupportedCommands().indexOf('EndSession') !== -1) { + + require(['dialog'], function (dialog) { + + var menuItems = []; + + menuItems.push({ + name: globalize.translate('Yes'), + id: 'yes' + }); + menuItems.push({ + name: globalize.translate('No'), + id: 'no' + }); + + dialog({ + buttons: menuItems, + //positionTo: positionTo, + text: globalize.translate('ConfirmEndPlayerSession', currentDeviceName) + + }).then(function (id) { + switch (id) { + + case 'yes': + playbackManager.getCurrentPlayer().endSession(); + playbackManager.setDefaultPlayerActive(); + break; + case 'no': + playbackManager.setDefaultPlayerActive(); + break; + default: + break; + } + }); + + }); + + } else { + + playbackManager.setDefaultPlayerActive(); + } +} + +function showActivePlayerMenuInternal(dialogHelper, playerInfo) { + + var html = ''; + + var dialogOptions = { + removeOnClose: true }; + + dialogOptions.modal = false; + dialogOptions.entryAnimationDuration = 160; + dialogOptions.exitAnimationDuration = 160; + dialogOptions.autoFocus = false; + + var dlg = dialogHelper.createDialog(dialogOptions); + + dlg.classList.add('promptDialog'); + + var currentDeviceName = (playerInfo.deviceName || playerInfo.name); + + html += '
'; + html += '

'; + html += currentDeviceName; + html += '

'; + + html += '
'; + + if (playerInfo.supportedCommands.indexOf('DisplayContent') !== -1) { + + html += ''; + } + + html += '
'; + + html += '
'; + + html += ''; + html += ''; + html += ''; + html += '
'; + + html += '
'; + dlg.innerHTML = html; + + var chkMirror = dlg.querySelector('.chkMirror'); + + if (chkMirror) { + chkMirror.addEventListener('change', onMirrorChange); + } + + var destination = ''; + + var btnRemoteControl = dlg.querySelector('.btnRemoteControl'); + if (btnRemoteControl) { + btnRemoteControl.addEventListener('click', function () { + destination = 'nowplaying'; + dialogHelper.close(dlg); + }); + } + + dlg.querySelector('.btnDisconnect').addEventListener('click', function () { + destination = 'disconnectFromPlayer'; + dialogHelper.close(dlg); + }); + + dlg.querySelector('.btnCancel').addEventListener('click', function () { + dialogHelper.close(dlg); + }); + + dialogHelper.open(dlg).then(function () { + if (destination === 'nowplaying') { + appRouter.showNowPlaying(); + } else if (destination === 'disconnectFromPlayer') { + disconnectFromPlayer(currentDeviceName); + } + }, emptyCallback); +} + +function onMirrorChange() { + playbackManager.enableDisplayMirroring(this.checked); +} + +document.addEventListener('viewshow', function (e) { + + var state = e.detail.state || {}; + var item = state.item; + + if (item && item.ServerId) { + mirrorIfEnabled({ + item: item + }); + return; + } }); + +events.on(appSettings, 'change', function (e, name) { + if (name === 'displaymirror') { + mirrorIfEnabled(); + } +}); + +events.on(playbackManager, 'pairing', function (e) { + loading.show(); +}); + +events.on(playbackManager, 'paired', function (e) { + loading.hide(); +}); + +events.on(playbackManager, 'pairerror', function (e) { + loading.hide(); +}); + +export default { + show: show +}; diff --git a/src/components/playback/playersettingsmenu.js b/src/components/playback/playersettingsmenu.js index dd67b667e..33d252c52 100644 --- a/src/components/playback/playersettingsmenu.js +++ b/src/components/playback/playersettingsmenu.js @@ -1,270 +1,272 @@ -define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'globalize', 'appSettings', 'qualityoptions'], function (connectionManager, actionsheet, datetime, playbackManager, globalize, appSettings, qualityoptions) { - 'use strict'; +import connectionManager from 'connectionManager'; +import actionsheet from 'actionsheet'; +import playbackManager from 'playbackManager'; +import globalize from 'globalize'; +import qualityoptions from 'qualityoptions'; - function showQualityMenu(player, btn) { +function showQualityMenu(player, btn) { - var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { - return stream.Type === 'Video'; - })[0]; - var videoWidth = videoStream ? videoStream.Width : null; - var videoHeight = videoStream ? videoStream.Height : null; + var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { + return stream.Type === 'Video'; + })[0]; + var videoWidth = videoStream ? videoStream.Width : null; + var videoHeight = videoStream ? videoStream.Height : null; - var options = qualityoptions.getVideoQualityOptions({ - currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player), - isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player), - videoWidth: videoWidth, - videoHeight: videoHeight, - enableAuto: true - }); + var options = qualityoptions.getVideoQualityOptions({ + currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player), + isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player), + videoWidth: videoWidth, + videoHeight: videoHeight, + enableAuto: true + }); - var menuItems = options.map(function (o) { - var opt = { - name: o.name, - id: o.bitrate, - asideText: o.secondaryText - }; + var menuItems = options.map(function (o) { + var opt = { + name: o.name, + id: o.bitrate, + asideText: o.secondaryText + }; - if (o.selected) { - opt.selected = true; - } + if (o.selected) { + opt.selected = true; + } - return opt; - }); + return opt; + }); - var selectedId = options.filter(function (o) { - return o.selected; - }); + var selectedId = options.filter(function (o) { + return o.selected; + }); - selectedId = selectedId.length ? selectedId[0].bitrate : null; + selectedId = selectedId.length ? selectedId[0].bitrate : null; - return actionsheet.show({ - items: menuItems, - positionTo: btn - }).then(function (id) { - var bitrate = parseInt(id); - if (bitrate !== selectedId) { - playbackManager.setMaxStreamingBitrate({ - enableAutomaticBitrateDetection: bitrate ? false : true, - maxBitrate: bitrate - }, player); - } - }); + return actionsheet.show({ + items: menuItems, + positionTo: btn + }).then(function (id) { + var bitrate = parseInt(id); + if (bitrate !== selectedId) { + playbackManager.setMaxStreamingBitrate({ + enableAutomaticBitrateDetection: bitrate ? false : true, + maxBitrate: bitrate + }, player); + } + }); +} + +function showRepeatModeMenu(player, btn) { + var menuItems = []; + var currentValue = playbackManager.getRepeatMode(player); + + menuItems.push({ + name: globalize.translate('RepeatAll'), + id: 'RepeatAll', + selected: currentValue === 'RepeatAll' + }); + + menuItems.push({ + name: globalize.translate('RepeatOne'), + id: 'RepeatOne', + selected: currentValue === 'RepeatOne' + }); + + menuItems.push({ + name: globalize.translate('None'), + id: 'RepeatNone', + selected: currentValue === 'RepeatNone' + }); + + return actionsheet.show({ + items: menuItems, + positionTo: btn + }).then(function (mode) { + if (mode) { + playbackManager.setRepeatMode(mode, player); + } + }); +} + +function getQualitySecondaryText(player) { + var state = playbackManager.getPlayerState(player); + var isAutoEnabled = playbackManager.enableAutomaticBitrateDetection(player); + var currentMaxBitrate = playbackManager.getMaxStreamingBitrate(player); + + var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { + return stream.Type === 'Video'; + })[0]; + + var videoWidth = videoStream ? videoStream.Width : null; + var videoHeight = videoStream ? videoStream.Height : null; + + var options = qualityoptions.getVideoQualityOptions({ + currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player), + isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player), + videoWidth: videoWidth, + videoHeight: videoHeight, + enableAuto: true + }); + + var menuItems = options.map(function (o) { + var opt = { + name: o.name, + id: o.bitrate, + asideText: o.secondaryText + }; + + if (o.selected) { + opt.selected = true; + } + + return opt; + }); + + var selectedOption = options.filter(function (o) { + return o.selected; + }); + + if (!selectedOption.length) { + return null; } - function showRepeatModeMenu(player, btn) { - var menuItems = []; - var currentValue = playbackManager.getRepeatMode(player); + selectedOption = selectedOption[0]; + var text = selectedOption.name; - menuItems.push({ - name: globalize.translate('RepeatAll'), - id: 'RepeatAll', - selected: currentValue === 'RepeatAll' - }); - - menuItems.push({ - name: globalize.translate('RepeatOne'), - id: 'RepeatOne', - selected: currentValue === 'RepeatOne' - }); - - menuItems.push({ - name: globalize.translate('None'), - id: 'RepeatNone', - selected: currentValue === 'RepeatNone' - }); - - return actionsheet.show({ - items: menuItems, - positionTo: btn - }).then(function (mode) { - if (mode) { - playbackManager.setRepeatMode(mode, player); - } - }); + if (selectedOption.autoText) { + if (state.PlayState && state.PlayState.PlayMethod !== 'Transcode') { + text += ' - Direct'; + } else { + text += ' ' + selectedOption.autoText; + } } - function getQualitySecondaryText(player) { - var state = playbackManager.getPlayerState(player); - var isAutoEnabled = playbackManager.enableAutomaticBitrateDetection(player); - var currentMaxBitrate = playbackManager.getMaxStreamingBitrate(player); + return text; +} - var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { - return stream.Type === 'Video'; - })[0]; +function showAspectRatioMenu(player, btn) { + // each has a name and id + var currentId = playbackManager.getAspectRatio(player); + var menuItems = playbackManager.getSupportedAspectRatios(player).map(function (i) { + return { + id: i.id, + name: i.name, + selected: i.id === currentId + }; + }); - var videoWidth = videoStream ? videoStream.Width : null; - var videoHeight = videoStream ? videoStream.Height : null; - - var options = qualityoptions.getVideoQualityOptions({ - currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player), - isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player), - videoWidth: videoWidth, - videoHeight: videoHeight, - enableAuto: true - }); - - var menuItems = options.map(function (o) { - var opt = { - name: o.name, - id: o.bitrate, - asideText: o.secondaryText - }; - - if (o.selected) { - opt.selected = true; - } - - return opt; - }); - - var selectedOption = options.filter(function (o) { - return o.selected; - }); - - if (!selectedOption.length) { - return null; - } - - selectedOption = selectedOption[0]; - var text = selectedOption.name; - - if (selectedOption.autoText) { - if (state.PlayState && state.PlayState.PlayMethod !== 'Transcode') { - text += ' - Direct'; - } else { - text += ' ' + selectedOption.autoText; - } - } - - return text; - } - - function showAspectRatioMenu(player, btn) { - // each has a name and id - var currentId = playbackManager.getAspectRatio(player); - var menuItems = playbackManager.getSupportedAspectRatios(player).map(function (i) { - return { - id: i.id, - name: i.name, - selected: i.id === currentId - }; - }); - - return actionsheet.show({ - items: menuItems, - positionTo: btn - }).then(function (id) { - if (id) { - playbackManager.setAspectRatio(id, player); - return Promise.resolve(); - } - - return Promise.reject(); - }); - } - - function showWithUser(options, player, user) { - var supportedCommands = playbackManager.getSupportedCommands(player); - var mediaType = options.mediaType; - - var menuItems = []; - if (supportedCommands.indexOf('SetAspectRatio') !== -1) { - var currentAspectRatioId = playbackManager.getAspectRatio(player); - var currentAspectRatio = playbackManager.getSupportedAspectRatios(player).filter(function (i) { - return i.id === currentAspectRatioId; - })[0]; - - menuItems.push({ - name: globalize.translate('AspectRatio'), - id: 'aspectratio', - asideText: currentAspectRatio ? currentAspectRatio.name : null - }); - } - - if (user && user.Policy.EnableVideoPlaybackTranscoding) { - var secondaryQualityText = getQualitySecondaryText(player); - - menuItems.push({ - name: globalize.translate('Quality'), - id: 'quality', - asideText: secondaryQualityText - }); - } - - var repeatMode = playbackManager.getRepeatMode(player); - - if (supportedCommands.indexOf('SetRepeatMode') !== -1 && playbackManager.currentMediaSource(player).RunTimeTicks) { - menuItems.push({ - name: globalize.translate('RepeatMode'), - id: 'repeatmode', - asideText: repeatMode === 'RepeatNone' ? globalize.translate('None') : globalize.translate('' + repeatMode) - }); - } - - if (options.suboffset) { - menuItems.push({ - name: globalize.translate('SubtitleOffset'), - id: 'suboffset', - asideText: null - }); - } - - if (options.stats) { - menuItems.push({ - name: globalize.translate('PlaybackData'), - id: 'stats', - asideText: null - }); - } - - return actionsheet.show({ - items: menuItems, - positionTo: options.positionTo - }).then(function (id) { - return handleSelectedOption(id, options, player); - }); - } - - function show(options) { - var player = options.player; - var currentItem = playbackManager.currentItem(player); - - if (!currentItem || !currentItem.ServerId) { - return showWithUser(options, player, null); - } - - var apiClient = connectionManager.getApiClient(currentItem.ServerId); - return apiClient.getCurrentUser().then(function (user) { - return showWithUser(options, player, user); - }); - } - - function handleSelectedOption(id, options, player) { - switch (id) { - case 'quality': - return showQualityMenu(player, options.positionTo); - case 'aspectratio': - return showAspectRatioMenu(player, options.positionTo); - case 'repeatmode': - return showRepeatModeMenu(player, options.positionTo); - case 'stats': - if (options.onOption) { - options.onOption('stats'); - } - return Promise.resolve(); - case 'suboffset': - if (options.onOption) { - options.onOption('suboffset'); - } - return Promise.resolve(); - default: - break; + return actionsheet.show({ + items: menuItems, + positionTo: btn + }).then(function (id) { + if (id) { + playbackManager.setAspectRatio(id, player); + return Promise.resolve(); } return Promise.reject(); + }); +} + +function showWithUser(options, player, user) { + var supportedCommands = playbackManager.getSupportedCommands(player); + var mediaType = options.mediaType; + + var menuItems = []; + if (supportedCommands.indexOf('SetAspectRatio') !== -1) { + var currentAspectRatioId = playbackManager.getAspectRatio(player); + var currentAspectRatio = playbackManager.getSupportedAspectRatios(player).filter(function (i) { + return i.id === currentAspectRatioId; + })[0]; + + menuItems.push({ + name: globalize.translate('AspectRatio'), + id: 'aspectratio', + asideText: currentAspectRatio ? currentAspectRatio.name : null + }); } - return { - show: show - }; -}); + if (user && user.Policy.EnableVideoPlaybackTranscoding) { + var secondaryQualityText = getQualitySecondaryText(player); + + menuItems.push({ + name: globalize.translate('Quality'), + id: 'quality', + asideText: secondaryQualityText + }); + } + + var repeatMode = playbackManager.getRepeatMode(player); + + if (supportedCommands.indexOf('SetRepeatMode') !== -1 && playbackManager.currentMediaSource(player).RunTimeTicks) { + menuItems.push({ + name: globalize.translate('RepeatMode'), + id: 'repeatmode', + asideText: repeatMode === 'RepeatNone' ? globalize.translate('None') : globalize.translate('' + repeatMode) + }); + } + + if (options.suboffset) { + menuItems.push({ + name: globalize.translate('SubtitleOffset'), + id: 'suboffset', + asideText: null + }); + } + + if (options.stats) { + menuItems.push({ + name: globalize.translate('PlaybackData'), + id: 'stats', + asideText: null + }); + } + + return actionsheet.show({ + items: menuItems, + positionTo: options.positionTo + }).then(function (id) { + return handleSelectedOption(id, options, player); + }); +} + +export function show(options) { + var player = options.player; + var currentItem = playbackManager.currentItem(player); + + if (!currentItem || !currentItem.ServerId) { + return showWithUser(options, player, null); + } + + var apiClient = connectionManager.getApiClient(currentItem.ServerId); + return apiClient.getCurrentUser().then(function (user) { + return showWithUser(options, player, user); + }); +} + +function handleSelectedOption(id, options, player) { + switch (id) { + case 'quality': + return showQualityMenu(player, options.positionTo); + case 'aspectratio': + return showAspectRatioMenu(player, options.positionTo); + case 'repeatmode': + return showRepeatModeMenu(player, options.positionTo); + case 'stats': + if (options.onOption) { + options.onOption('stats'); + } + return Promise.resolve(); + case 'suboffset': + if (options.onOption) { + options.onOption('suboffset'); + } + return Promise.resolve(); + default: + break; + } + + return Promise.reject(); +} + +export default { + show: show +}; diff --git a/src/components/playback/playmethodhelper.js b/src/components/playback/playmethodhelper.js index 75af04035..62793b9a3 100644 --- a/src/components/playback/playmethodhelper.js +++ b/src/components/playback/playmethodhelper.js @@ -1,24 +1,20 @@ -define([], function () { - 'use strict'; +export function getDisplayPlayMethod(session) { - function getDisplayPlayMethod(session) { - - if (!session.NowPlayingItem) { - return null; - } - - if (session.TranscodingInfo && session.TranscodingInfo.IsVideoDirect) { - return 'DirectStream'; - } else if (session.PlayState.PlayMethod === 'Transcode') { - return 'Transcode'; - } else if (session.PlayState.PlayMethod === 'DirectStream') { - return 'DirectPlay'; - } else if (session.PlayState.PlayMethod === 'DirectPlay') { - return 'DirectPlay'; - } + if (!session.NowPlayingItem) { + return null; } - return { - getDisplayPlayMethod: getDisplayPlayMethod - }; -}); + if (session.TranscodingInfo && session.TranscodingInfo.IsVideoDirect) { + return 'DirectStream'; + } else if (session.PlayState.PlayMethod === 'Transcode') { + return 'Transcode'; + } else if (session.PlayState.PlayMethod === 'DirectStream') { + return 'DirectPlay'; + } else if (session.PlayState.PlayMethod === 'DirectPlay') { + return 'DirectPlay'; + } +} + +export default { + getDisplayPlayMethod: getDisplayPlayMethod +}; diff --git a/src/components/playback/remotecontrolautoplay.js b/src/components/playback/remotecontrolautoplay.js index 90a872cc6..c0adb57a4 100644 --- a/src/components/playback/remotecontrolautoplay.js +++ b/src/components/playback/remotecontrolautoplay.js @@ -1,47 +1,45 @@ -define(['events', 'playbackManager'], function (events, playbackManager) { - 'use strict'; +import events from 'events'; +import playbackManager from 'playbackManager'; - function transferPlayback(oldPlayer, newPlayer) { +function transferPlayback(oldPlayer, newPlayer) { + const state = playbackManager.getPlayerState(oldPlayer); + const item = state.NowPlayingItem; - var state = playbackManager.getPlayerState(oldPlayer); - - var item = state.NowPlayingItem; - - if (!item) { - return; - } - - var playState = state.PlayState || {}; - var resumePositionTicks = playState.PositionTicks || 0; - - playbackManager.stop(oldPlayer).then(function () { - - playbackManager.play({ - ids: [item.Id], - serverId: item.ServerId, - startPositionTicks: resumePositionTicks - - }, newPlayer); - }); + if (!item) { + return; } - events.on(playbackManager, 'playerchange', function (e, newPlayer, newTarget, oldPlayer) { + playbackManager.getPlaylist(oldPlayer).then(playlist => { + const playlistIds = playlist.map(x => x.Id); + const playState = state.PlayState || {}; + const resumePositionTicks = playState.PositionTicks || 0; + const playlistIndex = playlistIds.indexOf(item.Id) || 0; - if (!oldPlayer || !newPlayer) { - return; - } - - if (!oldPlayer.isLocalPlayer) { - console.debug('Skipping remote control autoplay because oldPlayer is not a local player'); - return; - } - - if (newPlayer.isLocalPlayer) { - console.debug('Skipping remote control autoplay because newPlayer is a local player'); - return; - } - - transferPlayback(oldPlayer, newPlayer); + playbackManager.stop(oldPlayer).then(() => { + playbackManager.play({ + ids: playlistIds, + serverId: item.ServerId, + startPositionTicks: resumePositionTicks, + startIndex: playlistIndex + }, newPlayer); + }); }); +} +events.on(playbackManager, 'playerchange', (e, newPlayer, newTarget, oldPlayer) => { + if (!oldPlayer || !newPlayer) { + return; + } + + if (!oldPlayer.isLocalPlayer) { + console.debug('Skipping remote control autoplay because oldPlayer is not a local player'); + return; + } + + if (newPlayer.isLocalPlayer) { + console.debug('Skipping remote control autoplay because newPlayer is a local player'); + return; + } + + transferPlayback(oldPlayer, newPlayer); }); diff --git a/src/components/playback/volumeosd.js b/src/components/playback/volumeosd.js index 95a13d769..c2f6761f5 100644 --- a/src/components/playback/volumeosd.js +++ b/src/components/playback/volumeosd.js @@ -1,159 +1,161 @@ -define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'material-icons'], function (events, playbackManager, dom, browser) { - 'use strict'; +import events from 'events'; +import playbackManager from 'playbackManager'; +import dom from 'dom'; +import browser from 'browser'; +import 'css!./iconosd'; +import 'material-icons'; - var currentPlayer; - var osdElement; - var iconElement; - var progressElement; +var currentPlayer; +var osdElement; +var iconElement; +var progressElement; - var enableAnimation; +var enableAnimation; - function getOsdElementHtml() { - var html = ''; +function getOsdElementHtml() { + var html = ''; - html += ''; + html += ''; - html += '
'; + html += '
'; - return html; + return html; +} + +function ensureOsdElement() { + + var elem = osdElement; + if (!elem) { + + enableAnimation = browser.supportsCssAnimation(); + + elem = document.createElement('div'); + elem.classList.add('hide'); + elem.classList.add('iconOsd'); + elem.classList.add('iconOsd-hidden'); + elem.classList.add('volumeOsd'); + elem.innerHTML = getOsdElementHtml(); + + iconElement = elem.querySelector('.material-icons'); + progressElement = elem.querySelector('.iconOsdProgressInner'); + + document.body.appendChild(elem); + osdElement = elem; } +} - function ensureOsdElement() { +function onHideComplete() { + this.classList.add('hide'); +} - var elem = osdElement; - if (!elem) { +var hideTimeout; +function showOsd() { - enableAnimation = browser.supportsCssAnimation(); + clearHideTimeout(); - elem = document.createElement('div'); - elem.classList.add('hide'); - elem.classList.add('iconOsd'); - elem.classList.add('iconOsd-hidden'); - elem.classList.add('volumeOsd'); - elem.innerHTML = getOsdElementHtml(); + var elem = osdElement; - iconElement = elem.querySelector('.material-icons'); - progressElement = elem.querySelector('.iconOsdProgressInner'); - - document.body.appendChild(elem); - osdElement = elem; - } - } - - function onHideComplete() { - this.classList.add('hide'); - } - - var hideTimeout; - function showOsd() { - - clearHideTimeout(); - - var elem = osdElement; - - dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { - once: true - }); - - elem.classList.remove('hide'); - - // trigger reflow - void elem.offsetWidth; - - requestAnimationFrame(function () { - elem.classList.remove('iconOsd-hidden'); - - hideTimeout = setTimeout(hideOsd, 3000); - }); - } - - function clearHideTimeout() { - if (hideTimeout) { - clearTimeout(hideTimeout); - hideTimeout = null; - } - } - - function hideOsd() { - - clearHideTimeout(); - - var elem = osdElement; - if (elem) { - - if (enableAnimation) { - // trigger reflow - void elem.offsetWidth; - - requestAnimationFrame(function () { - elem.classList.add('iconOsd-hidden'); - - dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { - once: true - }); - }); - } else { - onHideComplete.call(elem); - } - } - } - - function updatePlayerVolumeState(isMuted, volume) { - - if (iconElement) { - iconElement.classList.remove('volume_off', 'volume_up'); - iconElement.classList.add(isMuted ? 'volume_off' : 'volume_up'); - } - if (progressElement) { - progressElement.style.width = (volume || 0) + '%'; - } - } - - function releaseCurrentPlayer() { - - var player = currentPlayer; - - if (player) { - events.off(player, 'volumechange', onVolumeChanged); - events.off(player, 'playbackstop', hideOsd); - currentPlayer = null; - } - } - - function onVolumeChanged(e) { - - var player = this; - - ensureOsdElement(); - - updatePlayerVolumeState(player.isMuted(), player.getVolume()); - - showOsd(); - } - - function bindToPlayer(player) { - - if (player === currentPlayer) { - return; - } - - releaseCurrentPlayer(); - - currentPlayer = player; - - if (!player) { - return; - } - - hideOsd(); - events.on(player, 'volumechange', onVolumeChanged); - events.on(player, 'playbackstop', hideOsd); - } - - events.on(playbackManager, 'playerchange', function () { - bindToPlayer(playbackManager.getCurrentPlayer()); + dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { + once: true }); - bindToPlayer(playbackManager.getCurrentPlayer()); + elem.classList.remove('hide'); + // trigger reflow + void elem.offsetWidth; + + requestAnimationFrame(function () { + elem.classList.remove('iconOsd-hidden'); + + hideTimeout = setTimeout(hideOsd, 3000); + }); +} + +function clearHideTimeout() { + if (hideTimeout) { + clearTimeout(hideTimeout); + hideTimeout = null; + } +} + +function hideOsd() { + + clearHideTimeout(); + + var elem = osdElement; + if (elem) { + + if (enableAnimation) { + // trigger reflow + void elem.offsetWidth; + + requestAnimationFrame(function () { + elem.classList.add('iconOsd-hidden'); + + dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { + once: true + }); + }); + } else { + onHideComplete.call(elem); + } + } +} + +function updatePlayerVolumeState(isMuted, volume) { + + if (iconElement) { + iconElement.classList.remove('volume_off', 'volume_up'); + iconElement.classList.add(isMuted ? 'volume_off' : 'volume_up'); + } + if (progressElement) { + progressElement.style.width = (volume || 0) + '%'; + } +} + +function releaseCurrentPlayer() { + + var player = currentPlayer; + + if (player) { + events.off(player, 'volumechange', onVolumeChanged); + events.off(player, 'playbackstop', hideOsd); + currentPlayer = null; + } +} + +function onVolumeChanged(e) { + + var player = this; + + ensureOsdElement(); + + updatePlayerVolumeState(player.isMuted(), player.getVolume()); + + showOsd(); +} + +function bindToPlayer(player) { + + if (player === currentPlayer) { + return; + } + + releaseCurrentPlayer(); + + currentPlayer = player; + + if (!player) { + return; + } + + hideOsd(); + events.on(player, 'volumechange', onVolumeChanged); + events.on(player, 'playbackstop', hideOsd); +} + +events.on(playbackManager, 'playerchange', function () { + bindToPlayer(playbackManager.getCurrentPlayer()); }); + +bindToPlayer(playbackManager.getCurrentPlayer()); diff --git a/src/components/skinManager.js b/src/components/skinManager.js index b0a9178ac..c38d34181 100644 --- a/src/components/skinManager.js +++ b/src/components/skinManager.js @@ -57,7 +57,6 @@ define(['apphost', 'userSettings', 'browser', 'events', 'backdrop', 'globalize', var selectedTheme; for (var i = 0, length = themes.length; i < length; i++) { - var theme = themes[i]; if (theme[isDefaultProperty]) { defaultTheme = theme; diff --git a/src/components/syncplay/groupSelectionMenu.js b/src/components/syncPlay/groupSelectionMenu.js similarity index 100% rename from src/components/syncplay/groupSelectionMenu.js rename to src/components/syncPlay/groupSelectionMenu.js diff --git a/src/components/syncplay/playbackPermissionManager.js b/src/components/syncPlay/playbackPermissionManager.js similarity index 100% rename from src/components/syncplay/playbackPermissionManager.js rename to src/components/syncPlay/playbackPermissionManager.js diff --git a/src/components/syncplay/syncPlayManager.js b/src/components/syncPlay/syncPlayManager.js similarity index 99% rename from src/components/syncplay/syncPlayManager.js rename to src/components/syncPlay/syncPlayManager.js index f5c9ac446..6116884d7 100644 --- a/src/components/syncplay/syncPlayManager.js +++ b/src/components/syncPlay/syncPlayManager.js @@ -1,6 +1,6 @@ /** * Module that manages the SyncPlay feature. - * @module components/syncplay/syncPlayManager + * @module components/syncPlay/syncPlayManager */ import events from 'events'; @@ -265,10 +265,9 @@ class SyncPlayManager { events.on(player, 'timeupdate', this._onTimeUpdate); events.on(player, 'playing', this._onPlaying); events.on(player, 'waiting', this._onWaiting); - this.playbackRateSupported = player.supports('PlaybackRate'); // Save player current PlaybackRate value - if (this.playbackRateSupported) { + if (player.supports && player.supports('PlaybackRate')) { this.localPlayerPlaybackRate = player.getPlaybackRate(); } } diff --git a/src/components/syncplay/timeSyncManager.js b/src/components/syncPlay/timeSyncManager.js similarity index 99% rename from src/components/syncplay/timeSyncManager.js rename to src/components/syncPlay/timeSyncManager.js index ca9293957..6c151b368 100644 --- a/src/components/syncplay/timeSyncManager.js +++ b/src/components/syncPlay/timeSyncManager.js @@ -1,6 +1,6 @@ /** * Module that manages time syncing with server. - * @module components/syncplay/timeSyncManager + * @module components/syncPlay/timeSyncManager */ import events from 'events'; diff --git a/src/components/viewsettings/viewsettings.js b/src/components/viewSettings/viewSettings.js similarity index 98% rename from src/components/viewsettings/viewsettings.js rename to src/components/viewSettings/viewSettings.js index 441c35157..087ba3e37 100644 --- a/src/components/viewsettings/viewsettings.js +++ b/src/components/viewSettings/viewSettings.js @@ -57,7 +57,7 @@ define(['require', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'conne return new Promise(function (resolve, reject) { - require(['text!./viewsettings.template.html'], function (template) { + require(['text!./viewSettings.template.html'], function (template) { var dialogOptions = { removeOnClose: true, diff --git a/src/components/viewsettings/viewsettings.template.html b/src/components/viewSettings/viewSettings.template.html similarity index 100% rename from src/components/viewsettings/viewsettings.template.html rename to src/components/viewSettings/viewSettings.template.html diff --git a/src/config.json b/src/config.json new file mode 120000 index 000000000..f1bd2db71 --- /dev/null +++ b/src/config.json @@ -0,0 +1 @@ +config.template.json \ No newline at end of file diff --git a/src/config.template.json b/src/config.template.json index 1e7927094..4b22a699d 100644 --- a/src/config.template.json +++ b/src/config.template.json @@ -1,3 +1,3 @@ { - "multiserver": true + "multiserver": false } diff --git a/src/controllers/dashboard/dlna/profile.js b/src/controllers/dashboard/dlna/profile.js index 3fe238c8a..81eb099f5 100644 --- a/src/controllers/dashboard/dlna/profile.js +++ b/src/controllers/dashboard/dlna/profile.js @@ -1,4 +1,4 @@ -define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-button', 'emby-input', 'emby-checkbox', 'listViewStyle', 'emby-button'], function ($, loading, globalize) { +define(['jQuery', 'loading', 'globalize', 'emby-select', 'emby-button', 'emby-input', 'emby-checkbox', 'listViewStyle', 'emby-button'], function ($, loading, globalize) { 'use strict'; function loadProfile(page) { @@ -23,8 +23,8 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt $('.chkMediaType', page).each(function () { this.checked = -1 != (profile.SupportedMediaTypes || '').split(',').indexOf(this.getAttribute('data-value')); }); - $('#chkEnableAlbumArtInDidl', page).checked(profile.EnableAlbumArtInDidl); - $('#chkEnableSingleImageLimit', page).checked(profile.EnableSingleAlbumArtLimit); + $('#chkEnableAlbumArtInDidl', page).checked = profile.EnableAlbumArtInDidl; + $('#chkEnableSingleImageLimit', page).checked = profile.EnableSingleAlbumArtLimit; renderXmlDocumentAttributes(page, profile.XmlRootAttributes || []); var idInfo = profile.Identification || {}; renderIdentificationHeaders(page, idInfo.Headers || []); @@ -51,11 +51,11 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt $('#txtAlbumArtMaxHeight', page).val(profile.MaxAlbumArtHeight || ''); $('#txtIconMaxWidth', page).val(profile.MaxIconWidth || ''); $('#txtIconMaxHeight', page).val(profile.MaxIconHeight || ''); - $('#chkIgnoreTranscodeByteRangeRequests', page).checked(profile.IgnoreTranscodeByteRangeRequests); + $('#chkIgnoreTranscodeByteRangeRequests', page).checked = profile.IgnoreTranscodeByteRangeRequests; $('#txtMaxAllowedBitrate', page).val(profile.MaxStreamingBitrate || ''); $('#txtMusicStreamingTranscodingBitrate', page).val(profile.MusicStreamingTranscodingBitrate || ''); - $('#chkRequiresPlainFolders', page).checked(profile.RequiresPlainFolders); - $('#chkRequiresPlainVideoItems', page).checked(profile.RequiresPlainVideoItems); + $('#chkRequiresPlainFolders', page).checked = profile.RequiresPlainFolders; + $('#chkRequiresPlainVideoItems', page).checked = profile.RequiresPlainVideoItems; $('#txtProtocolInfo', page).val(profile.ProtocolInfo || ''); $('#txtXDlnaCap', page).val(profile.XDlnaCap || ''); $('#txtXDlnaDoc', page).val(profile.XDlnaDoc || ''); @@ -357,9 +357,9 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt $('#txtTranscodingAudioCodec', popup).val(transcodingProfile.AudioCodec || ''); $('#txtTranscodingVideoCodec', popup).val(transcodingProfile.VideoCodec || ''); $('#selectTranscodingProtocol', popup).val(transcodingProfile.Protocol || 'Http'); - $('#chkEnableMpegtsM2TsMode', popup).checked(transcodingProfile.EnableMpegtsM2TsMode || false); - $('#chkEstimateContentLength', popup).checked(transcodingProfile.EstimateContentLength || false); - $('#chkReportByteRangeRequests', popup).checked('Bytes' == transcodingProfile.TranscodeSeekInfo); + $('#chkEnableMpegtsM2TsMode', popup).checked = transcodingProfile.EnableMpegtsM2TsMode || false; + $('#chkEstimateContentLength', popup).checked = transcodingProfile.EstimateContentLength || false; + $('#chkReportByteRangeRequests', popup).checked = 'Bytes' == transcodingProfile.TranscodeSeekInfo; $('.radioTabButton:first', popup).trigger('click'); openPopup(popup[0]); } @@ -376,9 +376,9 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt currentSubProfile.VideoCodec = $('#txtTranscodingVideoCodec', page).val(); currentSubProfile.Protocol = $('#selectTranscodingProtocol', page).val(); currentSubProfile.Context = 'Streaming'; - currentSubProfile.EnableMpegtsM2TsMode = $('#chkEnableMpegtsM2TsMode', page).checked(); - currentSubProfile.EstimateContentLength = $('#chkEstimateContentLength', page).checked(); - currentSubProfile.TranscodeSeekInfo = $('#chkReportByteRangeRequests', page).checked() ? 'Bytes' : 'Auto'; + currentSubProfile.EnableMpegtsM2TsMode = $('#chkEnableMpegtsM2TsMode', page).checked; + currentSubProfile.EstimateContentLength = $('#chkEstimateContentLength', page).checked; + currentSubProfile.TranscodeSeekInfo = $('#chkReportByteRangeRequests', page).checked ? 'Bytes' : 'Auto'; if (isSubProfileNew) { currentProfile.TranscodingProfiles.push(currentSubProfile); @@ -647,8 +647,8 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt function updateProfile(page, profile) { profile.Name = $('#txtName', page).val(); - profile.EnableAlbumArtInDidl = $('#chkEnableAlbumArtInDidl', page).checked(); - profile.EnableSingleAlbumArtLimit = $('#chkEnableSingleImageLimit', page).checked(); + profile.EnableAlbumArtInDidl = $('#chkEnableAlbumArtInDidl', page).checked; + profile.EnableSingleAlbumArtLimit = $('#chkEnableSingleImageLimit', page).checked; profile.SupportedMediaTypes = $('.chkMediaType:checked', page).get().map(function (c) { return c.getAttribute('data-value'); }).join(','); @@ -675,9 +675,9 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt profile.MaxAlbumArtHeight = $('#txtAlbumArtMaxHeight', page).val(); profile.MaxIconWidth = $('#txtIconMaxWidth', page).val(); profile.MaxIconHeight = $('#txtIconMaxHeight', page).val(); - profile.RequiresPlainFolders = $('#chkRequiresPlainFolders', page).checked(); - profile.RequiresPlainVideoItems = $('#chkRequiresPlainVideoItems', page).checked(); - profile.IgnoreTranscodeByteRangeRequests = $('#chkIgnoreTranscodeByteRangeRequests', page).checked(); + profile.RequiresPlainFolders = $('#chkRequiresPlainFolders', page).checked; + profile.RequiresPlainVideoItems = $('#chkRequiresPlainVideoItems', page).checked; + profile.IgnoreTranscodeByteRangeRequests = $('#chkIgnoreTranscodeByteRangeRequests', page).checked; profile.MaxStreamingBitrate = $('#txtMaxAllowedBitrate', page).val(); profile.MusicStreamingTranscodingBitrate = $('#txtMusicStreamingTranscodingBitrate', page).val(); profile.ProtocolInfo = $('#txtProtocolInfo', page).val(); diff --git a/src/controllers/dashboard/dlna/settings.js b/src/controllers/dashboard/dlna/settings.js index a818002d0..da254c0bd 100644 --- a/src/controllers/dashboard/dlna/settings.js +++ b/src/controllers/dashboard/dlna/settings.js @@ -1,12 +1,12 @@ -define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function ($, loading, libraryMenu, globalize) { +define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading, libraryMenu, globalize) { 'use strict'; function loadPage(page, config, users) { page.querySelector('#chkEnablePlayTo').checked = config.EnablePlayTo; page.querySelector('#chkEnableDlnaDebugLogging').checked = config.EnableDebugLog; $('#txtClientDiscoveryInterval', page).val(config.ClientDiscoveryIntervalSeconds); - $('#chkEnableServer', page).checked(config.EnableServer); - $('#chkBlastAliveMessages', page).checked(config.BlastAliveMessages); + $('#chkEnableServer', page).checked = config.EnableServer; + $('#chkBlastAliveMessages', page).checked = config.BlastAliveMessages; $('#txtBlastInterval', page).val(config.BlastAliveMessageIntervalSeconds); var usersHtml = users.map(function (u) { return ''; @@ -22,8 +22,8 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function config.EnablePlayTo = form.querySelector('#chkEnablePlayTo').checked; config.EnableDebugLog = form.querySelector('#chkEnableDlnaDebugLogging').checked; config.ClientDiscoveryIntervalSeconds = $('#txtClientDiscoveryInterval', form).val(); - config.EnableServer = $('#chkEnableServer', form).checked(); - config.BlastAliveMessages = $('#chkBlastAliveMessages', form).checked(); + config.EnableServer = $('#chkEnableServer', form).checked; + config.BlastAliveMessages = $('#chkBlastAliveMessages', form).checked; config.BlastAliveMessageIntervalSeconds = $('#txtBlastInterval', form).val(); config.DefaultUserId = $('#selectUser', form).val(); ApiClient.updateNamedConfiguration('dlna', config).then(Dashboard.processServerConfigurationUpdateResult); diff --git a/src/controllers/dashboard/general.js b/src/controllers/dashboard/general.js index 778285054..f215ace28 100644 --- a/src/controllers/dashboard/general.js +++ b/src/controllers/dashboard/general.js @@ -1,16 +1,8 @@ -define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox', 'emby-textarea', 'emby-input', 'emby-select', 'emby-button'], function ($, loading, globalize) { +define(['jQuery', 'loading', 'globalize', 'emby-checkbox', 'emby-textarea', 'emby-input', 'emby-select', 'emby-button'], function ($, loading, globalize) { 'use strict'; function loadPage(page, config, languageOptions, systemInfo) { page.querySelector('#txtServerName').value = systemInfo.ServerName; - $('#chkAutoRunWebApp', page).checked(config.AutoRunWebApp); - - if (systemInfo.CanLaunchWebBrowser) { - page.querySelector('#fldAutoRunWebApp').classList.remove('hide'); - } else { - page.querySelector('#fldAutoRunWebApp').classList.add('hide'); - } - page.querySelector('#txtCachePath').value = systemInfo.CachePath || ''; $('#txtMetadataPath', page).val(systemInfo.InternalMetadataPath || ''); $('#txtMetadataNetworkPath', page).val(systemInfo.MetadataNetworkPath || ''); @@ -33,7 +25,6 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox', 'emby-te config.MetadataPath = $('#txtMetadataPath', form).val(); config.MetadataNetworkPath = $('#txtMetadataNetworkPath', form).val(); var requiresReload = config.UICulture !== currentLanguage; - config.AutoRunWebApp = $('#chkAutoRunWebApp', form).checked(); ApiClient.updateServerConfiguration(config).then(function() { ApiClient.getNamedConfiguration(brandingConfigKey).then(function(brandingConfig) { brandingConfig.LoginDisclaimer = form.querySelector('#txtLoginDisclaimer').value; diff --git a/src/controllers/dashboard/metadataImages.js b/src/controllers/dashboard/metadataImages.js index 277eecb42..3047736a6 100644 --- a/src/controllers/dashboard/metadataImages.js +++ b/src/controllers/dashboard/metadataImages.js @@ -29,14 +29,18 @@ define(['jQuery', 'dom', 'loading', 'libraryMenu', 'globalize', 'listViewStyle'] var promises = [ApiClient.getServerConfiguration(), populateLanguages(page.querySelector('#selectLanguage')), populateCountries(page.querySelector('#selectCountry'))]; Promise.all(promises).then(function(responses) { var config = responses[0]; - page.querySelector('#selectLanguage').value = config.PreferredMetadataLanguage || '', page.querySelector('#selectCountry').value = config.MetadataCountryCode || '', loading.hide(); + page.querySelector('#selectLanguage').value = config.PreferredMetadataLanguage || ''; + page.querySelector('#selectCountry').value = config.MetadataCountryCode || ''; + loading.hide(); }); } function onSubmit() { var form = this; return loading.show(), ApiClient.getServerConfiguration().then(function(config) { - config.PreferredMetadataLanguage = form.querySelector('#selectLanguage').value, config.MetadataCountryCode = form.querySelector('#selectCountry').value, ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult); + config.PreferredMetadataLanguage = form.querySelector('#selectLanguage').value; + config.MetadataCountryCode = form.querySelector('#selectCountry').value; + ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult); }), !1; } @@ -59,6 +63,8 @@ define(['jQuery', 'dom', 'loading', 'libraryMenu', 'globalize', 'listViewStyle'] $(document).on('pageinit', '#metadataImagesConfigurationPage', function() { $('.metadataImagesConfigurationForm').off('submit', onSubmit).on('submit', onSubmit); }).on('pageshow', '#metadataImagesConfigurationPage', function() { - libraryMenu.setTabs('metadata', 2, getTabs), loading.show(), loadPage(this); + libraryMenu.setTabs('metadata', 2, getTabs); + loading.show(); + loadPage(this); }); }); diff --git a/src/controllers/dashboard/notifications/notification.js b/src/controllers/dashboard/notifications/notification.js index 90d453cda..370fc6a36 100644 --- a/src/controllers/dashboard/notifications/notification.js +++ b/src/controllers/dashboard/notifications/notification.js @@ -1,4 +1,4 @@ -define(['jQuery', 'emby-checkbox', 'fnchecked'], function ($) { +define(['jQuery', 'emby-checkbox'], function ($) { 'use strict'; function fillItems(elem, items, cssClass, idPrefix, currentList, isEnabledList) { @@ -50,7 +50,7 @@ define(['jQuery', 'emby-checkbox', 'fnchecked'], function ($) { fillItems($('.monitorUsersList', page), users, 'chkMonitor', 'chkMonitor', notificationConfig.DisabledMonitorUsers); fillItems($('.sendToUsersList', page), users, 'chkSendTo', 'chkSendTo', notificationConfig.SendToUsers, true); fillItems($('.servicesList', page), services, 'chkService', 'chkService', notificationConfig.DisabledServices); - $('#chkEnabled', page).checked(notificationConfig.Enabled || false); + $('#chkEnabled', page).checked = notificationConfig.Enabled || false; $('#selectUsers', page).val(notificationConfig.SendToUserMode).trigger('change'); }); } @@ -58,10 +58,10 @@ define(['jQuery', 'emby-checkbox', 'fnchecked'], function ($) { function save(page) { var type = getParameterByName('type'); var promise1 = ApiClient.getNamedConfiguration(notificationsConfigurationKey); + // TODO: Check if this promise is really needed, as it's unused. var promise2 = ApiClient.getJSON(ApiClient.getUrl('Notifications/Types')); Promise.all([promise1, promise2]).then(function (responses) { var notificationOptions = responses[0]; - var types = responses[1]; var notificationConfig = notificationOptions.Options.filter(function (n) { return n.Type == type; })[0]; @@ -73,10 +73,7 @@ define(['jQuery', 'emby-checkbox', 'fnchecked'], function ($) { notificationOptions.Options.push(notificationConfig); } - types.filter(function (n) { - return n.Type == type; - })[0]; - notificationConfig.Enabled = $('#chkEnabled', page).checked(); + notificationConfig.Enabled = $('#chkEnabled', page).checked; notificationConfig.SendToUserMode = $('#selectUsers', page).val(); notificationConfig.DisabledMonitorUsers = $('.chkMonitor', page).get().filter(function (c) { return !c.checked; diff --git a/src/controllers/dashboard/plugins/installed.js b/src/controllers/dashboard/plugins/installed.js index 5ca739f71..87e9428cc 100644 --- a/src/controllers/dashboard/plugins/installed.js +++ b/src/controllers/dashboard/plugins/installed.js @@ -50,7 +50,7 @@ define(['loading', 'libraryMenu', 'dom', 'globalize', 'cardStyle', 'emby-button' html += ''; html += '
'; html += "
"; - html += configPage.DisplayName || plugin.Name; + html += configPage && configPage.DisplayName ? configPage.DisplayName : plugin.Name; html += '
'; html += "
"; html += plugin.Version; diff --git a/src/controllers/dashboard/users/useredit.js b/src/controllers/dashboard/users/useredit.js index 125c57136..c71c81d9e 100644 --- a/src/controllers/dashboard/users/useredit.js +++ b/src/controllers/dashboard/users/useredit.js @@ -1,4 +1,4 @@ -define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function ($, loading, libraryMenu, globalize) { +define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading, libraryMenu, globalize) { 'use strict'; function loadDeleteFolders(page, user, mediaFolders) { @@ -27,7 +27,7 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function } $('.deleteAccess', page).html(html).trigger('create'); - $('#chkEnableDeleteAllFolders', page).checked(user.Policy.EnableContentDeletion).trigger('change'); + $('#chkEnableDeleteAllFolders', page).checked = user.Policy.EnableContentDeletion; }); } @@ -85,23 +85,23 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function libraryMenu.setTitle(user.Name); page.querySelector('.username').innerHTML = user.Name; $('#txtUserName', page).val(user.Name); - $('#chkIsAdmin', page).checked(user.Policy.IsAdministrator); - $('#chkDisabled', page).checked(user.Policy.IsDisabled); - $('#chkIsHidden', page).checked(user.Policy.IsHidden); - $('#chkRemoteControlSharedDevices', page).checked(user.Policy.EnableSharedDeviceControl); - $('#chkEnableRemoteControlOtherUsers', page).checked(user.Policy.EnableRemoteControlOfOtherUsers); - $('#chkEnableDownloading', page).checked(user.Policy.EnableContentDownloading); - $('#chkManageLiveTv', page).checked(user.Policy.EnableLiveTvManagement); - $('#chkEnableLiveTvAccess', page).checked(user.Policy.EnableLiveTvAccess); - $('#chkEnableMediaPlayback', page).checked(user.Policy.EnableMediaPlayback); - $('#chkEnableAudioPlaybackTranscoding', page).checked(user.Policy.EnableAudioPlaybackTranscoding); - $('#chkEnableVideoPlaybackTranscoding', page).checked(user.Policy.EnableVideoPlaybackTranscoding); - $('#chkEnableVideoPlaybackRemuxing', page).checked(user.Policy.EnablePlaybackRemuxing); - $('#chkForceRemoteSourceTranscoding', page).checked(user.Policy.ForceRemoteSourceTranscoding); - $('#chkRemoteAccess', page).checked(null == user.Policy.EnableRemoteAccess || user.Policy.EnableRemoteAccess); - $('#chkEnableSyncTranscoding', page).checked(user.Policy.EnableSyncTranscoding); - $('#chkEnableConversion', page).checked(user.Policy.EnableMediaConversion || false); - $('#chkEnableSharing', page).checked(user.Policy.EnablePublicSharing); + $('#chkIsAdmin', page).checked = user.Policy.IsAdministrator; + $('#chkDisabled', page).checked = user.Policy.IsDisabled; + $('#chkIsHidden', page).checked = user.Policy.IsHidden; + $('#chkRemoteControlSharedDevices', page).checked = user.Policy.EnableSharedDeviceControl; + $('#chkEnableRemoteControlOtherUsers', page).checked = user.Policy.EnableRemoteControlOfOtherUsers; + $('#chkEnableDownloading', page).checked = user.Policy.EnableContentDownloading; + $('#chkManageLiveTv', page).checked = user.Policy.EnableLiveTvManagement; + $('#chkEnableLiveTvAccess', page).checked = user.Policy.EnableLiveTvAccess; + $('#chkEnableMediaPlayback', page).checked = user.Policy.EnableMediaPlayback; + $('#chkEnableAudioPlaybackTranscoding', page).checked = user.Policy.EnableAudioPlaybackTranscoding; + $('#chkEnableVideoPlaybackTranscoding', page).checked = user.Policy.EnableVideoPlaybackTranscoding; + $('#chkEnableVideoPlaybackRemuxing', page).checked = user.Policy.EnablePlaybackRemuxing; + $('#chkForceRemoteSourceTranscoding', page).checked = user.Policy.ForceRemoteSourceTranscoding; + $('#chkRemoteAccess', page).checked = null == user.Policy.EnableRemoteAccess || user.Policy.EnableRemoteAccess; + $('#chkEnableSyncTranscoding', page).checked = user.Policy.EnableSyncTranscoding; + $('#chkEnableConversion', page).checked = user.Policy.EnableMediaConversion || false; + $('#chkEnableSharing', page).checked = user.Policy.EnablePublicSharing; $('#txtRemoteClientBitrateLimit', page).val(user.Policy.RemoteClientBitrateLimit / 1e6 || ''); $('#txtLoginAttemptsBeforeLockout', page).val(user.Policy.LoginAttemptsBeforeLockout || '0'); $('#selectSyncPlayAccess').val(user.Policy.SyncPlayAccess); @@ -119,28 +119,28 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function function saveUser(user, page) { user.Name = $('#txtUserName', page).val(); - user.Policy.IsAdministrator = $('#chkIsAdmin', page).checked(); - user.Policy.IsHidden = $('#chkIsHidden', page).checked(); - user.Policy.IsDisabled = $('#chkDisabled', page).checked(); - user.Policy.EnableRemoteControlOfOtherUsers = $('#chkEnableRemoteControlOtherUsers', page).checked(); - user.Policy.EnableLiveTvManagement = $('#chkManageLiveTv', page).checked(); - user.Policy.EnableLiveTvAccess = $('#chkEnableLiveTvAccess', page).checked(); - user.Policy.EnableSharedDeviceControl = $('#chkRemoteControlSharedDevices', page).checked(); - user.Policy.EnableMediaPlayback = $('#chkEnableMediaPlayback', page).checked(); - user.Policy.EnableAudioPlaybackTranscoding = $('#chkEnableAudioPlaybackTranscoding', page).checked(); - user.Policy.EnableVideoPlaybackTranscoding = $('#chkEnableVideoPlaybackTranscoding', page).checked(); - user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).checked(); - user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).checked(); - user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).checked(); - user.Policy.EnableSyncTranscoding = $('#chkEnableSyncTranscoding', page).checked(); - user.Policy.EnableMediaConversion = $('#chkEnableConversion', page).checked(); - user.Policy.EnablePublicSharing = $('#chkEnableSharing', page).checked(); - user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).checked(); + user.Policy.IsAdministrator = $('#chkIsAdmin', page).checked; + user.Policy.IsHidden = $('#chkIsHidden', page).checked; + user.Policy.IsDisabled = $('#chkDisabled', page).checked; + user.Policy.EnableRemoteControlOfOtherUsers = $('#chkEnableRemoteControlOtherUsers', page).checked; + user.Policy.EnableLiveTvManagement = $('#chkManageLiveTv', page).checked; + user.Policy.EnableLiveTvAccess = $('#chkEnableLiveTvAccess', page).checked; + user.Policy.EnableSharedDeviceControl = $('#chkRemoteControlSharedDevices', page).checked; + user.Policy.EnableMediaPlayback = $('#chkEnableMediaPlayback', page).checked; + user.Policy.EnableAudioPlaybackTranscoding = $('#chkEnableAudioPlaybackTranscoding', page).checked; + user.Policy.EnableVideoPlaybackTranscoding = $('#chkEnableVideoPlaybackTranscoding', page).checked; + user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).checked; + user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).checked; + user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).checked; + user.Policy.EnableSyncTranscoding = $('#chkEnableSyncTranscoding', page).checked; + user.Policy.EnableMediaConversion = $('#chkEnableConversion', page).checked; + user.Policy.EnablePublicSharing = $('#chkEnableSharing', page).checked; + user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).checked; user.Policy.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($('#txtRemoteClientBitrateLimit', page).val() || '0')); user.Policy.LoginAttemptsBeforeLockout = parseInt($('#txtLoginAttemptsBeforeLockout', page).val() || '0'); user.Policy.AuthenticationProviderId = page.querySelector('.selectLoginProvider').value; user.Policy.PasswordResetProviderId = page.querySelector('.selectPasswordResetProvider').value; - user.Policy.EnableContentDeletion = $('#chkEnableDeleteAllFolders', page).checked(); + user.Policy.EnableContentDeletion = $('#chkEnableDeleteAllFolders', page).checked; user.Policy.EnableContentDeletionFromFolders = user.Policy.EnableContentDeletion ? [] : $('.chkFolder', page).get().filter(function (c) { return c.checked; }).map(function (c) { diff --git a/src/controllers/dashboard/users/userlibraryaccess.js b/src/controllers/dashboard/users/userlibraryaccess.js index 95664c1eb..1fdb6cb59 100644 --- a/src/controllers/dashboard/users/userlibraryaccess.js +++ b/src/controllers/dashboard/users/userlibraryaccess.js @@ -1,4 +1,4 @@ -define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function ($, loading, libraryMenu, globalize) { +define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading, libraryMenu, globalize) { 'use strict'; function triggerChange(select) { @@ -47,7 +47,7 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function $('.channelAccessContainer', page).hide(); } - $('#chkEnableAllChannels', page).checked(user.Policy.EnableAllChannels).trigger('change'); + $('#chkEnableAllChannels', page).checked = user.Policy.EnableAllChannels; } function loadDevices(page, user, devices) { @@ -63,7 +63,7 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function html += '
'; $('.deviceAccess', page).show().html(html); - $('#chkEnableAllDevices', page).checked(user.Policy.EnableAllDevices).trigger('change'); + $('#chkEnableAllDevices', page).checked = user.Policy.EnableAllDevices; if (user.Policy.IsAdministrator) { page.querySelector('.deviceAccessContainer').classList.add('hide'); @@ -90,19 +90,19 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function } function saveUser(user, page) { - user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).checked(); + user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).checked; user.Policy.EnabledFolders = user.Policy.EnableAllFolders ? [] : $('.chkFolder', page).get().filter(function (c) { return c.checked; }).map(function (c) { return c.getAttribute('data-id'); }); - user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).checked(); + user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).checked; user.Policy.EnabledChannels = user.Policy.EnableAllChannels ? [] : $('.chkChannel', page).get().filter(function (c) { return c.checked; }).map(function (c) { return c.getAttribute('data-id'); }); - user.Policy.EnableAllDevices = $('#chkEnableAllDevices', page).checked(); + user.Policy.EnableAllDevices = $('#chkEnableAllDevices', page).checked; user.Policy.EnabledDevices = user.Policy.EnableAllDevices ? [] : $('.chkDevice', page).get().filter(function (c) { return c.checked; }).map(function (c) { diff --git a/src/controllers/dashboard/users/usernew.js b/src/controllers/dashboard/users/usernew.js index 5646b239d..1e4e2bbee 100644 --- a/src/controllers/dashboard/users/usernew.js +++ b/src/controllers/dashboard/users/usernew.js @@ -1,4 +1,4 @@ -define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], function ($, loading, globalize) { +define(['jQuery', 'loading', 'globalize', 'emby-checkbox'], function ($, loading, globalize) { 'use strict'; function loadMediaFolders(page, mediaFolders) { @@ -13,7 +13,7 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], functio html += '
'; $('.folderAccess', page).html(html).trigger('create'); - $('#chkEnableAllFolders', page).checked(false).trigger('change'); + $('#chkEnableAllFolders', page).checked = false; } function loadChannels(page, channels) { @@ -35,7 +35,7 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], functio $('.channelAccessContainer', page).hide(); } - $('#chkEnableAllChannels', page).checked(false).trigger('change'); + $('#chkEnableAllChannels', page).checked = false; } function loadUser(page) { @@ -58,7 +58,7 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], functio user.Name = $('#txtUsername', page).val(); user.Password = $('#txtPassword', page).val(); ApiClient.createUser(user).then(function (user) { - user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).checked(); + user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).checked; user.Policy.EnabledFolders = []; if (!user.Policy.EnableAllFolders) { @@ -69,7 +69,7 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], functio }); } - user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).checked(); + user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).checked; user.Policy.EnabledChannels = []; if (!user.Policy.EnableAllChannels) { diff --git a/src/controllers/itemDetails.js b/src/controllers/itemDetails.js index 0fad1ba96..cbb8a1b43 100644 --- a/src/controllers/itemDetails.js +++ b/src/controllers/itemDetails.js @@ -972,6 +972,19 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti } } + function toggleLineClamp(clampTarget, e) { + var expandButton = e.target; + var clampClassName = 'detail-clamp-text'; + + if (clampTarget.classList.contains(clampClassName)) { + clampTarget.classList.remove(clampClassName); + expandButton.innerHTML = globalize.translate('ShowLess'); + } else { + clampTarget.classList.add(clampClassName); + expandButton.innerHTML = globalize.translate('ShowMore'); + } + } + function renderOverview(elems, item) { for (var i = 0, length = elems.length; i < length; i++) { var elem = elems[i]; @@ -980,6 +993,21 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti if (overview) { elem.innerHTML = overview; elem.classList.remove('hide'); + elem.classList.add('detail-clamp-text'); + + // Grab the sibling element to control the expand state + var expandButton = elem.parentElement.querySelector('.overview-expand'); + + // Detect if we have overflow of text. Based on this StackOverflow answer + // https://stackoverflow.com/a/35157976 + if (Math.abs(elem.scrollHeight - elem.offsetHeight) > 2) { + expandButton.classList.remove('hide'); + } else { + expandButton.classList.add('hide'); + } + + expandButton.addEventListener('click', toggleLineClamp.bind(null, elem)); + var anchors = elem.querySelectorAll('a'); for (var j = 0, length2 = anchors.length; j < length2; j++) { @@ -1863,7 +1891,8 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti itemsContainer: castContent, coverImage: true, serverId: item.ServerId, - shape: 'overflowPortrait' + shape: 'overflowPortrait', + imageBlurhashes: item.ImageBlurHashes }); }); } diff --git a/src/controllers/livetv/livetvchannels.js b/src/controllers/livetv/livetvchannels.js index 7f22d3dd1..62906d9d2 100644 --- a/src/controllers/livetv/livetvchannels.js +++ b/src/controllers/livetv/livetvchannels.js @@ -86,7 +86,7 @@ define(['cardBuilder', 'imageLoader', 'libraryBrowser', 'loading', 'events', 'us } function showFilterMenu(context) { - require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) { var filterDialog = new filterDialogFactory({ query: getQuery(), mode: 'livetvchannels', diff --git a/src/controllers/livetvsettings.js b/src/controllers/livetvsettings.js index 7a8552b9a..4c5fdc60d 100644 --- a/src/controllers/livetvsettings.js +++ b/src/controllers/livetvsettings.js @@ -1,4 +1,4 @@ -define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-button'], function ($, loading, globalize) { +define(['jQuery', 'loading', 'globalize', 'emby-button'], function ($, loading, globalize) { 'use strict'; function loadPage(page, config) { diff --git a/src/controllers/movies/moviecollections.js b/src/controllers/movies/moviecollections.js index e9ae599b9..54d30c0c3 100644 --- a/src/controllers/movies/moviecollections.js +++ b/src/controllers/movies/moviecollections.js @@ -171,7 +171,12 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB } if (!result.Items.length) { - html = '

' + globalize.translate('MessageNoCollectionsAvailable') + '

'; + html = ''; + + html += '
'; + html += '

' + globalize.translate('MessageNothingHere') + '

'; + html += '

' + globalize.translate('MessageNoCollectionsAvailable') + '

'; + html += '
'; } var itemsContainer = tabContent.querySelector('.itemsContainer'); diff --git a/src/controllers/movies/moviegenres.js b/src/controllers/movies/moviegenres.js index e8e49ff9d..ab410c1bd 100644 --- a/src/controllers/movies/moviegenres.js +++ b/src/controllers/movies/moviegenres.js @@ -165,6 +165,15 @@ define(['layoutManager', 'loading', 'libraryBrowser', 'cardBuilder', 'lazyLoader html += '
'; } + if (!result.Items.length) { + html = ''; + + html += '
'; + html += '

' + globalize.translate('MessageNothingHere') + '

'; + html += '

' + globalize.translate('MessageNoGenresAvailable') + '

'; + html += '
'; + } + elem.innerHTML = html; lazyLoader.lazyChildren(elem, fillItemsContainer); libraryBrowser.saveQueryValues(getSavedQueryKey(), query); diff --git a/src/controllers/movies/movies.js b/src/controllers/movies/movies.js index 89bcc215e..c22b52c47 100644 --- a/src/controllers/movies/movies.js +++ b/src/controllers/movies/movies.js @@ -270,7 +270,7 @@ define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser', query = userSettings.loadQuerySettings(savedQueryKey, query); self.showFilterMenu = function () { - require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) { var filterDialog = new filterDialogFactory({ query: query, mode: 'movies', diff --git a/src/controllers/movies/movietrailers.js b/src/controllers/movies/movietrailers.js index 25d41d4fb..5daad8d7c 100644 --- a/src/controllers/movies/movietrailers.js +++ b/src/controllers/movies/movietrailers.js @@ -158,7 +158,12 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', ' } if (!result.Items.length) { - html = '

' + globalize.translate('MessageNoTrailersFound') + '

'; + html = ''; + + html += '
'; + html += '

' + globalize.translate('MessageNothingHere') + '

'; + html += '

' + globalize.translate('MessageNoTrailersFound') + '

'; + html += '
'; } var itemsContainer = tabContent.querySelector('.itemsContainer'); @@ -180,7 +185,7 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', ' var isLoading = false; self.showFilterMenu = function () { - require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) { var filterDialog = new filterDialogFactory({ query: getQuery(tabContent), mode: 'movies', diff --git a/src/controllers/music/musicalbums.js b/src/controllers/music/musicalbums.js index ecb51f9dc..645daf4ad 100644 --- a/src/controllers/music/musicalbums.js +++ b/src/controllers/music/musicalbums.js @@ -186,7 +186,7 @@ define(['layoutManager', 'playbackManager', 'loading', 'events', 'libraryBrowser var isLoading = false; self.showFilterMenu = function () { - require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) { var filterDialog = new filterDialogFactory({ query: getQuery(), mode: 'albums', diff --git a/src/controllers/music/musicartists.js b/src/controllers/music/musicartists.js index bd9341be6..7a889ff8b 100644 --- a/src/controllers/music/musicartists.js +++ b/src/controllers/music/musicartists.js @@ -170,7 +170,7 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', ' var isLoading = false; self.showFilterMenu = function () { - require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) { var filterDialog = new filterDialogFactory({ query: getQuery(tabContent), mode: self.mode, diff --git a/src/controllers/music/songs.js b/src/controllers/music/songs.js index 8e50cd720..aa63ec51f 100644 --- a/src/controllers/music/songs.js +++ b/src/controllers/music/songs.js @@ -124,7 +124,7 @@ define(['events', 'libraryBrowser', 'imageLoader', 'listView', 'loading', 'userS var isLoading = false; self.showFilterMenu = function () { - require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) { var filterDialog = new filterDialogFactory({ query: getQuery(tabContent), mode: 'songs', diff --git a/src/controllers/playback/videoosd.js b/src/controllers/playback/videoosd.js index 831aea557..d6caf24e8 100644 --- a/src/controllers/playback/videoosd.js +++ b/src/controllers/playback/videoosd.js @@ -157,7 +157,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med }); if (!displayName) { - displayItem.Type; + displayName = displayItem.Type; } titleElement.innerHTML = displayName; diff --git a/src/controllers/shows/episodes.js b/src/controllers/shows/episodes.js index ca9a807cb..eeede2066 100644 --- a/src/controllers/shows/episodes.js +++ b/src/controllers/shows/episodes.js @@ -164,7 +164,7 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB var isLoading = false; self.showFilterMenu = function () { - require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) { var filterDialog = new filterDialogFactory({ query: getQuery(tabContent), mode: 'episodes', diff --git a/src/controllers/shows/tvgenres.js b/src/controllers/shows/tvgenres.js index de38763e9..7d09307fc 100644 --- a/src/controllers/shows/tvgenres.js +++ b/src/controllers/shows/tvgenres.js @@ -161,6 +161,15 @@ define(['layoutManager', 'loading', 'libraryBrowser', 'cardBuilder', 'lazyLoader html += '
'; } + if (!result.Items.length) { + html = ''; + + html += '
'; + html += '

' + globalize.translate('MessageNothingHere') + '

'; + html += '

' + globalize.translate('MessageNoGenresAvailable') + '

'; + html += '
'; + } + elem.innerHTML = html; lazyLoader.lazyChildren(elem, fillItemsContainer); libraryBrowser.saveQueryValues(getSavedQueryKey(), query); diff --git a/src/controllers/shows/tvshows.js b/src/controllers/shows/tvshows.js index 753516f90..0bd5e4b52 100644 --- a/src/controllers/shows/tvshows.js +++ b/src/controllers/shows/tvshows.js @@ -197,7 +197,7 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', ' var isLoading = false; self.showFilterMenu = function () { - require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) { var filterDialog = new filterDialogFactory({ query: getQuery(tabContent), mode: 'series', diff --git a/src/controllers/user/display.js b/src/controllers/user/display.js index 3aeb7db8c..26c75f209 100644 --- a/src/controllers/user/display.js +++ b/src/controllers/user/display.js @@ -1,6 +1,9 @@ define(['displaySettings', 'userSettings', 'autoFocuser'], function (DisplaySettings, userSettings, autoFocuser) { 'use strict'; + // Shortcuts + const UserSettings = userSettings.UserSettings; + return function (view, params) { function onBeforeUnload(e) { if (hasChanges) { @@ -11,7 +14,7 @@ define(['displaySettings', 'userSettings', 'autoFocuser'], function (DisplaySett var settingsInstance; var hasChanges; var userId = params.userId || ApiClient.getCurrentUserId(); - var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); + var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings(); view.addEventListener('viewshow', function () { window.addEventListener('beforeunload', onBeforeUnload); diff --git a/src/controllers/user/home.js b/src/controllers/user/home.js index aa7d147c3..8f826c425 100644 --- a/src/controllers/user/home.js +++ b/src/controllers/user/home.js @@ -1,6 +1,9 @@ define(['homescreenSettings', 'dom', 'globalize', 'loading', 'userSettings', 'autoFocuser', 'listViewStyle'], function (HomescreenSettings, dom, globalize, loading, userSettings, autoFocuser) { 'use strict'; + // Shortcuts + const UserSettings = userSettings.UserSettings; + return function (view, params) { function onBeforeUnload(e) { if (hasChanges) { @@ -11,7 +14,7 @@ define(['homescreenSettings', 'dom', 'globalize', 'loading', 'userSettings', 'au var homescreenSettingsInstance; var hasChanges; var userId = params.userId || ApiClient.getCurrentUserId(); - var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); + var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings(); view.addEventListener('viewshow', function () { window.addEventListener('beforeunload', onBeforeUnload); diff --git a/src/controllers/user/playback.js b/src/controllers/user/playback.js index e945a46aa..02a718eb8 100644 --- a/src/controllers/user/playback.js +++ b/src/controllers/user/playback.js @@ -1,6 +1,9 @@ define(['playbackSettings', 'dom', 'globalize', 'loading', 'userSettings', 'autoFocuser', 'listViewStyle'], function (PlaybackSettings, dom, globalize, loading, userSettings, autoFocuser) { 'use strict'; + // Shortcuts + const UserSettings = userSettings.UserSettings; + return function (view, params) { function onBeforeUnload(e) { if (hasChanges) { @@ -11,7 +14,7 @@ define(['playbackSettings', 'dom', 'globalize', 'loading', 'userSettings', 'auto var settingsInstance; var hasChanges; var userId = params.userId || ApiClient.getCurrentUserId(); - var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); + var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings(); view.addEventListener('viewshow', function () { window.addEventListener('beforeunload', onBeforeUnload); diff --git a/src/controllers/user/subtitles.js b/src/controllers/user/subtitles.js index 152301f31..7e7e7fb8a 100644 --- a/src/controllers/user/subtitles.js +++ b/src/controllers/user/subtitles.js @@ -1,6 +1,9 @@ define(['subtitleSettings', 'userSettings', 'autoFocuser'], function (SubtitleSettings, userSettings, autoFocuser) { 'use strict'; + // Shortcuts + const UserSettings = userSettings.UserSettings; + return function (view, params) { function onBeforeUnload(e) { if (hasChanges) { @@ -11,7 +14,7 @@ define(['subtitleSettings', 'userSettings', 'autoFocuser'], function (SubtitleSe var subtitleSettingsInstance; var hasChanges; var userId = params.userId || ApiClient.getCurrentUserId(); - var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); + var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings(); view.addEventListener('viewshow', function () { window.addEventListener('beforeunload', onBeforeUnload); diff --git a/src/dashboardgeneral.html b/src/dashboardgeneral.html index 6c0f43eb3..99e6414dd 100644 --- a/src/dashboardgeneral.html +++ b/src/dashboardgeneral.html @@ -23,13 +23,6 @@
-
- -
${LaunchWebAppOnStartupHelp}
-
diff --git a/src/dlnaprofiles.html b/src/dlnaprofiles.html index 9f2a5e129..b47b2fd6b 100644 --- a/src/dlnaprofiles.html +++ b/src/dlnaprofiles.html @@ -11,7 +11,7 @@ - ${Help} + ${Help}

${CustomDlnaProfilesHelp}

diff --git a/src/elements/emby-slider/emby-slider.js b/src/elements/emby-slider/emby-slider.js index e37455dfe..1b78fca0a 100644 --- a/src/elements/emby-slider/emby-slider.js +++ b/src/elements/emby-slider/emby-slider.js @@ -148,7 +148,7 @@ define(['browser', 'dom', 'layoutManager', 'keyboardnavigation', 'css!./emby-sli this.classList.add('mdl-slider'); this.classList.add('mdl-js-slider'); - if (browser.edge || browser.msie) { + if (browser.edge) { this.classList.add('slider-browser-edge'); } if (!layoutManager.mobile) { diff --git a/src/itemdetails.html b/src/itemdetails.html index 4d5cab026..18de25845 100644 --- a/src/itemdetails.html +++ b/src/itemdetails.html @@ -148,6 +148,9 @@

+

diff --git a/src/legacy/dashboard.js b/src/legacy/dashboard.js deleted file mode 100644 index 08c5e8330..000000000 --- a/src/legacy/dashboard.js +++ /dev/null @@ -1,24 +0,0 @@ -Dashboard.confirm = function(message, title, callback) { - 'use strict'; - require(['confirm'], function(confirm) { - confirm(message, title).then(function() { - callback(!0); - }).catch(function() { - callback(!1); - }); - }); -}; - -Dashboard.showLoadingMsg = function() { - 'use strict'; - require(['loading'], function(loading) { - loading.show(); - }); -}; - -Dashboard.hideLoadingMsg = function() { - 'use strict'; - require(['loading'], function(loading) { - loading.hide(); - }); -}; diff --git a/src/plugins/backdropScreensaver/plugin.js b/src/plugins/backdropScreensaver/plugin.js new file mode 100644 index 000000000..88bfa1f4b --- /dev/null +++ b/src/plugins/backdropScreensaver/plugin.js @@ -0,0 +1,52 @@ +/* eslint-disable indent */ +import connectionManager from 'connectionManager'; + +class BackdropScreensaver { + constructor() { + this.name = 'Backdrop ScreenSaver'; + this.type = 'screensaver'; + this.id = 'backdropscreensaver'; + this.supportsAnonymous = false; + } + show() { + const query = { + ImageTypes: 'Backdrop', + EnableImageTypes: 'Backdrop', + IncludeItemTypes: 'Movie,Series,MusicArtist', + SortBy: 'Random', + Recursive: true, + Fields: 'Taglines', + ImageTypeLimit: 1, + StartIndex: 0, + Limit: 200 + }; + + const apiClient = connectionManager.currentApiClient(); + apiClient.getItems(apiClient.getCurrentUserId(), query).then((result) => { + + if (result.Items.length) { + + import('slideshow').then(({default: Slideshow}) => { + const newSlideShow = new Slideshow({ + showTitle: true, + cover: true, + items: result.Items + }); + + newSlideShow.show(); + this.currentSlideshow = newSlideShow; + }).catch(console.error); + } + }); + } + + hide() { + if (this.currentSlideshow) { + this.currentSlideshow.hide(); + this.currentSlideshow = null; + } + } + } +/* eslint-enable indent */ + +export default BackdropScreensaver; diff --git a/src/components/bookPlayer/plugin.js b/src/plugins/bookPlayer/plugin.js similarity index 94% rename from src/components/bookPlayer/plugin.js rename to src/plugins/bookPlayer/plugin.js index b655b038a..5e8732e97 100644 --- a/src/components/bookPlayer/plugin.js +++ b/src/plugins/bookPlayer/plugin.js @@ -7,7 +7,7 @@ import 'css!./style'; import 'material-icons'; import 'paper-icon-button-light'; -import TableOfContent from './tableOfContent'; +import TableOfContents from './tableOfContents'; export class BookPlayer { constructor() { @@ -163,7 +163,7 @@ export class BookPlayer { openTableOfContents() { if (this._loaded) { - this._tocElement = new TableOfContent(this); + this._tocElement = new TableOfContents(this); } } @@ -238,11 +238,17 @@ export class BookPlayer { this.bindEvents(); - return this._rendition.book.locations.generate(1024).then(() => { + return this._rendition.book.locations.generate(1024).then(async () => { if (cancellationToken.shouldCancel) { return reject(); } + const percentageTicks = options.startPositionTicks / 10000000; + if (percentageTicks !== 0.0) { + const resumeLocation = book.locations.cfiFromPercentage(percentageTicks); + await rendition.display(resumeLocation); + } + this._loaded = true; epubElem.style.display = 'block'; rendition.on('relocated', (locations) => { @@ -271,6 +277,7 @@ export class BookPlayer { if (item.Path && (item.Path.endsWith('epub'))) { return true; } + return false; } } diff --git a/src/components/bookPlayer/style.css b/src/plugins/bookPlayer/style.css similarity index 100% rename from src/components/bookPlayer/style.css rename to src/plugins/bookPlayer/style.css diff --git a/src/components/bookPlayer/tableOfContent.js b/src/plugins/bookPlayer/tableOfContents.js similarity index 98% rename from src/components/bookPlayer/tableOfContent.js rename to src/plugins/bookPlayer/tableOfContents.js index 6a35966b1..23e288aff 100644 --- a/src/components/bookPlayer/tableOfContent.js +++ b/src/plugins/bookPlayer/tableOfContents.js @@ -1,6 +1,6 @@ import dialogHelper from 'dialogHelper'; -export default class TableOfContent { +export default class TableOfContents { constructor(bookPlayer) { this._bookPlayer = bookPlayer; this._rendition = bookPlayer._rendition; @@ -59,6 +59,7 @@ export default class TableOfContent { autoFocus: false, removeOnClose: true }); + elem.id = 'dialogToc'; let tocHtml = '
'; @@ -72,6 +73,7 @@ export default class TableOfContent { tocHtml += `${chapter.label}`; tocHtml += ''; }); + tocHtml += ''; elem.innerHTML = tocHtml; @@ -84,7 +86,6 @@ export default class TableOfContent { this._elem = elem; this.bindEvents(); - dialogHelper.open(elem); } } diff --git a/src/components/chromecast/chromecasthelpers.js b/src/plugins/chromecastPlayer/chromecastHelpers.js similarity index 100% rename from src/components/chromecast/chromecasthelpers.js rename to src/plugins/chromecastPlayer/chromecastHelpers.js diff --git a/src/components/chromecast/chromecastplayer.js b/src/plugins/chromecastPlayer/plugin.js similarity index 99% rename from src/components/chromecast/chromecastplayer.js rename to src/plugins/chromecastPlayer/plugin.js index 5a9945539..b3f75f7a6 100644 --- a/src/components/chromecast/chromecastplayer.js +++ b/src/plugins/chromecastPlayer/plugin.js @@ -57,11 +57,6 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' var applicationStable = 'F007D354'; var applicationNightly = '6F511C87'; - var applicationID = applicationStable; - if (userSettings.chromecastVersion === 'nightly') { - applicationID = applicationNightly; - } - var messageNamespace = 'urn:x-cast:com.connectsdk'; var CastPlayer = function () { @@ -105,6 +100,11 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' return; } + var applicationID = applicationStable; + if (userSettings.chromecastVersion() === 'nightly') { + applicationID = applicationNightly; + } + // request session var sessionRequest = new chrome.cast.SessionRequest(applicationID); var apiConfig = new chrome.cast.ApiConfig(sessionRequest, diff --git a/src/components/playback/experimentalwarnings.js b/src/plugins/experimentalWarnings/plugin.js similarity index 100% rename from src/components/playback/experimentalwarnings.js rename to src/plugins/experimentalWarnings/plugin.js diff --git a/src/components/htmlAudioPlayer/plugin.js b/src/plugins/htmlAudioPlayer/plugin.js similarity index 100% rename from src/components/htmlAudioPlayer/plugin.js rename to src/plugins/htmlAudioPlayer/plugin.js diff --git a/src/components/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js similarity index 98% rename from src/components/htmlVideoPlayer/plugin.js rename to src/plugins/htmlVideoPlayer/plugin.js index 0c9e15146..f8ba7c415 100644 --- a/src/components/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -281,14 +281,6 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa } self.play = function (options) { - - if (browser.msie) { - if (options.playMethod === 'Transcode' && !window.MediaSource) { - alert('Playback of this content is not supported in Internet Explorer. For a better experience, try a modern browser such as Microsoft Edge, Google Chrome, Firefox or Opera.'); - return Promise.reject(); - } - } - self._started = false; self._timeUpdated = false; @@ -1425,13 +1417,6 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa var video = document.createElement('video'); if (video.webkitSupportsPresentationMode && typeof video.webkitSetPresentationMode === 'function' || document.pictureInPictureEnabled) { list.push('PictureInPicture'); - } else if (browser.ipad) { - // Unfortunately this creates a false positive on devices where its' not actually supported - if (navigator.userAgent.toLowerCase().indexOf('os 9') === -1) { - if (video.webkitSupportsPresentationMode && video.webkitSupportsPresentationMode && typeof video.webkitSetPresentationMode === 'function') { - list.push('PictureInPicture'); - } - } } else if (window.Windows) { if (Windows.UI.ViewManagement.ApplicationView.getForCurrentView().isViewModeSupported(Windows.UI.ViewManagement.ApplicationViewMode.compactOverlay)) { list.push('PictureInPicture'); diff --git a/src/components/htmlVideoPlayer/style.css b/src/plugins/htmlVideoPlayer/style.css similarity index 100% rename from src/components/htmlVideoPlayer/style.css rename to src/plugins/htmlVideoPlayer/style.css diff --git a/src/components/logoScreensaver/plugin.js b/src/plugins/logoScreensaver/plugin.js similarity index 100% rename from src/components/logoScreensaver/plugin.js rename to src/plugins/logoScreensaver/plugin.js diff --git a/src/components/logoScreensaver/style.css b/src/plugins/logoScreensaver/style.css similarity index 100% rename from src/components/logoScreensaver/style.css rename to src/plugins/logoScreensaver/style.css diff --git a/src/components/photoPlayer/plugin.js b/src/plugins/photoPlayer/plugin.js similarity index 99% rename from src/components/photoPlayer/plugin.js rename to src/plugins/photoPlayer/plugin.js index d8d4ee70e..d8e55fa67 100644 --- a/src/components/photoPlayer/plugin.js +++ b/src/plugins/photoPlayer/plugin.js @@ -9,17 +9,12 @@ export default class PhotoPlayer { } play(options) { - return new Promise(function (resolve, reject) { - import('slideshow').then(({default: slideshow}) => { - var index = options.startIndex || 0; var apiClient = connectionManager.currentApiClient(); - apiClient.getCurrentUser().then(function(result) { - var newSlideShow = new slideshow({ showTitle: false, cover: false, @@ -31,7 +26,6 @@ export default class PhotoPlayer { }); newSlideShow.show(); - resolve(); }); }); @@ -39,7 +33,6 @@ export default class PhotoPlayer { } canPlayMediaType(mediaType) { - return (mediaType || '').toLowerCase() === 'photo'; } } diff --git a/src/components/playback/playaccessvalidation.js b/src/plugins/playAccessValidation/plugin.js similarity index 100% rename from src/components/playback/playaccessvalidation.js rename to src/plugins/playAccessValidation/plugin.js diff --git a/src/components/sessionPlayer.js b/src/plugins/sessionPlayer/plugin.js similarity index 100% rename from src/components/sessionPlayer.js rename to src/plugins/sessionPlayer/plugin.js diff --git a/src/components/youtubeplayer/plugin.js b/src/plugins/youtubePlayer/plugin.js similarity index 100% rename from src/components/youtubeplayer/plugin.js rename to src/plugins/youtubePlayer/plugin.js diff --git a/src/components/youtubeplayer/style.css b/src/plugins/youtubePlayer/style.css similarity index 100% rename from src/components/youtubeplayer/style.css rename to src/plugins/youtubePlayer/style.css diff --git a/src/scripts/browser.js b/src/scripts/browser.js index b1912862b..a377f08fd 100644 --- a/src/scripts/browser.js +++ b/src/scripts/browser.js @@ -14,10 +14,6 @@ define([], function () { return true; } - if (userAgent.indexOf('nintendo') !== -1) { - return true; - } - if (userAgent.indexOf('viera') !== -1) { return true; } @@ -93,7 +89,7 @@ define([], function () { var _supportsCssAnimation; var _supportsCssAnimationWithPrefix; function supportsCssAnimation(allowPrefix) { - + // TODO: Assess if this is still needed, as all of our targets should natively support CSS animations. if (allowPrefix) { if (_supportsCssAnimationWithPrefix === true || _supportsCssAnimationWithPrefix === false) { return _supportsCssAnimationWithPrefix; @@ -145,7 +141,6 @@ define([], function () { /(chrome)[ \/]([\w.]+)/.exec(ua) || /(safari)[ \/]([\w.]+)/.exec(ua) || /(firefox)[ \/]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || ua.indexOf('compatible') < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || []; @@ -161,14 +156,6 @@ define([], function () { if (browser === 'edge') { platform_match = ['']; - } else { - if (ua.indexOf('windows phone') !== -1 || ua.indexOf('iemobile') !== -1) { - - // http://www.neowin.net/news/ie11-fakes-user-agent-to-fool-gmail-in-windows-phone-81-gdr1-update - browser = 'msie'; - } else if (ua.indexOf('like gecko') !== -1 && ua.indexOf('webkit') === -1 && ua.indexOf('opera') === -1 && ua.indexOf('chrome') === -1 && ua.indexOf('safari') === -1) { - browser = 'msie'; - } } if (browser === 'opr') { @@ -211,7 +198,7 @@ define([], function () { browser[matched.platform] = true; } - if (!browser.chrome && !browser.msie && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf('webkit') !== -1) { + if (!browser.chrome && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf('webkit') !== -1) { browser.safari = true; } @@ -224,7 +211,10 @@ define([], function () { browser.mobile = true; } - browser.xboxOne = userAgent.toLowerCase().indexOf('xbox') !== -1; + if (userAgent.toLowerCase().indexOf('xbox') !== -1) { + browser.xboxOne = true; + browser.tv = true; + } browser.animate = typeof document !== 'undefined' && document.documentElement.animate != null; browser.tizen = userAgent.toLowerCase().indexOf('tizen') !== -1 || self.tizen != null; browser.web0s = userAgent.toLowerCase().indexOf('Web0S'.toLowerCase()) !== -1; diff --git a/src/scripts/browserDeviceProfile.js b/src/scripts/browserDeviceProfile.js index 2668f2091..a63f39ba9 100644 --- a/src/scripts/browserDeviceProfile.js +++ b/src/scripts/browserDeviceProfile.js @@ -6,18 +6,10 @@ define(['browser'], function (browser) { } function canPlayH265(videoTestElement, options) { - if (browser.tizen || browser.orsay || browser.xboxOne || browser.web0s || options.supportsHevc) { + if (browser.tizen || browser.xboxOne || browser.web0s || options.supportsHevc) { return true; } - var userAgent = navigator.userAgent.toLowerCase(); - if (browser.chromecast) { - var isChromecastUltra = userAgent.indexOf('aarch64') !== -1; - if (isChromecastUltra) { - return true; - } - } - if (browser.ps4) { return false; } @@ -31,7 +23,7 @@ define(['browser'], function (browser) { var _supportsTextTracks; function supportsTextTracks() { - if (browser.tizen || browser.orsay) { + if (browser.tizen) { return true; } @@ -53,7 +45,7 @@ define(['browser'], function (browser) { } function canPlayNativeHls() { - if (browser.tizen || browser.orsay) { + if (browser.tizen) { return true; } @@ -72,7 +64,7 @@ define(['browser'], function (browser) { } function supportsAc3(videoTestElement) { - if (browser.edgeUwp || browser.tizen || browser.orsay || browser.web0s) { + if (browser.edgeUwp || browser.tizen || browser.web0s) { return true; } @@ -80,7 +72,7 @@ define(['browser'], function (browser) { } function supportsEac3(videoTestElement) { - if (browser.tizen || browser.orsay || browser.web0s) { + if (browser.tizen || browser.web0s) { return true; } @@ -88,7 +80,7 @@ define(['browser'], function (browser) { } function supportsAc3InHls(videoTestElement) { - if (browser.tizen || browser.orsay || browser.web0s) { + if (browser.tizen || browser.web0s) { return true; } @@ -104,11 +96,11 @@ define(['browser'], function (browser) { var typeString; if (format === 'flac') { - if (browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp) { + if (browser.tizen || browser.web0s || browser.edgeUwp) { return true; } } else if (format === 'wma') { - if (browser.tizen || browser.orsay || browser.edgeUwp) { + if (browser.tizen || browser.edgeUwp) { return true; } } else if (format === 'asf') { @@ -143,7 +135,7 @@ define(['browser'], function (browser) { } function testCanPlayMkv(videoTestElement) { - if (browser.tizen || browser.orsay || browser.web0s) { + if (browser.tizen || browser.web0s) { return true; } @@ -152,23 +144,6 @@ define(['browser'], function (browser) { return true; } - // Unfortunately there's no real way to detect mkv support - if (browser.chrome) { - // Not supported on opera tv - if (browser.operaTv) { - return false; - } - - var userAgent = navigator.userAgent.toLowerCase(); - - // Filter out browsers based on chromium that don't support mkv - if (userAgent.indexOf('vivaldi') !== -1 || userAgent.indexOf('opera') !== -1) { - return false; - } - - return true; - } - if (browser.edgeUwp) { return true; } @@ -177,29 +152,15 @@ define(['browser'], function (browser) { } function testCanPlayTs() { - return browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; + return browser.tizen || browser.web0s || browser.edgeUwp; } function supportsMpeg2Video() { - return browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; + return browser.tizen || browser.web0s || browser.edgeUwp; } function supportsVc1() { - return browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; - } - - function getFlvMseDirectPlayProfile() { - var videoAudioCodecs = ['aac']; - if (!browser.edge && !browser.msie) { - videoAudioCodecs.push('mp3'); - } - - return { - Container: 'flv', - Type: 'Video', - VideoCodec: 'h264', - AudioCodec: videoAudioCodecs.join(',') - }; + return browser.tizen || browser.web0s || browser.edgeUwp; } function getDirectPlayProfileForVideoContainer(container, videoAudioCodecs, videoTestElement, options) { @@ -209,11 +170,11 @@ define(['browser'], function (browser) { switch (container) { case 'asf': - supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; + supported = browser.tizen || browser.web0s || browser.edgeUwp; videoAudioCodecs = []; break; case 'avi': - supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; + supported = browser.tizen || browser.web0s || browser.edgeUwp; // New Samsung TV don't support XviD/DivX // Explicitly add supported codecs to make other codecs be transcoded if (browser.tizenVersion >= 4) { @@ -226,27 +187,24 @@ define(['browser'], function (browser) { break; case 'mpg': case 'mpeg': - supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; + supported = browser.tizen || browser.web0s || browser.edgeUwp; break; case 'flv': - supported = browser.tizen || browser.orsay; - //if (!supported && window.MediaSource != null && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"')) { - // return getFlvMseDirectPlayProfile(); - //} + supported = browser.tizen; break; case '3gp': case 'mts': case 'trp': case 'vob': case 'vro': - supported = browser.tizen || browser.orsay; + supported = browser.tizen; break; case 'mov': - supported = browser.tizen || browser.orsay || browser.web0s || browser.chrome || browser.edgeUwp; + supported = browser.tizen || browser.web0s || browser.chrome || browser.edgeUwp; videoCodecs.push('h264'); break; case 'm2ts': - supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; + supported = browser.tizen || browser.web0s || browser.edgeUwp; videoCodecs.push('h264'); if (supportsVc1()) { videoCodecs.push('vc1'); @@ -256,7 +214,7 @@ define(['browser'], function (browser) { } break; case 'wmv': - supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; + supported = browser.tizen || browser.web0s || browser.edgeUwp; videoAudioCodecs = []; break; case 'ts': @@ -291,21 +249,6 @@ define(['browser'], function (browser) { } function getGlobalMaxVideoBitrate() { - var userAgent = navigator.userAgent.toLowerCase(); - if (browser.chromecast) { - var isChromecastUltra = userAgent.indexOf('aarch64') !== -1; - if (isChromecastUltra) { - return null; - } - - // This is a hack to try and detect chromecast on vizio - if (self.screen && self.screen.width >= 3800) { - return null; - } - - return 30000000; - } - var isTizenFhd = false; if (browser.tizen) { try { @@ -350,11 +293,12 @@ define(['browser'], function (browser) { var videoAudioCodecs = []; var hlsVideoAudioCodecs = []; - var supportsMp3VideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"').replace(/no/, '') || - videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"').replace(/no/, ''); + var supportsMp3VideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"').replace(/no/, '') + || videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"').replace(/no/, '') + || videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp3"').replace(/no/, ''); // Not sure how to test for this - var supportsMp2VideoAudio = browser.edgeUwp || browser.tizen || browser.orsay || browser.web0s; + var supportsMp2VideoAudio = browser.edgeUwp || browser.tizen || browser.web0s; var maxVideoWidth = browser.xboxOne ? (self.screen ? self.screen.width : null) : @@ -366,11 +310,6 @@ define(['browser'], function (browser) { var canPlayAacVideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"').replace(/no/, ''); - if (canPlayAacVideoAudio && browser.chromecast && physicalAudioChannels <= 2) { - // prioritize this first - videoAudioCodecs.push('aac'); - } - // Only put mp3 first if mkv support is there // Otherwise with HLS and mp3 audio we're seeing some browsers // safari is lying @@ -393,11 +332,6 @@ define(['browser'], function (browser) { } } - if (canPlayAacVideoAudio && browser.chromecast && videoAudioCodecs.indexOf('aac') === -1) { - // prioritize this first - videoAudioCodecs.push('aac'); - } - if (supportsMp3VideoAudio) { videoAudioCodecs.push('mp3'); @@ -432,7 +366,7 @@ define(['browser'], function (browser) { videoAudioCodecs.push('mp2'); } - var supportsDts = browser.tizen || browser.orsay || browser.web0s || options.supportsDts; + var supportsDts = browser.tizen || browser.web0s || options.supportsDts; // DTS audio not supported in 2018 models (Tizen 4.0) if (browser.tizenVersion >= 4) { @@ -444,7 +378,7 @@ define(['browser'], function (browser) { videoAudioCodecs.push('dts'); } - if (browser.tizen || browser.orsay || browser.web0s) { + if (browser.tizen || browser.web0s) { videoAudioCodecs.push('pcm_s16le'); videoAudioCodecs.push('pcm_s24le'); } @@ -453,7 +387,7 @@ define(['browser'], function (browser) { videoAudioCodecs.push('truehd'); } - if (browser.tizen || browser.orsay) { + if (browser.tizen) { videoAudioCodecs.push('aac_latm'); } @@ -501,7 +435,7 @@ define(['browser'], function (browser) { mp4VideoCodecs.push('vc1'); } - if (browser.tizen || browser.orsay) { + if (browser.tizen) { mp4VideoCodecs.push('msmpeg4v2'); } @@ -513,7 +447,7 @@ define(['browser'], function (browser) { mp4VideoCodecs.push('vp9'); } - if (canPlayVp8 || browser.tizen || browser.orsay) { + if (canPlayVp8 || browser.tizen) { videoAudioCodecs.push('vorbis'); } @@ -645,7 +579,7 @@ define(['browser'], function (browser) { }); }); - if (canPlayMkv && !browser.tizen && !browser.orsay && options.enableMkvProgressive !== false) { + if (canPlayMkv && !browser.tizen && options.enableMkvProgressive !== false) { profile.TranscodingProfiles.push({ Container: 'mkv', Type: 'Video', @@ -710,7 +644,7 @@ define(['browser'], function (browser) { profile.CodecProfiles = []; - var supportsSecondaryAudio = browser.tizen || browser.orsay || videoTestElement.audioTracks; + var supportsSecondaryAudio = browser.tizen || videoTestElement.audioTracks; var aacCodecProfileConditions = []; @@ -733,15 +667,6 @@ define(['browser'], function (browser) { }); } - if (browser.chromecast) { - aacCodecProfileConditions.push({ - Condition: 'LessThanEqual', - Property: 'AudioChannels', - Value: '2', - IsRequired: true - }); - } - if (aacCodecProfileConditions.length) { profile.CodecProfiles.push({ Type: 'VideoAudio', @@ -767,7 +692,7 @@ define(['browser'], function (browser) { var maxH264Level = 42; var h264Profiles = 'high|main|baseline|constrained baseline'; - if (browser.tizen || browser.orsay || browser.web0s || + if (browser.tizen || browser.web0s || videoTestElement.canPlayType('video/mp4; codecs="avc1.640833"').replace(/no/, '')) { maxH264Level = 51; } @@ -777,7 +702,7 @@ define(['browser'], function (browser) { maxH264Level = 52; } - if (browser.tizen || browser.orsay || + if (browser.tizen || videoTestElement.canPlayType('video/mp4; codecs="avc1.6e0033"').replace(/no/, '')) { // These tests are passing in safari, but playback is failing @@ -811,20 +736,13 @@ define(['browser'], function (browser) { ] }); - if (!browser.edgeUwp && !browser.tizen && !browser.orsay && !browser.web0s) { - //profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({ - // Condition: 'NotEquals', - // Property: 'IsAVC', - // Value: 'false', - // IsRequired: false - //}); - - //profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({ - // Condition: 'NotEquals', - // Property: 'IsInterlaced', - // Value: 'true', - // IsRequired: false - //}); + if (!browser.edgeUwp && !browser.tizen && !browser.web0s) { + profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({ + Condition: 'NotEquals', + Property: 'IsInterlaced', + Value: 'true', + IsRequired: false + }); } if (maxVideoWidth) { @@ -875,19 +793,6 @@ define(['browser'], function (browser) { }); } - if (browser.chromecast) { - profile.CodecProfiles.push({ - Type: 'Audio', - Codec: 'flac', - Conditions: [ - { - Condition: 'LessThanEqual', - Property: 'AudioSampleRate', - Value: '96000' - }] - }); - } - // Subtitle profiles // External vtt or burn in profile.SubtitleProfiles = []; diff --git a/src/scripts/editorsidebar.js b/src/scripts/editorsidebar.js index ee7788407..816838956 100644 --- a/src/scripts/editorsidebar.js +++ b/src/scripts/editorsidebar.js @@ -209,7 +209,7 @@ define(['datetime', 'jQuery', 'globalize', 'material-icons'], function (datetime function onNodeOpen(event, data) { var page = $(this).parents('.page')[0]; var node = data.node; - if (node.children && node.children) { + if (node.children) { loadNodesToLoad(page, node); } if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) { @@ -221,7 +221,7 @@ define(['datetime', 'jQuery', 'globalize', 'material-icons'], function (datetime function onNodeLoad(event, data) { var page = $(this).parents('.page')[0]; var node = data.node; - if (node.children && node.children) { + if (node.children) { loadNodesToLoad(page, node); } if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) { diff --git a/src/scripts/libraryMenu.js b/src/scripts/libraryMenu.js index 9e3f77b31..937ba4279 100644 --- a/src/scripts/libraryMenu.js +++ b/src/scripts/libraryMenu.js @@ -602,27 +602,25 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', ' if (libraryMenuOptions) { getUserViews(apiClient, userId).then(function (result) { var items = result; - var html = ''; - html += '

'; - html += globalize.translate('HeaderMedia'); - html += '

'; + var html = `

${globalize.translate('HeaderMedia')}

`; html += items.map(function (i) { var icon = i.icon || imageHelper.getLibraryIcon(i.CollectionType); var itemId = i.Id; - if (i.onclick) { - i.onclick; - } + const linkHtml = ` + + ${i.Name} + `; - return '' + i.Name + ''; + return linkHtml; }).join(''); libraryMenuOptions.innerHTML = html; var elem = libraryMenuOptions; var sidebarLinks = elem.querySelectorAll('.navMenuOption'); - for (var i = 0, length = sidebarLinks.length; i < length; i++) { - sidebarLinks[i].removeEventListener('click', onSidebarLinkClick); - sidebarLinks[i].addEventListener('click', onSidebarLinkClick); + for (const sidebarLink of sidebarLinks) { + sidebarLink.removeEventListener('click', onSidebarLinkClick); + sidebarLink.addEventListener('click', onSidebarLinkClick); } }); } @@ -936,6 +934,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', ' updateMenuForPageType(isDashboardPage, isLibraryPage); + // TODO: Seems to do nothing? Check if needed (also in other views). if (!e.detail.isRestored) { window.scrollTo(0, 0); } diff --git a/src/scripts/playlists.js b/src/scripts/playlists.js index 52e7ccb3b..974d00f8e 100644 --- a/src/scripts/playlists.js +++ b/src/scripts/playlists.js @@ -69,10 +69,11 @@ define(['loading', 'listView', 'cardBuilder', 'libraryMenu', 'libraryBrowser', ' showLoadingMessage(); var query = getQuery(view); var promise1 = ApiClient.getItems(Dashboard.getCurrentUserId(), query); + // TODO: promise2 is unused, check if necessary. var promise2 = Dashboard.getCurrentUser(); Promise.all([promise1, promise2]).then(function (responses) { var result = responses[0]; - responses[1]; + // TODO: Is the scroll necessary? window.scrollTo(0, 0); var html = ''; var viewStyle = getPageData(view).view; diff --git a/src/scripts/settings/userSettings.js b/src/scripts/settings/userSettings.js index 06c5fa40a..1b5283fa4 100644 --- a/src/scripts/settings/userSettings.js +++ b/src/scripts/settings/userSettings.js @@ -1,23 +1,30 @@ -/* eslint-disable indent */ - import appSettings from 'appSettings'; import events from 'events'; - function onSaveTimeout() { - var self = this; - self.saveTimeout = null; - self.currentApiClient.updateDisplayPreferences('usersettings', self.displayPrefs, self.currentUserId, 'emby'); +function onSaveTimeout() { + var self = this; + self.saveTimeout = null; + self.currentApiClient.updateDisplayPreferences('usersettings', self.displayPrefs, self.currentUserId, 'emby'); +} + +function saveServerPreferences(instance) { + if (instance.saveTimeout) { + clearTimeout(instance.saveTimeout); } - function saveServerPreferences(instance) { - if (instance.saveTimeout) { - clearTimeout(instance.saveTimeout); - } + instance.saveTimeout = setTimeout(onSaveTimeout.bind(instance), 50); +} - instance.saveTimeout = setTimeout(onSaveTimeout.bind(instance), 50); +export class UserSettings { + constructor() { } - export function setUserInfo(userId, apiClient) { + /** + * Bind UserSettings instance to user. + * @param {string} - User identifier. + * @param {Object} - ApiClient instance. + */ + setUserInfo(userId, apiClient) { if (this.saveTimeout) { clearTimeout(this.saveTimeout); } @@ -38,15 +45,24 @@ import events from 'events'; }); } - export function getData() { + // FIXME: Seems unused + getData() { return this.displayPrefs; } - export function importFrom(instance) { + // FIXME: Seems unused + importFrom(instance) { this.displayPrefs = instance.getData(); } - export function set(name, value, enableOnServer) { + // FIXME: 'appSettings.set' doesn't return any value + /** + * Set value of setting. + * @param {string} name - Name of setting. + * @param {mixed} value - Value of setting. + * @param {boolean} enableOnServer - Flag to save preferences on server. + */ + set(name, value, enableOnServer) { var userId = this.currentUserId; var currentValue = this.get(name, enableOnServer); var result = appSettings.set(name, value, userId); @@ -63,7 +79,13 @@ import events from 'events'; return result; } - export function get(name, enableOnServer) { + /** + * Get value of setting. + * @param {string} name - Name of setting. + * @param {boolean} enableOnServer - Flag to return preferences from server (cached). + * @return {string} Value of setting. + */ + get(name, enableOnServer) { var userId = this.currentUserId; if (enableOnServer !== false && this.displayPrefs) { return this.displayPrefs.CustomPrefs[name]; @@ -72,7 +94,12 @@ import events from 'events'; return appSettings.get(name, userId); } - export function serverConfig(config) { + /** + * Get or set user config. + * @param {Object|undefined} config - Configuration or undefined. + * @return {Object|Promise} Configuration or Promise. + */ + serverConfig(config) { var apiClient = this.currentApiClient; if (config) { return apiClient.updateUserConfiguration(this.currentUserId, config); @@ -83,7 +110,12 @@ import events from 'events'; }); } - export function enableCinemaMode(val) { + /** + * Get or set 'Cinema Mode' state. + * @param {boolean|undefined} val - Flag to enable 'Cinema Mode' or undefined. + * @return {boolean} 'Cinema Mode' state. + */ + enableCinemaMode(val) { if (val !== undefined) { return this.set('enableCinemaMode', val.toString(), false); } @@ -92,7 +124,12 @@ import events from 'events'; return val !== 'false'; } - export function enableNextVideoInfoOverlay(val) { + /** + * Get or set 'Next Video Info Overlay' state. + * @param {boolean|undefined} val - Flag to enable 'Next Video Info Overlay' or undefined. + * @return {boolean} 'Next Video Info Overlay' state. + */ + enableNextVideoInfoOverlay(val) { if (val !== undefined) { return this.set('enableNextVideoInfoOverlay', val.toString()); } @@ -101,7 +138,12 @@ import events from 'events'; return val !== 'false'; } - export function enableThemeSongs(val) { + /** + * Get or set 'Theme Songs' state. + * @param {boolean|undefined} val - Flag to enable 'Theme Songs' or undefined. + * @return {boolean} 'Theme Songs' state. + */ + enableThemeSongs(val) { if (val !== undefined) { return this.set('enableThemeSongs', val.toString(), false); } @@ -110,7 +152,12 @@ import events from 'events'; return val === 'true'; } - export function enableThemeVideos(val) { + /** + * Get or set 'Theme Videos' state. + * @param {boolean|undefined} val - Flag to enable 'Theme Videos' or undefined. + * @return {boolean} 'Theme Videos' state. + */ + enableThemeVideos(val) { if (val !== undefined) { return this.set('enableThemeVideos', val.toString(), false); } @@ -119,7 +166,12 @@ import events from 'events'; return val === 'true'; } - export function enableFastFadein(val) { + /** + * Get or set 'Fast Fade-in' state. + * @param {boolean|undefined} val - Flag to enable 'Fast Fade-in' or undefined. + * @return {boolean} 'Fast Fade-in' state. + */ + enableFastFadein(val) { if (val !== undefined) { return this.set('fastFadein', val.toString(), false); } @@ -128,7 +180,26 @@ import events from 'events'; return val !== 'false'; } - export function enableBackdrops(val) { + /** + * Get or set 'Blurhash' state. + * @param {boolean|undefined} val - Flag to enable 'Blurhash' or undefined. + * @return {boolean} 'Blurhash' state. + */ + enableBlurhash(val) { + if (val !== undefined) { + return this.set('blurhash', val.toString(), false); + } + + val = this.get('blurhash', false); + return val !== 'false'; + } + + /** + * Get or set 'Backdrops' state. + * @param {boolean|undefined} val - Flag to enable 'Backdrops' or undefined. + * @return {boolean} 'Backdrops' state. + */ + enableBackdrops(val) { if (val !== undefined) { return this.set('enableBackdrops', val.toString(), false); } @@ -137,7 +208,12 @@ import events from 'events'; return val !== 'false'; } - export function detailsBanner(val) { + /** + * Get or set 'Details Banner' state. + * @param {boolean|undefined} val - Flag to enable 'Details Banner' or undefined. + * @return {boolean} 'Details Banner' state. + */ + detailsBanner(val) { if (val !== undefined) { return this.set('detailsBanner', val.toString(), false); } @@ -146,7 +222,12 @@ import events from 'events'; return val !== 'false'; } - export function language(val) { + /** + * Get or set language. + * @param {string|undefined} val - Language. + * @return {string} Language. + */ + language(val) { if (val !== undefined) { return this.set('language', val.toString(), false); } @@ -154,7 +235,12 @@ import events from 'events'; return this.get('language', false); } - export function dateTimeLocale(val) { + /** + * Get or set datetime locale. + * @param {string|undefined} val - Datetime locale. + * @return {string} Datetime locale. + */ + dateTimeLocale(val) { if (val !== undefined) { return this.set('datetimelocale', val.toString(), false); } @@ -162,7 +248,12 @@ import events from 'events'; return this.get('datetimelocale', false); } - export function chromecastVersion(val) { + /** + * Get or set Chromecast version. + * @param {string|undefined} val - Chromecast version. + * @return {string} Chromecast version. + */ + chromecastVersion(val) { if (val !== undefined) { return this.set('chromecastVersion', val.toString()); } @@ -170,7 +261,12 @@ import events from 'events'; return this.get('chromecastVersion') || 'stable'; } - export function skipBackLength(val) { + /** + * Get or set amount of rewind. + * @param {number|undefined} val - Amount of rewind. + * @return {number} Amount of rewind. + */ + skipBackLength(val) { if (val !== undefined) { return this.set('skipBackLength', val.toString()); } @@ -178,7 +274,12 @@ import events from 'events'; return parseInt(this.get('skipBackLength') || '10000'); } - export function skipForwardLength(val) { + /** + * Get or set amount of fast forward. + * @param {number|undefined} val - Amount of fast forward. + * @return {number} Amount of fast forward. + */ + skipForwardLength(val) { if (val !== undefined) { return this.set('skipForwardLength', val.toString()); } @@ -186,7 +287,12 @@ import events from 'events'; return parseInt(this.get('skipForwardLength') || '30000'); } - export function dashboardTheme(val) { + /** + * Get or set theme for Dashboard. + * @param {string|undefined} val - Theme for Dashboard. + * @return {string} Theme for Dashboard. + */ + dashboardTheme(val) { if (val !== undefined) { return this.set('dashboardTheme', val); } @@ -194,7 +300,12 @@ import events from 'events'; return this.get('dashboardTheme'); } - export function skin(val) { + /** + * Get or set skin. + * @param {string|undefined} val - Skin. + * @return {string} Skin. + */ + skin(val) { if (val !== undefined) { return this.set('skin', val, false); } @@ -202,7 +313,12 @@ import events from 'events'; return this.get('skin', false); } - export function theme(val) { + /** + * Get or set main theme. + * @param {string|undefined} val - Main theme. + * @return {string} Main theme. + */ + theme(val) { if (val !== undefined) { return this.set('appTheme', val, false); } @@ -210,7 +326,12 @@ import events from 'events'; return this.get('appTheme', false); } - export function screensaver(val) { + /** + * Get or set screensaver. + * @param {string|undefined} val - Screensaver. + * @return {string} Screensaver. + */ + screensaver(val) { if (val !== undefined) { return this.set('screensaver', val, false); } @@ -218,7 +339,12 @@ import events from 'events'; return this.get('screensaver', false); } - export function libraryPageSize(val) { + /** + * Get or set library page size. + * @param {number|undefined} val - Library page size. + * @return {number} Library page size. + */ + libraryPageSize(val) { if (val !== undefined) { return this.set('libraryPageSize', parseInt(val, 10), false); } @@ -232,7 +358,12 @@ import events from 'events'; } } - export function soundEffects(val) { + /** + * Get or set sound effects. + * @param {string|undefined} val - Sound effects. + * @return {string} Sound effects. + */ + soundEffects(val) { if (val !== undefined) { return this.set('soundeffects', val, false); } @@ -240,7 +371,13 @@ import events from 'events'; return this.get('soundeffects', false); } - export function loadQuerySettings(key, query) { + /** + * Load query settings. + * @param {string} key - Query key. + * @param {Object} query - Query base. + * @return {Object} Query. + */ + loadQuerySettings(key, query) { var values = this.get(key); if (values) { values = JSON.parse(values); @@ -250,7 +387,12 @@ import events from 'events'; return query; } - export function saveQuerySettings(key, query) { + /** + * Save query settings. + * @param {string} key - Query key. + * @param {Object} query - Query. + */ + saveQuerySettings(key, query) { var values = {}; if (query.SortBy) { values.SortBy = query.SortBy; @@ -263,52 +405,76 @@ import events from 'events'; return this.set(key, JSON.stringify(values)); } - export function getSubtitleAppearanceSettings(key) { + /** + * Get subtitle appearance settings. + * @param {string|undefined} key - Settings key. + * @return {Object} Subtitle appearance settings. + */ + getSubtitleAppearanceSettings(key) { key = key || 'localplayersubtitleappearance3'; return JSON.parse(this.get(key, false) || '{}'); } - export function setSubtitleAppearanceSettings(value, key) { + /** + * Set subtitle appearance settings. + * @param {Object} value - Subtitle appearance settings. + * @param {string|undefined} key - Settings key. + */ + setSubtitleAppearanceSettings(value, key) { key = key || 'localplayersubtitleappearance3'; return this.set(key, JSON.stringify(value), false); } - export function setFilter(key, value) { + /** + * Set filter. + * @param {string} key - Filter key. + * @param {string} value - Filter value. + */ + setFilter(key, value) { return this.set(key, value, true); } - export function getFilter(key) { + /** + * Get filter. + * @param {string} key - Filter key. + * @return {string} Filter value. + */ + getFilter(key) { return this.get(key, true); } +} -/* eslint-enable indent */ -export default { - setUserInfo: setUserInfo, - getData: getData, - importFrom: importFrom, - set: set, - get: get, - serverConfig: serverConfig, - enableCinemaMode: enableCinemaMode, - enableNextVideoInfoOverlay: enableNextVideoInfoOverlay, - enableThemeSongs: enableThemeSongs, - enableThemeVideos: enableThemeVideos, - enableFastFadein: enableFastFadein, - enableBackdrops: enableBackdrops, - language: language, - dateTimeLocale: dateTimeLocale, - skipBackLength: skipBackLength, - skipForwardLength: skipForwardLength, - dashboardTheme: dashboardTheme, - skin: skin, - theme: theme, - screensaver: screensaver, - libraryPageSize: libraryPageSize, - soundEffects: soundEffects, - loadQuerySettings: loadQuerySettings, - saveQuerySettings: saveQuerySettings, - getSubtitleAppearanceSettings: getSubtitleAppearanceSettings, - setSubtitleAppearanceSettings: setSubtitleAppearanceSettings, - setFilter: setFilter, - getFilter: getFilter -}; +export const currentSettings = new UserSettings; + +// Wrappers for non-ES6 modules and backward compatibility +export const setUserInfo = currentSettings.setUserInfo.bind(currentSettings); +export const getData = currentSettings.getData.bind(currentSettings); +export const importFrom = currentSettings.importFrom.bind(currentSettings); +export const set = currentSettings.set.bind(currentSettings); +export const get = currentSettings.get.bind(currentSettings); +export const serverConfig = currentSettings.serverConfig.bind(currentSettings); +export const enableCinemaMode = currentSettings.enableCinemaMode.bind(currentSettings); +export const enableNextVideoInfoOverlay = currentSettings.enableNextVideoInfoOverlay.bind(currentSettings); +export const enableThemeSongs = currentSettings.enableThemeSongs.bind(currentSettings); +export const enableThemeVideos = currentSettings.enableThemeVideos.bind(currentSettings); +export const enableFastFadein = currentSettings.enableFastFadein.bind(currentSettings); +export const enableBlurhash = currentSettings.enableBlurhash.bind(currentSettings); +export const enableBackdrops = currentSettings.enableBackdrops.bind(currentSettings); +export const detailsBanner = currentSettings.detailsBanner.bind(currentSettings); +export const language = currentSettings.language.bind(currentSettings); +export const dateTimeLocale = currentSettings.dateTimeLocale.bind(currentSettings); +export const chromecastVersion = currentSettings.chromecastVersion.bind(currentSettings); +export const skipBackLength = currentSettings.skipBackLength.bind(currentSettings); +export const skipForwardLength = currentSettings.skipForwardLength.bind(currentSettings); +export const dashboardTheme = currentSettings.dashboardTheme.bind(currentSettings); +export const skin = currentSettings.skin.bind(currentSettings); +export const theme = currentSettings.theme.bind(currentSettings); +export const screensaver = currentSettings.screensaver.bind(currentSettings); +export const libraryPageSize = currentSettings.libraryPageSize.bind(currentSettings); +export const soundEffects = currentSettings.soundEffects.bind(currentSettings); +export const loadQuerySettings = currentSettings.loadQuerySettings.bind(currentSettings); +export const saveQuerySettings = currentSettings.saveQuerySettings.bind(currentSettings); +export const getSubtitleAppearanceSettings = currentSettings.getSubtitleAppearanceSettings.bind(currentSettings); +export const setSubtitleAppearanceSettings = currentSettings.setSubtitleAppearanceSettings.bind(currentSettings); +export const setFilter = currentSettings.setFilter.bind(currentSettings); +export const getFilter = currentSettings.getFilter.bind(currentSettings); diff --git a/src/scripts/settings/webSettings.js b/src/scripts/settings/webSettings.js index d999724af..64989b4fc 100644 --- a/src/scripts/settings/webSettings.js +++ b/src/scripts/settings/webSettings.js @@ -2,7 +2,7 @@ let data; function getConfig() { if (data) return Promise.resolve(data); - return fetch('/config.json?nocache=' + new Date().getUTCMilliseconds()).then(response => { + return fetch('config.json?nocache=' + new Date().getUTCMilliseconds()).then(response => { data = response.json(); return data; }).catch(error => { @@ -12,7 +12,7 @@ function getConfig() { } function getDefaultConfig() { - return fetch('/config.template.json').then(function (response) { + return fetch('config.template.json').then(function (response) { data = response.json(); return data; }); diff --git a/src/scripts/site.js b/src/scripts/site.js index 1eae51ed1..65ecfd1b0 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -228,6 +228,28 @@ var Dashboard = { } else { Dashboard.navigate('selectserver.html'); } + }, + hideLoadingMsg: function() { + 'use strict'; + require(['loading'], function(loading) { + loading.hide(); + }); + }, + showLoadingMsg: function() { + 'use strict'; + require(['loading'], function(loading) { + loading.show(); + }); + }, + confirm: function(message, title, callback) { + 'use strict'; + require(['confirm'], function(confirm) { + confirm(message, title).then(function() { + callback(!0); + }).catch(function() { + callback(!1); + }); + }); } }; @@ -375,8 +397,7 @@ var AppInfo = {}; } } - function initRequireWithBrowser(browser) { - var bowerPath = getBowerPath(); + function initRequireWithBrowser() { var componentsPath = getComponentsPath(); var scriptsPath = getScriptsPath(); @@ -385,13 +406,7 @@ var AppInfo = {}; define('lazyLoader', [componentsPath + '/lazyLoader/lazyLoaderIntersectionObserver'], returnFirstDependency); define('shell', [scriptsPath + '/shell'], returnFirstDependency); - if ('registerElement' in document) { - define('registerElement', []); - } else if (browser.msie) { - define('registerElement', ['webcomponents'], returnFirstDependency); - } else { - define('registerElement', ['document-register-element'], returnFirstDependency); - } + define('registerElement', ['document-register-element'], returnFirstDependency); define('alert', [componentsPath + '/alert'], returnFirstDependency); @@ -486,22 +501,22 @@ var AppInfo = {}; function loadPlugins(appHost, browser, shell) { console.debug('loading installed plugins'); var list = [ - 'components/playback/playaccessvalidation', - 'components/playback/experimentalwarnings', - 'components/htmlAudioPlayer/plugin', - 'components/htmlVideoPlayer/plugin', - 'components/photoPlayer/plugin', - 'components/bookPlayer/plugin', - 'components/youtubeplayer/plugin', - 'components/backdropScreensaver/plugin', - 'components/logoScreensaver/plugin' + 'plugins/playAccessValidation/plugin', + 'plugins/experimentalWarnings/plugin', + 'plugins/htmlAudioPlayer/plugin', + 'plugins/htmlVideoPlayer/plugin', + 'plugins/photoPlayer/plugin', + 'plugins/bookPlayer/plugin', + 'plugins/youtubePlayer/plugin', + 'plugins/backdropScreensaver/plugin', + 'plugins/logoScreensaver/plugin' ]; if (appHost.supports('remotecontrol')) { - list.push('components/sessionPlayer'); + list.push('plugins/sessionPlayer/plugin'); if (browser.chrome || browser.opera) { - list.push('components/chromecast/chromecastplayer'); + list.push('plugins/chromecastPlayer/plugin'); } } @@ -618,8 +633,8 @@ var AppInfo = {}; /* eslint-enable compat/compat */ } - function onWebComponentsReady(browser) { - initRequireWithBrowser(browser); + function onWebComponentsReady() { + initRequireWithBrowser(); if (self.appMode === 'cordova' || self.appMode === 'android' || self.appMode === 'standalone') { AppInfo.isNativeApp = true; @@ -660,8 +675,9 @@ var AppInfo = {}; playQueueManager: componentsPath + '/playback/playqueuemanager', nowPlayingHelper: componentsPath + '/playback/nowplayinghelper', pluginManager: componentsPath + '/pluginManager', - packageManager: componentsPath + '/packagemanager', - screensaverManager: componentsPath + '/screensavermanager' + packageManager: componentsPath + '/packageManager', + screensaverManager: componentsPath + '/screensavermanager', + chromecastHelper: 'plugins/chromecastPlayer/chromecastHelpers' }; requirejs.onError = onRequireJsError; @@ -743,7 +759,6 @@ var AppInfo = {}; // define legacy features // TODO delete the rest of these define('fnchecked', ['legacy/fnchecked'], returnFirstDependency); - define('legacyDashboard', ['legacy/dashboard'], returnFirstDependency); define('legacySelectMenu', ['legacy/selectmenu'], returnFirstDependency); // there are several objects that need to be instantiated @@ -781,7 +796,6 @@ var AppInfo = {}; define('appSettings', [scriptsPath + '/settings/appSettings'], returnFirstDependency); define('userSettings', [scriptsPath + '/settings/userSettings'], returnFirstDependency); - define('chromecastHelper', [componentsPath + '/chromecast/chromecasthelpers'], returnFirstDependency); define('mediaSession', [componentsPath + '/playback/mediasession'], returnFirstDependency); define('actionsheet', [componentsPath + '/actionSheet/actionSheet'], returnFirstDependency); define('tunerPicker', [componentsPath + '/tunerPicker'], returnFirstDependency); @@ -827,10 +841,10 @@ var AppInfo = {}; define('playbackSettings', [componentsPath + '/playbackSettings/playbackSettings'], returnFirstDependency); define('homescreenSettings', [componentsPath + '/homeScreenSettings/homeScreenSettings'], returnFirstDependency); define('playbackManager', [componentsPath + '/playback/playbackmanager'], getPlaybackManager); - define('timeSyncManager', [componentsPath + '/syncplay/timeSyncManager'], returnDefault); - define('groupSelectionMenu', [componentsPath + '/syncplay/groupSelectionMenu'], returnFirstDependency); - define('syncPlayManager', [componentsPath + '/syncplay/syncPlayManager'], returnDefault); - define('playbackPermissionManager', [componentsPath + '/syncplay/playbackPermissionManager'], returnDefault); + define('timeSyncManager', [componentsPath + '/syncPlay/timeSyncManager'], returnDefault); + define('groupSelectionMenu', [componentsPath + '/syncPlay/groupSelectionMenu'], returnFirstDependency); + define('syncPlayManager', [componentsPath + '/syncPlay/syncPlayManager'], returnDefault); + define('playbackPermissionManager', [componentsPath + '/syncPlay/playbackPermissionManager'], returnDefault); define('layoutManager', [componentsPath + '/layoutManager', 'apphost'], getLayoutManager); define('homeSections', [componentsPath + '/homesections/homesections'], returnFirstDependency); define('playMenu', [componentsPath + '/playmenu'], returnFirstDependency); @@ -854,7 +868,7 @@ var AppInfo = {}; define('userdataButtons', [componentsPath + '/userdatabuttons/userdatabuttons'], returnFirstDependency); define('listView', [componentsPath + '/listview/listview'], returnFirstDependency); define('indicators', [componentsPath + '/indicators/indicators'], returnFirstDependency); - define('viewSettings', [componentsPath + '/viewsettings/viewsettings'], returnFirstDependency); + define('viewSettings', [componentsPath + '/viewSettings/viewSettings'], returnFirstDependency); define('filterMenu', [componentsPath + '/filtermenu/filtermenu'], returnFirstDependency); define('sortMenu', [componentsPath + '/sortmenu/sortmenu'], returnFirstDependency); define('sanitizefilename', [componentsPath + '/sanitizeFilename'], returnFirstDependency); @@ -1140,7 +1154,7 @@ var AppInfo = {}; }); })(); - return require(['browser'], onWebComponentsReady); + return onWebComponentsReady(); }(); pageClassOn('viewshow', 'standalonePage', function () { diff --git a/src/strings/cs.json b/src/strings/cs.json index 8b631caf5..626c63bec 100644 --- a/src/strings/cs.json +++ b/src/strings/cs.json @@ -1540,8 +1540,6 @@ "CopyStreamURLError": "Při kopírování URL došlo k chybě.", "LabelVideoResolution": "Rozlišení videa:", "LabelStreamType": "Typ streamu:", - "EnableFastImageFadeInHelp": "Zobrazí plakáty a další obrázky s rychlejší animací přechodu po dokončení načítání.", - "EnableFastImageFadeIn": "Rychlé animace přechodů obrazu", "LabelPlayerDimensions": "Zobrazené rozlišení:", "LabelDroppedFrames": "Vynechané snímky:", "LabelCorruptedFrames": "Poškozené snímky:", @@ -1603,7 +1601,7 @@ "HeaderDVR": "Nahrávání", "SaveChanges": "Uložit změny", "LabelSyncPlayPlaybackDiff": "Rozdíl v době přehrávání:", - "SyncPlayAccessHelp": "Určuje úroveň přístupu k synchronizaci přehrávání, kterou tento uživatel bude mít. Tato funkce umožňuje synchronizovat přehrávání s dalšími uživateli.", + "SyncPlayAccessHelp": "Určuje úroveň přístupu k synchronizaci přehrávání, kterou tento uživatel bude mít. Tato funkce umožňuje synchronizovat přehrávání s dalšími zařízeními.", "MessageSyncPlayErrorMedia": "Zapnutí synchronizace přehrávání se nezdařilo. Chyba média.", "MessageSyncPlayErrorMissingSession": "Zapnutí synchronizace přehrávání se nezdařilo. Nebyla nalezena relace.", "MessageSyncPlayErrorNoActivePlayer": "Nebyl nalezen žádný aktivní přehrávač. Synchronizace přehrávání byla vypnuta.", @@ -1633,5 +1631,7 @@ "HeaderSyncPlayEnabled": "Synchronizace přehrávání povolena", "HeaderSyncPlaySelectGroup": "Připojit ke skupině", "EnableDetailsBannerHelp": "Zobrazí obrázek ve vrchní části detailu položky.", - "EnableDetailsBanner": "Obrázek detailu" + "EnableDetailsBanner": "Obrázek detailu", + "ShowMore": "Zobrazit více", + "ShowLess": "Zobrazit méně" } diff --git a/src/strings/da.json b/src/strings/da.json index 45c0ddb33..5cc1f4ab5 100644 --- a/src/strings/da.json +++ b/src/strings/da.json @@ -1569,8 +1569,6 @@ "LabelStreamType": "Stream type:", "LabelSonyAggregationFlags": "Sony aggregering flag:", "LabelSize": "Størrelse:", - "EnableFastImageFadeInHelp": "Aktivér hurtigere fade-in-animation til indlæste billeder", - "EnableFastImageFadeIn": "Hurtigt billede indtoning", "LabelPleaseRestart": "Ændringer vil træde i kraft efter web klienten er blevet genindlæst manuelt.", "LabelPlayMethod": "Afspilnings metode:", "LabelPlayerDimensions": "Afspillerdimensioner:", diff --git a/src/strings/de.json b/src/strings/de.json index 4e9934e9c..daad4b05b 100644 --- a/src/strings/de.json +++ b/src/strings/de.json @@ -1478,8 +1478,6 @@ "MessageConfirmAppExit": "Wirklich verlassen?", "LabelVideoResolution": "Videoauflösung:", "LabelStreamType": "Streamtyp:", - "EnableFastImageFadeInHelp": "Zeige Poster und andere Bilder mit einer schnelleren Einblendeanimation, wenn diese fertig geladen sind.", - "EnableFastImageFadeIn": "Schnelle Bildeinblendungsanimationen", "LabelPlayerDimensions": "Playerabmessungen:", "LabelDroppedFrames": "Verlorene Frames:", "LabelCorruptedFrames": "Fehlerhafte Frames:", @@ -1571,5 +1569,7 @@ "HeaderSyncPlayEnabled": "SyncPlay aktiviert", "HeaderSyncPlaySelectGroup": "Tritt einer Gruppe bei", "EnableDetailsBannerHelp": "Zeigt ein Bannerbild im oberen Bereich der Seite Item-Details.", - "EnableDetailsBanner": "Detailbanner" + "EnableDetailsBanner": "Detailbanner", + "ShowMore": "Mehr anzeigen", + "ShowLess": "Weniger anzeigen" } diff --git a/src/strings/en-gb.json b/src/strings/en-gb.json index 6d49f52c7..3ce9a1047 100644 --- a/src/strings/en-gb.json +++ b/src/strings/en-gb.json @@ -837,8 +837,8 @@ "LabelSecureConnectionsMode": "Secure connection mode:", "LabelSeasonNumber": "Season number:", "LabelScreensaver": "Screensaver:", - "EnableFastImageFadeIn": "Fast image fade-in", - "EnableFastImageFadeInHelp": "Enable faster fade-in animation for loaded images", + "EnableFasterAnimations": "Faster animations", + "EnableFasterAnimationsHelp": "Use faster animations and transitions", "LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.", "LabelSaveLocalMetadataHelp": "Saving artwork into media folders will put them in a place where they can be easily edited.", "LabelRuntimeMinutes": "Run time (minutes):", diff --git a/src/strings/en-us.json b/src/strings/en-us.json index f26ba16c8..b8e081a58 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -826,8 +826,8 @@ "LabelSaveLocalMetadataHelp": "Saving artwork into media folders will put them in a place where they can be easily edited.", "LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.", "LabelScreensaver": "Screensaver:", - "EnableFastImageFadeIn": "Fast Image Fade Animations", - "EnableFastImageFadeInHelp": "Show posters and other images with a quicker fade animation when they finish loading.", + "EnableFasterAnimations": "Faster animations", + "EnableFasterAnimationsHelp": "Use faster animations and transitions", "LabelSeasonNumber": "Season number:", "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", @@ -1024,10 +1024,11 @@ "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item or the global default value.", "MessageNoAvailablePlugins": "No available plugins.", "MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, and Albums. Click the + button to start creating collections.", + "MessageNoGenresAvailable": "Enable some metadata providers to pull genres from the internet.", "MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.", "MessageNoPluginsInstalled": "You have no plugins installed.", "MessageNoServersAvailable": "No servers have been found using the automatic server discovery.", - "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.", + "MessageNoTrailersFound": "Install the trailers channel to enhance your movie experience by adding a library of internet trailers.", "MessageNothingHere": "Nothing here.", "MessagePasswordResetForUsers": "The following users have had their passwords reset. They can now sign in with the pin codes that were used to perform the reset.", "MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your server administrator for more information.", @@ -1373,6 +1374,8 @@ "Share": "Share", "ShowAdvancedSettings": "Show advanced settings", "ShowIndicatorsFor": "Show indicators for:", + "ShowLess": "Show less", + "ShowMore": "Show more", "ShowTitle": "Show title", "ShowYear": "Show year", "Shows": "Shows", @@ -1546,5 +1549,7 @@ "EveryHour": "Every hour", "EveryXHours": "Every {0} hours", "OnApplicationStartup": "On application startup", - "UnsupportedPlayback": "Jellyfin cannot decrypt content protected by DRM but all content will be attempted regardless, including protected titles. Some files may appear completely black due to encryption or other unsupported features, such as interactive titles." + "UnsupportedPlayback": "Jellyfin cannot decrypt content protected by DRM but all content will be attempted regardless, including protected titles. Some files may appear completely black due to encryption or other unsupported features, such as interactive titles.", + "EnableBlurhash": "Enable blurred placeholders for images", + "EnableBlurhashHelp": "Images that are still being loaded will be displayed with a blurred placeholder" } diff --git a/src/strings/es-mx.json b/src/strings/es-mx.json index 3a711a558..b41385feb 100644 --- a/src/strings/es-mx.json +++ b/src/strings/es-mx.json @@ -1453,7 +1453,6 @@ "LabelTranscodingFramerate": "Velocidad de cuadros de la transcodificación:", "LabelSize": "Tamaño:", "SelectAdminUsername": "Por favor, selecciona un nombre de usuario para la cuenta de administrador.", - "EnableFastImageFadeInHelp": "Habilita una animación más rápida de desvanecimiento para las imágenes cargadas.", "LabelDroppedFrames": "Cuadros saltados:", "CopyStreamURLError": "Hubo un error al copiar la URL.", "ButtonSplit": "Dividir", @@ -1484,7 +1483,6 @@ "MessageConfirmAppExit": "¿Deseas salir?", "LabelVideoResolution": "Resolución de video:", "LabelStreamType": "Tipo de transmisión:", - "EnableFastImageFadeIn": "Desvanecimiento rápido de animaciones", "LabelPlayerDimensions": "Dimensiones del reproductor:", "LabelCorruptedFrames": "Cuadros corruptos:", "HeaderNavigation": "Navegación", diff --git a/src/strings/es.json b/src/strings/es.json index ab46562f9..eedfa3d73 100644 --- a/src/strings/es.json +++ b/src/strings/es.json @@ -1,5 +1,5 @@ { - "AccessRestrictedTryAgainLater": "El acceso está restringido actualmente. Por favor, inténtalo más tarde.", + "AccessRestrictedTryAgainLater": "Actualmente el acceso está restringido. Por favor, inténtalo de nuevo más tarde.", "Add": "Añadir", "AddItemToCollectionHelp": "Agregue elementos a las colecciones buscándolos y haciendo clic con el botón derecho o tocando los menús para agregarlos a una colección.", "AddToCollection": "Añadir a la colección", @@ -1458,8 +1458,8 @@ "ButtonSplit": "Dividir", "HeaderNavigation": "Navegación", "MessageConfirmAppExit": "¿Quieres salir?", - "EnableFastImageFadeInHelp": "Mostrar carteles y otras imágenes con difuminado rápido cuando termine la carga.", - "EnableFastImageFadeIn": "Difuminado rápido de imágenes", + "EnableFasterAnimationsHelp": "Las animaciones y transiciones durarán menos tiempo", + "EnableFasterAnimations": "Animaciones más rápidas", "CopyStreamURLError": "Ha habido un error copiando la dirección.", "AllowFfmpegThrottlingHelp": "Cuando una transcodificación o un remux se adelanta lo suficiente desde la posición de reproducción actual, pause el proceso para que consuma menos recursos. Esto es más útil cuando se reproduce de forma linear, sin saltar de posición de reproducción a menudo. Desactívelo si experimenta problemas de reproducción.", "PlaybackErrorNoCompatibleStream": "Este contenido no es compatible con este dispositivo y no se puede reproducir: No se puede obtener del servidor en un formato compatible.", @@ -1524,8 +1524,10 @@ "LabelEnableHttps": "Activar HTTPS", "TabDVR": "DVR", "SaveChanges": "Guardar cambios", + "EnableBlurhash": "Mostrar una representación de las imágenes mientras cargan", + "EnableBlurhashHelp": "Aparecerá una representación de los colores de las imágenes antes de que terminen de cargar", "HeaderDVR": "DVR", - "SyncPlayAccessHelp": "Selecciona los permisos de este usuario para utilizar SyncPlay. SyncPlay te permite sincroniza la reproducción entre varios dispositivos.", + "SyncPlayAccessHelp": "Selecciona los permisos de este usuario para utilizar SyncPlay. SyncPlay te permite sincronizar la reproducción entre varios dispositivos.", "MessageSyncPlayErrorMedia": "¡No se pudo activar SyncPlay! Error de medio.", "MessageSyncPlayErrorMissingSession": "¡No se pudo activar SyncPlay! Sesión desconectada.", "MessageSyncPlayErrorNoActivePlayer": "No hay reproductor activo. SyncPlay ha sido desactivado.", @@ -1556,5 +1558,7 @@ "HeaderSyncPlayEnabled": "Syncplay activo", "HeaderSyncPlaySelectGroup": "Unirse a un grupo", "EnableDetailsBannerHelp": "Mostrar imagen de banner en el tope de la página de detalles del elemento.", - "EnableDetailsBanner": "Barra de Detalles" + "EnableDetailsBanner": "Barra de Detalles", + "ShowMore": "Mostrar más", + "ShowLess": "Mostrar menos" } diff --git a/src/strings/fa.json b/src/strings/fa.json index b91a2c82f..f8e2cf820 100644 --- a/src/strings/fa.json +++ b/src/strings/fa.json @@ -612,7 +612,7 @@ "ConfirmDeleteItem": "حذف این مورد، آن را هم از فایل سیستمی و هم از کتابخانه رسانه شما حذف می کند. آیا اطمینان دارید که می‌خواهید ادامه دهید؟", "AlwaysPlaySubtitlesHelp": "زیرنویس‌های متناسب با توجه به اولویت زبان بدون در نظر گرفتن زبان صوتی ویدیو پخش می شوند.", "AllowedRemoteAddressesHelp": "لیستی از آدرس های IP یا ورودی‌های IP/‌netmask برای شبکه هایی که به آنها امکان ارتباط از راه دور داده می‌شود ، با کاما از هم جدا شدند. در صورت خالی ماندن ، تمام آدرسهای راه دور مجاز خواهند بود.", - "AllowOnTheFlySubtitleExtractionHelp": "زیرنویس های جاسازی شده را می‌توان از فیلم‌ها استخراج کرد و به منظور جلوگیری از کدگذاری فیلم ، به صورت متن ساده به بازدید کننده ارسال کرد. در بعضی از سیستم‌ها این می‌تواند مدت زیادی طول بکشد و باعث شود پخش فیلم در طول فرآیند استخراج متوقف شود. این گزینه را غیرفعال کنید تا زیرنویس‌های جاسازی شده با استفاده از رمزگذاری ویدیو در حالی که به طور محلی توسط دستگاه بازدیدکننده پشتیبانی نمی‌شوند ارسال شود.", + "AllowOnTheFlySubtitleExtractionHelp": "زیرنویس های جاسازی شده را می‌توان از ویدئو ها استخراج کرد و به منظور جلوگیری از کدگذاری فیلم ، به صورت متن ساده به بازدید کننده ارسال کرد. در بعضی از سیستم‌ها این می‌تواند مدت زیادی طول بکشد و باعث شود پخش فیلم در طول فرآیند استخراج متوقف شود. این گزینه را غیرفعال کنید تا زیرنویس‌های جاسازی شده با استفاده از رمزگذاری ویدیو در حالی که به طور محلی توسط دستگاه بازدیدکننده پشتیبانی نمی‌شوند ارسال شود.", "AdditionalNotificationServices": "برای نصب سرویس‌های اعلان اضافی، در فروشگاه افزونه‌ها جستجو کنید.", "OptionThumbCard": "کارت بندانگشتی", "OptionThumb": "بندانگشتی", @@ -702,5 +702,102 @@ "MessageUnauthorizedUser": "در حال حاضر مجاز به دسترسی به سرور نیستید. لطفا برای اطلاعات بیشتر با مدیر سرور خود تماس بگیرید.", "MessageInvalidUser": "نام کاربری یا گذرواژه نامعتبر است. لطفا دوباره تلاش کنید.", "MessageInvalidForgotPasswordPin": "کد پین نامعتبر یا منقضی شده وارد شد. لطفا دوباره تلاش کنید.", - "MessageInstallPluginFromApp": "این افزونه باید از داخل برنامه‌ای که قصد استفاده از آن را دارید نصب شود." + "MessageInstallPluginFromApp": "این افزونه باید از داخل برنامه‌ای که قصد استفاده از آن را دارید نصب شود.", + "PasswordResetHeader": "بازنشانی گذرواژه", + "PasswordResetConfirmation": "آیا واقعا تمایل به بازنشانی گذرواژه دارید؟", + "PasswordResetComplete": "گذرواژه بازنشانی شد.", + "PasswordMatchError": "گذرواژه و تکرار گذرواژه باید یکسان باشند.", + "PackageInstallFailed": "{0} (نسخه {1}) نصب به مشکل برخورد.", + "PackageInstallCompleted": "{0} (نسخه {1})نصب به پایان رسید.", + "PackageInstallCancelled": "{0} ( نسخه {1})نصب لغو شد.", + "Overview": "بررسی اجمالی", + "OtherArtist": "هنرمند دیگر", + "OriginalAirDateValue": "زمان پخش اصلی : {0}", + "OptionWeekly": "هفتگی", + "OptionWeekends": "آخر هفته ها", + "OptionWeekdays": "روز های هفته", + "OptionWednesday": "چهارشنبه", + "OptionWakeFromSleep": "از خواب بیدار شدن", + "OptionUnairedEpisode": "قسمت های پخش نشده", + "OptionTvdbRating": "نمره TVDB", + "OptionTuesday": "سه شنبه", + "OptionTrackName": "نام ترک", + "OptionRequirePerfectSubtitleMatchHelp": "نتیجه کامل زیرنویس ها را به صورتی فیلتر می کند که فقط مواردی را که دقیقا با فایل تصویری شما آزمایش و تأیید شده اند ،شامل شود. حذف این گزینه احتمال بارگیری زیرنویس ها را افزایش می دهد ، اما شانس متن زیرنویس ناهماهنگ یا غلط نیز افزایش می یابد.", + "ServerNameIsShuttingDown": "سرور جلی فین - {0} در حال خاموش شدن می باشد.", + "ServerNameIsRestarting": "سرور جلی فین - {0} در حال راه اندازی مجدد می باشد.", + "SeriesYearToPresent": "{0}- در حال حاضر", + "SeriesSettings": "تنظیمات سریال", + "SeriesRecordingScheduled": "ضبط کردن سریال زمانبندی شد.", + "SeriesDisplayOrderHelp": "قسمت ها را بر اساس تاریخ پخش شدن، ترتیب دی وی دی یا فقط شماره مرتب کنید.", + "SeriesCancelled": "سریال متوقف شده است.", + "Series": "سریال ها", + "SelectAdminUsername": "لطفا یک نام کاربری برای حساب مدیر انتخاب کنید.", + "Season": "فصل", + "SearchResults": "نتایج جستجو", + "SearchForSubtitles": "زیرنویس ها را جستجو کنید", + "SearchForMissingMetadata": "فراداده های گم شده را جستجو کنید", + "SearchForCollectionInternetMetadata": "در اینترنت برای پیدا کردن فراداده و عکس جستجو کنید", + "Search": "جستجو کردن", + "Screenshots": "نماگرفت ها", + "Screenshot": "نماگرفت", + "Schedule": "برنامه زمانی", + "ScanLibrary": "کتابخانه را اسکن کنید", + "ScanForNewAndUpdatedFiles": "فایل های جدید و به روز رسانی شده را اسکن کنید", + "ChannelAccessHelp": "کانال هایی که قصد اشتراک گذاری با این کاربر را دارید انتخاب کنید. مدیران توانایی ویرایش همه ی کانال ها را با استفاده از مدیریت فراداده دارند.", + "ChangingMetadataImageSettingsNewContent": "تغییر تنظیمات دانلود فراداده ها و عکس ها فقط بر روی محتواهای جدیدی که به کتابخانه اضافه می شوند، اعمال می شوند. برای اعمال تغییرات بر روی محتوای موجود، شما باید فراداده را به صورت دستی به روزرسانی کنید.", + "Refresh": "به‌روز‌رسانی", + "Recordings": "ضبط شده ها", + "RecordingScheduled": "ضبط برنامه ریزی شد.", + "RecordingPathChangeMessage": "با تغییر محل ذخیره فایل های ضبط شده، فایل های موجود به صورت خودکار منتقل نمی شوند. در صورت نیاز، شما باید خودتان این کار را انجام دهید.", + "RecordingCancelled": "ضبط شدن لغو شد.", + "RecordSeries": "ضبط کردن سریال ها", + "Record": "ضبط کردن", + "RecommendationStarring": "با هنرمندی {0}", + "RecommendationDirectedBy": "کارگردانی شده توسط {0}", + "RecommendationBecauseYouWatched": "برای اینکه تو {0} مشاهده کردی", + "RecommendationBecauseYouLike": "برای اینکه تو {0} را نیز دوست داری", + "RecentlyWatched": "اخیرا مشاهده شده", + "Rate": "ارزیابی کن", + "Raised": "مطرح شده", + "QueueAllFromHere": "همه را از اینجا در صف قرار بده", + "Quality": "کیفیت", + "Programs": "برنامه ها", + "ProductionLocations": "محل تولید", + "Producer": "تولید کننده", + "Primary": "اصلی", + "Previous": "قبلی", + "Premieres": "برتر ها", + "Premiere": "برتر", + "PreferEmbeddedEpisodeInfosOverFileNames": "اطلاعات تعبیه شده در فراداده را به اسم فایل ترجیح بده", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "این از اطلاعات قسمت در فراداده های تعبیه شده در صورت موجود استفاده می کند.", + "PreferEmbeddedTitlesOverFileNamesHelp": "این عنوان نمایش را به صورت پیش فرض تعیین می کند، زمانی که فراداده اینترنتی یا محلی موجود نباشند.", + "PreferEmbeddedTitlesOverFileNames": "عنوان های تعبیه شده را به نام فایل ترجیح بده", + "PluginInstalledMessage": "افزونه با موفقیت نصب شد. برای اعمال تغییرات سرور جلیفین نیاز به بارگذاری مجدد دارد.", + "PleaseSelectTwoItems": "لطفا حداقل دو مورد را انتخاب کنید.", + "PleaseRestartServerName": "لطفا سرور جلیفین را دوباره بارگذاری کنید - {0}.", + "PleaseEnterNameOrId": "لطفا یک نام یا شناسه خارجی را وارد کنید.", + "PleaseConfirmPluginInstallation": "لطفا با کلیک بر روی OK تایید کنید که شما متن بالا را خوانده اید و می خواهید که افزونه را نصب کنید.", + "PleaseAddAtLeastOneFolder": "لطفا حداقل یک پوشه به این کتابخانه با کلیک بر روی \"افزودن\" اضافه کنید.", + "Played": "اجرا شده", + "PlaybackErrorNoCompatibleStream": "سرویس گیرنده با مدیا سازگاری ندارد و سرور یک فرمت سازگار را ارسال نمی کند.", + "PlayNextEpisodeAutomatically": "قسمت بعدی را به صورت خودکار اجرا کن", + "PlayNext": "بعدی را اجرا کن", + "PlayFromBeginning": "از ابتدا اجرا کن", + "PlaybackData": "اجرای مجدد داده", + "PlayAllFromHere": "همه را از اینجا اجرا کن", + "Play": "اجرا کردن", + "PinCodeResetConfirmation": "آیا مطمئن هستید که می خواهید کد پین را باز نشانی کنید؟", + "PinCodeResetComplete": "کد پین بازنشانی شد.", + "PictureInPicture": "تصویر در تصویر", + "Person": "فرد", + "PerfectMatch": "همتای کامل", + "People": "افراد", + "MillisecondsUnit": "میلی‌ثانیه", + "LabelSyncPlayTimeOffset": "اختلاف زمانی با سرور:", + "LabelSeriesRecordingPath": "مسیر ضبط سریال‌ها (اختیاری):", + "LabelSelectFolderGroups": "به طور خودکار محتواهای پوشه‌های زیر را به فیلم ، موسیقی و تلویزیون گروه بندی شود:", + "LabelSeasonNumber": "شماره فصل:", + "ConfigureDateAdded": "تنظیم کنید که چگونه تاریخ اضافه شده در داشبورد سرور Jellyfin تحت تنظیمات کتابخانه تعیین می‌شود", + "CinemaModeConfigurationHelp": "حالت سینما تجربه تئاتر گونه را مستقیم به اتاق نشیمن شما می‌آورد با قابلیت پخش تریلرها و پیش نمایش‌ها قبل از سایر ویژگی‌های اصلی.", + "LaunchWebAppOnStartup": "نمای وب هنگامی که سرور آغاز به کار می‌کند باز بشود" } diff --git a/src/strings/fr.json b/src/strings/fr.json index 01c8ae439..81d6470ee 100644 --- a/src/strings/fr.json +++ b/src/strings/fr.json @@ -1458,8 +1458,6 @@ "MessageConfirmAppExit": "Voulez-vous quitter ?", "LabelVideoResolution": "Résolution vidéo :", "LabelStreamType": "Type de flux :", - "EnableFastImageFadeInHelp": "Activer un fondu plus rapide pour l'animation des images chargées.", - "EnableFastImageFadeIn": "Fondu d'image rapide", "LabelPlayerDimensions": "Dimension du lecteur :", "LabelDroppedFrames": "Images perdues :", "LabelCorruptedFrames": "Images corrompues :", diff --git a/src/strings/hu.json b/src/strings/hu.json index 6d6307285..9382927ac 100644 --- a/src/strings/hu.json +++ b/src/strings/hu.json @@ -1393,8 +1393,6 @@ "ButtonSplit": "Szétvág", "Absolute": "Abszolút", "LabelSkipIfAudioTrackPresentHelp": "Vedd ki a pipát, ha minden videóhoz szeretnél feliratot az audio nyelvétől függetlenül.", - "EnableFastImageFadeInHelp": "Poszterek és más képek megjelenítése gyorsabb animációkkal.", - "EnableFastImageFadeIn": "Gyors kép-előtűnés", "SubtitleOffset": "Felirat eltolása", "SeriesDisplayOrderHelp": "Rakd sorba az epizódokat az adásba kerülésük dátuma, a DVD sorszám, vagy az abszolút számozás szerint.", "SelectAdminUsername": "Kérjük válassz felhasználónevet az adminisztrátor fiók számára.", diff --git a/src/strings/it.json b/src/strings/it.json index d678cf6e0..474ff5480 100644 --- a/src/strings/it.json +++ b/src/strings/it.json @@ -1455,8 +1455,6 @@ "MessageConfirmAppExit": "Vuoi uscire?", "HeaderNavigation": "Navigazione", "CopyStreamURLError": "Si è verificato un errore nel copiare l'indirizzo.", - "EnableFastImageFadeInHelp": "Mostra i poster e le altre immagini con una dissolvenza veloce alla fine del caricamento.", - "EnableFastImageFadeIn": "Dissolvenza Immagine Veloce", "PlaybackErrorNoCompatibleStream": "Il client è incompatibile con il media e il server non sta inviando un formato compatibile.", "OptionForceRemoteSourceTranscoding": "Forza la transcodifica da fonti di media remoti (come LiveTV)", "NoCreatedLibraries": "Sembra che tu non abbia ancora creato delle librerie. {0}Vuoi crearne una adesso?{1}", diff --git a/src/strings/kk.json b/src/strings/kk.json index f32fe9d9e..2c2c7c378 100644 --- a/src/strings/kk.json +++ b/src/strings/kk.json @@ -1484,8 +1484,6 @@ "MessageConfirmAppExit": "Shyǵýdy qalaısyz ba?", "LabelVideoResolution": "Beıne ajyratymdylyǵy:", "LabelStreamType": "Aǵyn túri:", - "EnableFastImageFadeInHelp": "Júktelgen sýretter úshin shapshan kórsetilýin qosý", - "EnableFastImageFadeIn": "Sýrettiń shapshan kórsetilýi", "LabelPlayerDimensions": "Oınatqysh ólshemderi:", "LabelDroppedFrames": "Ótkizilgen kadrlar:", "LabelCorruptedFrames": "Búlingen kadrlar:", diff --git a/src/strings/ko.json b/src/strings/ko.json index 33c44334a..4c3cd60da 100644 --- a/src/strings/ko.json +++ b/src/strings/ko.json @@ -1343,8 +1343,6 @@ "LabelSkipIfAudioTrackPresentHelp": "오디오 언어와 상관없이 모든 비디오가 자막을 갖추도록 하려면 이 항목을 체크하지 마십시오.", "LabelSelectFolderGroupsHelp": "체크되지 않은 폴더는 폴더 고유의 보기 방식으로 표시됩니다.", "LabelSelectFolderGroups": "자동으로 이하의 폴더의 항목을 영화, 음악, TV 와 같은 보기 방식으로 그룹화:", - "EnableFastImageFadeInHelp": "로드된 이미지에 더 빠른 페이드 인 효과를 적용", - "EnableFastImageFadeIn": "빠른 이미지 페이드 인 효과", "LabelScheduledTaskLastRan": "최근 실행: {0}, 소모시간: {1}.", "LabelRemoteClientBitrateLimitHelp": "(선택) 모든 외부 네트워크로 접속된 장치들에 적용되는 각 스트리밍별 비트레이트 제한입니다. 이는 서버의 인터넷이 처리할 수 있는 한계보다 더 높은 비트레이트를 요청하는 것을 방지할 수 있습니다. 비디오를 더 낮은 비트레이트로 트랜스코딩하기 위해 서버에 높은 CPU 부하를 줄 수 있습니다.", "LabelReasonForTranscoding": "트랜스코딩 원인:", diff --git a/src/strings/lv.json b/src/strings/lv.json index 6c1086333..cfdb0c0c0 100644 --- a/src/strings/lv.json +++ b/src/strings/lv.json @@ -1232,7 +1232,5 @@ "MessageUnauthorizedUser": "Jūs neesat autorizēti lai piekļūtu serverim šajā brīdī. Lūdzu sazinieties ar savu servera administratoru priekš papildus informācijas.", "MessageInstallPluginFromApp": "Šis paplašinājums ir jāuzstāda no lietotnes, kurā jūs to vēlaties izmantot.", "LabelEmbedAlbumArtDidl": "Ievietot albumu vākus iekš Didl", - "EnableFastImageFadeIn": "Ātra attēlu ieplūšana", - "EnableFastImageFadeInHelp": "Iespējot ātrāku ieplūšanas animāciju priekš ielādētiem attēliem", "LabelSelectFolderGroups": "Automātiski grupēt saturu no sekojošām datnēm skatos kā Filmas, Mūzika un TV:" } diff --git a/src/strings/nb.json b/src/strings/nb.json index 0a616ae2e..3821c5544 100644 --- a/src/strings/nb.json +++ b/src/strings/nb.json @@ -1454,8 +1454,6 @@ "SelectAdminUsername": "Vennligst velg et brukernavn for administrator kontoen. ", "HeaderNavigation": "Navigering", "MessageConfirmAppExit": "Vil du avslutte?", - "EnableFastImageFadeInHelp": "Bruk rask inntoning av animasjon for lastede bilder", - "EnableFastImageFadeIn": "Rask bilde inntoning", "CopyStreamURLError": "Det var en feil under kopiering av URL'en.", "LabelVideoResolution": "Oppløsning på video:", "LabelPlayerDimensions": "Dimensjoner på avspiller:", diff --git a/src/strings/nl.json b/src/strings/nl.json index 23a563a8f..132fd7780 100644 --- a/src/strings/nl.json +++ b/src/strings/nl.json @@ -1471,8 +1471,6 @@ "Artist": "Artiest", "AllowFfmpegThrottlingHelp": "Wanneer een transcode of remux ver genoeg voorloopt op de huidige afspeelpositie, pauzeer het proces, zodat het minder middelen verbruikt. Dit is vooral handig wanneer u kijkt zonder vaak te zoeken. Schakel dit uit als u afspeelproblemen ondervindt.", "AllowFfmpegThrottling": "Throttle Transcodes", - "EnableFastImageFadeInHelp": "Toon posters en andere afbeeldingen met een snellere fade-animatie wanneer ze klaar zijn met laden.", - "EnableFastImageFadeIn": "Fast Image Fade Animaties", "LabelPlayerDimensions": "Afspeellengte:", "LabelLibraryPageSizeHelp": "Kies het aantal artikelen dat wordt weergegeven op een bibliotheekpagina. Kies 0 om dit te verbergen.", "LabelLibraryPageSize": "Bibliotheekpagina grootte:", diff --git a/src/strings/pl.json b/src/strings/pl.json index 1cea825bf..f2aa4f9fa 100644 --- a/src/strings/pl.json +++ b/src/strings/pl.json @@ -1466,8 +1466,6 @@ "NoCreatedLibraries": "Wygląda na to, że nie utworzyłeś jeszcze żadnych bibliotek. {0}Czy chcesz utworzyć jedną teraz?{1}", "LabelVideoResolution": "Rozdzielczość wideo:", "LabelStreamType": "Typ transmisji:", - "EnableFastImageFadeInHelp": "Włącz szybszą animację pojawiania się dla załadowanych obrazów", - "EnableFastImageFadeIn": "Szybkie pojawianie się obrazów", "Artist": "Artysta", "AlbumArtist": "Album artysty", "Album": "Album", diff --git a/src/strings/pt-br.json b/src/strings/pt-br.json index e1e8acfc3..b7948cb6a 100644 --- a/src/strings/pt-br.json +++ b/src/strings/pt-br.json @@ -1456,7 +1456,6 @@ "MessageConfirmAppExit": "Você quer sair?", "LabelVideoResolution": "Resolução de vídeo:", "LabelStreamType": "Tipo de stream:", - "EnableFastImageFadeIn": "Fade-in rápido da imagem", "LabelPlayerDimensions": "Dimensões do player:", "LabelCorruptedFrames": "Quadros corrompidos:", "HeaderNavigation": "Navegação", @@ -1465,7 +1464,6 @@ "AskAdminToCreateLibrary": "Peça a um administrador para criar uma biblioteca.", "AllowFfmpegThrottling": "Transcodes do Acelerador", "PlaybackErrorNoCompatibleStream": "Este cliente não é compatível com a media e o servidor não está enviando um formato de mídia compatível.", - "EnableFastImageFadeInHelp": "Mostrar pôsteres e outras imagens com uma animação mais rápida ao terminar de carregar.", "LabelDroppedFrames": "Quadros caídos:", "AllowFfmpegThrottlingHelp": "Quando uma transcodificação ou remux estiver suficientemente avançada da posição atual de reprodução, pause o processo para que consuma menos recursos. Isso é mais proveitoso para quando não há avanço ou retrocesso do vídeo com frequência. Desative se tiver problemas de reprodução.", "PreferEmbeddedEpisodeInfosOverFileNames": "Preferir informações dos episódios incorporadas nos arquivos ao invés dos nomes", diff --git a/src/strings/pt.json b/src/strings/pt.json index 370a1343e..7e263dbeb 100644 --- a/src/strings/pt.json +++ b/src/strings/pt.json @@ -1314,8 +1314,6 @@ "LabelSortOrder": "Ordem de classificação:", "LabelSortBy": "Ordenar por:", "LabelSkin": "Pele:", - "EnableFastImageFadeInHelp": "Habilite uma animação mais rápida para imagens carregadas", - "EnableFastImageFadeIn": "Efeito de imagem fade-in rápido", "LabelRemoteClientBitrateLimitHelp": "Um limite opcional de taxa de bits por fluxo para todos os dispositivos fora da rede. Isso é útil para impedir que os dispositivos solicitem uma taxa de bits mais alta do que a sua conexão à Internet pode suportar. Isso pode resultar no aumento da carga da CPU no servidor para transcodificar vídeos em tempo real para uma taxa de bits mais baixa.", "LabelPlayerDimensions": "Dimensões do reprodutor:", "LabelParentNumber": "Número pai:", diff --git a/src/strings/ro.json b/src/strings/ro.json index 4e1227d85..358474111 100644 --- a/src/strings/ro.json +++ b/src/strings/ro.json @@ -1454,8 +1454,6 @@ "HeaderNavigation": "Navigare", "MessageConfirmAppExit": "Vrei să ieși?", "CopyStreamURLError": "A apărut o eroare la copierea adresei URL.", - "EnableFastImageFadeInHelp": "Arătați postere și alte imagini cu o animație de tranziție rapidă când sunt deja încărcate.", - "EnableFastImageFadeIn": "Animație de Tranziție a Imaginii Rapidă", "LabelVideoResolution": "Rezoluția video:", "LabelStreamType": "Tipul streamului:", "LabelPlayerDimensions": "Dimensiunile soft redare:", diff --git a/src/strings/ru.json b/src/strings/ru.json index 4a7e2aa8a..dcc3a0f5d 100644 --- a/src/strings/ru.json +++ b/src/strings/ru.json @@ -1460,8 +1460,6 @@ "HeaderNavigation": "Навигация", "LabelVideoResolution": "Разрешение видео:", "LabelStreamType": "Тип потока:", - "EnableFastImageFadeInHelp": "Показывать постеры и другие рисунки анимацией побыстрее , когда они закончат загружаться.", - "EnableFastImageFadeIn": "Быстрое анимация рисунка", "LabelPlayerDimensions": "Размеры проигрывателя:", "LabelDroppedFrames": "Пропущенные кадры:", "LabelCorruptedFrames": "Испорченные кадры:", @@ -1552,5 +1550,7 @@ "SyncPlayAccessHelp": "Выберите уровень доступа данного пользователя к функциональности SyncPlay. SyncPlay позволяет синхронизировать воспроизведение с другими устройствами.", "MessageSyncPlayErrorMedia": "Не удалось включить SyncPlay! Ошибка медиаданных.", "MessageSyncPlayErrorMissingSession": "Не удалось включить SyncPlay! Отсутствует сеанс.", - "MessageSyncPlayErrorNoActivePlayer": "Активный проигрыватель не найден. SyncPlay был отключен." + "MessageSyncPlayErrorNoActivePlayer": "Активный проигрыватель не найден. SyncPlay был отключен.", + "ShowMore": "Показать больше", + "ShowLess": "Показать меньше" } diff --git a/src/strings/sk.json b/src/strings/sk.json index e99883d24..eb236ff9e 100644 --- a/src/strings/sk.json +++ b/src/strings/sk.json @@ -1457,8 +1457,6 @@ "MessageConfirmAppExit": "Chceli by ste odísiť?", "LabelVideoResolution": "Rozlíšenie videa:", "LabelStreamType": "Typ streamu:", - "EnableFastImageFadeInHelp": "Zobrazí plagát a ostatné obrázky s rýchlejšou animáciou prechodu po dokončení načítania.", - "EnableFastImageFadeIn": "Rýchla animácia prechodu obrázku", "LabelPlayerDimensions": "Rozmery prehrávača:", "LabelDroppedFrames": "Vynechané snímky:", "LabelCorruptedFrames": "Poškodené snímky:", diff --git a/src/strings/sv.json b/src/strings/sv.json index 282fec7b7..a2b1c68e0 100644 --- a/src/strings/sv.json +++ b/src/strings/sv.json @@ -1344,8 +1344,6 @@ "LabelSize": "Storlek:", "LabelServerName": "Servernamn:", "LabelSecureConnectionsMode": "Säker uppkopplings läge:", - "EnableFastImageFadeInHelp": "Aktivera snabbare fade-in animationer för laddade bilder", - "EnableFastImageFadeIn": "Snabb bild fade-in", "LabelPostProcessorArgumentsHelp": "Använd {path} som sökväg till inspelade filen.", "LabelPostProcessorArguments": "Post-processor kommandoradsargument:", "LabelDroppedFrames": "Tappade ramar:", diff --git a/src/strings/zh-cn.json b/src/strings/zh-cn.json index d57c46395..237dafb16 100644 --- a/src/strings/zh-cn.json +++ b/src/strings/zh-cn.json @@ -1464,8 +1464,6 @@ "HeaderNavigation": "导航", "CopyStreamURLError": "复制URL地址时发生错误。", "MessageConfirmAppExit": "你要退出吗?", - "EnableFastImageFadeIn": "快速图片淡入淡出", - "EnableFastImageFadeInHelp": "为已加载的图片启用更快的图片淡入动画", "OptionForceRemoteSourceTranscoding": "强制远程转码(像电视直播一样)", "NoCreatedLibraries": "看上去您还未创建任何资料库。{0} 您想现在创建一个吗? {1}", "AskAdminToCreateLibrary": "请联系管理员以创建一个新的资料库。", @@ -1524,7 +1522,7 @@ "LabelEnableHttps": "启用 HTTPS", "LabelChromecastVersion": "Chromecast版本", "HeaderDVR": "DVR", - "LabelNightly": "Nightly", + "LabelNightly": "开发版", "MessageSyncPlayErrorAccessingGroups": "访问群组列表时发生错误。", "MessageSyncPlayLibraryAccessDenied": "搜限制的访问权限。", "MessageSyncPlayCreateGroupDenied": "需要权限创建该组。", diff --git a/src/strings/zh-tw.json b/src/strings/zh-tw.json index ae086d08c..7023e564b 100644 --- a/src/strings/zh-tw.json +++ b/src/strings/zh-tw.json @@ -1610,8 +1610,6 @@ "LaunchWebAppOnStartupHelp": "伺服器啓動時在默認游覽器中打開網頁端。使用重啓伺服器功能時此項不生效。", "LabelVideoResolution": "視頻解析度:", "LabelStreamType": "串流類型:", - "EnableFastImageFadeInHelp": "對已載入的圖片啟用更快的淡入動畫", - "EnableFastImageFadeIn": "圖片快速淡入效果", "LabelPlayerDimensions": "播放器尺寸:", "LabelDroppedFrames": "丟棄的幀:", "LabelCorruptedFrames": "損壞的幀:", diff --git a/src/themes/blueradiance/theme.css b/src/themes/blueradiance/theme.css index 3e86782f3..74a60c91c 100644 --- a/src/themes/blueradiance/theme.css +++ b/src/themes/blueradiance/theme.css @@ -131,23 +131,23 @@ html { } .defaultCardBackground1 { - background-color: #d2b019; + background-color: #213440; } .defaultCardBackground2 { - background-color: #338abb; + background-color: #8c6565; } .defaultCardBackground3 { - background-color: #6b689d; + background-color: #57778c; } .defaultCardBackground4 { - background-color: #dd452b; + background-color: #8c8c49; } .defaultCardBackground5 { - background-color: #5ccea9; + background-color: #404024; } .cardText-secondary, diff --git a/src/themes/dark/theme.css b/src/themes/dark/theme.css index f9163d82f..a32e60638 100644 --- a/src/themes/dark/theme.css +++ b/src/themes/dark/theme.css @@ -113,23 +113,23 @@ html { } .defaultCardBackground1 { - background-color: #d2b019; + background-color: #00455c; } .defaultCardBackground2 { - background-color: #338abb; + background-color: #44bae1; } .defaultCardBackground3 { - background-color: #6b689d; + background-color: #00a4db; } .defaultCardBackground4 { - background-color: #dd452b; + background-color: #1c4c5c; } .defaultCardBackground5 { - background-color: #5ccea9; + background-color: #007ea8; } .cardText-secondary, diff --git a/src/themes/purplehaze/theme.css b/src/themes/purplehaze/theme.css index 82b774a73..de69a5542 100644 --- a/src/themes/purplehaze/theme.css +++ b/src/themes/purplehaze/theme.css @@ -221,23 +221,23 @@ a[data-role=button] { } .defaultCardBackground1 { - background-color: #d2b019; + background-color: #9c20ab; } .defaultCardBackground2 { - background-color: #338abb; + background-color: #d799de; } .defaultCardBackground3 { - background-color: #6b689d; + background-color: #412378; } .defaultCardBackground4 { - background-color: #dd452b; + background-color: #857b48; } .defaultCardBackground5 { - background-color: #5ccea9; + background-color: #ab8820; } .cardText-secondary, diff --git a/webpack.dev.js b/webpack.dev.js index 0bb2f1fdb..17377acf1 100644 --- a/webpack.dev.js +++ b/webpack.dev.js @@ -15,7 +15,7 @@ module.exports = merge(common, { rules: [ { test: /\.js$/, - exclude: /node_modules[\\/](?!date-fns|jellyfin-apiclient|query-string|split-on-first|strict-uri-encode)/, + exclude: /node_modules[\\/](?!date-fns|epubjs|jellyfin-apiclient|query-string|split-on-first|strict-uri-encode)/, use: { loader: 'babel-loader', options: { diff --git a/webpack.prod.js b/webpack.prod.js index 82f1d4d2f..1b7f4d029 100644 --- a/webpack.prod.js +++ b/webpack.prod.js @@ -8,7 +8,7 @@ module.exports = merge(common, { rules: [ { test: /\.js$/, - exclude: /node_modules[\\/](?!date-fns|jellyfin-apiclient|query-string|split-on-first|strict-uri-encode)/, + exclude: /node_modules[\\/](?!date-fns|epubjs|jellyfin-apiclient|query-string|split-on-first|strict-uri-encode)/, use: { loader: 'babel-loader', options: { diff --git a/yarn.lock b/yarn.lock index ac827f401..88dc31d55 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,14 +2,7 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" - integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== - dependencies: - "@babel/highlight" "^7.8.3" - -"@babel/code-frame@^7.10.1", "@babel/code-frame@^7.8.3": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.1.tgz#d5481c5095daa1c57e16e54c6f9198443afb49ff" integrity sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw== @@ -25,41 +18,19 @@ invariant "^2.2.4" semver "^5.5.0" -"@babel/core@>=7.2.2", "@babel/core@>=7.9.0": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.6.tgz#d9aa1f580abf3b2286ef40b6904d390904c63376" - integrity sha512-nD3deLvbsApbHAHttzIssYqgb883yU/d9roe4RZymBCDaZryMJDbptVpEpeQuRh4BJ+SYI8le9YGxKvFEvl1Wg== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.6" - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helpers" "^7.9.6" - "@babel/parser" "^7.9.6" - "@babel/template" "^7.8.6" - "@babel/traverse" "^7.9.6" - "@babel/types" "^7.9.6" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/core@^7.9.6": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.1.tgz#2a0ad0ea693601820defebad2140206503d89af3" - integrity sha512-u8XiZ6sMXW/gPmoP5ijonSUln4unazG291X0XAQ5h0s8qnAFr6BRRZGUEK+jtRWdmB0NTJQt7Uga25q8GetIIg== +"@babel/core@>=7.2.2", "@babel/core@>=7.9.0", "@babel/core@^7.10.2": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.2.tgz#bd6786046668a925ac2bd2fd95b579b92a23b36a" + integrity sha512-KQmV9yguEjQsXqyOUGKjS4+3K8/DlOCE2pZcq4augdQmtTy5iv5EHtmMSJ7V4c1BIPjuwtZYqYLCq9Ga+hGBRQ== dependencies: "@babel/code-frame" "^7.10.1" - "@babel/generator" "^7.10.1" + "@babel/generator" "^7.10.2" "@babel/helper-module-transforms" "^7.10.1" "@babel/helpers" "^7.10.1" - "@babel/parser" "^7.10.1" + "@babel/parser" "^7.10.2" "@babel/template" "^7.10.1" "@babel/traverse" "^7.10.1" - "@babel/types" "^7.10.1" + "@babel/types" "^7.10.2" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.1" @@ -69,12 +40,12 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.10.1", "@babel/generator@^7.9.6": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.1.tgz#4d14458e539bcb04ffe34124143f5c489f2dbca9" - integrity sha512-AT0YPLQw9DI21tliuJIdplVfLHya6mcGa8ctkv7n4Qv+hYacJrKmNWIteAK1P9iyLikFIAkwqJ7HAOqIDLFfgA== +"@babel/generator@^7.10.1", "@babel/generator@^7.10.2": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.2.tgz#0fa5b5b2389db8bfdfcc3492b551ee20f5dd69a9" + integrity sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA== dependencies: - "@babel/types" "^7.10.1" + "@babel/types" "^7.10.2" jsesc "^2.5.1" lodash "^4.17.13" source-map "^0.5.0" @@ -94,10 +65,10 @@ "@babel/helper-explode-assignable-expression" "^7.10.1" "@babel/types" "^7.10.1" -"@babel/helper-compilation-targets@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.1.tgz#ad6f69b4c3bae955081ef914a84e5878ffcaca63" - integrity sha512-YuF8IrgSmX/+MV2plPkjEnzlC2wf+gaok8ehMNN0jodF3/sejZauExqpEVGbJua62oaWoNYIXwz4RmAsVcGyHw== +"@babel/helper-compilation-targets@^7.10.2": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.2.tgz#a17d9723b6e2c750299d2a14d4637c76936d8285" + integrity sha512-hYgOhF4To2UTB4LTaZepN/4Pl9LD4gfbJx8A34mqoluT8TLbof1mhUlYuNWTEebONa8+UlCC4X0TEXu7AOUyGA== dependencies: "@babel/compat-data" "^7.10.1" browserslist "^4.12.0" @@ -180,7 +151,7 @@ dependencies: "@babel/types" "^7.10.1" -"@babel/helper-module-transforms@^7.10.1", "@babel/helper-module-transforms@^7.9.0": +"@babel/helper-module-transforms@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz#24e2f08ee6832c60b157bb0936c86bef7210c622" integrity sha512-RLHRCAzyJe7Q7sF4oy2cB+kRnU4wDZY/H2xJFGof+M+SJEGhZsb+GFj5j1AD8NiSaVBJ+Pf0/WObiXu/zxWpFg== @@ -263,7 +234,7 @@ "@babel/traverse" "^7.10.1" "@babel/types" "^7.10.1" -"@babel/helpers@^7.10.1", "@babel/helpers@^7.9.6": +"@babel/helpers@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.1.tgz#a6827b7cb975c9d9cef5fd61d919f60d8844a973" integrity sha512-muQNHF+IdU6wGgkaJyhhEmI54MOZBKsFfsXFhboz1ybwJ1Kl7IHlbm2a++4jwrmY5UYsgitt5lfqo1wMFcHmyw== @@ -272,7 +243,7 @@ "@babel/traverse" "^7.10.1" "@babel/types" "^7.10.1" -"@babel/highlight@^7.10.1", "@babel/highlight@^7.8.3": +"@babel/highlight@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.1.tgz#841d098ba613ba1a427a2b383d79e35552c38ae0" integrity sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg== @@ -281,10 +252,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.10.1", "@babel/parser@^7.9.6": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.1.tgz#2e142c27ca58aa2c7b119d09269b702c8bbad28c" - integrity sha512-AUTksaz3FqugBkbTZ1i+lDLG5qy8hIzCaAxEtttU6C0BtZZU9pkNZtWSVAht4EW9kl46YBiyTGMp9xTTGqViNg== +"@babel/parser@^7.10.1", "@babel/parser@^7.10.2": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.2.tgz#871807f10442b92ff97e4783b9b54f6a0ca812d0" + integrity sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ== "@babel/plugin-proposal-async-generator-functions@^7.10.1": version "7.10.1" @@ -705,13 +676,13 @@ core-js "^2.6.5" regenerator-runtime "^0.13.4" -"@babel/preset-env@^7.8.6": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.10.1.tgz#099e1b76379739bdcbfab3d548dc7e7edb2ac808" - integrity sha512-bGWNfjfXRLnqbN2T4lB3pMfoic8dkRrmHpVZamSFHzGy5xklyHTobZ28TVUD2grhE5WDnu67tBj8oslIhkiOMQ== +"@babel/preset-env@^7.10.2": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.10.2.tgz#715930f2cf8573b0928005ee562bed52fb65fdfb" + integrity sha512-MjqhX0RZaEgK/KueRzh+3yPSk30oqDKJ5HP5tqTSB1e2gzGS3PLy7K0BIpnp78+0anFuSwOeuCf1zZO7RzRvEA== dependencies: "@babel/compat-data" "^7.10.1" - "@babel/helper-compilation-targets" "^7.10.1" + "@babel/helper-compilation-targets" "^7.10.2" "@babel/helper-module-imports" "^7.10.1" "@babel/helper-plugin-utils" "^7.10.1" "@babel/plugin-proposal-async-generator-functions" "^7.10.1" @@ -768,7 +739,7 @@ "@babel/plugin-transform-unicode-escapes" "^7.10.1" "@babel/plugin-transform-unicode-regex" "^7.10.1" "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.10.1" + "@babel/types" "^7.10.2" browserslist "^4.12.0" core-js-compat "^3.6.2" invariant "^2.2.2" @@ -800,7 +771,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.10.1", "@babel/template@^7.8.6": +"@babel/template@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811" integrity sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig== @@ -809,7 +780,7 @@ "@babel/parser" "^7.10.1" "@babel/types" "^7.10.1" -"@babel/traverse@^7.10.1", "@babel/traverse@^7.9.6": +"@babel/traverse@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.1.tgz#bbcef3031e4152a6c0b50147f4958df54ca0dd27" integrity sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ== @@ -824,10 +795,10 @@ globals "^11.1.0" lodash "^4.17.13" -"@babel/types@^7.10.1", "@babel/types@^7.4.4", "@babel/types@^7.9.6": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.1.tgz#6886724d31c8022160a7db895e6731ca33483921" - integrity sha512-L2yqUOpf3tzlW9GVuipgLEcZxnO+96SzR6fjXMuxxNkIgFJ5+07mHCZ+HkHqaeZu8+3LKnNJJ1bKbjBETQAsrA== +"@babel/types@^7.10.1", "@babel/types@^7.10.2", "@babel/types@^7.4.4": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.2.tgz#30283be31cad0dbf6fb00bd40641ca0ea675172d" + integrity sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng== dependencies: "@babel/helper-validator-identifier" "^7.10.1" lodash "^4.17.13" @@ -940,6 +911,11 @@ resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#551a4589b6ee2cc9c1dff08056128aec29b94880" integrity sha512-iYCgjm1dGPRuo12+BStjd1HiVQqhlRhWDOQigNxn023HcjnhsiFz9pc6CzJj4HwDCSQca9bxTL4PxJDbkdm3PA== +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + "@types/jszip@^3.4.1": version "3.4.1" resolved "https://registry.yarnpkg.com/@types/jszip/-/jszip-3.4.1.tgz#e7a4059486e494c949ef750933d009684227846f" @@ -1456,7 +1432,7 @@ array-find-index@^1.0.1: resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= -array-includes@^3.0.3: +array-includes@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== @@ -1516,7 +1492,7 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -array.prototype.flat@^1.2.1: +array.prototype.flat@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== @@ -1635,7 +1611,7 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -autoprefixer@^9.0.0, autoprefixer@^9.6.1, autoprefixer@^9.7.6, autoprefixer@^9.8.0: +autoprefixer@^9.0.0, autoprefixer@^9.6.1, autoprefixer@^9.8.0: version "9.8.0" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.0.tgz#68e2d2bef7ba4c3a65436f662d0a56a741e56511" integrity sha512-D96ZiIHXbDmU02dBaemyAg53ez+6F5yZmapmgKcjm35yEe1uVDYI8hGW3VYoGRaG290ZFf91YxHrR518vC0u/A== @@ -1865,6 +1841,11 @@ bluebird@^3.5.5: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== +blurhash@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/blurhash/-/blurhash-1.1.3.tgz#dc325af7da836d07a0861d830bdd63694382483e" + integrity sha512-yUhPJvXexbqbyijCIE/T2NCXcj9iNPhWmOKbPTuR/cm7Q5snXYIfnVnz6m7MWOXxODMz/Cr3UcVkRdHiuDVRDw== + bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" @@ -3867,7 +3848,7 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -eslint-import-resolver-node@^0.3.2: +eslint-import-resolver-node@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404" integrity sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg== @@ -3875,7 +3856,7 @@ eslint-import-resolver-node@^0.3.2: debug "^2.6.9" resolve "^1.13.1" -eslint-module-utils@^2.4.1: +eslint-module-utils@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6" integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== @@ -3896,31 +3877,32 @@ eslint-plugin-compat@^3.5.1: mdn-browser-compat-data "^1.0.21" semver "7.3.2" -eslint-plugin-eslint-comments@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.1.2.tgz#4ef6c488dbe06aa1627fea107b3e5d059fc8a395" - integrity sha512-QexaqrNeteFfRTad96W+Vi4Zj1KFbkHHNMMaHZEYcovKav6gdomyGzaxSDSL3GoIyUOo078wRAdYlu1caiauIQ== +eslint-plugin-eslint-comments@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz#9e1cd7b4413526abb313933071d7aba05ca12ffa" + integrity sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ== dependencies: escape-string-regexp "^1.0.5" ignore "^5.0.5" -eslint-plugin-import@^2.20.2: - version "2.20.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz#91fc3807ce08be4837141272c8b99073906e588d" - integrity sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg== +eslint-plugin-import@^2.21.1: + version "2.21.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.21.1.tgz#3398318e5e4abbd23395c4964ce61538705154c8" + integrity sha512-qYOOsgUv63vHof7BqbzuD+Ud34bXHxFJxntuAC1ZappFZXYbRIek3aJ7jc9i2dHDGDyZ/0zlO0cpioES265Lsw== dependencies: - array-includes "^3.0.3" - array.prototype.flat "^1.2.1" + array-includes "^3.1.1" + array.prototype.flat "^1.2.3" contains-path "^0.1.0" debug "^2.6.9" doctrine "1.5.0" - eslint-import-resolver-node "^0.3.2" - eslint-module-utils "^2.4.1" + eslint-import-resolver-node "^0.3.3" + eslint-module-utils "^2.6.0" has "^1.0.3" minimatch "^3.0.4" - object.values "^1.1.0" + object.values "^1.1.1" read-pkg-up "^2.0.0" - resolve "^1.12.0" + resolve "^1.17.0" + tsconfig-paths "^3.9.0" eslint-plugin-promise@^4.2.1: version "4.2.1" @@ -4898,10 +4880,10 @@ globby@^10.0.0, globby@^10.0.1: merge2 "^1.2.3" slash "^3.0.0" -globby@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.0.tgz#56fd0e9f0d4f8fb0c456f1ab0dee96e1380bc154" - integrity sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg== +globby@^11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" + integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== dependencies: array-union "^2.1.0" dir-glob "^3.0.1" @@ -5046,10 +5028,10 @@ gulp-babel@^8.0.0: through2 "^2.0.0" vinyl-sourcemaps-apply "^0.2.0" -gulp-cli@^2.2.0, gulp-cli@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/gulp-cli/-/gulp-cli-2.2.1.tgz#376e427661b7996430a89d71c15df75defa3360a" - integrity sha512-yEMxrXqY8mJFlaauFQxNrCpzWJThu0sH1sqlToaTOT063Hub9s/Nt2C+GSLe6feQ/IMWrHvGOOsyES7CQc9O+A== +gulp-cli@^2.2.0, gulp-cli@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/gulp-cli/-/gulp-cli-2.3.0.tgz#ec0d380e29e52aa45e47977f0d32e18fd161122f" + integrity sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A== dependencies: ansi-colors "^1.0.1" archy "^1.0.0" @@ -5059,7 +5041,7 @@ gulp-cli@^2.2.0, gulp-cli@^2.2.1: copy-props "^2.0.1" fancy-log "^1.3.2" gulplog "^1.0.0" - interpret "^1.1.0" + interpret "^1.4.0" isobject "^3.0.1" liftoff "^3.1.0" matchdep "^2.0.0" @@ -5067,7 +5049,7 @@ gulp-cli@^2.2.0, gulp-cli@^2.2.1: pretty-hrtime "^1.0.0" replace-homedir "^1.0.0" semver-greatest-satisfied-range "^1.1.0" - v8flags "^3.0.1" + v8flags "^3.2.0" yargs "^7.1.0" gulp-concat@^2.6.1: @@ -5581,10 +5563,10 @@ ignore@^4.0.3, ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.0.4, ignore@^5.0.5, ignore@^5.1.1, ignore@^5.1.4: - version "5.1.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" - integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A== +ignore@^5.0.4, ignore@^5.0.5, ignore@^5.1.1, ignore@^5.1.4, ignore@^5.1.8: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== imagemin-gifsicle@^7.0.0: version "7.0.0" @@ -5773,10 +5755,10 @@ inquirer@^7.0.0: strip-ansi "^6.0.0" through "^2.3.6" -interpret@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" - integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== +interpret@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== intersection-observer@^0.10.0: version "0.10.0" @@ -6257,10 +6239,10 @@ isurl@^1.0.0-alpha5: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" -jellyfin-apiclient@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/jellyfin-apiclient/-/jellyfin-apiclient-1.2.1.tgz#1da577f7e22c37be8ec23c139b9ddab2c36da5a2" - integrity sha512-5aNtUq7YsoDPZ0LL6cq55HDnSTVfECfw05hbPFxNsFlUogEiHwaoIz+ahWRO13OUFQJuiu8f3fy16glcGzrBIQ== +jellyfin-apiclient@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jellyfin-apiclient/-/jellyfin-apiclient-1.2.2.tgz#64f058320603df02d926f4c1b929b42c6acc4527" + integrity sha512-UwC56orm4darWlnNQJ1nbKo+W8ywlheJSJC6d9zm06CslYtOc/Dkv9kz2PadQEh+6EiBsB0hAZCc7FJ9ahOoGQ== "jellyfin-noto@https://github.com/jellyfin/jellyfin-noto": version "1.0.3" @@ -7683,7 +7665,7 @@ object.reduce@^1.0.0: for-own "^1.0.0" make-iterator "^1.0.0" -object.values@^1.1.0: +object.values@^1.1.0, object.values@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== @@ -8880,12 +8862,12 @@ postcss-sass@^0.4.4: gonzales-pe "^4.3.0" postcss "^7.0.21" -postcss-scss@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-2.0.0.tgz#248b0a28af77ea7b32b1011aba0f738bda27dea1" - integrity sha512-um9zdGKaDZirMm+kZFKKVsnKPF7zF7qBAtIfTSnZXD1jZ0JNZIxdB6TxQOjCnlSzLRInVl2v3YdBh/M881C4ug== +postcss-scss@^2.0.0, postcss-scss@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-2.1.1.tgz#ec3a75fa29a55e016b90bf3269026c53c1d2b383" + integrity sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA== dependencies: - postcss "^7.0.0" + postcss "^7.0.6" postcss-selector-matches@^4.0.0: version "4.0.0" @@ -9008,10 +8990,10 @@ postcss@^5.0.0, postcss@^5.0.18: source-map "^0.5.6" supports-color "^3.2.3" -postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.13, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.30, postcss@^7.0.5, postcss@^7.0.6, postcss@^7.0.7: - version "7.0.30" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.30.tgz#cc9378beffe46a02cbc4506a0477d05fcea9a8e2" - integrity sha512-nu/0m+NtIzoubO+xdAlwZl/u5S5vi/y6BCsoL8D+8IxsD3XvBS8X4YEADNIVXKVuQvduiucnRv+vPIqj56EGMQ== +postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.13, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.30, postcss@^7.0.31, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6, postcss@^7.0.7: + version "7.0.32" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d" + integrity sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw== dependencies: chalk "^2.4.2" source-map "^0.6.1" @@ -9171,10 +9153,10 @@ query-string@^5.0.1: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -query-string@^6.11.1: - version "6.12.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.12.1.tgz#2ae4d272db4fba267141665374e49a1de09e8a7c" - integrity sha512-OHj+zzfRMyj3rmo/6G8a5Ifvw3AleL/EbcHMD27YA31Q+cO5lfmQxECkImuNVjcskLcvBRVHNAB3w6udMs1eAA== +query-string@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.0.tgz#8d875f66581c854d7480ac79478abb847de742f6" + integrity sha512-KJe8p8EUcixhPCp4cJoTYVfmgKHjnAB/Pq3fiqlmyNHvpHnOL5U4YE7iI2PYivGHp4HFocWz300906BAQX0H7g== dependencies: decode-uri-component "^0.2.0" split-on-first "^1.0.0" @@ -9707,7 +9689,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.3.2, resolve@^1.4.0: +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2, resolve@^1.4.0: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== @@ -10052,10 +10034,10 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" -shaka-player@^2.5.11: - version "2.5.11" - resolved "https://registry.yarnpkg.com/shaka-player/-/shaka-player-2.5.11.tgz#af550a0ee3aadf7be4e64e1a4d615c8d728e0b0f" - integrity sha512-SiZd/vCUPeKXNPnfWcBdraskdUYLtm+DITWceCZvRP4eoxxQuRI0MekVJTGqu5d7B2yW9TdQh5ojyRAjbQPFGA== +shaka-player@^2.5.12: + version "2.5.12" + resolved "https://registry.yarnpkg.com/shaka-player/-/shaka-player-2.5.12.tgz#4e8d9b2ab4147368b2a32f537ffed5e884301729" + integrity sha512-mnoMzE5iLnj6HYrovcnd55Lvd8bwV8712Inq3ECMJmBl2nYi7GXDRwYd3fLk6T0EfOsXwSELuHRQ1iyzk4NVNg== dependencies: eme-encryption-scheme-polyfill "^2.0.1" @@ -10754,23 +10736,23 @@ stylelint-order@^2.2.1: postcss "^7.0.2" postcss-sorting "^4.1.0" -stylelint-order@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/stylelint-order/-/stylelint-order-4.0.0.tgz#2a945c2198caac3ff44687d7c8582c81d044b556" - integrity sha512-bXV0v+jfB0+JKsqIn3mLglg1Dj2QCYkFHNfL1c+rVMEmruZmW5LUqT/ARBERfBm8SFtCuXpEdatidw/3IkcoiA== +stylelint-order@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/stylelint-order/-/stylelint-order-4.1.0.tgz#692d05b7d0c235ac66fcf5ea1d9e5f08a76747f6" + integrity sha512-sVTikaDvMqg2aJjh4r48jsdfmqLT+nqB1MOsaBnvM3OwLx4S+WXcsxsgk5w18h/OZoxZCxuyXMh61iBHcj9Qiw== dependencies: lodash "^4.17.15" - postcss "^7.0.26" + postcss "^7.0.31" postcss-sorting "^5.0.1" -stylelint@^13.5.0: - version "13.5.0" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-13.5.0.tgz#9edbf90c8c02c47fd0c4818376e3799145f22cab" - integrity sha512-+Jy7ieKAWKTf2tmcAE7jgScxH39Urb87i0bjK/enScFaGWWaFn4kAPwepGOSk2b7CLUDVt/O6kwA0x0p/V7moQ== +stylelint@^13.6.0: + version "13.6.0" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-13.6.0.tgz#3528bc402a71f2af2a3de32fa4e9f1c24e49666d" + integrity sha512-55gG2pNjVr183JJM/tlr3KAua6vTVX7Ho/lgKKuCIWszTZ1gmrXjX4Wok53SI8wRYFPbwKAcJGULQ77OJxTcNw== dependencies: "@stylelint/postcss-css-in-js" "^0.37.1" "@stylelint/postcss-markdown" "^0.36.1" - autoprefixer "^9.7.6" + autoprefixer "^9.8.0" balanced-match "^1.0.0" chalk "^4.0.0" cosmiconfig "^6.0.0" @@ -10779,10 +10761,10 @@ stylelint@^13.5.0: file-entry-cache "^5.0.1" get-stdin "^8.0.0" global-modules "^2.0.0" - globby "^11.0.0" + globby "^11.0.1" globjoin "^0.1.4" html-tags "^3.1.0" - ignore "^5.1.4" + ignore "^5.1.8" import-lazy "^4.0.0" imurmurhash "^0.1.4" known-css-properties "^0.19.0" @@ -10793,7 +10775,7 @@ stylelint@^13.5.0: meow "^7.0.1" micromatch "^4.0.2" normalize-selector "^0.2.0" - postcss "^7.0.30" + postcss "^7.0.32" postcss-html "^0.36.0" postcss-less "^3.1.4" postcss-media-query-parser "^0.2.3" @@ -10801,7 +10783,7 @@ stylelint@^13.5.0: postcss-resolve-nested-selector "^0.1.1" postcss-safe-parser "^4.0.2" postcss-sass "^0.4.4" - postcss-scss "^2.0.0" + postcss-scss "^2.1.1" postcss-selector-parser "^6.0.2" postcss-syntax "^0.36.2" postcss-value-parser "^4.1.0" @@ -10814,7 +10796,7 @@ stylelint@^13.5.0: sugarss "^2.0.0" svg-tags "^1.0.0" table "^5.4.6" - v8-compile-cache "^2.1.0" + v8-compile-cache "^2.1.1" write-file-atomic "^3.0.3" stylelint@^9.1, stylelint@^9.10.1: @@ -10942,10 +10924,10 @@ svgo@^1.0.0, svgo@^1.3.2: unquote "~1.1.1" util.promisify "~1.0.0" -swiper@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/swiper/-/swiper-5.4.1.tgz#6731e000e97f8b6560c11b141ebaf559063af565" - integrity sha512-l2EiWe7uOXB2EBMVLtJqn51FW22wF9e24WETT+S+tuFNvSDq1gadc/hyGGsAMqFGKJKIO6q6cqk7ToVaOI+onw== +swiper@^5.4.2: + version "5.4.2" + resolved "https://registry.yarnpkg.com/swiper/-/swiper-5.4.2.tgz#ed4cf60ea7100edac2703e406ae4ae2c43d33e7c" + integrity sha512-c6E5kDC3xAhnhdV0omIkDKLr+qNxzMfTO3Nw/T4xNAwSMoJwPvgsRoVzDBEUQbkWqwomHsvcjPMn12VQ6IHDTQ== dependencies: dom7 "^2.1.5" ssr-window "^2.0.0" @@ -11248,6 +11230,16 @@ trough@^1.0.0: dependencies: glob "^7.1.2" +tsconfig-paths@^3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" + integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + tslib@^1.10.0, tslib@^1.9.0: version "1.11.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" @@ -11697,15 +11689,15 @@ uuid@^3.0.1, uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -v8-compile-cache@^2.0.3, v8-compile-cache@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" - integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== +v8-compile-cache@^2.0.3, v8-compile-cache@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" + integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== -v8flags@^3.0.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.1.3.tgz#fc9dc23521ca20c5433f81cc4eb9b3033bb105d8" - integrity sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w== +v8flags@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.2.0.tgz#b243e3b4dfd731fa774e7492128109a0fe66d656" + integrity sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg== dependencies: homedir-polyfill "^1.0.1"