1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Merge branch 'master' into return-of-the-scrollbar

This commit is contained in:
Dmitry Lyzo 2020-10-31 11:42:58 +03:00 committed by GitHub
commit 88b0d6d458
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
151 changed files with 4431 additions and 2598 deletions

View file

@ -49,6 +49,7 @@ module.exports = {
'prefer-const': ['error', {'destructuring': 'all'}], 'prefer-const': ['error', {'destructuring': 'all'}],
'quotes': ['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': false }], 'quotes': ['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': false }],
'@babel/semi': ['error'], '@babel/semi': ['error'],
'no-var': ['error'],
'space-before-blocks': ['error'], 'space-before-blocks': ['error'],
'space-infix-ops': 'error', 'space-infix-ops': 'error',
'yoda': 'error' 'yoda': 'error'

3
.gitignore vendored
View file

@ -3,6 +3,9 @@ dist
web web
node_modules node_modules
# config
config.json
# ide # ide
.idea .idea
.vscode .vscode

View file

@ -5,28 +5,28 @@
"repository": "https://github.com/jellyfin/jellyfin-web", "repository": "https://github.com/jellyfin/jellyfin-web",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"devDependencies": { "devDependencies": {
"@babel/core": "^7.11.6", "@babel/core": "^7.12.3",
"@babel/eslint-parser": "^7.11.5", "@babel/eslint-parser": "^7.12.1",
"@babel/eslint-plugin": "^7.11.5", "@babel/eslint-plugin": "^7.12.1",
"@babel/plugin-proposal-class-properties": "^7.10.1", "@babel/plugin-proposal-class-properties": "^7.10.1",
"@babel/plugin-proposal-private-methods": "^7.10.1", "@babel/plugin-proposal-private-methods": "^7.12.1",
"@babel/plugin-transform-modules-amd": "^7.10.5", "@babel/plugin-transform-modules-amd": "^7.12.1",
"@babel/polyfill": "^7.11.5", "@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.11.5", "@babel/preset-env": "^7.12.1",
"autoprefixer": "^9.8.6", "autoprefixer": "^9.8.6",
"babel-loader": "^8.0.6", "babel-loader": "^8.0.6",
"browser-sync": "^2.26.12", "browser-sync": "^2.26.13",
"confusing-browser-globals": "^1.0.9", "confusing-browser-globals": "^1.0.10",
"copy-webpack-plugin": "^5.1.1", "copy-webpack-plugin": "^5.1.1",
"css-loader": "^4.3.0", "css-loader": "^5.0.0",
"cssnano": "^4.1.10", "cssnano": "^4.1.10",
"del": "^5.1.0", "del": "^6.0.0",
"eslint": "^7.9.0", "eslint": "^7.12.0",
"eslint-plugin-compat": "^3.5.1", "eslint-plugin-compat": "^3.5.1",
"eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.21.2", "eslint-plugin-import": "^2.22.1",
"eslint-plugin-promise": "^4.2.1", "eslint-plugin-promise": "^4.2.1",
"file-loader": "^6.1.0", "file-loader": "^6.1.1",
"gulp": "^4.0.2", "gulp": "^4.0.2",
"gulp-babel": "^8.0.0", "gulp-babel": "^8.0.0",
"gulp-cli": "^2.3.0", "gulp-cli": "^2.3.0",
@ -45,12 +45,12 @@
"node-sass": "^4.13.1", "node-sass": "^4.13.1",
"postcss-loader": "^3.0.0", "postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0", "postcss-preset-env": "^6.7.0",
"style-loader": "^1.1.3", "style-loader": "^2.0.0",
"stylelint": "^13.7.1", "stylelint": "^13.7.2",
"stylelint-config-rational-order": "^0.1.2", "stylelint-config-rational-order": "^0.1.2",
"stylelint-no-browser-hacks": "^1.2.1", "stylelint-no-browser-hacks": "^1.2.1",
"stylelint-order": "^4.1.0", "stylelint-order": "^4.1.0",
"webpack": "^4.44.2", "webpack": "^5.2.0",
"webpack-merge": "^4.2.2", "webpack-merge": "^4.2.2",
"webpack-stream": "^6.1.0", "webpack-stream": "^6.1.0",
"worker-plugin": "^5.0.0" "worker-plugin": "^5.0.0"
@ -62,14 +62,14 @@
"core-js": "^3.6.5", "core-js": "^3.6.5",
"date-fns": "^2.16.1", "date-fns": "^2.16.1",
"epubjs": "^0.3.85", "epubjs": "^0.3.85",
"pdfjs-dist": "2.4.456",
"fast-text-encoding": "^1.0.3", "fast-text-encoding": "^1.0.3",
"flv.js": "^1.5.0", "flv.js": "^1.5.0",
"headroom.js": "^0.11.0", "headroom.js": "^0.12.0",
"hls.js": "^0.14.12", "hls.js": "^0.14.16",
"howler": "^2.2.0", "howler": "^2.2.1",
"intersection-observer": "^0.11.0", "intersection-observer": "^0.11.0",
"jellyfin-apiclient": "^1.4.1", "jellyfin-apiclient": "^1.4.2",
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
"jquery": "^3.5.1", "jquery": "^3.5.1",
"jstree": "^3.3.10", "jstree": "^3.3.10",
"libarchive.js": "^1.3.0", "libarchive.js": "^1.3.0",
@ -77,11 +77,11 @@
"material-design-icons-iconfont": "^6.1.0", "material-design-icons-iconfont": "^6.1.0",
"native-promise-only": "^0.8.0-a", "native-promise-only": "^0.8.0-a",
"page": "^1.11.6", "page": "^1.11.6",
"query-string": "^6.13.2", "query-string": "^6.13.6",
"resize-observer-polyfill": "^1.5.1", "resize-observer-polyfill": "^1.5.1",
"screenfull": "^5.0.2", "screenfull": "^5.0.2",
"sortablejs": "^1.12.0", "sortablejs": "^1.12.0",
"swiper": "^6.2.0", "swiper": "^6.3.4",
"webcomponents.js": "^0.7.24", "webcomponents.js": "^0.7.24",
"whatwg-fetch": "^3.4.1" "whatwg-fetch": "^3.4.1"
}, },
@ -245,7 +245,7 @@
"src/controllers/dashboard/plugins/installed/index.js", "src/controllers/dashboard/plugins/installed/index.js",
"src/controllers/dashboard/plugins/available/index.js", "src/controllers/dashboard/plugins/available/index.js",
"src/controllers/dashboard/plugins/repositories/index.js", "src/controllers/dashboard/plugins/repositories/index.js",
"src/controllers/dashboard/quickconnect.js", "src/controllers/dashboard/quickConnect.js",
"src/controllers/dashboard/scheduledtasks/scheduledtask.js", "src/controllers/dashboard/scheduledtasks/scheduledtask.js",
"src/controllers/dashboard/scheduledtasks/scheduledtasks.js", "src/controllers/dashboard/scheduledtasks/scheduledtasks.js",
"src/controllers/dashboard/serveractivity.js", "src/controllers/dashboard/serveractivity.js",
@ -326,6 +326,7 @@
"src/libraries/scroller.js", "src/libraries/scroller.js",
"src/plugins/backdropScreensaver/plugin.js", "src/plugins/backdropScreensaver/plugin.js",
"src/plugins/bookPlayer/plugin.js", "src/plugins/bookPlayer/plugin.js",
"src/plugins/pdfPlayer/plugin.js",
"src/plugins/bookPlayer/tableOfContents.js", "src/plugins/bookPlayer/tableOfContents.js",
"src/plugins/chromecastPlayer/chromecastHelper.js", "src/plugins/chromecastPlayer/chromecastHelper.js",
"src/plugins/photoPlayer/plugin.js", "src/plugins/photoPlayer/plugin.js",

View file

@ -6,29 +6,42 @@
-ms-user-select: none; -ms-user-select: none;
} }
.osdPoster img,
.videoOsdBottom { .videoOsdBottom {
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
position: fixed;
background: linear-gradient(0deg, rgba(16, 16, 16, 0.75) 0%, rgba(16, 16, 16, 0) 100%);
padding-top: 7.5em;
padding-bottom: 1.75em;
display: flex;
flex-direction: row;
justify-content: center;
will-change: opacity;
transition: opacity 0.3s ease-out;
color: #fff;
user-select: none;
-webkit-touch-callout: none;
} }
.osdHeader { .skinHeader-withBackground.osdHeader {
-webkit-transition: opacity 0.3s ease-out;
-o-transition: opacity 0.3s ease-out;
transition: opacity 0.3s ease-out; transition: opacity 0.3s ease-out;
position: relative; position: relative;
z-index: 1; z-index: 1;
background: rgba(0, 0, 0, 0.7) !important; background: linear-gradient(180deg, rgba(16, 16, 16, 0.75) 0%, rgba(16, 16, 16, 0) 100%);
-webkit-backdrop-filter: none !important; backdrop-filter: none;
backdrop-filter: none !important; color: #eee;
color: #eee !important; height: 7.5em;
} }
.osdHeader-hidden { .osdHeader-hidden {
opacity: 0; opacity: 0;
} }
.osdHeader .headerTop {
max-height: 3.5em;
}
.osdHeader .headerButton:not(.headerBackButton):not(.headerCastButton):not(.headerSyncButton) { .osdHeader .headerButton:not(.headerBackButton):not(.headerCastButton):not(.headerSyncButton) {
display: none; display: none;
} }
@ -86,34 +99,17 @@
opacity: 0.6; opacity: 0.6;
} }
.videoOsdBottom {
position: fixed;
background-color: rgba(0, 0, 0, 0.7);
padding: 1%;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
flex-direction: row;
will-change: opacity;
-webkit-transition: opacity 0.3s ease-out;
-o-transition: opacity 0.3s ease-out;
transition: opacity 0.3s ease-out;
color: #fff;
user-select: none;
-webkit-touch-callout: none;
}
.videoOsdBottom-hidden { .videoOsdBottom-hidden {
opacity: 0; opacity: 0;
} }
.osdControls { .osdControls {
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1; flex-grow: 1;
padding: 0 0.8em;
}
.layout-desktop .osdControls {
max-width: calc(100vh * 1.77 - 2vh);
} }
.videoOsdBottom .buttons { .videoOsdBottom .buttons {
@ -145,7 +141,7 @@
} }
.volumeButtons { .volumeButtons {
margin: 0 0.5em 0 auto; margin: 0 1em 0 0.29em;
display: flex; display: flex;
-webkit-align-items: center; -webkit-align-items: center;
align-items: center; align-items: center;
@ -153,33 +149,13 @@
.osdTimeText { .osdTimeText {
margin-left: 1em; margin-left: 1em;
margin-right: auto;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
user-select: none; user-select: none;
} }
.osdPoster {
width: 10%;
position: relative;
margin-right: 0.5em;
}
.osdPoster img {
position: absolute;
height: auto;
width: 100%;
-webkit-box-shadow: 0 0 1.9vh #000;
box-shadow: 0 0 1.9vh #000;
border: 0.08em solid #222;
user-drag: none;
user-select: none;
-moz-user-select: none;
-webkit-user-drag: none;
-webkit-user-select: none;
-ms-user-select: none;
}
.osdTitle, .osdTitle,
.osdTitleSmall { .osdTitleSmall {
margin: 0 1em 0 0; margin: 0 1em 0 0;

View file

@ -90,17 +90,16 @@ _define('material-icons', function() {
return materialIcons; return materialIcons;
}); });
// noto font
const noto = require('jellyfin-noto');
_define('jellyfin-noto', function () {
return noto;
});
const epubjs = require('epubjs'); const epubjs = require('epubjs');
_define('epubjs', function () { _define('epubjs', function () {
return epubjs; return epubjs;
}); });
const pdfjs = require('pdfjs-dist/build/pdf');
_define('pdfjs', function () {
return pdfjs;
});
// page.js // page.js
const page = require('page'); const page = require('page');
_define('page', function() { _define('page', function() {
@ -177,7 +176,7 @@ _define('appStorage', function () {
}); });
// libarchive.js // libarchive.js
var libarchive = require('libarchive.js'); const libarchive = require('libarchive.js');
_define('libarchive', function () { _define('libarchive', function () {
return libarchive; return libarchive;
}); });

View file

@ -27,7 +27,7 @@ class appFooter {
}; };
} }
destroy() { destroy() {
var self = this; const self = this;
self.element = null; self.element = null;
} }

View file

@ -78,7 +78,7 @@ function getDeviceId() {
} }
function getDeviceName() { function getDeviceName() {
var deviceName; let deviceName;
if (browser.tizen) { if (browser.tizen) {
deviceName = 'Samsung Smart TV'; deviceName = 'Samsung Smart TV';
} else if (browser.web0s) { } else if (browser.web0s) {
@ -172,7 +172,6 @@ function supportsCue() {
function onAppVisible() { function onAppVisible() {
if (isHidden) { if (isHidden) {
isHidden = false; isHidden = false;
console.debug('triggering app resume event');
events.trigger(appHost, 'resume'); events.trigger(appHost, 'resume');
} }
} }
@ -180,7 +179,6 @@ function onAppVisible() {
function onAppHidden() { function onAppHidden() {
if (!isHidden) { if (!isHidden) {
isHidden = true; isHidden = true;
console.debug('app is hidden');
} }
} }

View file

@ -23,7 +23,7 @@ import 'emby-button';
}).join(''); }).join('');
// get default theme // get default theme
var defaultTheme = themes.find(theme => { const defaultTheme = themes.find(theme => {
return theme.default; return theme.default;
}); });

View file

@ -19,7 +19,7 @@ function onSubmit(e) {
return false; return false;
} }
function renderOptions(context, selector, cssClass, items, isCheckedFn) { function renderOptions(context, selector, cssClass, items, isCheckedFn) {
var elem = context.querySelector(selector); const elem = context.querySelector(selector);
if (items.length) { if (items.length) {
elem.classList.remove('hide'); elem.classList.remove('hide');
@ -27,12 +27,12 @@ function renderOptions(context, selector, cssClass, items, isCheckedFn) {
elem.classList.add('hide'); elem.classList.add('hide');
} }
var html = ''; let html = '';
html += items.map(function (filter) { html += items.map(function (filter) {
var itemHtml = ''; let itemHtml = '';
var checkedHtml = isCheckedFn(filter) ? ' checked' : ''; const checkedHtml = isCheckedFn(filter) ? ' checked' : '';
itemHtml += '<label>'; itemHtml += '<label>';
itemHtml += '<input is="emby-checkbox" type="checkbox"' + checkedHtml + ' data-filter="' + filter.Id + '" class="' + cssClass + '"/>'; itemHtml += '<input is="emby-checkbox" type="checkbox"' + checkedHtml + ' data-filter="' + filter.Id + '" class="' + cssClass + '"/>';
itemHtml += '<span>' + filter.Name + '</span>'; itemHtml += '<span>' + filter.Name + '</span>';
@ -47,21 +47,21 @@ function renderOptions(context, selector, cssClass, items, isCheckedFn) {
function renderDynamicFilters(context, result, options) { function renderDynamicFilters(context, result, options) {
renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) { renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) {
// Switching from | to , // Switching from | to ,
var delimeter = (options.settings.GenreIds || '').indexOf('|') === -1 ? ',' : '|'; const delimeter = (options.settings.GenreIds || '').indexOf('|') === -1 ? ',' : '|';
return (delimeter + (options.settings.GenreIds || '') + delimeter).indexOf(delimeter + i.Id + delimeter) !== -1; return (delimeter + (options.settings.GenreIds || '') + delimeter).indexOf(delimeter + i.Id + delimeter) !== -1;
}); });
} }
function setBasicFilter(context, key, elem) { function setBasicFilter(context, key, elem) {
var value = elem.checked; let value = elem.checked;
value = value ? value : null; value = value ? value : null;
userSettings.setFilter(key, value); userSettings.setFilter(key, value);
} }
function moveCheckboxFocus(elem, offset) { function moveCheckboxFocus(elem, offset) {
var parent = dom.parentWithClass(elem, 'checkboxList-verticalwrap'); const parent = dom.parentWithClass(elem, 'checkboxList-verticalwrap');
var elems = focusManager.getFocusableElements(parent); const elems = focusManager.getFocusableElements(parent);
var index = -1; let index = -1;
for (let i = 0, length = elems.length; i < length; i++) { for (let i = 0, length = elems.length; i < length; i++) {
if (elems[i] === elem) { if (elems[i] === elem) {
index = i; index = i;
@ -74,14 +74,14 @@ function moveCheckboxFocus(elem, offset) {
index = Math.min(elems.length - 1, index); index = Math.min(elems.length - 1, index);
index = Math.max(0, index); index = Math.max(0, index);
var newElem = elems[index]; const newElem = elems[index];
if (newElem) { if (newElem) {
focusManager.focus(newElem); focusManager.focus(newElem);
} }
} }
function centerFocus(elem, horiz, on) { function centerFocus(elem, horiz, on) {
import('scrollHelper').then(({ default: scrollHelper }) => { import('scrollHelper').then(({ default: scrollHelper }) => {
var fn = on ? 'on' : 'off'; const fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz); scrollHelper.centerFocus[fn](elem, horiz);
}); });
} }
@ -100,7 +100,7 @@ function onInputCommand(e) {
} }
} }
function saveValues(context, settings, settingsKey) { function saveValues(context, settings, settingsKey) {
var elems = context.querySelectorAll('.simpleFilter'); let elems = context.querySelectorAll('.simpleFilter');
for (let i = 0, length = elems.length; i < length; i++) { for (let i = 0, length = elems.length; i < length; i++) {
if (elems[i].tagName === 'INPUT') { if (elems[i].tagName === 'INPUT') {
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i]); setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i]);
@ -110,7 +110,7 @@ function saveValues(context, settings, settingsKey) {
} }
// Video type // Video type
var videoTypes = []; const videoTypes = [];
elems = context.querySelectorAll('.chkVideoTypeFilter'); elems = context.querySelectorAll('.chkVideoTypeFilter');
for (let i = 0, length = elems.length; i < length; i++) { for (let i = 0, length = elems.length; i < length; i++) {
@ -121,7 +121,7 @@ function saveValues(context, settings, settingsKey) {
userSettings.setFilter(settingsKey + '-filter-VideoTypes', videoTypes.join(',')); userSettings.setFilter(settingsKey + '-filter-VideoTypes', videoTypes.join(','));
// Series status // Series status
var seriesStatuses = []; const seriesStatuses = [];
elems = context.querySelectorAll('.chkSeriesStatus'); elems = context.querySelectorAll('.chkSeriesStatus');
for (let i = 0, length = elems.length; i < length; i++) { for (let i = 0, length = elems.length; i < length; i++) {
@ -131,7 +131,7 @@ function saveValues(context, settings, settingsKey) {
} }
// Genres // Genres
var genres = []; const genres = [];
elems = context.querySelectorAll('.chkGenreFilter'); elems = context.querySelectorAll('.chkGenreFilter');
for (let i = 0, length = elems.length; i < length; i++) { for (let i = 0, length = elems.length; i < length; i++) {
@ -142,7 +142,7 @@ function saveValues(context, settings, settingsKey) {
userSettings.setFilter(settingsKey + '-filter-GenreIds', genres.join(',')); userSettings.setFilter(settingsKey + '-filter-GenreIds', genres.join(','));
} }
function bindCheckboxInput(context, on) { function bindCheckboxInput(context, on) {
var elems = context.querySelectorAll('.checkboxList-verticalwrap'); const elems = context.querySelectorAll('.checkboxList-verticalwrap');
for (let i = 0, length = elems.length; i < length; i++) { for (let i = 0, length = elems.length; i < length; i++) {
if (on) { if (on) {
inputManager.on(elems[i], onInputCommand); inputManager.on(elems[i], onInputCommand);
@ -154,9 +154,9 @@ function bindCheckboxInput(context, on) {
function initEditor(context, settings) { function initEditor(context, settings) {
context.querySelector('form').addEventListener('submit', onSubmit); context.querySelector('form').addEventListener('submit', onSubmit);
var elems = context.querySelectorAll('.simpleFilter'); let elems = context.querySelectorAll('.simpleFilter');
var i; let i;
var length; let length;
for (i = 0, length = elems.length; i < length; i++) { for (i = 0, length = elems.length; i < length; i++) {
if (elems[i].tagName === 'INPUT') { if (elems[i].tagName === 'INPUT') {
@ -166,14 +166,14 @@ function initEditor(context, settings) {
} }
} }
var videoTypes = settings.VideoTypes ? settings.VideoTypes.split(',') : []; const videoTypes = settings.VideoTypes ? settings.VideoTypes.split(',') : [];
elems = context.querySelectorAll('.chkVideoTypeFilter'); elems = context.querySelectorAll('.chkVideoTypeFilter');
for (i = 0, length = elems.length; i < length; i++) { for (i = 0, length = elems.length; i < length; i++) {
elems[i].checked = videoTypes.indexOf(elems[i].getAttribute('data-filter')) !== -1; elems[i].checked = videoTypes.indexOf(elems[i].getAttribute('data-filter')) !== -1;
} }
var seriesStatuses = settings.SeriesStatus ? settings.SeriesStatus.split(',') : []; const seriesStatuses = settings.SeriesStatus ? settings.SeriesStatus.split(',') : [];
elems = context.querySelectorAll('.chkSeriesStatus'); elems = context.querySelectorAll('.chkSeriesStatus');
for (i = 0, length = elems.length; i < length; i++) { for (i = 0, length = elems.length; i < length; i++) {
@ -193,9 +193,9 @@ function initEditor(context, settings) {
} }
} }
function loadDynamicFilters(context, options) { function loadDynamicFilters(context, options) {
var apiClient = window.connectionManager.getApiClient(options.serverId); const apiClient = window.connectionManager.getApiClient(options.serverId);
var filterMenuOptions = Object.assign(options.filterMenuOptions, { const filterMenuOptions = Object.assign(options.filterMenuOptions, {
UserId: apiClient.getCurrentUserId(), UserId: apiClient.getCurrentUserId(),
ParentId: options.parentId, ParentId: options.parentId,
@ -210,7 +210,7 @@ class FilterMenu {
show(options) { show(options) {
return new Promise( (resolve, reject) => { return new Promise( (resolve, reject) => {
import('text!./filtermenu.template.html').then(({ default: template }) => { import('text!./filtermenu.template.html').then(({ default: template }) => {
var dialogOptions = { const dialogOptions = {
removeOnClose: true, removeOnClose: true,
scrollY: false scrollY: false
}; };
@ -220,11 +220,11 @@ class FilterMenu {
dialogOptions.size = 'small'; dialogOptions.size = 'small';
} }
var dlg = dialogHelper.createDialog(dialogOptions); const dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog'); dlg.classList.add('formDialog');
var html = ''; let html = '';
html += '<div class="formDialogHeader">'; html += '<div class="formDialogHeader">';
html += '<button is="paper-icon-button-light" class="btnCancel hide-mouse-idle-tv" tabindex="-1"><span class="material-icons arrow_back"></span></button>'; html += '<button is="paper-icon-button-light" class="btnCancel hide-mouse-idle-tv" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
@ -236,7 +236,7 @@ class FilterMenu {
dlg.innerHTML = globalize.translateHtml(html, 'core'); dlg.innerHTML = globalize.translateHtml(html, 'core');
var settingElements = dlg.querySelectorAll('.viewSetting'); const settingElements = dlg.querySelectorAll('.viewSetting');
for (let i = 0, length = settingElements.length; i < length; i++) { for (let i = 0, length = settingElements.length; i < length; i++) {
if (options.visibleSettings.indexOf(settingElements[i].getAttribute('data-settingname')) === -1) { if (options.visibleSettings.indexOf(settingElements[i].getAttribute('data-settingname')) === -1) {
settingElements[i].classList.add('hide'); settingElements[i].classList.add('hide');
@ -257,7 +257,7 @@ class FilterMenu {
centerFocus(dlg.querySelector('.formDialogContent'), false, true); centerFocus(dlg.querySelector('.formDialogContent'), false, true);
} }
var submitted; let submitted;
dlg.querySelector('form').addEventListener('change', function () { dlg.querySelector('form').addEventListener('change', function () {
submitted = true; submitted = true;

View file

@ -3,7 +3,7 @@
import dom from 'dom'; import dom from 'dom';
import scrollManager from 'scrollManager'; import scrollManager from 'scrollManager';
var scopes = []; const scopes = [];
function pushScope(elem) { function pushScope(elem) {
scopes.push(elem); scopes.push(elem);
} }
@ -15,7 +15,7 @@ import scrollManager from 'scrollManager';
} }
function autoFocus(view, defaultToFirst, findAutoFocusElement) { function autoFocus(view, defaultToFirst, findAutoFocusElement) {
var element; let element;
if (findAutoFocusElement !== false) { if (findAutoFocusElement !== false) {
element = view.querySelector('*[autofocus]'); element = view.querySelector('*[autofocus]');
if (element) { if (element) {
@ -46,9 +46,9 @@ import scrollManager from 'scrollManager';
} }
} }
var focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A']; const focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A'];
var focusableContainerTagNames = ['BODY', 'DIALOG']; const focusableContainerTagNames = ['BODY', 'DIALOG'];
var focusableQuery = focusableTagNames.map(function (t) { const focusableQuery = focusableTagNames.map(function (t) {
if (t === 'INPUT') { if (t === 'INPUT') {
t += ':not([type="range"]):not([type="file"])'; t += ':not([type="range"]):not([type="file"])';
} }
@ -69,7 +69,7 @@ import scrollManager from 'scrollManager';
function normalizeFocusable(elem, originalElement) { function normalizeFocusable(elem, originalElement) {
if (elem) { if (elem) {
var tagName = elem.tagName; const tagName = elem.tagName;
if (!tagName || tagName === 'HTML' || tagName === 'BODY') { if (!tagName || tagName === 'HTML' || tagName === 'BODY') {
elem = originalElement; elem = originalElement;
} }
@ -79,10 +79,10 @@ import scrollManager from 'scrollManager';
} }
function focusableParent(elem) { function focusableParent(elem) {
var originalElement = elem; const originalElement = elem;
while (!isFocusable(elem)) { while (!isFocusable(elem)) {
var parent = elem.parentNode; const parent = elem.parentNode;
if (!parent) { if (!parent) {
return normalizeFocusable(elem, originalElement); return normalizeFocusable(elem, originalElement);
@ -115,7 +115,7 @@ import scrollManager from 'scrollManager';
} }
if (elem.tagName === 'INPUT') { if (elem.tagName === 'INPUT') {
var type = elem.type; const type = elem.type;
if (type === 'range') { if (type === 'range') {
return false; return false;
} }
@ -132,11 +132,11 @@ import scrollManager from 'scrollManager';
} }
function getFocusableElements(parent, limit, excludeClass) { function getFocusableElements(parent, limit, excludeClass) {
var elems = (parent || getDefaultScope()).querySelectorAll(focusableQuery); const elems = (parent || getDefaultScope()).querySelectorAll(focusableQuery);
var focusableElements = []; const focusableElements = [];
for (var i = 0, length = elems.length; i < length; i++) { for (let i = 0, length = elems.length; i < length; i++) {
var elem = elems[i]; const elem = elems[i];
if (excludeClass && elem.classList.contains(excludeClass)) { if (excludeClass && elem.classList.contains(excludeClass)) {
continue; continue;
@ -159,7 +159,7 @@ import scrollManager from 'scrollManager';
return true; return true;
} }
var classList = elem.classList; const classList = elem.classList;
if (classList.contains('focuscontainer')) { if (classList.contains('focuscontainer')) {
return true; return true;
@ -208,7 +208,7 @@ import scrollManager from 'scrollManager';
} }
function getOffset(elem) { function getOffset(elem) {
var box; let box;
// Support: BlackBerry 5, iOS 3 (original iPhone) // Support: BlackBerry 5, iOS 3 (original iPhone)
// If we don't have gBCR, just use 0,0 rather than error // If we don't have gBCR, just use 0,0 rather than error
@ -225,7 +225,7 @@ import scrollManager from 'scrollManager';
if (box.right === null) { if (box.right === null) {
// Create a new object because some browsers will throw an error when trying to set data onto the Rect object // Create a new object because some browsers will throw an error when trying to set data onto the Rect object
var newBox = { const newBox = {
top: box.top, top: box.top,
left: box.left, left: box.left,
width: box.width, width: box.width,
@ -255,27 +255,27 @@ import scrollManager from 'scrollManager';
return; return;
} }
var focusableContainer = dom.parentWithClass(activeElement, 'focusable'); const focusableContainer = dom.parentWithClass(activeElement, 'focusable');
var rect = getOffset(activeElement); const rect = getOffset(activeElement);
// Get elements and work out x/y points // Get elements and work out x/y points
var point1x = parseFloat(rect.left) || 0; const point1x = parseFloat(rect.left) || 0;
var point1y = parseFloat(rect.top) || 0; const point1y = parseFloat(rect.top) || 0;
var point2x = parseFloat(point1x + rect.width - 1) || point1x; const point2x = parseFloat(point1x + rect.width - 1) || point1x;
var point2y = parseFloat(point1y + rect.height - 1) || point1y; const point2y = parseFloat(point1y + rect.height - 1) || point1y;
var sourceMidX = rect.left + (rect.width / 2); const sourceMidX = rect.left + (rect.width / 2);
var sourceMidY = rect.top + (rect.height / 2); const sourceMidY = rect.top + (rect.height / 2);
var focusable = focusableElements || container.querySelectorAll(focusableQuery); const focusable = focusableElements || container.querySelectorAll(focusableQuery);
var maxDistance = Infinity; const maxDistance = Infinity;
var minDistance = maxDistance; let minDistance = maxDistance;
var nearestElement; let nearestElement;
for (var i = 0, length = focusable.length; i < length; i++) { for (let i = 0, length = focusable.length; i < length; i++) {
var curr = focusable[i]; const curr = focusable[i];
if (curr === activeElement) { if (curr === activeElement) {
continue; continue;
@ -285,7 +285,7 @@ import scrollManager from 'scrollManager';
continue; continue;
} }
var elementRect = getOffset(curr); const elementRect = getOffset(curr);
// not currently visible // not currently visible
if (!elementRect.width && !elementRect.height) { if (!elementRect.width && !elementRect.height) {
@ -333,19 +333,19 @@ import scrollManager from 'scrollManager';
break; break;
} }
var x = elementRect.left; const x = elementRect.left;
var y = elementRect.top; const y = elementRect.top;
var x2 = x + elementRect.width - 1; const x2 = x + elementRect.width - 1;
var y2 = y + elementRect.height - 1; const y2 = y + elementRect.height - 1;
var intersectX = intersects(point1x, point2x, x, x2); const intersectX = intersects(point1x, point2x, x, x2);
var intersectY = intersects(point1y, point2y, y, y2); const intersectY = intersects(point1y, point2y, y, y2);
var midX = elementRect.left + (elementRect.width / 2); const midX = elementRect.left + (elementRect.width / 2);
var midY = elementRect.top + (elementRect.height / 2); const midY = elementRect.top + (elementRect.height / 2);
var distX; let distX;
var distY; let distY;
switch (direction) { switch (direction) {
case 0: case 0:
@ -372,7 +372,7 @@ import scrollManager from 'scrollManager';
break; break;
} }
var dist = Math.sqrt(distX * distX + distY * distY); const dist = Math.sqrt(distX * distX + distY * distY);
if (dist < minDistance) { if (dist < minDistance) {
nearestElement = curr; nearestElement = curr;
@ -383,7 +383,7 @@ import scrollManager from 'scrollManager';
if (nearestElement) { if (nearestElement) {
// See if there's a focusable container, and if so, send the focus command to that // See if there's a focusable container, and if so, send the focus command to that
if (activeElement) { if (activeElement) {
var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable'); const nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable');
if (nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement) { if (nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement) {
if (focusableContainer !== nearestElementFocusableParent) { if (focusableContainer !== nearestElementFocusableParent) {
nearestElement = nearestElementFocusableParent; nearestElement = nearestElementFocusableParent;
@ -403,16 +403,16 @@ import scrollManager from 'scrollManager';
} }
function sendText(text) { function sendText(text) {
var elem = document.activeElement; const elem = document.activeElement;
elem.value = text; elem.value = text;
} }
function focusFirst(container, focusableSelector) { function focusFirst(container, focusableSelector) {
var elems = container.querySelectorAll(focusableSelector); const elems = container.querySelectorAll(focusableSelector);
for (var i = 0, length = elems.length; i < length; i++) { for (let i = 0, length = elems.length; i < length; i++) {
var elem = elems[i]; const elem = elems[i];
if (isCurrentlyFocusableInternal(elem)) { if (isCurrentlyFocusableInternal(elem)) {
focus(elem); focus(elem);
@ -422,10 +422,10 @@ import scrollManager from 'scrollManager';
} }
function focusLast(container, focusableSelector) { function focusLast(container, focusableSelector) {
var elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse(); const elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse();
for (var i = 0, length = elems.length; i < length; i++) { for (let i = 0, length = elems.length; i < length; i++) {
var elem = elems[i]; const elem = elems[i];
if (isCurrentlyFocusableInternal(elem)) { if (isCurrentlyFocusableInternal(elem)) {
focus(elem); focus(elem);
@ -435,11 +435,11 @@ import scrollManager from 'scrollManager';
} }
function moveFocus(sourceElement, container, focusableSelector, offset) { function moveFocus(sourceElement, container, focusableSelector, offset) {
var elems = container.querySelectorAll(focusableSelector); const elems = container.querySelectorAll(focusableSelector);
var list = []; const list = [];
var i; let i;
var length; let length;
var elem; let elem;
for (i = 0, length = elems.length; i < length; i++) { for (i = 0, length = elems.length; i < length; i++) {
elem = elems[i]; elem = elems[i];
@ -449,7 +449,7 @@ import scrollManager from 'scrollManager';
} }
} }
var currentIndex = -1; let currentIndex = -1;
for (i = 0, length = list.length; i < length; i++) { for (i = 0, length = list.length; i < length; i++) {
elem = list[i]; elem = list[i];
@ -464,11 +464,11 @@ import scrollManager from 'scrollManager';
return; return;
} }
var newIndex = currentIndex + offset; let newIndex = currentIndex + offset;
newIndex = Math.max(0, newIndex); newIndex = Math.max(0, newIndex);
newIndex = Math.min(newIndex, list.length - 1); newIndex = Math.min(newIndex, list.length - 1);
var newElem = list[newIndex]; const newElem = list[newIndex];
if (newElem) { if (newElem) {
focus(newElem); focus(newElem);
} }
@ -482,23 +482,23 @@ export default {
focusableParent: focusableParent, focusableParent: focusableParent,
getFocusableElements: getFocusableElements, getFocusableElements: getFocusableElements,
moveLeft: function (sourceElement, options) { moveLeft: function (sourceElement, options) {
var container = options ? options.container : null; const container = options ? options.container : null;
var focusableElements = options ? options.focusableElements : null; const focusableElements = options ? options.focusableElements : null;
nav(sourceElement, 0, container, focusableElements); nav(sourceElement, 0, container, focusableElements);
}, },
moveRight: function (sourceElement, options) { moveRight: function (sourceElement, options) {
var container = options ? options.container : null; const container = options ? options.container : null;
var focusableElements = options ? options.focusableElements : null; const focusableElements = options ? options.focusableElements : null;
nav(sourceElement, 1, container, focusableElements); nav(sourceElement, 1, container, focusableElements);
}, },
moveUp: function (sourceElement, options) { moveUp: function (sourceElement, options) {
var container = options ? options.container : null; const container = options ? options.container : null;
var focusableElements = options ? options.focusableElements : null; const focusableElements = options ? options.focusableElements : null;
nav(sourceElement, 2, container, focusableElements); nav(sourceElement, 2, container, focusableElements);
}, },
moveDown: function (sourceElement, options) { moveDown: function (sourceElement, options) {
var container = options ? options.container : null; const container = options ? options.container : null;
var focusableElements = options ? options.focusableElements : null; const focusableElements = options ? options.focusableElements : null;
nav(sourceElement, 3, container, focusableElements); nav(sourceElement, 3, container, focusableElements);
}, },
sendText: sendText, sendText: sendText,

View file

@ -4,19 +4,19 @@ import dom from 'dom';
import appRouter from 'appRouter'; import appRouter from 'appRouter';
function onGroupedCardClick(e, card) { function onGroupedCardClick(e, card) {
var itemId = card.getAttribute('data-id'); const itemId = card.getAttribute('data-id');
var serverId = card.getAttribute('data-serverid'); const serverId = card.getAttribute('data-serverid');
var apiClient = window.connectionManager.getApiClient(serverId); const apiClient = window.connectionManager.getApiClient(serverId);
var userId = apiClient.getCurrentUserId(); const userId = apiClient.getCurrentUserId();
var playedIndicator = card.querySelector('.playedIndicator'); const playedIndicator = card.querySelector('.playedIndicator');
var playedIndicatorHtml = playedIndicator ? playedIndicator.innerHTML : null; const playedIndicatorHtml = playedIndicator ? playedIndicator.innerHTML : null;
var options = { const options = {
Limit: parseInt(playedIndicatorHtml || '10'), Limit: parseInt(playedIndicatorHtml || '10'),
Fields: 'PrimaryImageAspectRatio,DateCreated', Fields: 'PrimaryImageAspectRatio,DateCreated',
ParentId: itemId, ParentId: itemId,
GroupItems: false GroupItems: false
}; };
var actionableParent = dom.parentWithTag(e.target, ['A', 'BUTTON', 'INPUT']); const actionableParent = dom.parentWithTag(e.target, ['A', 'BUTTON', 'INPUT']);
if (!actionableParent || actionableParent.classList.contains('cardContent')) { if (!actionableParent || actionableParent.classList.contains('cardContent')) {
apiClient.getJSON(apiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) { apiClient.getJSON(apiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) {
@ -24,7 +24,7 @@ import appRouter from 'appRouter';
return void appRouter.showItem(items[0]); return void appRouter.showItem(items[0]);
} }
var url = 'details?id=' + itemId + '&serverId=' + serverId; const url = 'details?id=' + itemId + '&serverId=' + serverId;
Dashboard.navigate(url); Dashboard.navigate(url);
}); });
e.stopPropagation(); e.stopPropagation();
@ -34,7 +34,7 @@ import appRouter from 'appRouter';
} }
export default function onItemsContainerClick(e) { export default function onItemsContainerClick(e) {
var groupedCard = dom.parentWithClass(e.target, 'groupedCard'); const groupedCard = dom.parentWithClass(e.target, 'groupedCard');
if (groupedCard) { if (groupedCard) {
onGroupedCardClick(e, groupedCard); onGroupedCardClick(e, groupedCard);

View file

@ -75,26 +75,30 @@ import 'emby-checkbox';
value: 'suggestions' value: 'suggestions'
}); });
list.push({ list.push({
name: globalize.translate('Latest'), name: globalize.translate('Upcoming'),
value: 'latest' value: 'upcoming'
}); });
list.push({ list.push({
name: globalize.translate('Genres'), name: globalize.translate('Genres'),
value: 'genres' value: 'genres'
}); });
list.push({ list.push({
name: globalize.translate('Favorites'), name: globalize.translate('Networks'),
value: 'favorites' value: 'networks'
});
list.push({
name: globalize.translate('Episodes'),
value: 'episodes'
}); });
} else if (type === 'music') { } else if (type === 'music') {
list.push({ list.push({
name: globalize.translate('Suggestions'), name: globalize.translate('Albums'),
value: 'suggestions', value: 'albums',
isDefault: true isDefault: true
}); });
list.push({ list.push({
name: globalize.translate('Albums'), name: globalize.translate('Suggestions'),
value: 'albums' value: 'suggestions'
}); });
list.push({ list.push({
name: globalize.translate('HeaderAlbumArtists'), name: globalize.translate('HeaderAlbumArtists'),

View file

@ -23,7 +23,7 @@ import events from 'events';
} }
function canPlayNativeHls() { function canPlayNativeHls() {
var media = document.createElement('video'); const media = document.createElement('video');
if (media.canPlayType('application/x-mpegURL').replace(/no/, '') || if (media.canPlayType('application/x-mpegURL').replace(/no/, '') ||
media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, '')) { media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, '')) {
@ -71,16 +71,16 @@ import events from 'events';
return true; return true;
} }
var recoverDecodingErrorDate; let recoverDecodingErrorDate;
var recoverSwapAudioCodecDate; let recoverSwapAudioCodecDate;
export function handleHlsJsMediaError(instance, reject) { export function handleHlsJsMediaError(instance, reject) {
var hlsPlayer = instance._hlsPlayer; const hlsPlayer = instance._hlsPlayer;
if (!hlsPlayer) { if (!hlsPlayer) {
return; return;
} }
var now = Date.now(); let now = Date.now();
if (window.performance && window.performance.now) { if (window.performance && window.performance.now) {
now = performance.now(); // eslint-disable-line compat/compat now = performance.now(); // eslint-disable-line compat/compat
@ -136,7 +136,7 @@ import events from 'events';
} }
export function seekOnPlaybackStart(instance, element, ticks, onMediaReady) { export function seekOnPlaybackStart(instance, element, ticks, onMediaReady) {
var seconds = (ticks || 0) / 10000000; const seconds = (ticks || 0) / 10000000;
if (seconds) { if (seconds) {
// Appending #t=xxx to the query string doesn't seem to work with HLS // Appending #t=xxx to the query string doesn't seem to work with HLS
@ -148,8 +148,8 @@ import events from 'events';
if (onMediaReady) onMediaReady(); if (onMediaReady) onMediaReady();
} else { } else {
// update video player position when media is ready to be sought // update video player position when media is ready to be sought
var events = ['durationchange', 'loadeddata', 'play', 'loadedmetadata']; const events = ['durationchange', 'loadeddata', 'play', 'loadedmetadata'];
var onMediaChange = function(e) { const onMediaChange = function(e) {
if (element.currentTime === 0 && element.duration >= seconds) { if (element.currentTime === 0 && element.duration >= seconds) {
// seek only when video position is exactly zero, // seek only when video position is exactly zero,
// as this is true only if video hasn't started yet or // as this is true only if video hasn't started yet or
@ -173,10 +173,10 @@ import events from 'events';
export function applySrc(elem, src, options) { export function applySrc(elem, src, options) {
if (window.Windows && options.mediaSource && options.mediaSource.IsLocal) { if (window.Windows && options.mediaSource && options.mediaSource.IsLocal) {
return Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function (file) { return Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function (file) {
var playlist = new Windows.Media.Playback.MediaPlaybackList(); const playlist = new Windows.Media.Playback.MediaPlaybackList();
var source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file); const source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file);
var startTime = (options.playerStartPositionTicks || 0) / 10000; const startTime = (options.playerStartPositionTicks || 0) / 10000;
playlist.items.append(new Windows.Media.Playback.MediaPlaybackItem(source1, startTime)); playlist.items.append(new Windows.Media.Playback.MediaPlaybackItem(source1, startTime));
elem.src = URL.createObjectURL(playlist, { oneTimeOnly: true }); elem.src = URL.createObjectURL(playlist, { oneTimeOnly: true });
return Promise.resolve(); return Promise.resolve();
@ -194,11 +194,11 @@ import events from 'events';
export function playWithPromise(elem, onErrorFn) { export function playWithPromise(elem, onErrorFn) {
try { try {
var promise = elem.play(); const promise = elem.play();
if (promise && promise.then) { if (promise && promise.then) {
// Chrome now returns a promise // Chrome now returns a promise
return promise.catch(function (e) { return promise.catch(function (e) {
var errorName = (e.name || '').toLowerCase(); const errorName = (e.name || '').toLowerCase();
// safari uses aborterror // safari uses aborterror
if (errorName === 'notallowederror' || if (errorName === 'notallowederror' ||
errorName === 'aborterror') { errorName === 'aborterror') {
@ -219,7 +219,7 @@ import events from 'events';
} }
export function destroyCastPlayer(instance) { export function destroyCastPlayer(instance) {
var player = instance._castPlayer; const player = instance._castPlayer;
if (player) { if (player) {
try { try {
player.unload(); player.unload();
@ -232,7 +232,7 @@ import events from 'events';
} }
export function destroyHlsPlayer(instance) { export function destroyHlsPlayer(instance) {
var player = instance._hlsPlayer; const player = instance._hlsPlayer;
if (player) { if (player) {
try { try {
player.destroy(); player.destroy();
@ -245,7 +245,7 @@ import events from 'events';
} }
export function destroyFlvPlayer(instance) { export function destroyFlvPlayer(instance) {
var player = instance._flvPlayer; const player = instance._flvPlayer;
if (player) { if (player) {
try { try {
player.unload(); player.unload();
@ -322,9 +322,8 @@ import events from 'events';
break; break;
case Hls.ErrorTypes.MEDIA_ERROR: case Hls.ErrorTypes.MEDIA_ERROR:
console.debug('fatal media error encountered, try to recover'); console.debug('fatal media error encountered, try to recover');
var currentReject = reject; handleHlsJsMediaError(instance, reject);
reject = null; reject = null;
handleHlsJsMediaError(instance, currentReject);
break; break;
default: default:
@ -356,7 +355,7 @@ import events from 'events';
destroyFlvPlayer(instance); destroyFlvPlayer(instance);
destroyCastPlayer(instance); destroyCastPlayer(instance);
var stopInfo = { const stopInfo = {
src: instance._currentSrc src: instance._currentSrc
}; };
@ -368,20 +367,20 @@ import events from 'events';
} }
export function getBufferedRanges(instance, elem) { export function getBufferedRanges(instance, elem) {
var ranges = []; const ranges = [];
var seekable = elem.buffered || []; const seekable = elem.buffered || [];
var offset; let offset;
var currentPlayOptions = instance._currentPlayOptions; const currentPlayOptions = instance._currentPlayOptions;
if (currentPlayOptions) { if (currentPlayOptions) {
offset = currentPlayOptions.transcodingOffsetTicks; offset = currentPlayOptions.transcodingOffsetTicks;
} }
offset = offset || 0; offset = offset || 0;
for (var i = 0, length = seekable.length; i < length; i++) { for (let i = 0, length = seekable.length; i < length; i++) {
var start = seekable.start(i); let start = seekable.start(i);
var end = seekable.end(i); let end = seekable.end(i);
if (!isValidDuration(start)) { if (!isValidDuration(start)) {
start = 0; start = 0;

View file

@ -93,7 +93,7 @@ import 'emby-input';
const response = await fetch('components/imageOptionsEditor/imageOptionsEditor.template.html'); const response = await fetch('components/imageOptionsEditor/imageOptionsEditor.template.html');
const template = await response.text(); const template = await response.text();
var dlg = dialogHelper.createDialog({ const dlg = dialogHelper.createDialog({
size: 'small', size: 'small',
removeOnClose: true, removeOnClose: true,
scrollY: false scrollY: false

View file

@ -58,8 +58,8 @@ import 'css!./imageeditor';
currentItem = item; currentItem = item;
apiClient.getRemoteImageProviders(getBaseRemoteOptions()).then(function (providers) { apiClient.getRemoteImageProviders(getBaseRemoteOptions()).then(function (providers) {
var btnBrowseAllImages = page.querySelectorAll('.btnBrowseAllImages'); const btnBrowseAllImages = page.querySelectorAll('.btnBrowseAllImages');
for (var i = 0, length = btnBrowseAllImages.length; i < length; i++) { for (let i = 0, length = btnBrowseAllImages.length; i < length; i++) {
if (providers.length) { if (providers.length) {
btnBrowseAllImages[i].classList.remove('hide'); btnBrowseAllImages[i].classList.remove('hide');
} else { } else {

View file

@ -56,7 +56,7 @@ import 'css!./style';
throw new Error('entry cannot be null'); throw new Error('entry cannot be null');
} }
const target = entry.target; const target = entry.target;
var source = undefined; let source = undefined;
if (target) { if (target) {
source = target.getAttribute('data-src'); source = target.getAttribute('data-src');
@ -106,7 +106,7 @@ import 'css!./style';
} }
function emptyImageElement(elem) { function emptyImageElement(elem) {
var url; let url;
if (elem.tagName !== 'IMG') { if (elem.tagName !== 'IMG') {
url = elem.style.backgroundImage.slice(4, -1).replace(/"/g, ''); url = elem.style.backgroundImage.slice(4, -1).replace(/"/g, '');
@ -137,10 +137,10 @@ import 'css!./style';
} }
export function getPrimaryImageAspectRatio(items) { export function getPrimaryImageAspectRatio(items) {
var values = []; const values = [];
for (var i = 0, length = items.length; i < length; i++) { for (let i = 0, length = items.length; i < length; i++) {
var ratio = items[i].PrimaryImageAspectRatio || 0; const ratio = items[i].PrimaryImageAspectRatio || 0;
if (!ratio) { if (!ratio) {
continue; continue;
@ -158,9 +158,9 @@ import 'css!./style';
return a - b; return a - b;
}); });
var half = Math.floor(values.length / 2); const half = Math.floor(values.length / 2);
var result; let result;
if (values.length % 2) { if (values.length % 2) {
result = values[half]; result = values[half];
@ -169,13 +169,13 @@ import 'css!./style';
} }
// If really close to 2:3 (poster image), just return 2:3 // If really close to 2:3 (poster image), just return 2:3
var aspect2x3 = 2 / 3; const aspect2x3 = 2 / 3;
if (Math.abs(aspect2x3 - result) <= 0.15) { if (Math.abs(aspect2x3 - result) <= 0.15) {
return aspect2x3; return aspect2x3;
} }
// If really close to 16:9 (episode image), just return 16:9 // If really close to 16:9 (episode image), just return 16:9
var aspect16x9 = 16 / 9; const aspect16x9 = 16 / 9;
if (Math.abs(aspect16x9 - result) <= 0.2) { if (Math.abs(aspect16x9 - result) <= 0.2) {
return aspect16x9; return aspect16x9;
} }
@ -186,7 +186,7 @@ import 'css!./style';
} }
// If really close to 4:3 (poster image), just return 2:3 // If really close to 4:3 (poster image), just return 2:3
var aspect4x3 = 4 / 3; const aspect4x3 = 4 / 3;
if (Math.abs(aspect4x3 - result) <= 0.15) { if (Math.abs(aspect4x3 - result) <= 0.15) {
return aspect4x3; return aspect4x3;
} }
@ -195,8 +195,8 @@ import 'css!./style';
} }
export function fillImages(elems) { export function fillImages(elems) {
for (var i = 0, length = elems.length; i < length; i++) { for (let i = 0, length = elems.length; i < length; i++) {
var elem = elems[0]; const elem = elems[0];
fillImage(elem); fillImage(elem);
} }
} }

View file

@ -399,12 +399,10 @@ import 'emby-input';
} }
if (contentType === 'tvshows') { if (contentType === 'tvshows') {
parent.querySelector('.chkImportMissingEpisodesContainer').classList.remove('hide');
parent.querySelector('.chkAutomaticallyGroupSeriesContainer').classList.remove('hide'); parent.querySelector('.chkAutomaticallyGroupSeriesContainer').classList.remove('hide');
parent.querySelector('.fldSeasonZeroDisplayName').classList.remove('hide'); parent.querySelector('.fldSeasonZeroDisplayName').classList.remove('hide');
parent.querySelector('#txtSeasonZeroName').setAttribute('required', 'required'); parent.querySelector('#txtSeasonZeroName').setAttribute('required', 'required');
} else { } else {
parent.querySelector('.chkImportMissingEpisodesContainer').classList.add('hide');
parent.querySelector('.chkAutomaticallyGroupSeriesContainer').classList.add('hide'); parent.querySelector('.chkAutomaticallyGroupSeriesContainer').classList.add('hide');
parent.querySelector('.fldSeasonZeroDisplayName').classList.add('hide'); parent.querySelector('.fldSeasonZeroDisplayName').classList.add('hide');
parent.querySelector('#txtSeasonZeroName').removeAttribute('required'); parent.querySelector('#txtSeasonZeroName').removeAttribute('required');
@ -511,7 +509,6 @@ import 'emby-input';
EnableChapterImageExtraction: parent.querySelector('.chkExtractChapterImages').checked, EnableChapterImageExtraction: parent.querySelector('.chkExtractChapterImages').checked,
DownloadImagesInAdvance: parent.querySelector('#chkDownloadImagesInAdvance').checked, DownloadImagesInAdvance: parent.querySelector('#chkDownloadImagesInAdvance').checked,
EnableInternetProviders: true, EnableInternetProviders: true,
ImportMissingEpisodes: parent.querySelector('#chkImportMissingEpisodes').checked,
SaveLocalMetadata: parent.querySelector('#chkSaveLocal').checked, SaveLocalMetadata: parent.querySelector('#chkSaveLocal').checked,
EnableAutomaticSeriesGrouping: parent.querySelector('.chkAutomaticallyGroupSeries').checked, EnableAutomaticSeriesGrouping: parent.querySelector('.chkAutomaticallyGroupSeries').checked,
PreferredMetadataLanguage: parent.querySelector('#selectLanguage').value, PreferredMetadataLanguage: parent.querySelector('#selectLanguage').value,
@ -569,7 +566,6 @@ import 'emby-input';
parent.querySelector('.chkExtractChapterImages').checked = options.EnableChapterImageExtraction; parent.querySelector('.chkExtractChapterImages').checked = options.EnableChapterImageExtraction;
parent.querySelector('#chkDownloadImagesInAdvance').checked = options.DownloadImagesInAdvance; parent.querySelector('#chkDownloadImagesInAdvance').checked = options.DownloadImagesInAdvance;
parent.querySelector('#chkSaveLocal').checked = options.SaveLocalMetadata; parent.querySelector('#chkSaveLocal').checked = options.SaveLocalMetadata;
parent.querySelector('#chkImportMissingEpisodes').checked = options.ImportMissingEpisodes;
parent.querySelector('.chkAutomaticallyGroupSeries').checked = options.EnableAutomaticSeriesGrouping; parent.querySelector('.chkAutomaticallyGroupSeries').checked = options.EnableAutomaticSeriesGrouping;
parent.querySelector('#chkEnableEmbeddedTitles').checked = options.EnableEmbeddedTitles; parent.querySelector('#chkEnableEmbeddedTitles').checked = options.EnableEmbeddedTitles;
parent.querySelector('#chkEnableEmbeddedEpisodeInfos').checked = options.EnableEmbeddedEpisodeInfos; parent.querySelector('#chkEnableEmbeddedEpisodeInfos').checked = options.EnableEmbeddedEpisodeInfos;

View file

@ -85,14 +85,6 @@
<div class="fieldDescription checkboxFieldDescription">${OptionAutomaticallyGroupSeriesHelp}</div> <div class="fieldDescription checkboxFieldDescription">${OptionAutomaticallyGroupSeriesHelp}</div>
</div> </div>
<div class="checkboxContainer checkboxContainer-withDescription hide chkImportMissingEpisodesContainer advanced">
<label>
<input is="emby-checkbox" type="checkbox" id="chkImportMissingEpisodes" />
<span>${DisplayMissingEpisodesWithinSeasons}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${ImportMissingEpisodesHelp}</div>
</div>
<div class="chapterSettingsSection hide"> <div class="chapterSettingsSection hide">
<h2>${HeaderChapterImages}</h2> <h2>${HeaderChapterImages}</h2>
<div class="checkboxContainer checkboxContainer-withDescription fldExtractChapterImages"> <div class="checkboxContainer checkboxContainer-withDescription fldExtractChapterImages">

View file

@ -256,8 +256,8 @@ import 'emby-playstatebutton';
} }
if (options.image !== false) { if (options.image !== false) {
var imgUrl = options.imageSource === 'channel' ? getChannelImageUrl(item, downloadWidth) : getImageUrl(item, downloadWidth); const imgUrl = options.imageSource === 'channel' ? getChannelImageUrl(item, downloadWidth) : getImageUrl(item, downloadWidth);
var imageClass = isLargeStyle ? 'listItemImage listItemImage-large' : 'listItemImage'; let imageClass = isLargeStyle ? 'listItemImage listItemImage-large' : 'listItemImage';
if (isLargeStyle && layoutManager.tv) { if (isLargeStyle && layoutManager.tv) {
imageClass += ' listItemImage-large-tv'; imageClass += ' listItemImage-large-tv';

View file

@ -100,11 +100,10 @@ import 'emby-button';
return html; return html;
} }
export function getMediaInfoHtml(item, options) { export function getMediaInfoHtml(item, options = {}) {
let html = ''; let html = '';
const miscInfo = []; const miscInfo = [];
options = options || {};
let text; let text;
let date; let date;
let minutes; let minutes;
@ -289,7 +288,9 @@ import 'emby-button';
return getMediaInfoItem(m); return getMediaInfoItem(m);
}).join(''); }).join('');
html += getStarIconsHtml(item); if (options.starRating !== false) {
html += getStarIconsHtml(item);
}
if (item.HasSubtitles && options.subtitles !== false) { if (item.HasSubtitles && options.subtitles !== false) {
html += '<div class="mediaInfoItem mediaInfoText closedCaptionMediaInfoText">CC</div>'; html += '<div class="mediaInfoItem mediaInfoText closedCaptionMediaInfoText">CC</div>';
@ -418,9 +419,8 @@ import 'emby-button';
return false; return false;
} }
export function getPrimaryMediaInfoHtml(item, options) { export function getPrimaryMediaInfoHtml(item, options = {}) {
options = options || {}; if (options.interactive === undefined) {
if (options.interactive == null) {
options.interactive = false; options.interactive = false;
} }

View file

@ -239,7 +239,7 @@ import 'flexStyles';
} }
function afterDeleted(context, item) { function afterDeleted(context, item) {
var parentId = item.ParentId || item.SeasonId || item.SeriesId; const parentId = item.ParentId || item.SeasonId || item.SeriesId;
if (parentId) { if (parentId) {
reload(context, parentId, item.ServerId); reload(context, parentId, item.ServerId);
@ -252,7 +252,7 @@ import 'flexStyles';
function showMoreMenu(context, button, user) { function showMoreMenu(context, button, user) {
import('itemContextMenu').then(({default: itemContextMenu}) => { import('itemContextMenu').then(({default: itemContextMenu}) => {
var item = currentItem; const item = currentItem;
itemContextMenu.show({ itemContextMenu.show({
item: item, item: item,

View file

@ -251,7 +251,7 @@
</div> </div>
<br /> <br />
<div class="formDialogFooter"> <div class="formDialogFooter">
<button is="emby-button" class="raised button-cancel block btnCancel formDialogFooterItem"> <button is="emby-button" type="button" class="raised button-cancel block btnCancel formDialogFooterItem">
<span>${Cancel}</span> <span>${Cancel}</span>
</button> </button>
<button is="emby-button" type="submit" class="raised button-submit block btnSave formDialogFooterItem"> <button is="emby-button" type="submit" class="raised button-submit block btnSave formDialogFooterItem">

View file

@ -582,7 +582,7 @@ import 'emby-ratingbutton';
function onPlaybackStart(e, state) { function onPlaybackStart(e, state) {
console.debug('nowplaying event: ' + e.type); console.debug('nowplaying event: ' + e.type);
var player = this; const player = this;
onStateChanged.call(player, e, state); onStateChanged.call(player, e, state);
} }

View file

@ -8,7 +8,7 @@ import pluginManager from 'pluginManager';
init() { init() {
console.groupCollapsed('loading packages'); console.groupCollapsed('loading packages');
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]'); const manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
return Promise.all(manifestUrls.map((url) => { return Promise.all(manifestUrls.map((url) => {
return this.loadPackage(url); return this.loadPackage(url);
@ -30,7 +30,7 @@ import pluginManager from 'pluginManager';
install(url) { install(url) {
return this.loadPackage(url, true).then((pkg) => { return this.loadPackage(url, true).then((pkg) => {
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]'); const manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
if (!manifestUrls.includes(url)) { if (!manifestUrls.includes(url)) {
manifestUrls.push(url); manifestUrls.push(url);
@ -42,7 +42,7 @@ import pluginManager from 'pluginManager';
} }
uninstall(name) { uninstall(name) {
var pkg = this.#packagesList.filter((p) => { const pkg = this.#packagesList.filter((p) => {
return p.name === name; return p.name === name;
})[0]; })[0];
@ -58,12 +58,12 @@ import pluginManager from 'pluginManager';
} }
mapPath(pkg, pluginUrl) { mapPath(pkg, pluginUrl) {
var urlLower = pluginUrl.toLowerCase(); const urlLower = pluginUrl.toLowerCase();
if (urlLower.startsWith('http:') || urlLower.startsWith('https:') || urlLower.startsWith('file:')) { if (urlLower.startsWith('http:') || urlLower.startsWith('https:') || urlLower.startsWith('file:')) {
return pluginUrl; return pluginUrl;
} }
var packageUrl = pkg.url; let packageUrl = pkg.url;
packageUrl = packageUrl.substring(0, packageUrl.lastIndexOf('/')); packageUrl = packageUrl.substring(0, packageUrl.lastIndexOf('/'));
packageUrl += '/'; packageUrl += '/';
@ -81,7 +81,7 @@ import pluginManager from 'pluginManager';
} }
removeUrl(url) { removeUrl(url) {
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]'); let manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
manifestUrls = manifestUrls.filter((i) => { manifestUrls = manifestUrls.filter((i) => {
return i !== url; return i !== url;
@ -92,14 +92,14 @@ import pluginManager from 'pluginManager';
loadPackage(url, throwError = false) { loadPackage(url, throwError = false) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
var originalUrl = url; const originalUrl = url;
url += url.indexOf('?') === -1 ? '?' : '&'; url += url.indexOf('?') === -1 ? '?' : '&';
url += 't=' + new Date().getTime(); url += 't=' + new Date().getTime();
xhr.open('GET', url, true); xhr.open('GET', url, true);
var onError = () => { const onError = () => {
if (throwError === true) { if (throwError === true) {
reject(); reject();
} else { } else {
@ -110,16 +110,16 @@ import pluginManager from 'pluginManager';
xhr.onload = () => { xhr.onload = () => {
if (this.status < 400) { if (this.status < 400) {
var pkg = JSON.parse(this.response); const pkg = JSON.parse(this.response);
pkg.url = originalUrl; pkg.url = originalUrl;
this.addPackage(pkg); this.addPackage(pkg);
var plugins = pkg.plugins || []; const plugins = pkg.plugins || [];
if (pkg.plugin) { if (pkg.plugin) {
plugins.push(pkg.plugin); plugins.push(pkg.plugin);
} }
var promises = plugins.map((pluginUrl) => { const promises = plugins.map((pluginUrl) => {
return pluginManager.loadPlugin(this.mapPath(pkg, pluginUrl)); return pluginManager.loadPlugin(this.mapPath(pkg, pluginUrl));
}); });
Promise.all(promises).then(resolve, resolve); Promise.all(promises).then(resolve, resolve);

View file

@ -5,15 +5,15 @@ import browser from 'browser';
import 'css!./iconosd'; import 'css!./iconosd';
import 'material-icons'; import 'material-icons';
var currentPlayer; let currentPlayer;
var osdElement; let osdElement;
var iconElement; let iconElement;
var progressElement; let progressElement;
var enableAnimation; let enableAnimation;
function getOsdElementHtml() { function getOsdElementHtml() {
var html = ''; let html = '';
html += '<span class="material-icons iconOsdIcon brightness_high"></span>'; html += '<span class="material-icons iconOsdIcon brightness_high"></span>';
@ -23,7 +23,7 @@ function getOsdElementHtml() {
} }
function ensureOsdElement() { function ensureOsdElement() {
var elem = osdElement; let elem = osdElement;
if (!elem) { if (!elem) {
enableAnimation = browser.supportsCssAnimation(); enableAnimation = browser.supportsCssAnimation();
@ -46,11 +46,11 @@ function onHideComplete() {
this.classList.add('hide'); this.classList.add('hide');
} }
var hideTimeout; let hideTimeout;
function showOsd() { function showOsd() {
clearHideTimeout(); clearHideTimeout();
var elem = osdElement; const elem = osdElement;
dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
once: true once: true
@ -78,7 +78,7 @@ function clearHideTimeout() {
function hideOsd() { function hideOsd() {
clearHideTimeout(); clearHideTimeout();
var elem = osdElement; const elem = osdElement;
if (elem) { if (elem) {
if (enableAnimation) { if (enableAnimation) {
// trigger reflow // trigger reflow
@ -118,7 +118,7 @@ function updateElementsFromPlayer(brightness) {
} }
function releaseCurrentPlayer() { function releaseCurrentPlayer() {
var player = currentPlayer; const player = currentPlayer;
if (player) { if (player) {
events.off(player, 'brightnesschange', onBrightnessChanged); events.off(player, 'brightnesschange', onBrightnessChanged);
@ -128,7 +128,7 @@ function releaseCurrentPlayer() {
} }
function onBrightnessChanged(e) { function onBrightnessChanged(e) {
var player = this; const player = this;
ensureOsdElement(); ensureOsdElement();

View file

@ -1,5 +1,6 @@
import playbackManager from 'playbackManager'; import playbackManager from 'playbackManager';
import nowPlayingHelper from 'nowPlayingHelper'; import nowPlayingHelper from 'nowPlayingHelper';
import shell from 'shell';
import events from 'events'; import events from 'events';
/* eslint-disable indent */ /* eslint-disable indent */
@ -127,8 +128,7 @@ import events from 'events';
}); });
} else { } else {
const itemImageUrl = seriesImageUrl(item, { maxHeight: 3000 }) || imageUrl(item, { maxHeight: 3000 }); const itemImageUrl = seriesImageUrl(item, { maxHeight: 3000 }) || imageUrl(item, { maxHeight: 3000 });
shell.updateMediaSession({
window.NativeShell.updateMediaSession({
action: eventName, action: eventName,
isLocalPlayer: isLocalPlayer, isLocalPlayer: isLocalPlayer,
itemId: itemId, itemId: itemId,
@ -182,7 +182,7 @@ import events from 'events';
/* eslint-disable-next-line compat/compat */ /* eslint-disable-next-line compat/compat */
navigator.mediaSession.metadata = null; navigator.mediaSession.metadata = null;
} else { } else {
window.NativeShell.hideMediaSession(); shell.hideMediaSession();
} }
} }

View file

@ -1,7 +1,7 @@
export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) { export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
var topItem = nowPlayingItem; let topItem = nowPlayingItem;
var bottomItem = null; let bottomItem = null;
var topText = nowPlayingItem.Name; let topText = nowPlayingItem.Name;
if (nowPlayingItem.AlbumId && nowPlayingItem.MediaType === 'Audio') { if (nowPlayingItem.AlbumId && nowPlayingItem.MediaType === 'Audio') {
topItem = { topItem = {
@ -21,7 +21,7 @@ export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
} }
} }
var bottomText = ''; let bottomText = '';
if (nowPlayingItem.ArtistItems && nowPlayingItem.ArtistItems.length) { if (nowPlayingItem.ArtistItems && nowPlayingItem.ArtistItems.length) {
bottomItem = { bottomItem = {
@ -56,7 +56,7 @@ export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
bottomText = nowPlayingItem.ProductionYear; bottomText = nowPlayingItem.ProductionYear;
} }
var list = []; const list = [];
list.push({ list.push({
text: topText, text: topText,

View file

@ -2,7 +2,7 @@ import playbackManager from 'playbackManager';
import layoutManager from 'layoutManager'; import layoutManager from 'layoutManager';
import events from 'events'; import events from 'events';
var orientationLocked; let orientationLocked;
function onOrientationChangeSuccess() { function onOrientationChangeSuccess() {
orientationLocked = true; orientationLocked = true;
@ -14,15 +14,15 @@ function onOrientationChangeError(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); const isLocalVideo = player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player);
if (isLocalVideo && layoutManager.mobile) { if (isLocalVideo && layoutManager.mobile) {
/* eslint-disable-next-line compat/compat */ /* eslint-disable-next-line compat/compat */
var lockOrientation = window.screen.lockOrientation || window.screen.mozLockOrientation || window.screen.msLockOrientation || (window.screen.orientation && window.screen.orientation.lock); const lockOrientation = window.screen.lockOrientation || window.screen.mozLockOrientation || window.screen.msLockOrientation || (window.screen.orientation && window.screen.orientation.lock);
if (lockOrientation) { if (lockOrientation) {
try { try {
var promise = lockOrientation('landscape'); const promise = lockOrientation('landscape');
if (promise.then) { if (promise.then) {
promise.then(onOrientationChangeSuccess, onOrientationChangeError); promise.then(onOrientationChangeSuccess, onOrientationChangeError);
} else { } else {
@ -39,7 +39,7 @@ events.on(playbackManager, 'playbackstart', function (e, player, state) {
events.on(playbackManager, 'playbackstop', function (e, playbackStopInfo) { events.on(playbackManager, 'playbackstop', function (e, playbackStopInfo) {
if (orientationLocked && !playbackStopInfo.nextMediaType) { if (orientationLocked && !playbackStopInfo.nextMediaType) {
/* eslint-disable-next-line compat/compat */ /* eslint-disable-next-line compat/compat */
var unlockOrientation = window.screen.unlockOrientation || window.screen.mozUnlockOrientation || window.screen.msUnlockOrientation || (window.screen.orientation && window.screen.orientation.unlock); const unlockOrientation = window.screen.unlockOrientation || window.screen.mozUnlockOrientation || window.screen.msUnlockOrientation || (window.screen.orientation && window.screen.orientation.unlock);
if (unlockOrientation) { if (unlockOrientation) {
try { try {

View file

@ -9,7 +9,7 @@ import appHost from 'apphost';
import * as autocast from 'autocast'; import * as autocast from 'autocast';
function mirrorItem(info, player) { function mirrorItem(info, player) {
var item = info.item; const item = info.item;
playbackManager.displayContent({ playbackManager.displayContent({
@ -22,7 +22,7 @@ function mirrorItem(info, player) {
function mirrorIfEnabled(info) { function mirrorIfEnabled(info) {
if (info && playbackManager.enableDisplayMirroring()) { if (info && playbackManager.enableDisplayMirroring()) {
var getPlayerInfo = playbackManager.getPlayerInfo(); const getPlayerInfo = playbackManager.getPlayerInfo();
if (getPlayerInfo) { if (getPlayerInfo) {
if (!getPlayerInfo.isLocalPlayer && getPlayerInfo.supportedCommands.indexOf('DisplayContent') !== -1) { if (!getPlayerInfo.isLocalPlayer && getPlayerInfo.supportedCommands.indexOf('DisplayContent') !== -1) {
@ -45,7 +45,7 @@ function getTargetSecondaryText(target) {
} }
function getIcon(target) { function getIcon(target) {
var deviceType = target.deviceType; let deviceType = target.deviceType;
if (!deviceType && target.isLocalPlayer) { if (!deviceType && target.isLocalPlayer) {
if (browser.tv) { if (browser.tv) {
@ -78,7 +78,7 @@ function getIcon(target) {
} }
export function show(button) { export function show(button) {
var currentPlayerInfo = playbackManager.getPlayerInfo(); const currentPlayerInfo = playbackManager.getPlayerInfo();
if (currentPlayerInfo) { if (currentPlayerInfo) {
if (!currentPlayerInfo.isLocalPlayer) { if (!currentPlayerInfo.isLocalPlayer) {
@ -87,13 +87,13 @@ export function show(button) {
} }
} }
var currentPlayerId = currentPlayerInfo ? currentPlayerInfo.id : null; const currentPlayerId = currentPlayerInfo ? currentPlayerInfo.id : null;
loading.show(); loading.show();
playbackManager.getTargets().then(function (targets) { playbackManager.getTargets().then(function (targets) {
var menuItems = targets.map(function (t) { const menuItems = targets.map(function (t) {
var name = t.name; let name = t.name;
if (t.appName && t.appName !== t.name) { if (t.appName && t.appName !== t.name) {
name += ' - ' + t.appName; name += ' - ' + t.appName;
@ -111,7 +111,7 @@ export function show(button) {
import('actionsheet').then(({default: actionsheet}) => { import('actionsheet').then(({default: actionsheet}) => {
loading.hide(); loading.hide();
var menuOptions = { const menuOptions = {
title: globalize.translate('HeaderPlayOn'), title: globalize.translate('HeaderPlayOn'),
items: menuItems, items: menuItems,
positionTo: button, positionTo: button,
@ -127,7 +127,7 @@ export function show(button) {
} }
actionsheet.show(menuOptions).then(function (id) { actionsheet.show(menuOptions).then(function (id) {
var target = targets.filter(function (t) { const target = targets.filter(function (t) {
return t.id === id; return t.id === id;
})[0]; })[0];
@ -153,7 +153,7 @@ function showActivePlayerMenu(playerInfo) {
function disconnectFromPlayer(currentDeviceName) { function disconnectFromPlayer(currentDeviceName) {
if (playbackManager.getSupportedCommands().indexOf('EndSession') !== -1) { if (playbackManager.getSupportedCommands().indexOf('EndSession') !== -1) {
import('dialog').then(({default: dialog}) => { import('dialog').then(({default: dialog}) => {
var menuItems = []; const menuItems = [];
menuItems.push({ menuItems.push({
name: globalize.translate('Yes'), name: globalize.translate('Yes'),
@ -188,9 +188,9 @@ function disconnectFromPlayer(currentDeviceName) {
} }
function showActivePlayerMenuInternal(dialogHelper, playerInfo) { function showActivePlayerMenuInternal(dialogHelper, playerInfo) {
var html = ''; let html = '';
var dialogOptions = { const dialogOptions = {
removeOnClose: true removeOnClose: true
}; };
@ -199,11 +199,11 @@ function showActivePlayerMenuInternal(dialogHelper, playerInfo) {
dialogOptions.exitAnimationDuration = 160; dialogOptions.exitAnimationDuration = 160;
dialogOptions.autoFocus = false; dialogOptions.autoFocus = false;
var dlg = dialogHelper.createDialog(dialogOptions); const dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('promptDialog'); dlg.classList.add('promptDialog');
var currentDeviceName = (playerInfo.deviceName || playerInfo.name); const currentDeviceName = (playerInfo.deviceName || playerInfo.name);
html += '<div class="promptDialogContent" style="padding:1.5em;">'; html += '<div class="promptDialogContent" style="padding:1.5em;">';
html += '<h2 style="margin-top:.5em;">'; html += '<h2 style="margin-top:.5em;">';
@ -214,7 +214,7 @@ function showActivePlayerMenuInternal(dialogHelper, playerInfo) {
if (playerInfo.supportedCommands.indexOf('DisplayContent') !== -1) { if (playerInfo.supportedCommands.indexOf('DisplayContent') !== -1) {
html += '<label class="checkboxContainer">'; html += '<label class="checkboxContainer">';
var checkedHtml = playbackManager.enableDisplayMirroring() ? ' checked' : ''; const checkedHtml = playbackManager.enableDisplayMirroring() ? ' checked' : '';
html += '<input type="checkbox" is="emby-checkbox" class="chkMirror"' + checkedHtml + '/>'; html += '<input type="checkbox" is="emby-checkbox" class="chkMirror"' + checkedHtml + '/>';
html += '<span>' + globalize.translate('EnableDisplayMirroring') + '</span>'; html += '<span>' + globalize.translate('EnableDisplayMirroring') + '</span>';
html += '</label>'; html += '</label>';
@ -224,7 +224,7 @@ function showActivePlayerMenuInternal(dialogHelper, playerInfo) {
if (autocast.supported()) { if (autocast.supported()) {
html += '<div><label class="checkboxContainer">'; html += '<div><label class="checkboxContainer">';
var checkedHtmlAC = autocast.isEnabled() ? ' checked' : ''; const checkedHtmlAC = autocast.isEnabled() ? ' checked' : '';
html += '<input type="checkbox" is="emby-checkbox" class="chkAutoCast"' + checkedHtmlAC + '/>'; html += '<input type="checkbox" is="emby-checkbox" class="chkAutoCast"' + checkedHtmlAC + '/>';
html += '<span>' + globalize.translate('EnableAutoCast') + '</span>'; html += '<span>' + globalize.translate('EnableAutoCast') + '</span>';
html += '</label></div>'; html += '</label></div>';
@ -240,21 +240,21 @@ function showActivePlayerMenuInternal(dialogHelper, playerInfo) {
html += '</div>'; html += '</div>';
dlg.innerHTML = html; dlg.innerHTML = html;
var chkMirror = dlg.querySelector('.chkMirror'); const chkMirror = dlg.querySelector('.chkMirror');
if (chkMirror) { if (chkMirror) {
chkMirror.addEventListener('change', onMirrorChange); chkMirror.addEventListener('change', onMirrorChange);
} }
var chkAutoCast = dlg.querySelector('.chkAutoCast'); const chkAutoCast = dlg.querySelector('.chkAutoCast');
if (chkAutoCast) { if (chkAutoCast) {
chkAutoCast.addEventListener('change', onAutoCastChange); chkAutoCast.addEventListener('change', onAutoCastChange);
} }
var destination = ''; let destination = '';
var btnRemoteControl = dlg.querySelector('.btnRemoteControl'); const btnRemoteControl = dlg.querySelector('.btnRemoteControl');
if (btnRemoteControl) { if (btnRemoteControl) {
btnRemoteControl.addEventListener('click', function () { btnRemoteControl.addEventListener('click', function () {
destination = 'nowplaying'; destination = 'nowplaying';
@ -289,8 +289,8 @@ function onAutoCastChange() {
} }
document.addEventListener('viewshow', function (e) { document.addEventListener('viewshow', function (e) {
var state = e.detail.state || {}; const state = e.detail.state || {};
var item = state.item; const item = state.item;
if (item && item.ServerId) { if (item && item.ServerId) {
mirrorIfEnabled({ mirrorIfEnabled({

View file

@ -4,13 +4,13 @@ import globalize from 'globalize';
import qualityoptions from 'qualityoptions'; import qualityoptions from 'qualityoptions';
function showQualityMenu(player, btn) { function showQualityMenu(player, btn) {
var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { const videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) {
return stream.Type === 'Video'; return stream.Type === 'Video';
})[0]; })[0];
var videoWidth = videoStream ? videoStream.Width : null; const videoWidth = videoStream ? videoStream.Width : null;
var videoHeight = videoStream ? videoStream.Height : null; const videoHeight = videoStream ? videoStream.Height : null;
var options = qualityoptions.getVideoQualityOptions({ const options = qualityoptions.getVideoQualityOptions({
currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player), currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player),
isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player), isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player),
videoWidth: videoWidth, videoWidth: videoWidth,
@ -18,8 +18,8 @@ function showQualityMenu(player, btn) {
enableAuto: true enableAuto: true
}); });
var menuItems = options.map(function (o) { const menuItems = options.map(function (o) {
var opt = { const opt = {
name: o.name, name: o.name,
id: o.bitrate, id: o.bitrate,
asideText: o.secondaryText asideText: o.secondaryText
@ -32,7 +32,7 @@ function showQualityMenu(player, btn) {
return opt; return opt;
}); });
var selectedId = options.filter(function (o) { let selectedId = options.filter(function (o) {
return o.selected; return o.selected;
}); });
@ -42,7 +42,7 @@ function showQualityMenu(player, btn) {
items: menuItems, items: menuItems,
positionTo: btn positionTo: btn
}).then(function (id) { }).then(function (id) {
var bitrate = parseInt(id); const bitrate = parseInt(id);
if (bitrate !== selectedId) { if (bitrate !== selectedId) {
playbackManager.setMaxStreamingBitrate({ playbackManager.setMaxStreamingBitrate({
enableAutomaticBitrateDetection: bitrate ? false : true, enableAutomaticBitrateDetection: bitrate ? false : true,
@ -53,8 +53,8 @@ function showQualityMenu(player, btn) {
} }
function showRepeatModeMenu(player, btn) { function showRepeatModeMenu(player, btn) {
var menuItems = []; const menuItems = [];
var currentValue = playbackManager.getRepeatMode(player); const currentValue = playbackManager.getRepeatMode(player);
menuItems.push({ menuItems.push({
name: globalize.translate('RepeatAll'), name: globalize.translate('RepeatAll'),
@ -85,16 +85,16 @@ function showRepeatModeMenu(player, btn) {
} }
function getQualitySecondaryText(player) { function getQualitySecondaryText(player) {
var state = playbackManager.getPlayerState(player); const state = playbackManager.getPlayerState(player);
var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { const videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) {
return stream.Type === 'Video'; return stream.Type === 'Video';
})[0]; })[0];
var videoWidth = videoStream ? videoStream.Width : null; const videoWidth = videoStream ? videoStream.Width : null;
var videoHeight = videoStream ? videoStream.Height : null; const videoHeight = videoStream ? videoStream.Height : null;
var options = qualityoptions.getVideoQualityOptions({ const options = qualityoptions.getVideoQualityOptions({
currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player), currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player),
isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player), isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player),
videoWidth: videoWidth, videoWidth: videoWidth,
@ -102,7 +102,7 @@ function getQualitySecondaryText(player) {
enableAuto: true enableAuto: true
}); });
var selectedOption = options.filter(function (o) { let selectedOption = options.filter(function (o) {
return o.selected; return o.selected;
}); });
@ -111,7 +111,7 @@ function getQualitySecondaryText(player) {
} }
selectedOption = selectedOption[0]; selectedOption = selectedOption[0];
var text = selectedOption.name; let text = selectedOption.name;
if (selectedOption.autoText) { if (selectedOption.autoText) {
if (state.PlayState && state.PlayState.PlayMethod !== 'Transcode') { if (state.PlayState && state.PlayState.PlayMethod !== 'Transcode') {
@ -126,8 +126,8 @@ function getQualitySecondaryText(player) {
function showAspectRatioMenu(player, btn) { function showAspectRatioMenu(player, btn) {
// each has a name and id // each has a name and id
var currentId = playbackManager.getAspectRatio(player); const currentId = playbackManager.getAspectRatio(player);
var menuItems = playbackManager.getSupportedAspectRatios(player).map(function (i) { const menuItems = playbackManager.getSupportedAspectRatios(player).map(function (i) {
return { return {
id: i.id, id: i.id,
name: i.name, name: i.name,
@ -171,12 +171,12 @@ function showPlaybackRateMenu(player, btn) {
} }
function showWithUser(options, player, user) { function showWithUser(options, player, user) {
var supportedCommands = playbackManager.getSupportedCommands(player); const supportedCommands = playbackManager.getSupportedCommands(player);
var menuItems = []; const menuItems = [];
if (supportedCommands.indexOf('SetAspectRatio') !== -1) { if (supportedCommands.indexOf('SetAspectRatio') !== -1) {
var currentAspectRatioId = playbackManager.getAspectRatio(player); const currentAspectRatioId = playbackManager.getAspectRatio(player);
var currentAspectRatio = playbackManager.getSupportedAspectRatios(player).filter(function (i) { const currentAspectRatio = playbackManager.getSupportedAspectRatios(player).filter(function (i) {
return i.id === currentAspectRatioId; return i.id === currentAspectRatioId;
})[0]; })[0];
@ -199,7 +199,7 @@ function showWithUser(options, player, user) {
} }
if (user && user.Policy.EnableVideoPlaybackTranscoding) { if (user && user.Policy.EnableVideoPlaybackTranscoding) {
var secondaryQualityText = getQualitySecondaryText(player); const secondaryQualityText = getQualitySecondaryText(player);
menuItems.push({ menuItems.push({
name: globalize.translate('Quality'), name: globalize.translate('Quality'),
@ -208,7 +208,7 @@ function showWithUser(options, player, user) {
}); });
} }
var repeatMode = playbackManager.getRepeatMode(player); const repeatMode = playbackManager.getRepeatMode(player);
if (supportedCommands.indexOf('SetRepeatMode') !== -1 && playbackManager.currentMediaSource(player).RunTimeTicks) { if (supportedCommands.indexOf('SetRepeatMode') !== -1 && playbackManager.currentMediaSource(player).RunTimeTicks) {
menuItems.push({ menuItems.push({
@ -243,14 +243,14 @@ function showWithUser(options, player, user) {
} }
export function show(options) { export function show(options) {
var player = options.player; const player = options.player;
var currentItem = playbackManager.currentItem(player); const currentItem = playbackManager.currentItem(player);
if (!currentItem || !currentItem.ServerId) { if (!currentItem || !currentItem.ServerId) {
return showWithUser(options, player, null); return showWithUser(options, player, null);
} }
var apiClient = window.connectionManager.getApiClient(currentItem.ServerId); const apiClient = window.connectionManager.getApiClient(currentItem.ServerId);
return apiClient.getCurrentUser().then(function (user) { return apiClient.getCurrentUser().then(function (user) {
return showWithUser(options, player, user); return showWithUser(options, player, user);
}); });

View file

@ -5,15 +5,15 @@ import browser from 'browser';
import 'css!./iconosd'; import 'css!./iconosd';
import 'material-icons'; import 'material-icons';
var currentPlayer; let currentPlayer;
var osdElement; let osdElement;
var iconElement; let iconElement;
var progressElement; let progressElement;
var enableAnimation; let enableAnimation;
function getOsdElementHtml() { function getOsdElementHtml() {
var html = ''; let html = '';
html += '<span class="material-icons iconOsdIcon volume_up"></span>'; html += '<span class="material-icons iconOsdIcon volume_up"></span>';
@ -23,7 +23,7 @@ function getOsdElementHtml() {
} }
function ensureOsdElement() { function ensureOsdElement() {
var elem = osdElement; let elem = osdElement;
if (!elem) { if (!elem) {
enableAnimation = browser.supportsCssAnimation(); enableAnimation = browser.supportsCssAnimation();
@ -46,11 +46,11 @@ function onHideComplete() {
this.classList.add('hide'); this.classList.add('hide');
} }
var hideTimeout; let hideTimeout;
function showOsd() { function showOsd() {
clearHideTimeout(); clearHideTimeout();
var elem = osdElement; const elem = osdElement;
dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, { dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
once: true once: true
@ -78,7 +78,7 @@ function clearHideTimeout() {
function hideOsd() { function hideOsd() {
clearHideTimeout(); clearHideTimeout();
var elem = osdElement; const elem = osdElement;
if (elem) { if (elem) {
if (enableAnimation) { if (enableAnimation) {
// trigger reflow // trigger reflow
@ -108,7 +108,7 @@ function updatePlayerVolumeState(isMuted, volume) {
} }
function releaseCurrentPlayer() { function releaseCurrentPlayer() {
var player = currentPlayer; const player = currentPlayer;
if (player) { if (player) {
events.off(player, 'volumechange', onVolumeChanged); events.off(player, 'volumechange', onVolumeChanged);
@ -118,7 +118,7 @@ function releaseCurrentPlayer() {
} }
function onVolumeChanged(e) { function onVolumeChanged(e) {
var player = this; const player = this;
ensureOsdElement(); ensureOsdElement();

View file

@ -413,7 +413,7 @@ import 'css!./playerstats';
name: 'Original Media Info' name: 'Original Media Info'
}); });
var apiClient = window.connectionManager.getApiClient(playbackManager.currentItem(player).ServerId); const apiClient = window.connectionManager.getApiClient(playbackManager.currentItem(player).ServerId);
if (syncPlayManager.isSyncPlayEnabled() && apiClient.isMinServerVersion('10.6.0')) { if (syncPlayManager.isSyncPlayEnabled() && apiClient.isMinServerVersion('10.6.0')) {
categories.push({ categories.push({
stats: getSyncPlayStats(), stats: getSyncPlayStats(),

View file

@ -4,11 +4,11 @@ import playbackManager from 'playbackManager';
import globalize from 'globalize'; import globalize from 'globalize';
export function show(options) { export function show(options) {
var item = options.item; const item = options.item;
var resumePositionTicks = item.UserData ? item.UserData.PlaybackPositionTicks : null; const resumePositionTicks = item.UserData ? item.UserData.PlaybackPositionTicks : null;
var playableItemId = item.Type === 'Program' ? item.ChannelId : item.Id; const playableItemId = item.Type === 'Program' ? item.ChannelId : item.Id;
if (!resumePositionTicks || item.IsFolder) { if (!resumePositionTicks || item.IsFolder) {
playbackManager.play({ playbackManager.play({
@ -18,7 +18,7 @@ export function show(options) {
return; return;
} }
var menuItems = []; const menuItems = [];
menuItems.push({ menuItems.push({
name: globalize.translate('ResumeAt', datetime.getDisplayRunningTime(resumePositionTicks)), name: globalize.translate('ResumeAt', datetime.getDisplayRunningTime(resumePositionTicks)),

View file

@ -3,7 +3,7 @@ import globalize from 'globalize';
/* eslint-disable indent */ /* eslint-disable indent */
// TODO: replace with each plugin version // TODO: replace with each plugin version
var cacheParam = new Date().getTime(); const cacheParam = new Date().getTime();
class PluginManager { class PluginManager {
pluginsList = []; pluginsList = [];
@ -13,7 +13,7 @@ import globalize from 'globalize';
} }
#loadStrings(plugin) { #loadStrings(plugin) {
var strings = plugin.getTranslations ? plugin.getTranslations() : []; const strings = plugin.getTranslations ? plugin.getTranslations() : [];
return globalize.loadStrings({ return globalize.loadStrings({
name: plugin.id || plugin.packageName, name: plugin.id || plugin.packageName,
strings: strings strings: strings
@ -56,10 +56,10 @@ import globalize from 'globalize';
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
require([pluginSpec], (pluginFactory) => { require([pluginSpec], (pluginFactory) => {
var plugin = pluginFactory.default ? new pluginFactory.default() : new pluginFactory(); const plugin = pluginFactory.default ? new pluginFactory.default() : new pluginFactory();
// See if it's already installed // See if it's already installed
var existing = this.pluginsList.filter(function (p) { const existing = this.pluginsList.filter(function (p) {
return p.id === plugin.id; return p.id === plugin.id;
})[0]; })[0];
@ -69,10 +69,10 @@ import globalize from 'globalize';
plugin.installUrl = pluginSpec; plugin.installUrl = pluginSpec;
var separatorIndex = Math.max(pluginSpec.lastIndexOf('/'), pluginSpec.lastIndexOf('\\')); const separatorIndex = Math.max(pluginSpec.lastIndexOf('/'), pluginSpec.lastIndexOf('\\'));
plugin.baseUrl = pluginSpec.substring(0, separatorIndex); plugin.baseUrl = pluginSpec.substring(0, separatorIndex);
var paths = {}; const paths = {};
paths[plugin.id] = plugin.baseUrl; paths[plugin.id] = plugin.baseUrl;
requirejs.config({ requirejs.config({
@ -135,7 +135,7 @@ import globalize from 'globalize';
})[0]; })[0];
} }
var url = plugin.baseUrl + '/' + path; let url = plugin.baseUrl + '/' + path;
if (addCacheParam) { if (addCacheParam) {
url += url.includes('?') ? '&' : '?'; url += url.includes('?') ? '&' : '?';

View file

@ -1,9 +1,9 @@
import globalize from 'globalize'; import globalize from 'globalize';
export function getVideoQualityOptions(options) { export function getVideoQualityOptions(options) {
var maxStreamingBitrate = options.currentMaxBitrate; const maxStreamingBitrate = options.currentMaxBitrate;
var videoWidth = options.videoWidth; let videoWidth = options.videoWidth;
var videoHeight = options.videoHeight; const videoHeight = options.videoHeight;
// If the aspect ratio is less than 16/9 (1.77), set the width as if it were pillarboxed. // If the aspect ratio is less than 16/9 (1.77), set the width as if it were pillarboxed.
// 4:3 1440x1080 -> 1920x1080 // 4:3 1440x1080 -> 1920x1080
@ -11,9 +11,9 @@ export function getVideoQualityOptions(options) {
videoWidth = videoHeight * (16 / 9); videoWidth = videoHeight * (16 / 9);
} }
var maxAllowedWidth = videoWidth || 4096; const maxAllowedWidth = videoWidth || 4096;
var qualityOptions = []; const qualityOptions = [];
if (maxAllowedWidth >= 3800) { if (maxAllowedWidth >= 3800) {
qualityOptions.push({ name: '4K - 120 Mbps', maxHeight: 2160, bitrate: 120000000 }); qualityOptions.push({ name: '4K - 120 Mbps', maxHeight: 2160, bitrate: 120000000 });
@ -65,7 +65,7 @@ export function getVideoQualityOptions(options) {
qualityOptions.push({ name: '240p', maxHeight: 240, bitrate: 320000 }); qualityOptions.push({ name: '240p', maxHeight: 240, bitrate: 320000 });
qualityOptions.push({ name: '144p', maxHeight: 144, bitrate: 192000 }); qualityOptions.push({ name: '144p', maxHeight: 144, bitrate: 192000 });
var autoQualityOption = { const autoQualityOption = {
name: globalize.translate('Auto'), name: globalize.translate('Auto'),
bitrate: 0, bitrate: 0,
selected: options.isAutomaticBitrateEnabled selected: options.isAutomaticBitrateEnabled
@ -76,9 +76,9 @@ export function getVideoQualityOptions(options) {
} }
if (maxStreamingBitrate) { if (maxStreamingBitrate) {
var selectedIndex = -1; let selectedIndex = -1;
for (var i = 0, length = qualityOptions.length; i < length; i++) { for (let i = 0, length = qualityOptions.length; i < length; i++) {
var option = qualityOptions[i]; const option = qualityOptions[i];
if (selectedIndex === -1 && option.bitrate <= maxStreamingBitrate) { if (selectedIndex === -1 && option.bitrate <= maxStreamingBitrate) {
selectedIndex = i; selectedIndex = i;
@ -89,7 +89,7 @@ export function getVideoQualityOptions(options) {
selectedIndex = qualityOptions.length - 1; selectedIndex = qualityOptions.length - 1;
} }
var currentQualityOption = qualityOptions[selectedIndex]; const currentQualityOption = qualityOptions[selectedIndex];
if (!options.isAutomaticBitrateEnabled) { if (!options.isAutomaticBitrateEnabled) {
currentQualityOption.selected = true; currentQualityOption.selected = true;
@ -102,9 +102,9 @@ export function getVideoQualityOptions(options) {
} }
export function getAudioQualityOptions(options) { export function getAudioQualityOptions(options) {
var maxStreamingBitrate = options.currentMaxBitrate; const maxStreamingBitrate = options.currentMaxBitrate;
var qualityOptions = []; const qualityOptions = [];
qualityOptions.push({ name: '2 Mbps', bitrate: 2000000 }); qualityOptions.push({ name: '2 Mbps', bitrate: 2000000 });
qualityOptions.push({ name: '1.5 Mbps', bitrate: 1500000 }); qualityOptions.push({ name: '1.5 Mbps', bitrate: 1500000 });
@ -116,7 +116,7 @@ export function getAudioQualityOptions(options) {
qualityOptions.push({ name: '96 kbps', bitrate: 96000 }); qualityOptions.push({ name: '96 kbps', bitrate: 96000 });
qualityOptions.push({ name: '64 kbps', bitrate: 64000 }); qualityOptions.push({ name: '64 kbps', bitrate: 64000 });
var autoQualityOption = { const autoQualityOption = {
name: globalize.translate('Auto'), name: globalize.translate('Auto'),
bitrate: 0, bitrate: 0,
selected: options.isAutomaticBitrateEnabled selected: options.isAutomaticBitrateEnabled
@ -127,9 +127,9 @@ export function getAudioQualityOptions(options) {
} }
if (maxStreamingBitrate) { if (maxStreamingBitrate) {
var selectedIndex = -1; let selectedIndex = -1;
for (var i = 0, length = qualityOptions.length; i < length; i++) { for (let i = 0, length = qualityOptions.length; i < length; i++) {
var option = qualityOptions[i]; const option = qualityOptions[i];
if (selectedIndex === -1 && option.bitrate <= maxStreamingBitrate) { if (selectedIndex === -1 && option.bitrate <= maxStreamingBitrate) {
selectedIndex = i; selectedIndex = i;
@ -140,7 +140,7 @@ export function getAudioQualityOptions(options) {
selectedIndex = qualityOptions.length - 1; selectedIndex = qualityOptions.length - 1;
} }
var currentQualityOption = qualityOptions[selectedIndex]; const currentQualityOption = qualityOptions[selectedIndex];
if (!options.isAutomaticBitrateEnabled) { if (!options.isAutomaticBitrateEnabled) {
currentQualityOption.selected = true; currentQualityOption.selected = true;

View file

@ -1,7 +1,7 @@
define(function () { define(function () {
'use strict'; 'use strict';
var requireCss = {}; const requireCss = {};
requireCss.normalize = function (name, normalize) { requireCss.normalize = function (name, normalize) {
if (name.substr(name.length - 4, 4) === '.css') { if (name.substr(name.length - 4, 4) === '.css') {
@ -11,7 +11,7 @@ define(function () {
return normalize(name); return normalize(name);
}; };
var importedCss = []; let importedCss = [];
function isLoaded(url) { function isLoaded(url) {
return importedCss.indexOf(url) !== -1; return importedCss.indexOf(url) !== -1;
@ -27,14 +27,14 @@ define(function () {
requireCss.load = function (cssId, req, load, config) { requireCss.load = function (cssId, req, load, config) {
// Somehow if the url starts with /css, require will get all screwed up since this extension is also called css // Somehow if the url starts with /css, require will get all screwed up since this extension is also called css
var srch = 'components/require/requirecss'; const srch = 'components/require/requirecss';
var index = cssId.indexOf(srch); const index = cssId.indexOf(srch);
if (index !== -1) { if (index !== -1) {
cssId = 'css' + cssId.substring(index + srch.length); cssId = 'css' + cssId.substring(index + srch.length);
} }
var url = cssId + '.css'; let url = cssId + '.css';
if (url.indexOf('://') === -1) { if (url.indexOf('://') === -1) {
url = config.baseUrl + url; url = config.baseUrl + url;
@ -43,13 +43,13 @@ define(function () {
if (!isLoaded(url)) { if (!isLoaded(url)) {
importedCss.push(url); importedCss.push(url);
var link = document.createElement('link'); const link = document.createElement('link');
link.setAttribute('rel', 'stylesheet'); link.setAttribute('rel', 'stylesheet');
link.setAttribute('type', 'text/css'); link.setAttribute('type', 'text/css');
link.onload = load; link.onload = load;
var linkUrl = url; let linkUrl = url;
if (config.urlArgs) { if (config.urlArgs) {
linkUrl += config.urlArgs(cssId, url); linkUrl += config.urlArgs(cssId, url);

View file

@ -2,7 +2,7 @@ define(function () {
'use strict'; 'use strict';
// hack to work around the server's auto-redirection feature // hack to work around the server's auto-redirection feature
var addRedirectPrevention = window.dashboardVersion != null && window.Dashboard && !window.AppInfo.isNativeApp; const addRedirectPrevention = window.dashboardVersion != null && window.Dashboard && !window.AppInfo.isNativeApp;
return { return {
@ -25,7 +25,7 @@ define(function () {
url += 'r=0'; url += 'r=0';
} }
var xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
xhr.open('GET', url, true); xhr.open('GET', url, true);
xhr.onload = function (e) { xhr.onload = function (e) {

View file

@ -2,7 +2,7 @@
(function () { (function () {
'use strict'; 'use strict';
var connectionManager; let connectionManager;
function getApiClient(serverId) { function getApiClient(serverId) {
if (connectionManager) { if (connectionManager) {
@ -15,8 +15,7 @@
return getApiClient(serverId).then(function (apiClient) { return getApiClient(serverId).then(function (apiClient) {
switch (action) { switch (action) {
case 'cancel-install': case 'cancel-install':
var id = data.id; return apiClient.cancelPackageInstallation(data.id);
return apiClient.cancelPackageInstallation(id);
case 'restart': case 'restart':
return apiClient.restartServer(); return apiClient.restartServer();
default: default:
@ -28,12 +27,12 @@
/* eslint-disable-next-line no-restricted-globals -- self is valid in a serviceworker environment */ /* eslint-disable-next-line no-restricted-globals -- self is valid in a serviceworker environment */
self.addEventListener('notificationclick', function (event) { self.addEventListener('notificationclick', function (event) {
var notification = event.notification; const notification = event.notification;
notification.close(); notification.close();
var data = notification.data; const data = notification.data;
var serverId = data.serverId; const serverId = data.serverId;
var action = event.action; const action = event.action;
if (!action) { if (!action) {
clients.openWindow('/'); clients.openWindow('/');

View file

@ -12,7 +12,7 @@ import playbackPermissionManager from 'playbackPermissionManager';
* @returns {string} The player's id. * @returns {string} The player's id.
*/ */
function getActivePlayerId () { function getActivePlayerId () {
var info = playbackManager.getPlayerInfo(); const info = playbackManager.getPlayerInfo();
return info ? info.id : null; return info ? info.id : null;
} }
@ -38,7 +38,7 @@ function showNewJoinGroupSelection (button, user, apiClient) {
apiClient.getSyncPlayGroups().then(function (response) { apiClient.getSyncPlayGroups().then(function (response) {
response.json().then(function (groups) { response.json().then(function (groups) {
var menuItems = groups.map(function (group) { const menuItems = groups.map(function (group) {
return { return {
name: group.PlayingItemName, name: group.PlayingItemName,
icon: 'group', icon: 'group',
@ -72,7 +72,7 @@ function showNewJoinGroupSelection (button, user, apiClient) {
return; return;
} }
var menuOptions = { const menuOptions = {
title: globalize.translate('HeaderSyncPlaySelectGroup'), title: globalize.translate('HeaderSyncPlaySelectGroup'),
items: menuItems, items: menuItems,
positionTo: button, positionTo: button,
@ -129,7 +129,7 @@ function showLeaveGroupSelection (button, user, apiClient) {
secondaryText: globalize.translate('LabelSyncPlayLeaveGroupDescription') secondaryText: globalize.translate('LabelSyncPlayLeaveGroupDescription')
}]; }];
var menuOptions = { const menuOptions = {
title: globalize.translate('HeaderSyncPlayEnabled'), title: globalize.translate('HeaderSyncPlayEnabled'),
items: menuItems, items: menuItems,
positionTo: button, positionTo: button,

View file

@ -40,7 +40,7 @@ function waitForEventOnce(emitter, eventType, timeout) {
* @returns {string} The player's id. * @returns {string} The player's id.
*/ */
function getActivePlayerId() { function getActivePlayerId() {
var info = playbackManager.getPlayerInfo(); const info = playbackManager.getPlayerInfo();
return info ? info.id : null; return info ? info.id : null;
} }
@ -276,7 +276,7 @@ class SyncPlayManager {
* Removes the bindings to the current player's events. * Removes the bindings to the current player's events.
*/ */
releaseCurrentPlayer () { releaseCurrentPlayer () {
var player = this.currentPlayer; const player = this.currentPlayer;
if (player) { if (player) {
events.off(player, 'unpause', this._onPlayerUnpause); events.off(player, 'unpause', this._onPlayerUnpause);
events.off(player, 'pause', this._onPlayerPause); events.off(player, 'pause', this._onPlayerPause);
@ -426,7 +426,7 @@ class SyncPlayManager {
serverId: serverId serverId: serverId
}).then(() => { }).then(() => {
waitForEventOnce(this, 'playbackstart', WaitForEventDefaultTimeout).then(() => { waitForEventOnce(this, 'playbackstart', WaitForEventDefaultTimeout).then(() => {
var sessionId = getActivePlayerId(); const sessionId = getActivePlayerId();
if (!sessionId) { if (!sessionId) {
console.error('Missing sessionId!'); console.error('Missing sessionId!');
toast({ toast({
@ -659,7 +659,7 @@ class SyncPlayManager {
* Overrides PlaybackManager's unpause method. * Overrides PlaybackManager's unpause method.
*/ */
playRequest (player) { playRequest (player) {
var apiClient = window.connectionManager.currentApiClient(); const apiClient = window.connectionManager.currentApiClient();
apiClient.requestSyncPlayStart(); apiClient.requestSyncPlayStart();
} }
@ -667,7 +667,7 @@ class SyncPlayManager {
* Overrides PlaybackManager's pause method. * Overrides PlaybackManager's pause method.
*/ */
pauseRequest (player) { pauseRequest (player) {
var apiClient = window.connectionManager.currentApiClient(); const apiClient = window.connectionManager.currentApiClient();
apiClient.requestSyncPlayPause(); apiClient.requestSyncPlayPause();
// Pause locally as well, to give the user some little control // Pause locally as well, to give the user some little control
playbackManager._localUnpause(player); playbackManager._localUnpause(player);
@ -677,7 +677,7 @@ class SyncPlayManager {
* Overrides PlaybackManager's seek method. * Overrides PlaybackManager's seek method.
*/ */
seekRequest (PositionTicks, player) { seekRequest (PositionTicks, player) {
var apiClient = window.connectionManager.currentApiClient(); const apiClient = window.connectionManager.currentApiClient();
apiClient.requestSyncPlaySeek({ apiClient.requestSyncPlaySeek({
PositionTicks: PositionTicks PositionTicks: PositionTicks
}); });

View file

@ -4,7 +4,7 @@ import layoutManager from 'layoutManager';
import 'emby-tabs'; import 'emby-tabs';
function onViewDestroy(e) { function onViewDestroy(e) {
var tabControllers = this.tabControllers; const tabControllers = this.tabControllers;
if (tabControllers) { if (tabControllers) {
tabControllers.forEach(function (t) { tabControllers.forEach(function (t) {
@ -32,9 +32,9 @@ class TabbedView {
this.view = view; this.view = view;
this.params = params; this.params = params;
var self = this; const self = this;
var currentTabIndex = parseInt(params.tab || this.getDefaultTabIndex(params.parentId)); let currentTabIndex = parseInt(params.tab || this.getDefaultTabIndex(params.parentId));
this.initialTabIndex = currentTabIndex; this.initialTabIndex = currentTabIndex;
function validateTabLoad(index) { function validateTabLoad(index) {
@ -44,7 +44,7 @@ class TabbedView {
function loadTab(index, previousIndex) { function loadTab(index, previousIndex) {
validateTabLoad(index).then(function () { validateTabLoad(index).then(function () {
self.getTabController(index).then(function (controller) { self.getTabController(index).then(function (controller) {
var refresh = !controller.refreshed; const refresh = !controller.refreshed;
controller.onResume({ controller.onResume({
autoFocus: previousIndex == null && layoutManager.tv, autoFocus: previousIndex == null && layoutManager.tv,
@ -64,10 +64,10 @@ class TabbedView {
} }
function onTabChange(e) { function onTabChange(e) {
var newIndex = parseInt(e.detail.selectedTabIndex); const newIndex = parseInt(e.detail.selectedTabIndex);
var previousIndex = e.detail.previousIndex; const previousIndex = e.detail.previousIndex;
var previousTabController = previousIndex == null ? null : self.tabControllers[previousIndex]; const previousTabController = previousIndex == null ? null : self.tabControllers[previousIndex];
if (previousTabController && previousTabController.onPause) { if (previousTabController && previousTabController.onPause) {
previousTabController.onPause(); previousTabController.onPause();
} }
@ -92,7 +92,7 @@ class TabbedView {
this.setTitle(); this.setTitle();
backdrop.clearBackdrop(); backdrop.clearBackdrop();
var currentTabController = this.currentTabController; const currentTabController = this.currentTabController;
if (!currentTabController) { if (!currentTabController) {
mainTabsManager.selectedTabIndex(this.initialTabIndex); mainTabsManager.selectedTabIndex(this.initialTabIndex);
@ -102,7 +102,7 @@ class TabbedView {
} }
onPause() { onPause() {
var currentTabController = this.currentTabController; const currentTabController = this.currentTabController;
if (currentTabController && currentTabController.onPause) { if (currentTabController && currentTabController.onPause) {
currentTabController.onPause(); currentTabController.onPause();

View file

@ -1,9 +1,10 @@
.upNextDialog { .upNextContainer {
position: fixed; position: fixed;
left: 0;
bottom: 0;
right: 0; right: 0;
padding: 1%; bottom: 0;
width: 30em;
padding: 1em;
margin: 0 2em 2em 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
will-change: transform, opacity; will-change: transform, opacity;
@ -22,13 +23,18 @@
font-weight: 500; font-weight: 500;
} }
.upNextDialog-poster { .upNextDialog-nextVideoText,
max-width: 40%; .upNextDialog-title {
max-height: 15%; width: 25.5em;
position: relative; white-space: nowrap;
margin-right: 1em; overflow: hidden;
flex-shrink: 0; text-overflow: ellipsis;
margin-bottom: 0.5em; }
.upNextDialog-buttons {
width: 29.75em;
justify-content: end;
align-content: flex-end;
} }
.upNextDialog-button { .upNextDialog-button {
@ -40,34 +46,4 @@
.upNextDialog { .upNextDialog {
flex-direction: row; flex-direction: row;
} }
.upNextDialog-poster {
max-width: initial;
max-height: initial;
width: 10%;
margin-bottom: 0;
}
}
@media all and (max-width: 50em) {
.upNextDialog-overview {
display: none !important;
}
}
.upNextDialog-poster-img {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: auto;
width: 100%;
box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37);
user-drag: none;
border: 0;
user-select: none;
-moz-user-select: none;
-webkit-user-drag: none;
-webkit-user-select: none;
-ms-user-select: none;
} }

View file

@ -14,84 +14,9 @@ import 'flexStyles';
const transitionEndEventName = dom.whichTransitionEvent(); const transitionEndEventName = dom.whichTransitionEvent();
function seriesImageUrl(item, options) {
if (item.Type !== 'Episode') {
return null;
}
options = options || {};
options.type = options.type || 'Primary';
if (options.type === 'Primary') {
if (item.SeriesPrimaryImageTag) {
options.tag = item.SeriesPrimaryImageTag;
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
}
}
if (options.type === 'Thumb') {
if (item.SeriesThumbImageTag) {
options.tag = item.SeriesThumbImageTag;
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
}
if (item.ParentThumbImageTag) {
options.tag = item.ParentThumbImageTag;
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
}
}
return null;
}
function imageUrl(item, options) {
options = options || {};
options.type = options.type || 'Primary';
if (item.ImageTags && item.ImageTags[options.type]) {
options.tag = item.ImageTags[options.type];
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options);
}
if (options.type === 'Primary') {
if (item.AlbumId && item.AlbumPrimaryImageTag) {
options.tag = item.AlbumPrimaryImageTag;
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
}
}
return null;
}
function setPoster(osdPoster, item, secondaryItem) {
if (item) {
let imgUrl = seriesImageUrl(item, { type: 'Primary' }) ||
seriesImageUrl(item, { type: 'Thumb' }) ||
imageUrl(item, { type: 'Primary' });
if (!imgUrl && secondaryItem) {
imgUrl = seriesImageUrl(secondaryItem, { type: 'Primary' }) ||
seriesImageUrl(secondaryItem, { type: 'Thumb' }) ||
imageUrl(secondaryItem, { type: 'Primary' });
}
if (imgUrl) {
osdPoster.innerHTML = '<img class="upNextDialog-poster-img" src="' + imgUrl + '" />';
return;
}
}
osdPoster.innerHTML = '';
}
function getHtml() { function getHtml() {
let html = ''; let html = '';
html += '<div class="upNextDialog-poster">';
html += '</div>';
html += '<div class="flex flex-direction-column flex-grow">'; html += '<div class="flex flex-direction-column flex-grow">';
html += '<h2 class="upNextDialog-nextVideoText" style="margin:.25em 0;">&nbsp;</h2>'; html += '<h2 class="upNextDialog-nextVideoText" style="margin:.25em 0;">&nbsp;</h2>';
@ -101,8 +26,6 @@ import 'flexStyles';
html += '<div class="flex flex-direction-row upNextDialog-mediainfo">'; html += '<div class="flex flex-direction-row upNextDialog-mediainfo">';
html += '</div>'; html += '</div>';
html += '<div class="upNextDialog-overview" style="margin-top:1em;"></div>';
html += '<div class="flex flex-direction-row upNextDialog-buttons" style="margin-top:1em;">'; html += '<div class="flex flex-direction-row upNextDialog-buttons" style="margin-top:1em;">';
html += '<button type="button" is="emby-button" class="raised raised-mini btnStartNow upNextDialog-button">'; html += '<button type="button" is="emby-button" class="raised raised-mini btnStartNow upNextDialog-button">';
@ -145,11 +68,11 @@ import 'flexStyles';
const elem = instance.options.parent; const elem = instance.options.parent;
setPoster(elem.querySelector('.upNextDialog-poster'), item);
elem.querySelector('.upNextDialog-overview').innerHTML = item.Overview || '';
elem.querySelector('.upNextDialog-mediainfo').innerHTML = mediaInfo.getPrimaryMediaInfoHtml(item, { elem.querySelector('.upNextDialog-mediainfo').innerHTML = mediaInfo.getPrimaryMediaInfoHtml(item, {
criticRating: false,
originalAirDate: false,
starRating: false,
subtitles: false
}); });
let title = itemHelper.getDisplayName(item); let title = itemHelper.getDisplayName(item);

View file

@ -37,53 +37,56 @@ import 'css!components/viewManager/viewContainer';
const newViewInfo = normalizeNewView(options, isPluginpage); const newViewInfo = normalizeNewView(options, isPluginpage);
const newView = newViewInfo.elem; const newView = newViewInfo.elem;
return new Promise((resolve) => { const currentPage = allPages[pageIndex];
const currentPage = allPages[pageIndex];
if (currentPage) { if (currentPage) {
triggerDestroy(currentPage); triggerDestroy(currentPage);
} }
let view = newView; let view = newView;
if (typeof view == 'string') { if (typeof view == 'string') {
view = document.createElement('div'); view = document.createElement('div');
view.innerHTML = newView; view.innerHTML = newView;
} }
view.classList.add('mainAnimatedPage'); view.classList.add('mainAnimatedPage');
if (currentPage) { if (currentPage) {
if (newViewInfo.hasScript && window.$) { if (newViewInfo.hasScript && window.$) {
mainAnimatedPages.removeChild(currentPage); mainAnimatedPages.removeChild(currentPage);
view = $(view).appendTo(mainAnimatedPages)[0]; view = $(view).appendTo(mainAnimatedPages)[0];
} else {
mainAnimatedPages.replaceChild(view, currentPage);
}
} else { } else {
if (newViewInfo.hasScript && window.$) { mainAnimatedPages.replaceChild(view, currentPage);
view = $(view).appendTo(mainAnimatedPages)[0];
} else {
mainAnimatedPages.appendChild(view);
}
} }
} else {
if (options.type) { if (newViewInfo.hasScript && window.$) {
view.setAttribute('data-type', options.type); view = $(view).appendTo(mainAnimatedPages)[0];
} else {
mainAnimatedPages.appendChild(view);
} }
}
const properties = []; if (options.type) {
view.setAttribute('data-type', options.type);
}
if (options.fullscreen) { const properties = [];
properties.push('fullscreen');
}
if (properties.length) { if (options.fullscreen) {
view.setAttribute('data-properties', properties.join(',')); properties.push('fullscreen');
} }
allPages[pageIndex] = view; if (properties.length) {
setControllerClass(view, options).then(() => { view.setAttribute('data-properties', properties.join(','));
}
allPages[pageIndex] = view;
return setControllerClass(view, options)
// Timeout for polyfilled CustomElements (webOS 1.2)
.then(() => new Promise((resolve) => setTimeout(resolve, 0)))
.then(() => {
if (onBeforeChange) { if (onBeforeChange) {
onBeforeChange(view, false, options); onBeforeChange(view, false, options);
} }
@ -101,9 +104,8 @@ import 'css!components/viewManager/viewContainer';
$.mobile.activePage = view; $.mobile.activePage = view;
} }
resolve(view); return view;
}); });
});
} }
} }

View file

@ -1 +0,0 @@
config.template.json

46
src/config.json Normal file
View file

@ -0,0 +1,46 @@
{
"multiserver": false,
"themes": [
{
"name": "Apple TV",
"id": "appletv"
}, {
"name": "Blue Radiance",
"id": "blueradiance"
}, {
"name": "Dark",
"id": "dark",
"default": true
}, {
"name": "Light",
"id": "light"
}, {
"name": "Purple Haze",
"id": "purplehaze"
}, {
"name": "WMC",
"id": "wmc"
}
],
"fonts": [
"https://repo.jellyfin.org/releases/other/jellyfin-noto/font-faces.css",
"https://repo.jellyfin.org/releases/other/jellyfin-noto/css/KR.css",
"https://repo.jellyfin.org/releases/other/jellyfin-noto/css/JP.css",
"https://repo.jellyfin.org/releases/other/jellyfin-noto/css/SC.css"
],
"plugins": [
"plugins/playAccessValidation/plugin",
"plugins/experimentalWarnings/plugin",
"plugins/htmlAudioPlayer/plugin",
"plugins/htmlVideoPlayer/plugin",
"plugins/photoPlayer/plugin",
"plugins/comicsPlayer/plugin",
"plugins/bookPlayer/plugin",
"plugins/youtubePlayer/plugin",
"plugins/backdropScreensaver/plugin",
"plugins/pdfPlayer/plugin",
"plugins/logoScreensaver/plugin",
"plugins/sessionPlayer/plugin",
"plugins/chromecastPlayer/plugin"
]
}

View file

@ -1,39 +0,0 @@
{
"multiserver": false,
"themes": [
{
"name": "Apple TV",
"id": "appletv"
}, {
"name": "Blue Radiance",
"id": "blueradiance"
}, {
"name": "Dark",
"id": "dark",
"default": true
}, {
"name": "Light",
"id": "light"
}, {
"name": "Purple Haze",
"id": "purplehaze"
}, {
"name": "WMC",
"id": "wmc"
}
],
"plugins": [
"plugins/playAccessValidation/plugin",
"plugins/experimentalWarnings/plugin",
"plugins/htmlAudioPlayer/plugin",
"plugins/htmlVideoPlayer/plugin",
"plugins/photoPlayer/plugin",
"plugins/comicsPlayer/plugin",
"plugins/bookPlayer/plugin",
"plugins/youtubePlayer/plugin",
"plugins/backdropScreensaver/plugin",
"plugins/logoScreensaver/plugin",
"plugins/sessionPlayer/plugin",
"plugins/chromecastPlayer/plugin"
]
}

View file

@ -16,6 +16,9 @@
</div> </div>
<div style="margin-top:1em;"> <div style="margin-top:1em;">
<button is="emby-button" type="button" class="raised btnRefresh">
<span>${ButtonScanAllLibraries}</span>
</button>
<button is="emby-button" type="button" id="btnRestartServer" class="raised" onclick="DashboardPage.restart(this);" style="margin-left:0;"> <button is="emby-button" type="button" id="btnRestartServer" class="raised" onclick="DashboardPage.restart(this);" style="margin-left:0;">
<span>${Restart}</span> <span>${Restart}</span>
</button> </button>

View file

@ -3,6 +3,7 @@ import events from 'events';
import itemHelper from 'itemHelper'; import itemHelper from 'itemHelper';
import serverNotifications from 'serverNotifications'; import serverNotifications from 'serverNotifications';
import dom from 'dom'; import dom from 'dom';
import taskButton from 'scripts/taskbutton';
import globalize from 'globalize'; import globalize from 'globalize';
import * as datefns from 'date-fns'; import * as datefns from 'date-fns';
import dfnshelper from 'dfnshelper'; import dfnshelper from 'dfnshelper';
@ -550,13 +551,13 @@ import 'emby-itemscontainer';
row.classList.remove('playingSession'); row.classList.remove('playingSession');
} }
if (session.ServerId && session.SupportedCommands.indexOf('DisplayMessage') !== -1 && session.DeviceId !== window.connectionManager.deviceId()) { if (session.ServerId && session.SupportedCommands.indexOf('DisplayMessage') !== -1) {
row.querySelector('.btnSessionSendMessage').classList.remove('hide'); row.querySelector('.btnSessionSendMessage').classList.remove('hide');
} else { } else {
row.querySelector('.btnSessionSendMessage').classList.add('hide'); row.querySelector('.btnSessionSendMessage').classList.add('hide');
} }
if (session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons.length) { if (session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo) {
row.querySelector('.btnSessionInfo').classList.remove('hide'); row.querySelector('.btnSessionInfo').classList.remove('hide');
} else { } else {
row.querySelector('.btnSessionInfo').classList.add('hide'); row.querySelector('.btnSessionInfo').classList.add('hide');
@ -564,7 +565,7 @@ import 'emby-itemscontainer';
const btnSessionPlayPause = row.querySelector('.btnSessionPlayPause'); const btnSessionPlayPause = row.querySelector('.btnSessionPlayPause');
if (session.ServerId && nowPlayingItem && session.SupportsRemoteControl && session.DeviceId !== window.connectionManager.deviceId()) { if (session.ServerId && nowPlayingItem && session.SupportsRemoteControl) {
btnSessionPlayPause.classList.remove('hide'); btnSessionPlayPause.classList.remove('hide');
row.querySelector('.btnSessionStop').classList.remove('hide'); row.querySelector('.btnSessionStop').classList.remove('hide');
} else { } else {
@ -827,9 +828,17 @@ import 'emby-itemscontainer';
refreshActiveRecordings(view, apiClient); refreshActiveRecordings(view, apiClient);
loading.hide(); loading.hide();
} }
taskButton({
mode: 'on',
taskKey: 'RefreshLibrary',
button: page.querySelector('.btnRefresh')
});
}); });
view.addEventListener('viewbeforehide', function () { view.addEventListener('viewbeforehide', function () {
const apiClient = ApiClient; const apiClient = ApiClient;
const page = this;
events.off(serverNotifications, 'RestartRequired', onRestartRequired); events.off(serverNotifications, 'RestartRequired', onRestartRequired);
events.off(serverNotifications, 'ServerShuttingDown', onServerShuttingDown); events.off(serverNotifications, 'ServerShuttingDown', onServerShuttingDown);
events.off(serverNotifications, 'ServerRestarting', onServerRestarting); events.off(serverNotifications, 'ServerRestarting', onServerRestarting);
@ -841,6 +850,12 @@ import 'emby-itemscontainer';
if (apiClient) { if (apiClient) {
DashboardPage.stopInterval(apiClient); DashboardPage.stopInterval(apiClient);
} }
taskButton({
mode: 'off',
taskKey: 'RefreshLibrary',
button: page.querySelector('.btnRefresh')
});
}); });
view.addEventListener('viewdestroy', function () { view.addEventListener('viewdestroy', function () {
const page = this; const page = this;

View file

@ -5,6 +5,7 @@
<div class="sectionTitleContainer sectionTitleContainer-cards flex align-items-center"> <div class="sectionTitleContainer sectionTitleContainer-cards flex align-items-center">
<h2 class="sectionTitle sectionTitle-cards">${HeaderDevices}</h2> <h2 class="sectionTitle sectionTitle-cards">${HeaderDevices}</h2>
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://docs.jellyfin.org/general/server/devices.html">${Help}</a> <a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://docs.jellyfin.org/general/server/devices.html">${Help}</a>
<button id="deviceDeleteAll" is="emby-button" type="button" class="raised button-alt">${DeleteAll}</button>
</div> </div>
</div> </div>
<div is="emby-itemscontainer" class="devicesList vertical-wrap" data-multiselect="false"></div> <div is="emby-itemscontainer" class="devicesList vertical-wrap" data-multiselect="false"></div>

View file

@ -10,10 +10,32 @@ import 'cardStyle';
/* eslint-disable indent */ /* eslint-disable indent */
// Local cache of loaded
let deviceIds = [];
function canDelete(deviceId) { function canDelete(deviceId) {
return deviceId !== ApiClient.deviceId(); return deviceId !== ApiClient.deviceId();
} }
function deleteAllDevices(page) {
const msg = globalize.translate('DeleteDevicesConfirmation');
require(['confirm'], async function (confirm) {
await confirm({
text: msg,
title: globalize.translate('HeaderDeleteDevices'),
confirmText: globalize.translate('ButtonDelete'),
primary: 'delete'
});
loading.show();
await Promise.all(
deviceIds.filter(canDelete).map((id) => ApiClient.deleteDevice(id))
);
loadData(page);
});
}
function deleteDevice(page, id) { function deleteDevice(page, id) {
const msg = globalize.translate('DeleteDeviceConfirmation'); const msg = globalize.translate('DeleteDeviceConfirmation');
@ -23,16 +45,10 @@ import 'cardStyle';
title: globalize.translate('HeaderDeleteDevice'), title: globalize.translate('HeaderDeleteDevice'),
confirmText: globalize.translate('Delete'), confirmText: globalize.translate('Delete'),
primary: 'delete' primary: 'delete'
}).then(function () { }).then(async () => {
loading.show(); loading.show();
ApiClient.ajax({ await ApiClient.deleteDevice(id);
type: 'DELETE', loadData(page);
url: ApiClient.getUrl('Devices', {
Id: id
})
}).then(function () {
loadData(page);
});
}); });
}); });
} }
@ -129,6 +145,7 @@ import 'cardStyle';
loading.show(); loading.show();
ApiClient.getJSON(ApiClient.getUrl('Devices')).then(function (result) { ApiClient.getJSON(ApiClient.getUrl('Devices')).then(function (result) {
load(page, result.Items); load(page, result.Items);
deviceIds = result.Items.map((device) => device.Id);
loading.hide(); loading.hide();
}); });
} }
@ -145,6 +162,9 @@ import 'cardStyle';
view.addEventListener('viewshow', function () { view.addEventListener('viewshow', function () {
loadData(this); loadData(this);
}); });
}
view.querySelector('#deviceDeleteAll').addEventListener('click', function() {
deleteAllDevices(view);
});
}
/* eslint-enable indent */ /* eslint-enable indent */

View file

@ -9,21 +9,21 @@ import 'flexStyles';
export default function(view, params) { export default function(view, params) {
view.addEventListener('viewbeforeshow', function() { view.addEventListener('viewbeforeshow', function() {
loading.show(); loading.show();
var apiClient = ApiClient; const apiClient = ApiClient;
apiClient.getJSON(apiClient.getUrl('System/Logs')).then(function(logs) { apiClient.getJSON(apiClient.getUrl('System/Logs')).then(function(logs) {
var html = ''; let html = '';
html += '<div class="paperList">'; html += '<div class="paperList">';
html += logs.map(function(log) { html += logs.map(function(log) {
var logUrl = apiClient.getUrl('System/Logs/Log', { let logUrl = apiClient.getUrl('System/Logs/Log', {
name: log.Name name: log.Name
}); });
logUrl += '&api_key=' + apiClient.accessToken(); logUrl += '&api_key=' + apiClient.accessToken();
var logHtml = ''; let logHtml = '';
logHtml += '<a is="emby-linkbutton" href="' + logUrl + '" target="_blank" class="listItem listItem-border" style="color:inherit;">'; logHtml += '<a is="emby-linkbutton" href="' + logUrl + '" target="_blank" class="listItem listItem-border" style="color:inherit;">';
logHtml += '<div class="listItemBody two-line">'; logHtml += '<div class="listItemBody two-line">';
logHtml += "<h3 class='listItemBodyText'>" + log.Name + '</h3>'; logHtml += "<h3 class='listItemBodyText'>" + log.Name + '</h3>';
var date = datetime.parseISO8601Date(log.DateModified, true); const date = datetime.parseISO8601Date(log.DateModified, true);
var text = datetime.toLocaleDateString(date); let text = datetime.toLocaleDateString(date);
text += ' ' + datetime.getDisplayTime(date); text += ' ' + datetime.getDisplayTime(date);
logHtml += '<div class="listItemBodyText secondary">' + text + '</div>'; logHtml += '<div class="listItemBodyText secondary">' + text + '</div>';
logHtml += '</div>'; logHtml += '</div>';

View file

@ -42,10 +42,10 @@ function saveList(page) {
} }
function populateList(options) { function populateList(options) {
var html = ''; let html = '';
html += '<div class="paperList">'; html += '<div class="paperList">';
for (var i = 0; i < options.repositories.length; i++) { for (let i = 0; i < options.repositories.length; i++) {
html += getRepositoryHtml(options.repositories[i]); html += getRepositoryHtml(options.repositories[i]);
} }
@ -59,7 +59,7 @@ function populateList(options) {
} }
function getRepositoryHtml(repository) { function getRepositoryHtml(repository) {
var html = ''; let html = '';
html += '<div class="listItem listItem-border">'; html += '<div class="listItem listItem-border">';
html += `<a is="emby-linkbutton" style="margin:0;padding:0" class="clearLink listItemIconContainer" href="${repository.Url}">`; html += `<a is="emby-linkbutton" style="margin:0;padding:0" class="clearLink listItemIconContainer" href="${repository.Url}">`;
@ -93,9 +93,9 @@ export default function(view, params) {
libraryMenu.setTabs('plugins', 2, getTabs); libraryMenu.setTabs('plugins', 2, getTabs);
reloadList(this); reloadList(this);
var save = this; const save = this;
$('#repositories', view).on('click', '.btnDelete', function() { $('#repositories', view).on('click', '.btnDelete', function() {
var button = this; const button = this;
repositories = repositories.filter(function (r) { repositories = repositories.filter(function (r) {
return r.Url !== button.id; return r.Url !== button.id;
}); });

View file

@ -140,32 +140,13 @@
</div> </div>
<div class="fieldDescription">${OptionAllowRemoteSharedDevicesHelp}</div> <div class="fieldDescription">${OptionAllowRemoteSharedDevicesHelp}</div>
</div> </div>
<div class="verticalSection"> <h2 class="checkboxListLabel">${Other}</h2>
<h2 class="checkboxListLabel">${HeaderDownloadSync}</h2>
<div class="checkboxList paperList" style="padding:.5em 1em;">
<label>
<input type="checkbox" is="emby-checkbox" id="chkEnableDownloading" />
<span>${OptionAllowContentDownloading}</span>
</label>
<label>
<input type="checkbox" is="emby-checkbox" id="chkEnableSyncTranscoding" />
<span>${OptionAllowSyncTranscoding}</span>
</label>
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription"> <div class="checkboxContainer checkboxContainer-withDescription">
<label> <label>
<input type="checkbox" is="emby-checkbox" id="chkEnableConversion" /> <input type="checkbox" is="emby-checkbox" id="chkEnableDownloading" />
<span>${AllowMediaConversion}</span> <span>${OptionAllowContentDownload}</span>
</label> </label>
<div class="fieldDescription checkboxFieldDescription">${AllowMediaConversionHelp}</div> <div class="fieldDescription checkboxFieldDescription">${OptionAllowContentDownloadHelp}</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input type="checkbox" is="emby-checkbox" id="chkEnableSharing" />
<span>${OptionAllowLinkSharing}</span>
</label>
<div class="fieldDescription checkboxFieldDescription sharingHelp"></div>
</div> </div>
<div class="checkboxContainer checkboxContainer-withDescription" id="fldIsEnabled"> <div class="checkboxContainer checkboxContainer-withDescription" id="fldIsEnabled">
<label> <label>
@ -190,6 +171,14 @@
</div> </div>
</div> </div>
<br /> <br />
<div class=verticalSection>
<div class="inputContainer" id="fldMaxActiveSessions">
<input is="emby-input" type="number" id="txtMaxActiveSessions" min="0" step="1" label="${LabelUserMaxActiveSessions}"/>
<div class="fieldDescription">${OptionMaxActiveSessions}</div>
<div class="fieldDescription">${OptionMaxActiveSessionsHelp}</div>
</div>
</div>
<br />
<div> <div>
<button is="emby-button" type="submit" class="raised button-submit block"> <button is="emby-button" type="submit" class="raised button-submit block">
<span>${Save}</span> <span>${Save}</span>

View file

@ -97,11 +97,9 @@ import globalize from 'globalize';
$('#chkEnableVideoPlaybackRemuxing', page).prop('checked', user.Policy.EnablePlaybackRemuxing); $('#chkEnableVideoPlaybackRemuxing', page).prop('checked', user.Policy.EnablePlaybackRemuxing);
$('#chkForceRemoteSourceTranscoding', page).prop('checked', user.Policy.ForceRemoteSourceTranscoding); $('#chkForceRemoteSourceTranscoding', page).prop('checked', user.Policy.ForceRemoteSourceTranscoding);
$('#chkRemoteAccess', page).prop('checked', user.Policy.EnableRemoteAccess == null || user.Policy.EnableRemoteAccess); $('#chkRemoteAccess', page).prop('checked', user.Policy.EnableRemoteAccess == null || user.Policy.EnableRemoteAccess);
$('#chkEnableSyncTranscoding', page).prop('checked', user.Policy.EnableSyncTranscoding);
$('#chkEnableConversion', page).prop('checked', user.Policy.EnableMediaConversion || false);
$('#chkEnableSharing', page).prop('checked', user.Policy.EnablePublicSharing);
$('#txtRemoteClientBitrateLimit', page).val(user.Policy.RemoteClientBitrateLimit / 1e6 || ''); $('#txtRemoteClientBitrateLimit', page).val(user.Policy.RemoteClientBitrateLimit / 1e6 || '');
$('#txtLoginAttemptsBeforeLockout', page).val(user.Policy.LoginAttemptsBeforeLockout || '0'); $('#txtLoginAttemptsBeforeLockout', page).val(user.Policy.LoginAttemptsBeforeLockout || '0');
$('#txtMaxActiveSessions', page).val(user.Policy.MaxActiveSessions || '0');
if (ApiClient.isMinServerVersion('10.6.0')) { if (ApiClient.isMinServerVersion('10.6.0')) {
$('#selectSyncPlayAccess').val(user.Policy.SyncPlayAccess); $('#selectSyncPlayAccess').val(user.Policy.SyncPlayAccess);
} }
@ -132,12 +130,10 @@ import globalize from 'globalize';
user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).is(':checked'); user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).is(':checked');
user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).is(':checked'); user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).is(':checked');
user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).is(':checked'); user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).is(':checked');
user.Policy.EnableSyncTranscoding = $('#chkEnableSyncTranscoding', page).is(':checked');
user.Policy.EnableMediaConversion = $('#chkEnableConversion', page).is(':checked');
user.Policy.EnablePublicSharing = $('#chkEnableSharing', page).is(':checked');
user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).is(':checked'); user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).is(':checked');
user.Policy.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($('#txtRemoteClientBitrateLimit', page).val() || '0')); user.Policy.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($('#txtRemoteClientBitrateLimit', page).val() || '0'));
user.Policy.LoginAttemptsBeforeLockout = parseInt($('#txtLoginAttemptsBeforeLockout', page).val() || '0'); user.Policy.LoginAttemptsBeforeLockout = parseInt($('#txtLoginAttemptsBeforeLockout', page).val() || '0');
user.Policy.MaxActiveSessions = parseInt($('#txtMaxActiveSessions', page).val() || '0');
user.Policy.AuthenticationProviderId = page.querySelector('.selectLoginProvider').value; user.Policy.AuthenticationProviderId = page.querySelector('.selectLoginProvider').value;
user.Policy.PasswordResetProviderId = page.querySelector('.selectPasswordResetProvider').value; user.Policy.PasswordResetProviderId = page.querySelector('.selectPasswordResetProvider').value;
user.Policy.EnableContentDeletion = $('#chkEnableDeleteAllFolders', page).is(':checked'); user.Policy.EnableContentDeletion = $('#chkEnableDeleteAllFolders', page).is(':checked');

View file

@ -51,7 +51,9 @@ import globalize from 'globalize';
$('.channelAccessContainer', page).hide(); $('.channelAccessContainer', page).hide();
} }
$('#chkEnableAllChannels', page).prop('checked', user.Policy.EnableAllChannels); const chkEnableAllChannels = page.querySelector('#chkEnableAllChannels');
chkEnableAllChannels.checked = user.Policy.EnableAllChannels;
triggerChange(chkEnableAllChannels);
} }
function loadDevices(page, user, devices) { function loadDevices(page, user, devices) {
@ -67,7 +69,9 @@ import globalize from 'globalize';
html += '</div>'; html += '</div>';
$('.deviceAccess', page).show().html(html); $('.deviceAccess', page).show().html(html);
$('#chkEnableAllDevices', page).prop('checked', user.Policy.EnableAllDevices); const chkEnableAllDevices = page.querySelector('#chkEnableAllDevices');
chkEnableAllDevices.checked = user.Policy.EnableAllDevices;
triggerChange(chkEnableAllDevices);
if (user.Policy.IsAdministrator) { if (user.Policy.IsAdministrator) {
page.querySelector('.deviceAccessContainer').classList.add('hide'); page.querySelector('.deviceAccessContainer').classList.add('hide');

View file

@ -20,7 +20,7 @@ export default function (view, params) {
}); });
MetadataEditor.setCurrentItemId(null); MetadataEditor.setCurrentItemId(null);
view.querySelector('.libraryTree').addEventListener('itemclicked', function (event) { view.querySelector('.libraryTree').addEventListener('itemclicked', function (event) {
var data = event.detail; const data = event.detail;
if (data.id != MetadataEditor.getCurrentItemId()) { if (data.id != MetadataEditor.getCurrentItemId()) {
MetadataEditor.setCurrentItemId(data.id); MetadataEditor.setCurrentItemId(data.id);

View file

@ -1,6 +1,6 @@
<div id="moviesPage" data-role="page" data-dom-cache="true" class="page libraryPage backdropPage collectionEditorPage pageWithAbsoluteTabs withTabs" data-backdroptype="movie"> <div id="moviesPage" data-role="page" data-dom-cache="true" class="page libraryPage backdropPage collectionEditorPage pageWithAbsoluteTabs withTabs" data-backdroptype="movie">
<div class="pageTabContent" data-index="0"> <div class="pageTabContent" id="moviesTab" data-index="0">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom"> <div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <div class="paging"></div>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button> <button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
@ -17,7 +17,7 @@
<div class="paging"></div> <div class="paging"></div>
</div> </div>
</div> </div>
<div class="pageTabContent" data-index="1"> <div class="pageTabContent" id="suggestionsTab" data-index="1">
<div id="resumableSection" class="verticalSection hide"> <div id="resumableSection" class="verticalSection hide">
<div class="sectionTitleContainer sectionTitleContainer-cards"> <div class="sectionTitleContainer sectionTitleContainer-cards">
<h2 class="sectionTitle sectionTitle-cards padded-left">${HeaderContinueWatching}</h2> <h2 class="sectionTitle sectionTitle-cards padded-left">${HeaderContinueWatching}</h2>
@ -43,7 +43,7 @@
<p>${MessageNoMovieSuggestionsAvailable}</p> <p>${MessageNoMovieSuggestionsAvailable}</p>
</div> </div>
</div> </div>
<div class="pageTabContent" data-index="2"> <div class="pageTabContent" id="trailersTab" data-index="2">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom"> <div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <div class="paging"></div>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button> <button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
@ -59,7 +59,7 @@
<div class="paging"></div> <div class="paging"></div>
</div> </div>
</div> </div>
<div class="pageTabContent" data-index="3"> <div class="pageTabContent" id="favoritesTab" data-index="3">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom"> <div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <div class="paging"></div>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button> <button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
@ -71,7 +71,7 @@
<div class="paging"></div> <div class="paging"></div>
</div> </div>
</div> </div>
<div class="pageTabContent" data-index="4"> <div class="pageTabContent" id="collectionsTab" data-index="4">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom"> <div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <div class="paging"></div>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button> <button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
@ -85,9 +85,7 @@
<div class="paging"></div> <div class="paging"></div>
</div> </div>
</div> </div>
<div class="pageTabContent" data-index="5"> <div class="pageTabContent" id="genresTab" data-index="5">
<div id="items"></div> <div id="items"></div>
</div> </div>
<div class="pageTabContent" data-index="6">
</div>
</div> </div>

View file

@ -320,11 +320,6 @@ import 'emby-button';
if (index === suggestionsTabIndex) { if (index === suggestionsTabIndex) {
controller = this; controller = this;
} else if (index === 6) {
controller = new controllerFactory(view, tabContent, {
collectionType: 'movies',
parentId: params.topParentId
});
} else if (index == 0 || index == 3) { } else if (index == 0 || index == 3) {
controller = new controllerFactory(view, params, tabContent, { controller = new controllerFactory(view, params, tabContent, {
mode: index ? 'favorites' : 'movies' mode: index ? 'favorites' : 'movies'
@ -395,7 +390,7 @@ import 'emby-button';
view.addEventListener('viewshow', function (e) { view.addEventListener('viewshow', function (e) {
initTabs(); initTabs();
if (!view.getAttribute('data-title')) { if (!view.getAttribute('data-title')) {
var parentId = params.topParentId; const parentId = params.topParentId;
if (parentId) { if (parentId) {
ApiClient.getItem(ApiClient.getCurrentUserId(), parentId).then(function (item) { ApiClient.getItem(ApiClient.getCurrentUserId(), parentId).then(function (item) {

View file

@ -8,7 +8,26 @@
} }
} }
</style> </style>
<div class="pageTabContent pageTabContent" id="suggestionsTab" data-index="0"> <div class="pageTabContent pageTabContent" id="albumsTab" data-index="0">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnPlayAll musicglobalButton" title="${HeaderPlayAll}"><span class="material-icons play_arrow"></span></button>
<button is="paper-icon-button-light" class="btnShuffle musicglobalButton" title="${Shuffle}"><span class="material-icons shuffle"></span></button>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div>
<div class="alphaPicker alphaPicker-fixed alphaPicker-vertical">
</div>
<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right">
</div>
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
</div>
</div>
<div class="pageTabContent pageTabContent" id="suggestionsTab" data-index="1">
<div class="verticalSection"> <div class="verticalSection">
@ -34,25 +53,6 @@
<div class="favoriteSections verticalSection"></div> <div class="favoriteSections verticalSection"></div>
</div> </div>
<div class="pageTabContent pageTabContent" id="albumsTab" data-index="1">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnPlayAll musicglobalButton" title="${HeaderPlayAll}"><span class="material-icons play_arrow"></span></button>
<button is="paper-icon-button-light" class="btnShuffle musicglobalButton" title="${Shuffle}"><span class="material-icons shuffle"></span></button>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div>
<div class="alphaPicker alphaPicker-fixed alphaPicker-vertical">
</div>
<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right">
</div>
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
</div>
</div>
<div class="pageTabContent" id="albumArtistsTab" data-index="2"> <div class="pageTabContent" id="albumArtistsTab" data-index="2">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom"> <div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <div class="paging"></div>
@ -85,7 +85,7 @@
<div class="paging"></div> <div class="paging"></div>
</div> </div>
</div> </div>
<div class="pageTabContent" data-index="4"> <div class="pageTabContent" id="playlistsTab" data-index="4">
<div is="emby-itemscontainer" id="items" class="itemsContainer padded-left padded-right padded-top vertical-wrap centered"></div> <div is="emby-itemscontainer" id="items" class="itemsContainer padded-left padded-right padded-top vertical-wrap centered"></div>
</div> </div>
@ -105,6 +105,4 @@
<div class="pageTabContent" id="genresTab" data-index="6"> <div class="pageTabContent" id="genresTab" data-index="6">
<div is="emby-itemscontainer" id="items" class="itemsContainer padded-left padded-right padded-top vertical-wrap"></div> <div is="emby-itemscontainer" id="items" class="itemsContainer padded-left padded-right padded-top vertical-wrap"></div>
</div> </div>
<div class="pageTabContent" data-index="7">
</div>
</div> </div>

View file

@ -56,7 +56,7 @@ import 'flexStyles';
EnableTotalRecordCount: false EnableTotalRecordCount: false
}; };
ApiClient.getJSON(ApiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) { ApiClient.getJSON(ApiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) {
var elem = page.querySelector('#recentlyAddedSongs'); const elem = page.querySelector('#recentlyAddedSongs');
elem.innerHTML = cardBuilder.getCardsHtml({ elem.innerHTML = cardBuilder.getCardsHtml({
items: items, items: items,
showUnplayedIndicator: false, showUnplayedIndicator: false,
@ -103,7 +103,7 @@ import 'flexStyles';
elem.classList.add('hide'); elem.classList.add('hide');
} }
var itemsContainer = elem.querySelector('.itemsContainer'); const itemsContainer = elem.querySelector('.itemsContainer');
itemsContainer.innerHTML = cardBuilder.getCardsHtml({ itemsContainer.innerHTML = cardBuilder.getCardsHtml({
items: result.Items, items: result.Items,
showUnplayedIndicator: false, showUnplayedIndicator: false,
@ -145,7 +145,7 @@ import 'flexStyles';
elem.classList.add('hide'); elem.classList.add('hide');
} }
var itemsContainer = elem.querySelector('.itemsContainer'); const itemsContainer = elem.querySelector('.itemsContainer');
itemsContainer.innerHTML = cardBuilder.getCardsHtml({ itemsContainer.innerHTML = cardBuilder.getCardsHtml({
items: result.Items, items: result.Items,
showUnplayedIndicator: false, showUnplayedIndicator: false,
@ -177,9 +177,9 @@ import 'flexStyles';
function getTabs() { function getTabs() {
return [{ return [{
name: globalize.translate('Suggestions')
}, {
name: globalize.translate('Albums') name: globalize.translate('Albums')
}, {
name: globalize.translate('Suggestions')
}, { }, {
name: globalize.translate('HeaderAlbumArtists') name: globalize.translate('HeaderAlbumArtists')
}, { }, {
@ -195,7 +195,7 @@ import 'flexStyles';
function getDefaultTabIndex(folderId) { function getDefaultTabIndex(folderId) {
switch (userSettings.get('landing-' + folderId)) { switch (userSettings.get('landing-' + folderId)) {
case 'albums': case 'suggestions':
return 1; return 1;
case 'albumartists': case 'albumartists':
@ -221,7 +221,7 @@ import 'flexStyles';
export default function (view, params) { export default function (view, params) {
function reload() { function reload() {
loading.show(); loading.show();
const tabContent = view.querySelector(".pageTabContent[data-index='0']"); const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
loadSuggestionsTab(view, tabContent, params.topParentId); loadSuggestionsTab(view, tabContent, params.topParentId);
} }
@ -268,11 +268,11 @@ import 'flexStyles';
switch (index) { switch (index) {
case 0: case 0:
depends = 'controllers/music/musicrecommended'; depends = 'controllers/music/musicalbums';
break; break;
case 1: case 1:
depends = 'controllers/music/musicalbums'; depends = 'controllers/music/musicrecommended';
break; break;
case 2: case 2:
@ -296,7 +296,7 @@ import 'flexStyles';
import(depends).then(({default: controllerFactory}) => { import(depends).then(({default: controllerFactory}) => {
let tabContent; let tabContent;
if (index == 0) { if (index == 1) {
tabContent = view.querySelector(".pageTabContent[data-index='" + index + "']"); tabContent = view.querySelector(".pageTabContent[data-index='" + index + "']");
this.tabContent = tabContent; this.tabContent = tabContent;
} }
@ -306,13 +306,8 @@ import 'flexStyles';
if (!controller) { if (!controller) {
tabContent = view.querySelector(".pageTabContent[data-index='" + index + "']"); tabContent = view.querySelector(".pageTabContent[data-index='" + index + "']");
if (index === 0) { if (index === 1) {
controller = this; controller = this;
} else if (index === 7) {
controller = new controllerFactory(view, tabContent, {
collectionType: 'music',
parentId: params.topParentId
});
} else { } else {
controller = new controllerFactory(view, params, tabContent); controller = new controllerFactory(view, params, tabContent);
} }
@ -360,9 +355,10 @@ import 'flexStyles';
} }
let currentTabIndex = parseInt(params.tab || getDefaultTabIndex(params.topParentId)); let currentTabIndex = parseInt(params.tab || getDefaultTabIndex(params.topParentId));
const suggestionsTabIndex = 1;
this.initTab = function () { this.initTab = function () {
const tabContent = view.querySelector(".pageTabContent[data-index='0']"); const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
const containers = tabContent.querySelectorAll('.itemsContainer'); const containers = tabContent.querySelectorAll('.itemsContainer');
for (let i = 0, length = containers.length; i < length; i++) { for (let i = 0, length = containers.length; i < length; i++) {

View file

@ -1,11 +1,9 @@
<div id="videoOsdPage" data-role="page" class="page libraryPage" data-backbutton="true"> <div id="videoOsdPage" data-role="page" class="page libraryPage" data-backbutton="true">
<div class="upNextContainer hide"></div> <div class="upNextContainer hide"></div>
<div class="videoOsdBottom videoOsdBottom-maincontrols"> <div class="videoOsdBottom videoOsdBottom-maincontrols">
<div class="osdPoster"></div>
<div class="osdControls"> <div class="osdControls">
<div class="osdTextContainer osdMainTextContainer"> <div class="osdTextContainer osdMainTextContainer">
<h3 class="osdTitle"></h3> <h3 class="osdTitle"></h3>
<div class="osdMediaInfo"></div>
<div class="osdMediaStatus hide"> <div class="osdMediaStatus hide">
<span class="material-icons animate autorenew"></span> <span class="material-icons animate autorenew"></span>
<span>${FetchingData}</span> <span>${FetchingData}</span>
@ -16,7 +14,7 @@
<div class="flex flex-direction-row align-items-center"> <div class="flex flex-direction-row align-items-center">
<div class="osdTextContainer startTimeText" style="margin: 0 .25em 0 0;"></div> <div class="osdTextContainer startTimeText" style="margin: 0 .25em 0 0;"></div>
<div class="sliderContainer flex-grow" style="margin: .5em .5em .25em;"> <div class="sliderContainer flex-grow" style="margin: .5em 0 .25em;">
<input type="range" step=".01" min="0" max="100" value="0" is="emby-slider" class="osdPositionSlider" data-slider-keep-progress="true" /> <input type="range" step=".01" min="0" max="100" value="0" is="emby-slider" class="osdPositionSlider" data-slider-keep-progress="true" />
</div> </div>
<div class="osdTextContainer endTimeText" style="margin: 0 0 0 .25em;"></div> <div class="osdTextContainer endTimeText" style="margin: 0 0 0 .25em;"></div>
@ -47,32 +45,18 @@
<span class="xlargePaperIconButton material-icons skip_next"></span> <span class="xlargePaperIconButton material-icons skip_next"></span>
</button> </button>
<button is="paper-icon-button-light" class="btnAudio hide autoSize" title="${Audio}">
<span class="xlargePaperIconButton material-icons audiotrack"></span>
</button>
<button is="paper-icon-button-light" class="btnSubtitles hide autoSize" title="${Subtitles}">
<span class="xlargePaperIconButton material-icons closed_caption"></span>
</button>
<button is="paper-icon-button-light" class="btnVideoOsdSettings hide autoSize" title="${Settings}">
<span class="largePaperIconButton material-icons settings"></span>
</button>
<button is="paper-icon-button-light" class="btnFullscreen hide autoSize" title="${Fullscreen} (f)">
<span class="xlargePaperIconButton material-icons fullscreen"></span>
</button>
<button is="paper-icon-button-light" class="btnPip hide autoSize" title="${PictureInPicture}">
<span class="xlargePaperIconButton material-icons picture_in_picture_alt"></span>
</button>
<button is="paper-icon-button-light" class="btnAirPlay hide autoSize" title="${AirPlay}">
<span class="xlargePaperIconButton material-icons airplay"></span>
</button>
<div class="osdTimeText"> <div class="osdTimeText">
<span class="osdPositionText"></span> <span class="osdPositionText"></span>
<span class="osdDurationText"></span> <span class="osdDurationText"></span>
<span class="endsAtText"></span> <span class="endsAtText"></span>
</div> </div>
<button is="paper-icon-button-light" class="btnSubtitles hide autoSize" title="${Subtitles}">
<span class="xlargePaperIconButton material-icons closed_caption"></span>
</button>
<button is="paper-icon-button-light" class="btnAudio hide autoSize" title="${Audio}">
<span class="xlargePaperIconButton material-icons audiotrack"></span>
</button>
<div class="volumeButtons hide-mouse-idle-tv"> <div class="volumeButtons hide-mouse-idle-tv">
<button is="paper-icon-button-light" class="buttonMute autoSize" title="${Mute} (m)"> <button is="paper-icon-button-light" class="buttonMute autoSize" title="${Mute} (m)">
<span class="xlargePaperIconButton material-icons volume_up"></span> <span class="xlargePaperIconButton material-icons volume_up"></span>
@ -81,6 +65,18 @@
<input is="emby-slider" type="range" step="1" min="0" max="100" value="0" class="osdVolumeSlider" /> <input is="emby-slider" type="range" step="1" min="0" max="100" value="0" class="osdVolumeSlider" />
</div> </div>
</div> </div>
<button is="paper-icon-button-light" class="btnVideoOsdSettings hide autoSize" title="${Settings}">
<span class="largePaperIconButton material-icons settings"></span>
</button>
<button is="paper-icon-button-light" class="btnAirPlay hide autoSize" title="${AirPlay}">
<span class="xlargePaperIconButton material-icons airplay"></span>
</button>
<button is="paper-icon-button-light" class="btnPip hide autoSize" title="${PictureInPicture}">
<span class="xlargePaperIconButton material-icons picture_in_picture_alt"></span>
</button>
<button is="paper-icon-button-light" class="btnFullscreen hide autoSize" title="${Fullscreen} (f)">
<span class="xlargePaperIconButton material-icons fullscreen"></span>
</button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -20,50 +20,6 @@ import 'css!assets/css/videoosd';
/* eslint-disable indent */ /* eslint-disable indent */
function seriesImageUrl(item, options) {
if (item.Type !== 'Episode') {
return null;
}
options = options || {};
options.type = options.type || 'Primary';
if (options.type === 'Primary' && item.SeriesPrimaryImageTag) {
options.tag = item.SeriesPrimaryImageTag;
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
}
if (options.type === 'Thumb') {
if (item.SeriesThumbImageTag) {
options.tag = item.SeriesThumbImageTag;
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
}
if (item.ParentThumbImageTag) {
options.tag = item.ParentThumbImageTag;
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
}
}
return null;
}
function imageUrl(item, options) {
options = options || {};
options.type = options.type || 'Primary';
if (item.ImageTags && item.ImageTags[options.type]) {
options.tag = item.ImageTags[options.type];
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options);
}
if (options.type === 'Primary' && item.AlbumId && item.AlbumPrimaryImageTag) {
options.tag = item.AlbumPrimaryImageTag;
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
}
return null;
}
function getOpenedDialog() { function getOpenedDialog() {
return document.querySelector('.dialogContainer .dialog.opened'); return document.querySelector('.dialogContainer .dialog.opened');
} }
@ -163,7 +119,6 @@ import 'css!assets/css/videoosd';
currentItem = item; currentItem = item;
const displayItem = itemInfo.displayItem || item; const displayItem = itemInfo.displayItem || item;
updateRecordingButton(displayItem); updateRecordingButton(displayItem);
setPoster(displayItem, item);
let parentName = displayItem.SeriesName || displayItem.Album; let parentName = displayItem.SeriesName || displayItem.Album;
if (displayItem.EpisodeTitle || displayItem.IsSeries) { if (displayItem.EpisodeTitle || displayItem.IsSeries) {
@ -171,42 +126,6 @@ import 'css!assets/css/videoosd';
} }
setTitle(displayItem, parentName); setTitle(displayItem, parentName);
const titleElement = view.querySelector('.osdTitle');
let displayName = itemHelper.getDisplayName(displayItem, {
includeParentInfo: displayItem.Type !== 'Program',
includeIndexNumber: displayItem.Type !== 'Program'
});
if (!displayName) {
displayName = displayItem.Type;
}
titleElement.innerHTML = displayName;
if (displayName) {
titleElement.classList.remove('hide');
} else {
titleElement.classList.add('hide');
}
const mediaInfoHtml = mediaInfo.getPrimaryMediaInfoHtml(displayItem, {
runtime: false,
subtitles: false,
tomatoes: false,
endsAt: false,
episodeTitle: false,
originalAirDate: displayItem.Type !== 'Program',
episodeTitleIndexNumber: displayItem.Type !== 'Program',
programIndicator: false
});
const osdMediaInfo = view.querySelector('.osdMediaInfo');
osdMediaInfo.innerHTML = mediaInfoHtml;
if (mediaInfoHtml) {
osdMediaInfo.classList.remove('hide');
} else {
osdMediaInfo.classList.add('hide');
}
const secondaryMediaInfo = view.querySelector('.osdSecondaryMediaInfo'); const secondaryMediaInfo = view.querySelector('.osdSecondaryMediaInfo');
const secondaryMediaInfoHtml = mediaInfo.getSecondaryMediaInfoHtml(displayItem, { const secondaryMediaInfoHtml = mediaInfo.getSecondaryMediaInfoHtml(displayItem, {
@ -221,12 +140,6 @@ import 'css!assets/css/videoosd';
secondaryMediaInfo.classList.add('hide'); secondaryMediaInfo.classList.add('hide');
} }
if (displayName) {
view.querySelector('.osdMainTextContainer').classList.remove('hide');
} else {
view.querySelector('.osdMainTextContainer').classList.add('hide');
}
if (enableProgressByTimeOfDay) { if (enableProgressByTimeOfDay) {
setDisplayTime(startTimeText, displayItem.StartDate); setDisplayTime(startTimeText, displayItem.StartDate);
setDisplayTime(endTimeText, displayItem.EndDate); setDisplayTime(endTimeText, displayItem.EndDate);
@ -276,7 +189,6 @@ import 'css!assets/css/videoosd';
currentItem = item; currentItem = item;
if (!item) { if (!item) {
setPoster(null);
updateRecordingButton(null); updateRecordingButton(null);
Emby.Page.setTitle(''); Emby.Page.setTitle('');
nowPlayingVolumeSlider.disabled = true; nowPlayingVolumeSlider.disabled = true;
@ -313,7 +225,20 @@ import 'css!assets/css/videoosd';
} }
function setTitle(item, parentName) { function setTitle(item, parentName) {
Emby.Page.setTitle(parentName || ''); let itemName = itemHelper.getDisplayName(item, {
includeParentInfo: item.Type !== 'Program',
includeIndexNumber: item.Type !== 'Program'
});
if (itemName && parentName) {
itemName = `${parentName} - ${itemName}`;
}
if (!itemName) {
itemName = parentName || '';
}
Emby.Page.setTitle(itemName);
const documentTitle = parentName || (item ? item.Name : null); const documentTitle = parentName || (item ? item.Name : null);
@ -322,38 +247,6 @@ import 'css!assets/css/videoosd';
} }
} }
function setPoster(item, secondaryItem) {
const osdPoster = view.querySelector('.osdPoster');
if (item) {
let imgUrl = seriesImageUrl(item, {
maxWidth: osdPoster.clientWidth,
type: 'Primary'
}) || seriesImageUrl(item, {
maxWidth: osdPoster.clientWidth,
type: 'Thumb'
}) || imageUrl(item, {
maxWidth: osdPoster.clientWidth,
type: 'Primary'
});
if (!imgUrl && secondaryItem && (imgUrl = seriesImageUrl(secondaryItem, {
maxWidth: osdPoster.clientWidth,
type: 'Primary'
}) || seriesImageUrl(secondaryItem, {
maxWidth: osdPoster.clientWidth,
type: 'Thumb'
}) || imageUrl(secondaryItem, {
maxWidth: osdPoster.clientWidth,
type: 'Primary'
})), imgUrl) {
return void (osdPoster.innerHTML = '<img src="' + imgUrl + '" />');
}
}
osdPoster.innerHTML = '';
}
let mouseIsDown = false; let mouseIsDown = false;
function showOsd() { function showOsd() {

View file

@ -16,7 +16,7 @@ import 'emby-checkbox';
function authenticateUserByName(page, apiClient, username, password) { function authenticateUserByName(page, apiClient, username, password) {
loading.show(); loading.show();
apiClient.authenticateUserByName(username, password).then(function (result) { apiClient.authenticateUserByName(username, password).then(function (result) {
var user = result.User; const user = result.User;
loading.hide(); loading.hide();
onLoginSuccessful(user.Id, result.AccessToken, apiClient); onLoginSuccessful(user.Id, result.AccessToken, apiClient);

View file

@ -1,68 +0,0 @@
import loading from 'loading';
import groupedcards from 'components/groupedcards';
import cardBuilder from 'cardBuilder';
import imageLoader from 'imageLoader';
/* eslint-disable indent */
function getLatestPromise(context, params) {
loading.show();
const userId = ApiClient.getCurrentUserId();
const parentId = params.topParentId;
const options = {
IncludeItemTypes: 'Episode',
Limit: 30,
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo',
ParentId: parentId,
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Thumb'
};
return ApiClient.getJSON(ApiClient.getUrl('Users/' + userId + '/Items/Latest', options));
}
function loadLatest(context, params, promise) {
promise.then(function (items) {
let html = '';
html += cardBuilder.getCardsHtml({
items: items,
shape: 'backdrop',
preferThumb: true,
showTitle: true,
showSeriesYear: true,
showParentTitle: true,
overlayText: false,
cardLayout: false,
showUnplayedIndicator: false,
showChildCountIndicator: true,
centerText: true,
lazy: true,
overlayPlayButton: true,
lines: 2
});
const elem = context.querySelector('#latestEpisodes');
elem.innerHTML = html;
imageLoader.lazyChildren(elem);
loading.hide();
import('autoFocuser').then(({default: autoFocuser}) => {
autoFocuser.autoFocus(context);
});
});
}
export default function (view, params, tabContent) {
const self = this;
let latestPromise;
self.preRender = function () {
latestPromise = getLatestPromise(view, params);
};
self.renderTab = function () {
loadLatest(tabContent, params, latestPromise);
};
tabContent.querySelector('#latestEpisodes').addEventListener('click', groupedcards);
}
/* eslint-enable indent */

View file

@ -23,8 +23,15 @@
<div is="emby-itemscontainer" id="resumableItems" class="itemsContainer padded-left padded-right"></div> <div is="emby-itemscontainer" id="resumableItems" class="itemsContainer padded-left padded-right"></div>
</div> </div>
<div id="latestItemsSection" class="hide verticalSection">
<div class="sectionTitleContainer sectionTitleContainer-cards">
<h2 class="sectionTitle sectionTitle-cards padded-left">${HeaderLatestEpisodes}</h2>
</div>
<div class="verticalSection"> <div is="emby-itemscontainer" id="latestEpisodesItems" class="itemsContainer padded-left padded-right"></div>
</div>
<div id="nextUpItemsSection" class="hide verticalSection">
<div class="sectionTitleContainer sectionTitleContainer-cards"> <div class="sectionTitleContainer sectionTitleContainer-cards">
<h2 class="sectionTitle sectionTitle-cards padded-left nextUpHeader">${NextUp}</h2> <h2 class="sectionTitle sectionTitle-cards padded-left nextUpHeader">${NextUp}</h2>
</div> </div>
@ -33,16 +40,7 @@
</div> </div>
<p class="noNextUpItems" style="display: none;">${MessageNoNextUpItems}</p> <p class="noNextUpItems" style="display: none;">${MessageNoNextUpItems}</p>
</div> </div>
<div class="pageTabContent" id="latestTab" data-index="2"> <div class="pageTabContent" id="upcomingTab" data-index="2">
<div class="verticalSection">
<div class="sectionTitleContainer sectionTitleContainer-cards">
<h2 class="sectionTitle sectionTitle-cards padded-left">${HeaderLatestEpisodes}</h2>
</div>
<div is="emby-itemscontainer" id="latestEpisodes" class="itemsContainer vertical-wrap padded-left padded-right">
</div>
</div>
</div>
<div class="pageTabContent" id="upcomingTab" data-index="3">
<div id="upcomingItems"> <div id="upcomingItems">
</div> </div>
<div class="noItemsMessage centerMessage" style="display: none;"> <div class="noItemsMessage centerMessage" style="display: none;">
@ -50,13 +48,13 @@
<p>${MessagePleaseEnsureInternetMetadata}</p> <p>${MessagePleaseEnsureInternetMetadata}</p>
</div> </div>
</div> </div>
<div class="pageTabContent" id="genresTab" data-index="4"> <div class="pageTabContent" id="genresTab" data-index="3">
<div id="items"></div> <div id="items"></div>
</div> </div>
<div class="pageTabContent" id="studiosTab" data-index="5"> <div class="pageTabContent" id="studiosTab" data-index="4">
<div is="emby-itemscontainer" id="items" class="itemsContainer padded-left padded-right padded-top vertical-wrap" style="text-align: center;"></div> <div is="emby-itemscontainer" id="items" class="itemsContainer padded-left padded-right padded-top vertical-wrap" style="text-align: center;"></div>
</div> </div>
<div class="pageTabContent" data-index="6"> <div class="pageTabContent" id="episodesTab" data-index="5">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom"> <div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <div class="paging"></div>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button> <button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
@ -69,6 +67,4 @@
<div class="paging"></div> <div class="paging"></div>
</div> </div>
</div> </div>
<div class="pageTabContent" data-index="7">
</div>
</div> </div>

View file

@ -20,8 +20,6 @@ import 'emby-button';
name: globalize.translate('Shows') name: globalize.translate('Shows')
}, { }, {
name: globalize.translate('Suggestions') name: globalize.translate('Suggestions')
}, {
name: globalize.translate('TabLatest')
}, { }, {
name: globalize.translate('TabUpcoming') name: globalize.translate('TabUpcoming')
}, { }, {
@ -38,15 +36,18 @@ import 'emby-button';
case 'suggestions': case 'suggestions':
return 1; return 1;
case 'latest': case 'upcoming':
return 2; return 2;
case 'favorites':
return 1;
case 'genres': case 'genres':
return 3;
case 'networks':
return 4; return 4;
case 'episodes':
return 5;
default: default:
return 0; return 0;
} }
@ -70,102 +71,159 @@ import 'emby-button';
} }
} }
function initSuggestedTab(page, tabContent) {
const containers = tabContent.querySelectorAll('.itemsContainer');
for (let i = 0, length = containers.length; i < length; i++) {
setScrollClasses(containers[i], enableScrollX());
}
}
function loadSuggestionsTab(view, params, tabContent) {
const parentId = params.topParentId;
const userId = ApiClient.getCurrentUserId();
console.debug('loadSuggestionsTab');
loadResume(tabContent, userId, parentId);
loadLatest(tabContent, userId, parentId);
loadNextUp(tabContent, userId, parentId);
}
function loadResume(view, userId, parentId) {
const screenWidth = dom.getWindowSize().innerWidth;
const options = {
SortBy: 'DatePlayed',
SortOrder: 'Descending',
IncludeItemTypes: 'Episode',
Filters: 'IsResumable',
Limit: screenWidth >= 1920 ? 5 : screenWidth >= 1600 ? 5 : 3,
Recursive: true,
Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo',
CollapseBoxSetItems: false,
ParentId: parentId,
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
EnableTotalRecordCount: false
};
ApiClient.getItems(userId, options).then(function (result) {
if (result.Items.length) {
view.querySelector('#resumableSection').classList.remove('hide');
} else {
view.querySelector('#resumableSection').classList.add('hide');
}
const allowBottomPadding = !enableScrollX();
const container = view.querySelector('#resumableItems');
cardBuilder.buildCards(result.Items, {
itemsContainer: container,
preferThumb: true,
shape: getThumbShape(),
scalable: true,
overlayPlayButton: true,
allowBottomPadding: allowBottomPadding,
cardLayout: false,
showTitle: true,
showYear: true,
centerText: true
});
loading.hide();
import('autoFocuser').then(({default: autoFocuser}) => {
autoFocuser.autoFocus(view);
});
});
}
function loadLatest(view, userId, parentId) {
const options = {
userId: userId,
IncludeItemTypes: 'Episode',
Limit: 30,
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo',
ParentId: parentId,
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Thumb'
};
ApiClient.getLatestItems(options).then(function (items) {
const section = view.querySelector('#latestItemsSection');
const allowBottomPadding = !enableScrollX();
const container = section.querySelector('#latestEpisodesItems');
cardBuilder.buildCards(items, {
parentContainer: section,
itemsContainer: container,
items: items,
shape: 'backdrop',
preferThumb: true,
showTitle: true,
showSeriesYear: true,
showParentTitle: true,
overlayText: false,
cardLayout: false,
allowBottomPadding: allowBottomPadding,
showUnplayedIndicator: false,
showChildCountIndicator: true,
centerText: true,
lazy: true,
overlayPlayButton: true,
lines: 2
});
loading.hide();
import('autoFocuser').then(({default: autoFocuser}) => {
autoFocuser.autoFocus(view);
});
});
}
function loadNextUp(view, userId, parentId) {
const query = {
userId: userId,
Limit: 24,
Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo',
ParentId: parentId,
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Thumb',
EnableTotalRecordCount: false
};
query.ParentId = libraryMenu.getTopParentId();
ApiClient.getNextUpEpisodes(query).then(function (result) {
if (result.Items.length) {
view.querySelector('.noNextUpItems').classList.add('hide');
} else {
view.querySelector('.noNextUpItems').classList.remove('hide');
}
const section = view.querySelector('#nextUpItemsSection');
const container = section.querySelector('#nextUpItems');
cardBuilder.buildCards(result.Items, {
parentContainer: section,
itemsContainer: container,
preferThumb: true,
shape: 'backdrop',
scalable: true,
showTitle: true,
showParentTitle: true,
overlayText: false,
centerText: true,
overlayPlayButton: true,
cardLayout: false
});
loading.hide();
import('autoFocuser').then(({default: autoFocuser}) => {
autoFocuser.autoFocus(view);
});
});
}
function enableScrollX() {
return !layoutManager.desktop;
}
function getThumbShape() {
return enableScrollX() ? 'overflowBackdrop' : 'backdrop';
}
export default function (view, params) { export default function (view, params) {
function reload() {
loading.show();
loadResume();
loadNextUp();
}
function loadNextUp() {
const query = {
Limit: 24,
Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo',
UserId: ApiClient.getCurrentUserId(),
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Thumb',
EnableTotalRecordCount: false
};
query.ParentId = libraryMenu.getTopParentId();
ApiClient.getNextUpEpisodes(query).then(function (result) {
if (result.Items.length) {
view.querySelector('.noNextUpItems').classList.add('hide');
} else {
view.querySelector('.noNextUpItems').classList.remove('hide');
}
const container = view.querySelector('#nextUpItems');
cardBuilder.buildCards(result.Items, {
itemsContainer: container,
preferThumb: true,
shape: 'backdrop',
scalable: true,
showTitle: true,
showParentTitle: true,
overlayText: false,
centerText: true,
overlayPlayButton: true,
cardLayout: false
});
loading.hide();
import('autoFocuser').then(({default: autoFocuser}) => {
autoFocuser.autoFocus(view);
});
});
}
function enableScrollX() {
return !layoutManager.desktop;
}
function getThumbShape() {
return enableScrollX() ? 'overflowBackdrop' : 'backdrop';
}
function loadResume() {
const parentId = libraryMenu.getTopParentId();
const screenWidth = dom.getWindowSize().innerWidth;
const limit = screenWidth >= 1600 ? 5 : 6;
const options = {
SortBy: 'DatePlayed',
SortOrder: 'Descending',
IncludeItemTypes: 'Episode',
Filters: 'IsResumable',
Limit: limit,
Recursive: true,
Fields: 'PrimaryImageAspectRatio,SeriesInfo,UserData,BasicSyncInfo',
ExcludeLocationTypes: 'Virtual',
ParentId: parentId,
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Thumb',
EnableTotalRecordCount: false
};
ApiClient.getItems(ApiClient.getCurrentUserId(), options).then(function (result) {
if (result.Items.length) {
view.querySelector('#resumableSection').classList.remove('hide');
} else {
view.querySelector('#resumableSection').classList.add('hide');
}
const allowBottomPadding = !enableScrollX();
const container = view.querySelector('#resumableItems');
cardBuilder.buildCards(result.Items, {
itemsContainer: container,
preferThumb: true,
shape: getThumbShape(),
scalable: true,
showTitle: true,
showParentTitle: true,
overlayText: false,
centerText: true,
overlayPlayButton: true,
allowBottomPadding: allowBottomPadding,
cardLayout: false
});
});
}
function onBeforeTabChange(e) { function onBeforeTabChange(e) {
preLoadTab(view, parseInt(e.detail.selectedTabIndex)); preLoadTab(view, parseInt(e.detail.selectedTabIndex));
} }
@ -196,22 +254,18 @@ import 'emby-button';
break; break;
case 2: case 2:
depends = 'controllers/shows/tvlatest';
break;
case 3:
depends = 'controllers/shows/tvupcoming'; depends = 'controllers/shows/tvupcoming';
break; break;
case 4: case 3:
depends = 'controllers/shows/tvgenres'; depends = 'controllers/shows/tvgenres';
break; break;
case 5: case 4:
depends = 'controllers/shows/tvstudios'; depends = 'controllers/shows/tvstudios';
break; break;
case 6: case 5:
depends = 'controllers/shows/episodes'; depends = 'controllers/shows/episodes';
break; break;
} }
@ -231,11 +285,6 @@ import 'emby-button';
if (index === 1) { if (index === 1) {
controller = self; controller = self;
} else if (index === 7) {
controller = new controllerFactory(view, tabContent, {
collectionType: 'tvshows',
parentId: params.topParentId
});
} else { } else {
controller = new controllerFactory(view, params, tabContent); controller = new controllerFactory(view, params, tabContent);
} }
@ -294,19 +343,20 @@ import 'emby-button';
const self = this; const self = this;
let currentTabIndex = parseInt(params.tab || getDefaultTabIndex(params.topParentId)); let currentTabIndex = parseInt(params.tab || getDefaultTabIndex(params.topParentId));
const suggestionsTabIndex = 1;
self.initTab = function () { self.initTab = function () {
const tabContent = self.tabContent; const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
setScrollClasses(tabContent.querySelector('#resumableItems'), enableScrollX()); initSuggestedTab(view, tabContent);
}; };
self.renderTab = function () { self.renderTab = function () {
reload(); const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
loadSuggestionsTab(view, params, tabContent);
}; };
const tabControllers = []; const tabControllers = [];
let renderedTabs = []; let renderedTabs = [];
setScrollClasses(view.querySelector('#resumableItems'), enableScrollX());
view.addEventListener('viewshow', function (e) { view.addEventListener('viewshow', function (e) {
initTabs(); initTabs();
if (!view.getAttribute('data-title')) { if (!view.getAttribute('data-title')) {

View file

@ -14,14 +14,14 @@ import 'webcomponents';
if (window.MutationObserver) { if (window.MutationObserver) {
// create an observer instance // create an observer instance
var observer = new MutationObserver(function (mutations) { const observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) { mutations.forEach(function (mutation) {
instance.setProgress(parseFloat(instance.getAttribute('data-progress') || '0')); instance.setProgress(parseFloat(instance.getAttribute('data-progress') || '0'));
}); });
}); });
// configuration of the observer: // configuration of the observer:
var config = { attributes: true, childList: false, characterData: false }; const config = { attributes: true, childList: false, characterData: false };
// pass in the target node, as well as the observer options // pass in the target node, as well as the observer options
observer.observe(instance, config); observer.observe(instance, config);

View file

@ -54,7 +54,7 @@ import 'emby-input';
// Snap to step // Snap to step
if (range.step !== 'any') { if (range.step !== 'any') {
var step = range.step || 1; const step = range.step || 1;
value = Math.round(value / step) * step; value = Math.round(value / step) * step;
} }

View file

@ -2,16 +2,16 @@
if (HTMLElement.prototype.nativeFocus === undefined) { if (HTMLElement.prototype.nativeFocus === undefined) {
(function () { (function () {
var supportsPreventScrollOption = false; let supportsPreventScrollOption = false;
try { try {
var focusElem = document.createElement('div'); const focusElem = document.createElement('div');
focusElem.addEventListener('focus', function(event) { focusElem.addEventListener('focus', function(event) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
}, true); }, true);
var opts = Object.defineProperty({}, 'preventScroll', { const opts = Object.defineProperty({}, 'preventScroll', {
// eslint-disable-next-line getter-return // eslint-disable-next-line getter-return
get: function () { get: function () {
supportsPreventScrollOption = true; supportsPreventScrollOption = true;
@ -27,8 +27,8 @@ if (HTMLElement.prototype.nativeFocus === undefined) {
HTMLElement.prototype.nativeFocus = HTMLElement.prototype.focus; HTMLElement.prototype.nativeFocus = HTMLElement.prototype.focus;
HTMLElement.prototype.focus = function(options) { HTMLElement.prototype.focus = function(options) {
var scrollX = window.scrollX; const scrollX = window.scrollX;
var scrollY = window.scrollY; const scrollY = window.scrollY;
this.nativeFocus(); this.nativeFocus();

View file

@ -2,6 +2,7 @@
* and will be replaced soon by a Vue component. * and will be replaced soon by a Vue component.
*/ */
/* eslint-disable no-var */
import browser from 'browser'; import browser from 'browser';
import dom from 'dom'; import dom from 'dom';
import 'css!./navdrawer'; import 'css!./navdrawer';
@ -14,26 +15,26 @@ export default function (options) {
function onMenuTouchStart(e) { function onMenuTouchStart(e) {
options.target.classList.remove('transition'); options.target.classList.remove('transition');
var touches = getTouches(e); const touches = getTouches(e);
var touch = touches[0] || {}; const touch = touches[0] || {};
menuTouchStartX = touch.clientX; menuTouchStartX = touch.clientX;
menuTouchStartY = touch.clientY; menuTouchStartY = touch.clientY;
menuTouchStartTime = new Date().getTime(); menuTouchStartTime = new Date().getTime();
} }
function setVelocity(deltaX) { function setVelocity(deltaX) {
var time = new Date().getTime() - (menuTouchStartTime || 0); const time = new Date().getTime() - (menuTouchStartTime || 0);
velocity = Math.abs(deltaX) / time; velocity = Math.abs(deltaX) / time;
} }
function onMenuTouchMove(e) { function onMenuTouchMove(e) {
var isOpen = self.visible; const isOpen = self.visible;
var touches = getTouches(e); const touches = getTouches(e);
var touch = touches[0] || {}; const touch = touches[0] || {};
var endX = touch.clientX || 0; const endX = touch.clientX || 0;
var endY = touch.clientY || 0; const endY = touch.clientY || 0;
var deltaX = endX - (menuTouchStartX || 0); const deltaX = endX - (menuTouchStartX || 0);
var deltaY = endY - (menuTouchStartY || 0); const deltaY = endY - (menuTouchStartY || 0);
setVelocity(deltaX); setVelocity(deltaX);
if (isOpen && dragMode !== 1 && deltaX > 0) { if (isOpen && dragMode !== 1 && deltaX > 0) {
@ -58,12 +59,12 @@ export default function (options) {
options.target.classList.add('transition'); options.target.classList.add('transition');
scrollContainer.removeEventListener('scroll', disableEvent); scrollContainer.removeEventListener('scroll', disableEvent);
dragMode = 0; dragMode = 0;
var touches = getTouches(e); const touches = getTouches(e);
var touch = touches[0] || {}; const touch = touches[0] || {};
var endX = touch.clientX || 0; const endX = touch.clientX || 0;
var endY = touch.clientY || 0; const endY = touch.clientY || 0;
var deltaX = endX - (menuTouchStartX || 0); const deltaX = endX - (menuTouchStartX || 0);
var deltaY = endY - (menuTouchStartY || 0); const deltaY = endY - (menuTouchStartY || 0);
currentPos = deltaX; currentPos = deltaX;
self.checkMenuState(deltaX, deltaY); self.checkMenuState(deltaX, deltaY);
} }
@ -105,20 +106,20 @@ export default function (options) {
} }
function onBackgroundTouchStart(e) { function onBackgroundTouchStart(e) {
var touches = getTouches(e); const touches = getTouches(e);
var touch = touches[0] || {}; const touch = touches[0] || {};
backgroundTouchStartX = touch.clientX; backgroundTouchStartX = touch.clientX;
backgroundTouchStartTime = new Date().getTime(); backgroundTouchStartTime = new Date().getTime();
} }
function onBackgroundTouchMove(e) { function onBackgroundTouchMove(e) {
var touches = getTouches(e); const touches = getTouches(e);
var touch = touches[0] || {}; const touch = touches[0] || {};
var endX = touch.clientX || 0; const endX = touch.clientX || 0;
if (endX <= options.width && self.isVisible) { if (endX <= options.width && self.isVisible) {
countStart++; countStart++;
var deltaX = endX - (backgroundTouchStartX || 0); const deltaX = endX - (backgroundTouchStartX || 0);
if (countStart == 1) { if (countStart == 1) {
startPoint = deltaX; startPoint = deltaX;
@ -127,7 +128,7 @@ export default function (options) {
dragMode = 1; dragMode = 1;
newPos = deltaX - startPoint + options.width; newPos = deltaX - startPoint + options.width;
self.changeMenuPos(); self.changeMenuPos();
var time = new Date().getTime() - (backgroundTouchStartTime || 0); const time = new Date().getTime() - (backgroundTouchStartTime || 0);
velocity = Math.abs(deltaX) / time; velocity = Math.abs(deltaX) / time;
} }
} }
@ -137,25 +138,25 @@ export default function (options) {
} }
function onBackgroundTouchEnd(e) { function onBackgroundTouchEnd(e) {
var touches = getTouches(e); const touches = getTouches(e);
var touch = touches[0] || {}; const touch = touches[0] || {};
var endX = touch.clientX || 0; const endX = touch.clientX || 0;
var deltaX = endX - (backgroundTouchStartX || 0); const deltaX = endX - (backgroundTouchStartX || 0);
self.checkMenuState(deltaX); self.checkMenuState(deltaX);
countStart = 0; countStart = 0;
} }
function onMaskTransitionEnd() { function onMaskTransitionEnd() {
var classList = mask.classList; const classList = mask.classList;
if (!classList.contains('backdrop')) { if (!classList.contains('backdrop')) {
classList.add('hide'); classList.add('hide');
} }
} }
var self; let self;
var defaults; let defaults;
var mask; let mask;
var newPos = 0; var newPos = 0;
var currentPos = 0; var currentPos = 0;
var startPoint = 0; var startPoint = 0;
@ -166,7 +167,7 @@ export default function (options) {
var scrollContainer = options.target.querySelector('.mainDrawer-scrollContainer'); var scrollContainer = options.target.querySelector('.mainDrawer-scrollContainer');
scrollContainer.classList.add('scrollY'); scrollContainer.classList.add('scrollY');
var TouchMenuLA = function () { const TouchMenuLA = function () {
self = this; self = this;
defaults = { defaults = {
width: 260, width: 260,
@ -193,9 +194,9 @@ export default function (options) {
} }
}; };
var menuTouchStartX; let menuTouchStartX;
var menuTouchStartY; let menuTouchStartY;
var menuTouchStartTime; let menuTouchStartTime;
var edgeContainer = document.querySelector('.mainDrawerHandle'); var edgeContainer = document.querySelector('.mainDrawerHandle');
var isPeeking = false; var isPeeking = false;
@ -261,8 +262,8 @@ export default function (options) {
} }
}; };
var backgroundTouchStartX; let backgroundTouchStartX;
var backgroundTouchStartTime; let backgroundTouchStartTime;
TouchMenuLA.prototype.showMask = function () { TouchMenuLA.prototype.showMask = function () {
mask.classList.remove('hide'); mask.classList.remove('hide');
@ -280,7 +281,7 @@ export default function (options) {
} }
}; };
var _edgeSwipeEnabled; let _edgeSwipeEnabled;
TouchMenuLA.prototype.setEdgeSwipeEnabled = function (enabled) { TouchMenuLA.prototype.setEdgeSwipeEnabled = function (enabled) {
if (!options.disableEdgeSwipe) { if (!options.disableEdgeSwipe) {
@ -355,3 +356,4 @@ export default function (options) {
return new TouchMenuLA(); return new TouchMenuLA();
} }
/* eslint-enable no-var */

View file

@ -56,14 +56,14 @@ function within(number, min, max) {
} }
// Other global values // Other global values
var dragMouseEvents = ['mousemove', 'mouseup']; const dragMouseEvents = ['mousemove', 'mouseup'];
var dragTouchEvents = ['touchmove', 'touchend']; const dragTouchEvents = ['touchmove', 'touchend'];
var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel'); const wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel');
var interactiveElements = ['INPUT', 'SELECT', 'TEXTAREA']; const interactiveElements = ['INPUT', 'SELECT', 'TEXTAREA'];
var scrollerFactory = function (frame, options) { const scrollerFactory = function (frame, options) {
// Extend options // Extend options
var o = Object.assign({}, { const o = Object.assign({}, {
slidee: null, // Selector, DOM element, or jQuery object with DOM element representing SLIDEE. slidee: null, // Selector, DOM element, or jQuery object with DOM element representing SLIDEE.
horizontal: false, // Switch to horizontal mode. horizontal: false, // Switch to horizontal mode.
@ -83,7 +83,7 @@ var scrollerFactory = function (frame, options) {
}, options); }, options);
var isSmoothScrollSupported = 'scrollBehavior' in document.documentElement.style; const isSmoothScrollSupported = 'scrollBehavior' in document.documentElement.style;
// native scroll is a must with touch input // native scroll is a must with touch input
// also use native scroll when scrolling vertically in desktop mode - excluding horizontal because the mouse wheel support is choppy at the moment // also use native scroll when scrolling vertically in desktop mode - excluding horizontal because the mouse wheel support is choppy at the moment
@ -106,11 +106,11 @@ var scrollerFactory = function (frame, options) {
} }
// Private variables // Private variables
var self = this; const self = this;
self.options = o; self.options = o;
// Frame // Frame
var slideeElement = o.slidee ? o.slidee : sibling(frame.firstChild)[0]; const slideeElement = o.slidee ? o.slidee : sibling(frame.firstChild)[0];
self._pos = { self._pos = {
start: 0, start: 0,
center: 0, center: 0,
@ -119,15 +119,15 @@ var scrollerFactory = function (frame, options) {
dest: 0 dest: 0
}; };
var transform = !options.enableNativeScroll; const transform = !options.enableNativeScroll;
// Miscellaneous // Miscellaneous
var scrollSource = frame; const scrollSource = frame;
var dragSourceElement = o.dragSource ? o.dragSource : frame; const dragSourceElement = o.dragSource ? o.dragSource : frame;
var dragging = { const dragging = {
released: 1 released: 1
}; };
var scrolling = { const scrolling = {
last: 0, last: 0,
delta: 0, delta: 0,
resetTime: 200 resetTime: 200
@ -139,10 +139,10 @@ var scrollerFactory = function (frame, options) {
self.options = o; self.options = o;
self.dragging = dragging; self.dragging = dragging;
var nativeScrollElement = frame; const nativeScrollElement = frame;
function sibling(n, elem) { function sibling(n, elem) {
var matched = []; const matched = [];
for (; n; n = n.nextSibling) { for (; n; n = n.nextSibling) {
if (n.nodeType === 1 && n !== elem) { if (n.nodeType === 1 && n !== elem) {
@ -152,10 +152,10 @@ var scrollerFactory = function (frame, options) {
return matched; return matched;
} }
var requiresReflow = true; let requiresReflow = true;
var frameSize = 0; let frameSize = 0;
var slideeSize = 0; let slideeSize = 0;
function ensureSizeInfo() { function ensureSizeInfo() {
if (requiresReflow) { if (requiresReflow) {
requiresReflow = false; requiresReflow = false;
@ -185,13 +185,13 @@ var scrollerFactory = function (frame, options) {
ensureSizeInfo(); ensureSizeInfo();
// Fix possible overflowing // Fix possible overflowing
var pos = self._pos; const pos = self._pos;
self.slideTo(within(pos.dest, pos.start, pos.end)); self.slideTo(within(pos.dest, pos.start, pos.end));
} }
} }
function initFrameResizeObserver() { function initFrameResizeObserver() {
var observerOptions = {}; const observerOptions = {};
self.frameResizeObserver = new ResizeObserver(onResize, observerOptions); self.frameResizeObserver = new ResizeObserver(onResize, observerOptions);
@ -242,7 +242,7 @@ var scrollerFactory = function (frame, options) {
} }
} }
var lastAnimate; let lastAnimate;
/** /**
* Animate to a position. * Animate to a position.
@ -254,7 +254,7 @@ var scrollerFactory = function (frame, options) {
*/ */
self.slideTo = function (newPos, immediate, fullItemPos) { self.slideTo = function (newPos, immediate, fullItemPos) {
ensureSizeInfo(); ensureSizeInfo();
var pos = self._pos; const pos = self._pos;
if (layoutManager.tv) { if (layoutManager.tv) {
newPos = within(newPos, pos.start); newPos = within(newPos, pos.start);
@ -268,10 +268,10 @@ var scrollerFactory = function (frame, options) {
} }
// Update the animation object // Update the animation object
var from = pos.cur; const from = pos.cur;
immediate = immediate || dragging.init || !o.speed; immediate = immediate || dragging.init || !o.speed;
var now = new Date().getTime(); const now = new Date().getTime();
if (o.autoImmediate) { if (o.autoImmediate) {
if (!immediate && (now - (lastAnimate || 0)) <= 50) { if (!immediate && (now - (lastAnimate || 0)) <= 50) {
@ -291,7 +291,7 @@ var scrollerFactory = function (frame, options) {
}; };
function setStyleProperty(elem, name, value, speed, resetTransition) { function setStyleProperty(elem, name, value, speed, resetTransition) {
var style = elem.style; const style = elem.style;
if (resetTransition || browser.edge) { if (resetTransition || browser.edge) {
style.transition = 'none'; style.transition = 'none';
@ -312,7 +312,7 @@ var scrollerFactory = function (frame, options) {
} }
function renderAnimateWithTransform(fromPosition, toPosition, immediate) { function renderAnimateWithTransform(fromPosition, toPosition, immediate) {
var speed = o.speed; let speed = o.speed;
if (immediate) { if (immediate) {
speed = o.immediateSpeed || 50; speed = o.immediateSpeed || 50;
@ -346,18 +346,18 @@ var scrollerFactory = function (frame, options) {
* @return {Object} * @return {Object}
*/ */
self.getPos = function (item) { self.getPos = function (item) {
var scrollElement = transform ? slideeElement : nativeScrollElement; const scrollElement = transform ? slideeElement : nativeScrollElement;
var slideeOffset = getBoundingClientRect(scrollElement); const slideeOffset = getBoundingClientRect(scrollElement);
var itemOffset = getBoundingClientRect(item); const itemOffset = getBoundingClientRect(item);
var offset = o.horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top; let offset = o.horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top;
var size = o.horizontal ? itemOffset.width : itemOffset.height; let size = o.horizontal ? itemOffset.width : itemOffset.height;
if (!size && size !== 0) { if (!size && size !== 0) {
size = item[o.horizontal ? 'offsetWidth' : 'offsetHeight']; size = item[o.horizontal ? 'offsetWidth' : 'offsetHeight'];
} }
var centerOffset = o.centerOffset || 0; let centerOffset = o.centerOffset || 0;
if (!transform) { if (!transform) {
centerOffset = 0; centerOffset = 0;
@ -370,11 +370,11 @@ var scrollerFactory = function (frame, options) {
ensureSizeInfo(); ensureSizeInfo();
var currentStart = self._pos.cur; const currentStart = self._pos.cur;
var currentEnd = currentStart + frameSize; const currentEnd = currentStart + frameSize;
console.debug('offset:' + offset + ' currentStart:' + currentStart + ' currentEnd:' + currentEnd); console.debug('offset:' + offset + ' currentStart:' + currentStart + ' currentEnd:' + currentEnd);
var isVisible = offset >= currentStart && (offset + size) <= currentEnd; const isVisible = offset >= currentStart && (offset + size) <= currentEnd;
return { return {
start: offset, start: offset,
@ -388,12 +388,12 @@ var scrollerFactory = function (frame, options) {
self.getCenterPosition = function (item) { self.getCenterPosition = function (item) {
ensureSizeInfo(); ensureSizeInfo();
var pos = self.getPos(item); const pos = self.getPos(item);
return within(pos.center, pos.start, pos.end); return within(pos.center, pos.start, pos.end);
}; };
function dragInitSlidee(event) { function dragInitSlidee(event) {
var isTouch = event.type === 'touchstart'; const isTouch = event.type === 'touchstart';
// Ignore when already in progress, or interactive element in non-touch navivagion // Ignore when already in progress, or interactive element in non-touch navivagion
if (dragging.init || !isTouch && isInteractive(event.target)) { if (dragging.init || !isTouch && isInteractive(event.target)) {
@ -417,7 +417,7 @@ var scrollerFactory = function (frame, options) {
dragging.init = 0; dragging.init = 0;
dragging.source = event.target; dragging.source = event.target;
dragging.touch = isTouch; dragging.touch = isTouch;
var pointer = isTouch ? event.touches[0] : event; const pointer = isTouch ? event.touches[0] : event;
dragging.initX = pointer.pageX; dragging.initX = pointer.pageX;
dragging.initY = pointer.pageY; dragging.initY = pointer.pageY;
dragging.initPos = self._pos.cur; dragging.initPos = self._pos.cur;
@ -455,7 +455,7 @@ var scrollerFactory = function (frame, options) {
*/ */
function dragHandler(event) { function dragHandler(event) {
dragging.released = event.type === 'mouseup' || event.type === 'touchend'; dragging.released = event.type === 'mouseup' || event.type === 'touchend';
var pointer = dragging.touch ? event[dragging.released ? 'changedTouches' : 'touches'][0] : event; const pointer = dragging.touch ? event[dragging.released ? 'changedTouches' : 'touches'][0] : event;
dragging.pathX = pointer.pageX - dragging.initX; dragging.pathX = pointer.pageX - dragging.initX;
dragging.pathY = pointer.pageY - dragging.initY; dragging.pathY = pointer.pageY - dragging.initY;
dragging.path = Math.sqrt(Math.pow(dragging.pathX, 2) + Math.pow(dragging.pathY, 2)); dragging.path = Math.sqrt(Math.pow(dragging.pathX, 2) + Math.pow(dragging.pathY, 2));
@ -570,12 +570,12 @@ var scrollerFactory = function (frame, options) {
*/ */
function scrollHandler(event) { function scrollHandler(event) {
ensureSizeInfo(); ensureSizeInfo();
var pos = self._pos; const pos = self._pos;
// Ignore if there is no scrolling to be done // Ignore if there is no scrolling to be done
if (!o.scrollBy || pos.start === pos.end) { if (!o.scrollBy || pos.start === pos.end) {
return; return;
} }
var delta = normalizeWheelDelta(event); let delta = normalizeWheelDelta(event);
if (transform) { if (transform) {
// Trap scrolling only when necessary and/or requested // Trap scrolling only when necessary and/or requested
@ -635,13 +635,13 @@ var scrollerFactory = function (frame, options) {
return self; return self;
}; };
var contentRect = {}; let contentRect = {};
function onResize(entries) { function onResize(entries) {
var entry = entries[0]; const entry = entries[0];
if (entry) { if (entry) {
var newRect = entry.contentRect; const newRect = entry.contentRect;
// handle element being hidden // handle element being hidden
if (newRect.width === 0 || newRect.height === 0) { if (newRect.width === 0 || newRect.height === 0) {
@ -666,7 +666,7 @@ var scrollerFactory = function (frame, options) {
function onFrameClick(e) { function onFrameClick(e) {
if (e.which === 1) { if (e.which === 1) {
var focusableParent = focusManager.focusableParent(e.target); const focusableParent = focusManager.focusableParent(e.target);
if (focusableParent && focusableParent !== document.activeElement) { if (focusableParent && focusableParent !== document.activeElement) {
focusableParent.focus(); focusableParent.focus();
} }
@ -838,7 +838,7 @@ scrollerFactory.prototype.to = function (location, item, immediate) {
if (item === undefined) { if (item === undefined) {
this.slideTo(this._pos[location], immediate); this.slideTo(this._pos[location], immediate);
} else { } else {
var itemPos = this.getPos(item); const itemPos = this.getPos(item);
if (itemPos) { if (itemPos) {
this.slideTo(itemPos[location], immediate, itemPos); this.slideTo(itemPos[location], immediate, itemPos);
@ -883,7 +883,7 @@ scrollerFactory.prototype.toCenter = function (item, immediate) {
}; };
scrollerFactory.create = function (frame, options) { scrollerFactory.create = function (frame, options) {
var instance = new scrollerFactory(frame, options); const instance = new scrollerFactory(frame, options);
return Promise.resolve(instance); return Promise.resolve(instance);
}; };

View file

@ -1,3 +1,4 @@
import browser from 'browser';
import loading from 'loading'; import loading from 'loading';
import keyboardnavigation from 'keyboardnavigation'; import keyboardnavigation from 'keyboardnavigation';
import dialogHelper from 'dialogHelper'; import dialogHelper from 'dialogHelper';
@ -18,12 +19,15 @@ export class BookPlayer {
this.onDialogClosed = this.onDialogClosed.bind(this); this.onDialogClosed = this.onDialogClosed.bind(this);
this.openTableOfContents = this.openTableOfContents.bind(this); this.openTableOfContents = this.openTableOfContents.bind(this);
this.prevChapter = this.prevChapter.bind(this);
this.nextChapter = this.nextChapter.bind(this);
this.onWindowKeyUp = this.onWindowKeyUp.bind(this); this.onWindowKeyUp = this.onWindowKeyUp.bind(this);
} }
play(options) { play(options) {
this._progress = 0; this.progress = 0;
this._loaded = false; this.cancellationToken = false;
this.loaded = false;
loading.show(); loading.show();
const elem = this.createMediaElement(); const elem = this.createMediaElement();
@ -33,35 +37,35 @@ export class BookPlayer {
stop() { stop() {
this.unbindEvents(); this.unbindEvents();
const elem = this._mediaElement; const elem = this.mediaElement;
const tocElement = this._tocElement; const tocElement = this.tocElement;
const rendition = this._rendition; const rendition = this.rendition;
if (elem) { if (elem) {
dialogHelper.close(elem); dialogHelper.close(elem);
this._mediaElement = null; this.mediaElement = null;
} }
if (tocElement) { if (tocElement) {
tocElement.destroy(); tocElement.destroy();
this._tocElement = null; this.tocElement = null;
} }
if (rendition) { if (rendition) {
rendition.destroy(); rendition.destroy();
} }
// Hide loader in case player was not fully loaded yet // hide loader in case player was not fully loaded yet
loading.hide(); loading.hide();
this._cancellationToken.shouldCancel = true; this.cancellationToken = true;
} }
currentItem() { currentItem() {
return this._currentItem; return this.item;
} }
currentTime() { currentTime() {
return this._progress * 1000; return this.progress * 1000;
} }
duration() { duration() {
@ -93,12 +97,10 @@ export class BookPlayer {
onWindowKeyUp(e) { onWindowKeyUp(e) {
const key = keyboardnavigation.getKeyName(e); const key = keyboardnavigation.getKeyName(e);
const rendition = this.rendition;
// TODO: depending on the event this can be the document or the rendition itself
const rendition = this._rendition || this;
const book = rendition.book; const book = rendition.book;
if (this._loaded === false) return; if (!this.loaded) return;
switch (key) { switch (key) {
case 'l': case 'l':
case 'ArrowRight': case 'ArrowRight':
@ -111,9 +113,9 @@ export class BookPlayer {
book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev(); book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev();
break; break;
case 'Escape': case 'Escape':
if (this._tocElement) { if (this.tocElement) {
// Close table of contents on ESC if it is open // Close table of contents on ESC if it is open
this._tocElement.destroy(); this.tocElement.destroy();
} else { } else {
// Otherwise stop the entire book player // Otherwise stop the entire book player
this.stop(); this.stop();
@ -122,79 +124,73 @@ export class BookPlayer {
} }
} }
onTouchStart(e) {
// TODO: depending on the event this can be the document or the rendition itself
const rendition = this._rendition || this;
const book = rendition.book;
// check that the event is from the book or the document
if (!book || this._loaded === false) return;
// epubjs stores pages off the screen or something for preloading
// get the modulus of the touch event to account for the increased width
if (!e.touches || e.touches.length === 0) return;
const touch = e.touches[0].clientX % dom.getWindowSize().innerWidth;
if (touch < dom.getWindowSize().innerWidth / 2) {
book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev();
} else {
book.package.metadata.direction === 'rtl' ? rendition.prev() : rendition.next();
}
}
onDialogClosed() { onDialogClosed() {
this.stop(); this.stop();
} }
bindMediaElementEvents() { bindMediaElementEvents() {
const elem = this._mediaElement; const elem = this.mediaElement;
elem.addEventListener('close', this.onDialogClosed, {once: true}); elem.addEventListener('close', this.onDialogClosed, {once: true});
elem.querySelector('.btnBookplayerExit').addEventListener('click', this.onDialogClosed, {once: true}); elem.querySelector('#btnBookplayerExit').addEventListener('click', this.onDialogClosed, {once: true});
elem.querySelector('.btnBookplayerToc').addEventListener('click', this.openTableOfContents); elem.querySelector('#btnBookplayerToc').addEventListener('click', this.openTableOfContents);
if (browser.mobile) {
elem.querySelector('#btnBookplayerPrev').addEventListener('click', this.prevChapter);
elem.querySelector('#btnBookplayerNext').addEventListener('click', this.nextChapter);
}
} }
bindEvents() { bindEvents() {
this.bindMediaElementEvents(); this.bindMediaElementEvents();
document.addEventListener('keyup', this.onWindowKeyUp); document.addEventListener('keyup', this.onWindowKeyUp);
document.addEventListener('touchstart', this.onTouchStart);
// FIXME: I don't really get why document keyup event is not triggered when epub is in focus // FIXME: I don't really get why document keyup event is not triggered when epub is in focus
this._rendition.on('keyup', this.onWindowKeyUp); this.rendition.on('keyup', this.onWindowKeyUp);
this._rendition.on('touchstart', this.onTouchStart);
} }
unbindMediaElementEvents() { unbindMediaElementEvents() {
const elem = this._mediaElement; const elem = this.mediaElement;
elem.removeEventListener('close', this.onDialogClosed); elem.removeEventListener('close', this.onDialogClosed);
elem.querySelector('.btnBookplayerExit').removeEventListener('click', this.onDialogClosed); elem.querySelector('#btnBookplayerExit').removeEventListener('click', this.onDialogClosed);
elem.querySelector('.btnBookplayerToc').removeEventListener('click', this.openTableOfContents); elem.querySelector('#btnBookplayerToc').removeEventListener('click', this.openTableOfContents);
if (browser.mobile) {
elem.querySelector('#btnBookplayerPrev').removeEventListener('click', this.prevChapter);
elem.querySelector('#btnBookplayerNext').removeEventListener('click', this.nextChapter);
}
} }
unbindEvents() { unbindEvents() {
if (this._mediaElement) { if (this.mediaElement) {
this.unbindMediaElementEvents(); this.unbindMediaElementEvents();
} }
document.removeEventListener('keyup', this.onWindowKeyUp); document.removeEventListener('keyup', this.onWindowKeyUp);
document.removeEventListener('touchstart', this.onTouchStart);
if (this._rendition) { if (this.rendition) {
this._rendition.off('keyup', this.onWindowKeyUp); this.rendition.off('keyup', this.onWindowKeyUp);
this._rendition.off('touchstart', this.onTouchStart);
} }
} }
openTableOfContents() { openTableOfContents() {
if (this._loaded) { if (this.loaded) {
this._tocElement = new TableOfContents(this); this.tocElement = new TableOfContents(this);
} }
} }
prevChapter(e) {
this._rendition.prev();
e.preventDefault();
}
nextChapter(e) {
this._rendition.next();
e.preventDefault();
}
createMediaElement() { createMediaElement() {
let elem = this._mediaElement; let elem = this.mediaElement;
if (elem) { if (elem) {
return elem; return elem;
} }
@ -210,29 +206,51 @@ export class BookPlayer {
removeOnClose: true removeOnClose: true
}); });
elem.id = 'bookPlayer';
let html = ''; let html = '';
html += '<div class="topRightActionButtons">';
html += '<button is="paper-icon-button-light" class="autoSize bookplayerButton btnBookplayerExit hide-mouse-idle-tv" tabindex="-1"><i class="material-icons bookplayerButtonIcon close"></i></button>'; if (browser.mobile) {
html += '<div class="button-wrapper top-button"><button id="btnBookplayerPrev" is="paper-icon-button-light" class="autoSize bookplayerButton hide-mouse-idle-tv"><i class="material-icons bookplayerButtonIcon navigate_before"></i> Prev</button></div>';
}
html += '<div id="viewer">';
html += '<div class="topButtons">';
html += '<button is="paper-icon-button-light" id="btnBookplayerToc" class="autoSize bookplayerButton hide-mouse-idle-tv" tabindex="-1"><i class="material-icons bookplayerButtonIcon toc"></i></button>';
html += '<button is="paper-icon-button-light" id="btnBookplayerExit" class="autoSize bookplayerButton hide-mouse-idle-tv" tabindex="-1"><i class="material-icons bookplayerButtonIcon close"></i></button>';
html += '</div>'; html += '</div>';
html += '<div class="topLeftActionButtons">';
html += '<button is="paper-icon-button-light" class="autoSize bookplayerButton btnBookplayerToc hide-mouse-idle-tv" tabindex="-1"><i class="material-icons bookplayerButtonIcon toc"></i></button>';
html += '</div>'; html += '</div>';
if (browser.mobile) {
html += '<div class="button-wrapper bottom-button"><button id="btnBookplayerNext" is="paper-icon-button-light" class="autoSize bookplayerButton hide-mouse-idle-tv">Next <i class="material-icons bookplayerButtonIcon navigate_next"></i></button></div>';
}
elem.id = 'bookPlayer';
elem.innerHTML = html; elem.innerHTML = html;
dialogHelper.open(elem); dialogHelper.open(elem);
} }
this._mediaElement = elem; this.mediaElement = elem;
return elem; return elem;
} }
render(elem, book) {
if (browser.mobile) {
return book.renderTo(elem, {
width: '100%',
height: '100%',
flow: 'scrolled-doc'
});
} else {
return book.renderTo(elem, {
width: '100%',
height: '100%'
});
}
}
setCurrentSrc(elem, options) { setCurrentSrc(elem, options) {
const item = options.items[0]; const item = options.items[0];
this._currentItem = item; this.item = item;
this.streamInfo = { this.streamInfo = {
started: true, started: true,
ended: false, ended: false,
@ -248,15 +266,10 @@ export class BookPlayer {
import('epubjs').then(({default: epubjs}) => { import('epubjs').then(({default: epubjs}) => {
const downloadHref = apiClient.getItemDownloadUrl(item.Id); const downloadHref = apiClient.getItemDownloadUrl(item.Id);
const book = epubjs(downloadHref, {openAs: 'epub'}); const book = epubjs(downloadHref, {openAs: 'epub'});
const rendition = book.renderTo(elem, {width: '100%', height: '97%'}); const rendition = this.render('viewer', book);
this._currentSrc = downloadHref; this.currentSrc = downloadHref;
this._rendition = rendition; this.rendition = rendition;
const cancellationToken = {
shouldCancel: false
};
this._cancellationToken = cancellationToken;
return rendition.display().then(() => { return rendition.display().then(() => {
const epubElem = document.querySelector('.epub-container'); const epubElem = document.querySelector('.epub-container');
@ -264,10 +277,8 @@ export class BookPlayer {
this.bindEvents(); this.bindEvents();
return this._rendition.book.locations.generate(1024).then(async () => { return this.rendition.book.locations.generate(1024).then(async () => {
if (cancellationToken.shouldCancel) { if (this.cancellationToken) reject();
return reject();
}
const percentageTicks = options.startPositionTicks / 10000000; const percentageTicks = options.startPositionTicks / 10000000;
if (percentageTicks !== 0.0) { if (percentageTicks !== 0.0) {
@ -275,15 +286,14 @@ export class BookPlayer {
await rendition.display(resumeLocation); await rendition.display(resumeLocation);
} }
this._loaded = true; this.loaded = true;
epubElem.style.display = 'block'; epubElem.style.display = 'block';
rendition.on('relocated', (locations) => { rendition.on('relocated', (locations) => {
this._progress = book.locations.percentageFromCfi(locations.start.cfi); this.progress = book.locations.percentageFromCfi(locations.start.cfi);
events.trigger(this, 'timeupdate'); events.trigger(this, 'timeupdate');
}); });
loading.hide(); loading.hide();
return resolve(); return resolve();
}); });
}, () => { }, () => {
@ -299,7 +309,7 @@ export class BookPlayer {
} }
canPlayItem(item) { canPlayItem(item) {
if (item.Path && (item.Path.endsWith('epub'))) { if (item.Path && item.Path.endsWith('epub')) {
return true; return true;
} }

View file

@ -7,18 +7,20 @@
background: #fff; background: #fff;
} }
.topRightActionButtons { .topButtons {
right: 0.5vh;
top: 0.5vh; top: 0.5vh;
z-index: 1002; z-index: 1002;
position: absolute; position: sticky;
} }
.topLeftActionButtons { #btnBookplayerToc {
left: 0.5vh; float: left;
top: 0.5vh; margin-left: 2vw;
z-index: 1002; }
position: absolute;
#btnBookplayerExit {
float: right;
margin-right: 2vw;
} }
.bookplayerButtonIcon { .bookplayerButtonIcon {
@ -37,3 +39,31 @@
.bookplayerErrorMsg { .bookplayerErrorMsg {
text-align: center; text-align: center;
} }
#viewer {
align-items: flex-start;
}
#btnBookplayerPrev {
margin: 0.5vh 0.5vh;
color: black;
}
#btnBookplayerNext {
margin: 0.5vh 0.5vh;
color: black;
}
.button-wrapper {
text-align: center;
position: relative;
height: 0;
}
.top-button {
margin: 0.5vh 2em;
}
.bottom-button {
margin: 2em 0.5vh;
}

View file

@ -2,8 +2,8 @@ import dialogHelper from 'dialogHelper';
export default class TableOfContents { export default class TableOfContents {
constructor(bookPlayer) { constructor(bookPlayer) {
this._bookPlayer = bookPlayer; this.bookPlayer = bookPlayer;
this._rendition = bookPlayer._rendition; this.rendition = bookPlayer.rendition;
this.onDialogClosed = this.onDialogClosed.bind(this); this.onDialogClosed = this.onDialogClosed.bind(this);
@ -11,24 +11,24 @@ export default class TableOfContents {
} }
destroy() { destroy() {
const elem = this._elem; const elem = this.elem;
if (elem) { if (elem) {
this.unbindEvents(); this.unbindEvents();
dialogHelper.close(elem); dialogHelper.close(elem);
} }
this._bookPlayer._tocElement = null; this.bookPlayer.tocElement = null;
} }
bindEvents() { bindEvents() {
const elem = this._elem; const elem = this.elem;
elem.addEventListener('close', this.onDialogClosed, {once: true}); elem.addEventListener('close', this.onDialogClosed, {once: true});
elem.querySelector('.btnBookplayerTocClose').addEventListener('click', this.onDialogClosed, {once: true}); elem.querySelector('.btnBookplayerTocClose').addEventListener('click', this.onDialogClosed, {once: true});
} }
unbindEvents() { unbindEvents() {
const elem = this._elem; const elem = this.elem;
elem.removeEventListener('close', this.onDialogClosed); elem.removeEventListener('close', this.onDialogClosed);
elem.querySelector('.btnBookplayerTocClose').removeEventListener('click', this.onDialogClosed); elem.querySelector('.btnBookplayerTocClose').removeEventListener('click', this.onDialogClosed);
@ -52,7 +52,7 @@ export default class TableOfContents {
} }
createMediaElement() { createMediaElement() {
const rendition = this._rendition; const rendition = this.rendition;
const elem = dialogHelper.createDialog({ const elem = dialogHelper.createDialog({
size: 'small', size: 'small',
@ -68,7 +68,8 @@ export default class TableOfContents {
tocHtml += '<ul class="toc">'; tocHtml += '<ul class="toc">';
rendition.book.navigation.forEach((chapter) => { rendition.book.navigation.forEach((chapter) => {
tocHtml += '<li>'; tocHtml += '<li>';
// Remove '../' from href
// remove parent directory reference from href to fix certain books
const link = chapter.href.startsWith('../') ? chapter.href.substr(3) : chapter.href; const link = chapter.href.startsWith('../') ? chapter.href.substr(3) : chapter.href;
tocHtml += `<a href="${rendition.book.path.directory + link}">${chapter.label}</a>`; tocHtml += `<a href="${rendition.book.path.directory + link}">${chapter.label}</a>`;
tocHtml += '</li>'; tocHtml += '</li>';
@ -83,7 +84,7 @@ export default class TableOfContents {
this.destroy(); this.destroy();
}); });
this._elem = elem; this.elem = elem;
this.bindEvents(); this.bindEvents();
dialogHelper.open(elem); dialogHelper.open(elem);

View file

@ -103,7 +103,7 @@ export class ComicsPlayer {
const downloadUrl = apiClient.getItemDownloadUrl(item.Id); const downloadUrl = apiClient.getItemDownloadUrl(item.Id);
const archiveSource = new ArchiveSource(downloadUrl); const archiveSource = new ArchiveSource(downloadUrl);
var instance = this; const instance = this;
import('swiper').then(({default: Swiper}) => { import('swiper').then(({default: Swiper}) => {
archiveSource.load().then(() => { archiveSource.load().then(() => {
loading.hide(); loading.hide();

View file

@ -114,7 +114,6 @@ function tryRemoveElement(elem) {
return new Promise(resolve => { return new Promise(resolve => {
const duration = 240; const duration = 240;
elem.style.animation = `htmlvideoplayer-zoomin ${duration}ms ease-in normal`; elem.style.animation = `htmlvideoplayer-zoomin ${duration}ms ease-in normal`;
hidePrePlaybackPage();
dom.addEventListener(elem, dom.whichAnimationEvent(), resolve, { dom.addEventListener(elem, dom.whichAnimationEvent(), resolve, {
once: true once: true
}); });
@ -1329,17 +1328,24 @@ function tryRemoveElement(elem) {
this.#videoDialog = dlg; this.#videoDialog = dlg;
this.#mediaElement = videoElement; this.#mediaElement = videoElement;
if (options.fullscreen) {
hidePrePlaybackPage();
}
// don't animate on smart tv's, too slow // don't animate on smart tv's, too slow
if (options.fullscreen && browser.supportsCssAnimation() && !browser.slow) { if (options.fullscreen && browser.supportsCssAnimation() && !browser.slow) {
return zoomIn(dlg).then(function () { return zoomIn(dlg).then(function () {
return videoElement; return videoElement;
}); });
} else { } else {
hidePrePlaybackPage();
return videoElement; return videoElement;
} }
}); });
} else { } else {
if (options.fullscreen) {
hidePrePlaybackPage();
}
return Promise.resolve(dlg.querySelector('video')); return Promise.resolve(dlg.querySelector('video'));
} }
} }

View file

@ -17,7 +17,11 @@
order: -1; order: -1;
} }
video::-webkit-media-controls { /* Controls are enabled for devices that don't support autoplay. They will be hidden when playback starts.
In Tizen 2.3 (and probably other old web engines), subtitles are located under '-webkit-media-controls' tree.
Therefore, we hide controls only if they are enabled.
*/
video[controls]::-webkit-media-controls {
display: none !important; display: none !important;
} }

View file

@ -0,0 +1,306 @@
import loading from 'loading';
import keyboardnavigation from 'keyboardnavigation';
import dialogHelper from 'dialogHelper';
import dom from 'dom';
import appRouter from 'appRouter';
import events from 'events';
import 'css!./style';
import 'material-icons';
import 'paper-icon-button-light';
export class PdfPlayer {
constructor() {
this.name = 'PDF Player';
this.type = 'mediaplayer';
this.id = 'pdfplayer';
this.priority = 1;
this.onDialogClosed = this.onDialogClosed.bind(this);
this.onWindowKeyUp = this.onWindowKeyUp.bind(this);
this.onTouchStart = this.onTouchStart.bind(this);
}
play(options) {
this.progress = 0;
this.loaded = false;
this.cancellationToken = false;
this.pages = {};
loading.show();
const elem = this.createMediaElement();
return this.setCurrentSrc(elem, options);
}
stop() {
this.unbindEvents();
const elem = this.mediaElement;
if (elem) {
dialogHelper.close(elem);
this.mediaElement = null;
}
// hide loading animation
loading.hide();
// cancel page render
this.cancellationToken = true;
}
currentItem() {
return this.item;
}
currentTime() {
return this.progress;
}
duration() {
return this.book ? this.book.numPages : 0;
}
volume() {
return 100;
}
isMuted() {
return false;
}
paused() {
return false;
}
seekable() {
return true;
}
onWindowKeyUp(e) {
const key = keyboardnavigation.getKeyName(e);
if (!this.loaded) return;
switch (key) {
case 'l':
case 'ArrowRight':
case 'Right':
this.next();
break;
case 'j':
case 'ArrowLeft':
case 'Left':
this.previous();
break;
case 'Escape':
this.stop();
break;
}
}
onTouchStart(e) {
if (!this.loaded || !e.touches || e.touches.length === 0) return;
if (e.touches[0].clientX < dom.getWindowSize().innerWidth / 2) {
this.previous();
} else {
this.next();
}
}
onDialogClosed() {
this.stop();
}
bindMediaElementEvents() {
const elem = this.mediaElement;
elem.addEventListener('close', this.onDialogClosed, {once: true});
elem.querySelector('.btnExit').addEventListener('click', this.onDialogClosed, {once: true});
}
bindEvents() {
this.bindMediaElementEvents();
document.addEventListener('keyup', this.onWindowKeyUp);
document.addEventListener('touchstart', this.onTouchStart);
}
unbindMediaElementEvents() {
const elem = this.mediaElement;
elem.removeEventListener('close', this.onDialogClosed);
elem.querySelector('.btnExit').removeEventListener('click', this.onDialogClosed);
}
unbindEvents() {
if (this.mediaElement) {
this.unbindMediaElementEvents();
}
document.removeEventListener('keyup', this.onWindowKeyUp);
document.removeEventListener('touchstart', this.onTouchStart);
}
createMediaElement() {
let elem = this.mediaElement;
if (elem) {
return elem;
}
elem = document.getElementById('pdfPlayer');
if (!elem) {
elem = dialogHelper.createDialog({
exitAnimationDuration: 400,
size: 'fullscreen',
autoFocus: false,
scrollY: false,
exitAnimation: 'fadeout',
removeOnClose: true
});
let html = '';
html += '<canvas id="canvas"></canvas>';
html += '<div class="actionButtons">';
html += '<button is="paper-icon-button-light" class="autoSize btnExit" tabindex="-1"><i class="material-icons actionButtonIcon close"></i></button>';
html += '</div>';
elem.id = 'pdfPlayer';
elem.innerHTML = html;
dialogHelper.open(elem);
}
this.mediaElement = elem;
return elem;
}
setCurrentSrc(elem, options) {
const item = options.items[0];
this.item = item;
this.streamInfo = {
started: true,
ended: false,
mediaSource: {
Id: item.Id
}
};
const serverId = item.ServerId;
const apiClient = window.connectionManager.getApiClient(serverId);
return new Promise((resolve, reject) => {
import('pdfjs').then(({default: pdfjs}) => {
const downloadHref = apiClient.getItemDownloadUrl(item.Id);
this.bindEvents();
pdfjs.GlobalWorkerOptions.workerSrc = appRouter.baseUrl() + '/libraries/pdf.worker.js';
const downloadTask = pdfjs.getDocument(downloadHref);
downloadTask.promise.then(book => {
if (this.cancellationToken) return;
this.book = book;
this.loaded = true;
const percentageTicks = options.startPositionTicks / 10000;
if (percentageTicks !== 0) {
this.loadPage(percentageTicks);
this.progress = percentageTicks;
} else {
this.loadPage(1);
}
return resolve();
});
});
});
}
next() {
if (this.progress === this.duration() - 1) return;
this.loadPage(this.progress + 2);
this.progress = this.progress + 1;
}
previous() {
if (this.progress === 0) return;
this.loadPage(this.progress);
this.progress = this.progress - 1;
}
replaceCanvas(canvas) {
const old = document.getElementById('canvas');
canvas.id = 'canvas';
old.parentNode.replaceChild(canvas, old);
}
loadPage(number) {
const prefix = 'page';
const pad = 2;
// generate list of cached pages by padding the requested page on both sides
const pages = [prefix + number];
for (let i = 1; i <= pad; i++) {
if (number - i > 0) pages.push(prefix + (number - i));
if (number + i < this.duration()) pages.push(prefix + (number + i));
}
// load any missing pages in the cache
for (const page of pages) {
if (!this.pages[page]) {
this.pages[page] = document.createElement('canvas');
this.renderPage(this.pages[page], parseInt(page.substr(4)));
}
}
// show the requested page
this.replaceCanvas(this.pages[prefix + number], number);
// delete all pages outside the cache area
for (const page in this.pages) {
if (!pages.includes(page)) {
delete this.pages[page];
}
}
}
renderPage(canvas, number) {
this.book.getPage(number).then(page => {
events.trigger(this, 'timeupdate');
const original = page.getViewport({ scale: 1 });
const context = canvas.getContext('2d');
const widthRatio = dom.getWindowSize().innerWidth / original.width;
const heightRatio = dom.getWindowSize().innerHeight / original.height;
const scale = Math.min(heightRatio, widthRatio);
const viewport = page.getViewport({ scale: scale });
canvas.width = viewport.width;
canvas.height = viewport.height;
const renderContext = {
canvasContext: context,
viewport: viewport
};
const renderTask = page.render(renderContext);
renderTask.promise.then(() => {
loading.hide();
});
});
}
canPlayMediaType(mediaType) {
return (mediaType || '').toLowerCase() === 'book';
}
canPlayItem(item) {
if (item.Path && item.Path.endsWith('pdf')) {
return true;
}
return false;
}
}
export default PdfPlayer;

View file

@ -0,0 +1,25 @@
#pdfPlayer {
position: relative;
height: 100%;
width: 100%;
overflow: none;
z-index: 100;
background: #fff;
}
#canvas {
display: block;
margin: auto;
}
.actionButtons {
right: 0.5vh;
top: 0.5vh;
z-index: 1002;
position: absolute;
}
.actionButtonIcon {
color: black;
opacity: 0.7;
}

View file

@ -10,11 +10,11 @@ export default class PhotoPlayer {
play(options) { play(options) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
import('slideshow').then(({default: slideshow}) => { import('slideshow').then(({default: slideshow}) => {
var index = options.startIndex || 0; const index = options.startIndex || 0;
var apiClient = window.connectionManager.currentApiClient(); const apiClient = window.connectionManager.currentApiClient();
apiClient.getCurrentUser().then(function(result) { apiClient.getCurrentUser().then(function(result) {
var newSlideShow = new slideshow({ const newSlideShow = new slideshow({
showTitle: false, showTitle: false,
cover: false, cover: false,
items: options.items, items: options.items,

View file

@ -1,15 +1,26 @@
import * as userSettings from 'userSettings'; import * as userSettings from 'userSettings';
import * as webSettings from 'webSettings';
import skinManager from 'skinManager'; import skinManager from 'skinManager';
import events from 'events'; import events from 'events';
// Set the default theme when loading // set the default theme when loading
skinManager.setTheme(userSettings.theme()) skinManager.setTheme(userSettings.theme())
/* This keeps the scrollbar always present in all pages, so we avoid clipping while switching between pages /* this keeps the scrollbar always present in all pages, so we avoid clipping while switching between pages
that need the scrollbar and pages that don't. that need the scrollbar and pages that don't.
*/ */
.then(() => document.body.classList.add('force-scroll')); .then(() => document.body.classList.add('force-scroll'));
// Set the user's prefered theme when signing in // set the saved theme once a user authenticates
events.on(window.connectionManager, 'localusersignedin', function (e, user) { events.on(window.connectionManager, 'localusersignedin', function (e, user) {
skinManager.setTheme(userSettings.theme()); skinManager.setTheme(userSettings.theme());
}); });
webSettings.getFonts().then(fonts => {
for (const font of fonts) {
const link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.href = font;
document.getElementsByTagName('head')[0].appendChild(link);
}
});

View file

@ -32,7 +32,7 @@ function onOpen() {
const playerId = localStorage.getItem('autocastPlayerId'); const playerId = localStorage.getItem('autocastPlayerId');
playbackManager.getTargets().then(function (targets) { playbackManager.getTargets().then(function (targets) {
for (var i = 0; i < targets.length; i++) { for (let i = 0; i < targets.length; i++) {
if (targets[i].id == playerId) { if (targets[i].id == playerId) {
playbackManager.trySetActivePlayer(targets[i].playerName, targets[i]); playbackManager.trySetActivePlayer(targets[i].playerName, targets[i]);
break; break;

View file

@ -23,7 +23,7 @@ define(['browser'], function (browser) {
videoTestElement.canPlayType('video/mp4; codecs="hev1.1.0.L120"').replace(/no/, '')); videoTestElement.canPlayType('video/mp4; codecs="hev1.1.0.L120"').replace(/no/, ''));
} }
var _supportsTextTracks; let _supportsTextTracks;
function supportsTextTracks() { function supportsTextTracks() {
if (browser.tizen) { if (browser.tizen) {
return true; return true;
@ -37,7 +37,7 @@ define(['browser'], function (browser) {
return _supportsTextTracks; return _supportsTextTracks;
} }
var _canPlayHls; let _canPlayHls;
function canPlayHls() { function canPlayHls() {
if (_canPlayHls == null) { if (_canPlayHls == null) {
_canPlayHls = canPlayNativeHls() || canPlayHlsWithMSE(); _canPlayHls = canPlayNativeHls() || canPlayHlsWithMSE();
@ -51,7 +51,7 @@ define(['browser'], function (browser) {
return true; return true;
} }
var media = document.createElement('video'); const media = document.createElement('video');
if (media.canPlayType('application/x-mpegURL').replace(/no/, '') || if (media.canPlayType('application/x-mpegURL').replace(/no/, '') ||
media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, '')) { media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, '')) {
return true; return true;
@ -107,7 +107,7 @@ define(['browser'], function (browser) {
} }
function canPlayAudioFormat(format) { function canPlayAudioFormat(format) {
var typeString; let typeString;
if (format === 'flac') { if (format === 'flac') {
if (browser.tizen || browser.web0s || browser.edgeUwp) { if (browser.tizen || browser.web0s || browser.edgeUwp) {
@ -192,9 +192,9 @@ define(['browser'], function (browser) {
} }
function getDirectPlayProfileForVideoContainer(container, videoAudioCodecs, videoTestElement, options) { function getDirectPlayProfileForVideoContainer(container, videoAudioCodecs, videoTestElement, options) {
var supported = false; let supported = false;
var profileContainer = container; let profileContainer = container;
var videoCodecs = []; const videoCodecs = [];
switch (container) { switch (container) {
case 'asf': case 'asf':
@ -277,10 +277,10 @@ define(['browser'], function (browser) {
} }
function getGlobalMaxVideoBitrate() { function getGlobalMaxVideoBitrate() {
var isTizenFhd = false; let isTizenFhd = false;
if (browser.tizen) { if (browser.tizen) {
try { try {
var isTizenUhd = webapis.productinfo.isUdPanelSupported(); const isTizenUhd = webapis.productinfo.isUdPanelSupported();
isTizenFhd = !isTizenUhd; isTizenFhd = !isTizenUhd;
console.debug('isTizenFhd = ' + isTizenFhd); console.debug('isTizenFhd = ' + isTizenFhd);
} catch (error) { } catch (error) {
@ -297,19 +297,19 @@ define(['browser'], function (browser) {
return function (options) { return function (options) {
options = options || {}; options = options || {};
var physicalAudioChannels = options.audioChannels || (browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2); const physicalAudioChannels = options.audioChannels || (browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2);
var bitrateSetting = getMaxBitrate(); const bitrateSetting = getMaxBitrate();
var videoTestElement = document.createElement('video'); const videoTestElement = document.createElement('video');
var canPlayVp8 = videoTestElement.canPlayType('video/webm; codecs="vp8"').replace(/no/, ''); const canPlayVp8 = videoTestElement.canPlayType('video/webm; codecs="vp8"').replace(/no/, '');
var canPlayVp9 = videoTestElement.canPlayType('video/webm; codecs="vp9"').replace(/no/, ''); const canPlayVp9 = videoTestElement.canPlayType('video/webm; codecs="vp9"').replace(/no/, '');
var webmAudioCodecs = ['vorbis']; const webmAudioCodecs = ['vorbis'];
var canPlayMkv = testCanPlayMkv(videoTestElement); const canPlayMkv = testCanPlayMkv(videoTestElement);
var profile = {}; const profile = {};
profile.MaxStreamingBitrate = bitrateSetting; profile.MaxStreamingBitrate = bitrateSetting;
profile.MaxStaticBitrate = 100000000; profile.MaxStaticBitrate = 100000000;
@ -317,18 +317,18 @@ define(['browser'], function (browser) {
profile.DirectPlayProfiles = []; profile.DirectPlayProfiles = [];
var videoAudioCodecs = []; let videoAudioCodecs = [];
var hlsVideoAudioCodecs = []; let hlsVideoAudioCodecs = [];
var supportsMp3VideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"').replace(/no/, '') const supportsMp3VideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"').replace(/no/, '')
|| videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"').replace(/no/, '') || videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"').replace(/no/, '')
|| videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp3"').replace(/no/, ''); || videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp3"').replace(/no/, '');
// Not sure how to test for this // Not sure how to test for this
var supportsMp2VideoAudio = browser.edgeUwp || browser.tizen || browser.web0s; const supportsMp2VideoAudio = browser.edgeUwp || browser.tizen || browser.web0s;
/* eslint-disable compat/compat */ /* eslint-disable compat/compat */
var maxVideoWidth = browser.xboxOne ? let maxVideoWidth = browser.xboxOne ?
(window.screen ? window.screen.width : null) : (window.screen ? window.screen.width : null) :
null; null;
@ -337,7 +337,7 @@ define(['browser'], function (browser) {
maxVideoWidth = options.maxVideoWidth; maxVideoWidth = options.maxVideoWidth;
} }
var canPlayAacVideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"').replace(/no/, ''); const canPlayAacVideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"').replace(/no/, '');
// Only put mp3 first if mkv support is there // Only put mp3 first if mkv support is there
// Otherwise with HLS and mp3 audio we're seeing some browsers // Otherwise with HLS and mp3 audio we're seeing some browsers
@ -345,7 +345,7 @@ define(['browser'], function (browser) {
if (supportsAc3(videoTestElement)) { if (supportsAc3(videoTestElement)) {
videoAudioCodecs.push('ac3'); videoAudioCodecs.push('ac3');
var eAc3 = supportsEac3(videoTestElement); const eAc3 = supportsEac3(videoTestElement);
if (eAc3) { if (eAc3) {
videoAudioCodecs.push('eac3'); videoAudioCodecs.push('eac3');
} }
@ -394,7 +394,7 @@ define(['browser'], function (browser) {
videoAudioCodecs.push('mp2'); videoAudioCodecs.push('mp2');
} }
var supportsDts = browser.tizen || browser.web0s || options.supportsDts || videoTestElement.canPlayType('video/mp4; codecs="dts-"').replace(/no/, '') || videoTestElement.canPlayType('video/mp4; codecs="dts+"').replace(/no/, ''); let supportsDts = browser.tizen || browser.web0s || options.supportsDts || videoTestElement.canPlayType('video/mp4; codecs="dts-"').replace(/no/, '') || videoTestElement.canPlayType('video/mp4; codecs="dts+"').replace(/no/, '');
// DTS audio not supported in 2018 models (Tizen 4.0) // DTS audio not supported in 2018 models (Tizen 4.0)
if (browser.tizenVersion >= 4) { if (browser.tizenVersion >= 4) {
@ -437,9 +437,9 @@ define(['browser'], function (browser) {
return (options.disableHlsVideoAudioCodecs || []).indexOf(c) === -1; return (options.disableHlsVideoAudioCodecs || []).indexOf(c) === -1;
}); });
var mp4VideoCodecs = []; const mp4VideoCodecs = [];
var webmVideoCodecs = []; const webmVideoCodecs = [];
var hlsVideoCodecs = []; const hlsVideoCodecs = [];
if (canPlayH264(videoTestElement)) { if (canPlayH264(videoTestElement)) {
mp4VideoCodecs.push('h264'); mp4VideoCodecs.push('h264');
@ -555,7 +555,7 @@ define(['browser'], function (browser) {
profile.TranscodingProfiles = []; profile.TranscodingProfiles = [];
var hlsBreakOnNonKeyFrames = browser.iOS || browser.osx || browser.edge || !canPlayNativeHls() ? true : false; const hlsBreakOnNonKeyFrames = browser.iOS || browser.osx || browser.edge || !canPlayNativeHls() ? true : false;
if (canPlayHls() && browser.enableHlsAudio !== false) { if (canPlayHls() && browser.enableHlsAudio !== false) {
profile.TranscodingProfiles.push({ profile.TranscodingProfiles.push({
@ -661,9 +661,9 @@ define(['browser'], function (browser) {
profile.CodecProfiles = []; profile.CodecProfiles = [];
var supportsSecondaryAudio = browser.tizen || videoTestElement.audioTracks; const supportsSecondaryAudio = browser.tizen || videoTestElement.audioTracks;
var aacCodecProfileConditions = []; const aacCodecProfileConditions = [];
// Handle he-aac not supported // Handle he-aac not supported
if (!videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.5"').replace(/no/, '')) { if (!videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.5"').replace(/no/, '')) {
@ -706,8 +706,8 @@ define(['browser'], function (browser) {
}); });
} }
var maxH264Level = 42; let maxH264Level = 42;
var h264Profiles = 'high|main|baseline|constrained baseline'; let h264Profiles = 'high|main|baseline|constrained baseline';
if (browser.tizen || browser.web0s || if (browser.tizen || browser.web0s ||
videoTestElement.canPlayType('video/mp4; codecs="avc1.640833"').replace(/no/, '')) { videoTestElement.canPlayType('video/mp4; codecs="avc1.640833"').replace(/no/, '')) {
@ -766,9 +766,9 @@ define(['browser'], function (browser) {
}); });
} }
var globalMaxVideoBitrate = (getGlobalMaxVideoBitrate() || '').toString(); const globalMaxVideoBitrate = (getGlobalMaxVideoBitrate() || '').toString();
var h264MaxVideoBitrate = globalMaxVideoBitrate; const h264MaxVideoBitrate = globalMaxVideoBitrate;
if (h264MaxVideoBitrate) { if (h264MaxVideoBitrate) {
h264CodecProfileConditions.push({ h264CodecProfileConditions.push({
@ -806,7 +806,7 @@ define(['browser'], function (browser) {
Conditions: h264CodecProfileConditions Conditions: h264CodecProfileConditions
}); });
var globalVideoConditions = []; const globalVideoConditions = [];
if (globalMaxVideoBitrate) { if (globalMaxVideoBitrate) {
globalVideoConditions.push({ globalVideoConditions.push({

View file

@ -5,8 +5,8 @@ import 'material-icons';
/* eslint-disable indent */ /* eslint-disable indent */
function getNode(item, folderState, selected) { function getNode(item, folderState, selected) {
var htmlName = getNodeInnerHtml(item); const htmlName = getNodeInnerHtml(item);
var node = { const node = {
id: item.Id, id: item.Id,
text: htmlName, text: htmlName,
state: { state: {
@ -37,14 +37,14 @@ import 'material-icons';
} }
function getNodeInnerHtml(item) { function getNodeInnerHtml(item) {
var name = item.Name; let name = item.Name;
if (item.Number) { if (item.Number) {
name = item.Number + ' - ' + name; name = item.Number + ' - ' + name;
} }
if (item.IndexNumber != null && item.Type != 'Season') { if (item.IndexNumber != null && item.Type != 'Season') {
name = item.IndexNumber + ' - ' + name; name = item.IndexNumber + ' - ' + name;
} }
var htmlName = "<div class='editorNode'>"; let htmlName = "<div class='editorNode'>";
if (item.IsFolder) { if (item.IsFolder) {
htmlName += '<span class="material-icons metadataSidebarIcon folder"></span>'; htmlName += '<span class="material-icons metadataSidebarIcon folder"></span>';
} else if (item.MediaType === 'Video') { } else if (item.MediaType === 'Video') {
@ -70,7 +70,7 @@ import 'material-icons';
ApiClient.getLiveTvChannels({ ApiClient.getLiveTvChannels({
limit: 0 limit: 0
}).then(function (result) { }).then(function (result) {
var nodes = []; const nodes = [];
nodes.push({ nodes.push({
id: 'MediaFolders', id: 'MediaFolders',
text: globalize.translate('HeaderMediaFolders'), text: globalize.translate('HeaderMediaFolders'),
@ -110,8 +110,8 @@ import 'material-icons';
ServiceName: service, ServiceName: service,
AddCurrentProgram: false AddCurrentProgram: false
}).then(function (result) { }).then(function (result) {
var nodes = result.Items.map(function (i) { const nodes = result.Items.map(function (i) {
var state = openItems.indexOf(i.Id) == -1 ? 'closed' : 'open'; const state = openItems.indexOf(i.Id) == -1 ? 'closed' : 'open';
return getNode(i, state, false); return getNode(i, state, false);
}); });
callback(nodes); callback(nodes);
@ -120,12 +120,12 @@ import 'material-icons';
function loadMediaFolders(page, scope, openItems, callback) { function loadMediaFolders(page, scope, openItems, callback) {
ApiClient.getJSON(ApiClient.getUrl('Library/MediaFolders')).then(function (result) { ApiClient.getJSON(ApiClient.getUrl('Library/MediaFolders')).then(function (result) {
var nodes = result.Items.map(function (n) { const nodes = result.Items.map(function (n) {
var state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open'; const state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open';
return getNode(n, state, false); return getNode(n, state, false);
}); });
callback.call(scope, nodes); callback.call(scope, nodes);
for (var i = 0, length = nodes.length; i < length; i++) { for (let i = 0, length = nodes.length; i < length; i++) {
if (nodes[i].state.opened) { if (nodes[i].state.opened) {
nodesToLoad.push(nodes[i].id); nodesToLoad.push(nodes[i].id);
} }
@ -134,7 +134,7 @@ import 'material-icons';
} }
function loadNode(page, scope, node, openItems, selectedId, currentUser, callback) { function loadNode(page, scope, node, openItems, selectedId, currentUser, callback) {
var id = node.id; const id = node.id;
if (id == '#') { if (id == '#') {
loadChildrenOfRootNode(page, scope, callback); loadChildrenOfRootNode(page, scope, callback);
return; return;
@ -147,7 +147,7 @@ import 'material-icons';
loadMediaFolders(page, scope, openItems, callback); loadMediaFolders(page, scope, openItems, callback);
return; return;
} }
var query = { const query = {
ParentId: id, ParentId: id,
Fields: 'Settings', Fields: 'Settings',
IsVirtualUnaired: false, IsVirtualUnaired: false,
@ -156,17 +156,17 @@ import 'material-icons';
EnableImages: false, EnableImages: false,
EnableUserData: false EnableUserData: false
}; };
var itemtype = node.li_attr.itemtype; const itemtype = node.li_attr.itemtype;
if (itemtype != 'Season' && itemtype != 'Series') { if (itemtype != 'Season' && itemtype != 'Series') {
query.SortBy = 'SortName'; query.SortBy = 'SortName';
} }
ApiClient.getItems(Dashboard.getCurrentUserId(), query).then(function (result) { ApiClient.getItems(Dashboard.getCurrentUserId(), query).then(function (result) {
var nodes = result.Items.map(function (n) { const nodes = result.Items.map(function (n) {
var state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open'; const state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open';
return getNode(n, state, n.Id == selectedId); return getNode(n, state, n.Id == selectedId);
}); });
callback.call(scope, nodes); callback.call(scope, nodes);
for (var i = 0, length = nodes.length; i < length; i++) { for (let i = 0, length = nodes.length; i < length; i++) {
if (nodes[i].state.opened) { if (nodes[i].state.opened) {
nodesToLoad.push(nodes[i].id); nodesToLoad.push(nodes[i].id);
} }
@ -175,7 +175,7 @@ import 'material-icons';
} }
function scrollToNode(id) { function scrollToNode(id) {
var elem = $('#' + id)[0]; const elem = $('#' + id)[0];
if (elem) { if (elem) {
elem.scrollIntoView(); elem.scrollIntoView();
} }
@ -188,8 +188,8 @@ import 'material-icons';
} }
function onNodeSelect(event, data) { function onNodeSelect(event, data) {
var node = data.node; const node = data.node;
var eventData = { const eventData = {
id: node.id, id: node.id,
itemType: node.li_attr.itemtype, itemType: node.li_attr.itemtype,
serverItemType: node.li_attr.serveritemtype, serverItemType: node.li_attr.serveritemtype,
@ -210,8 +210,8 @@ import 'material-icons';
} }
function onNodeOpen(event, data) { function onNodeOpen(event, data) {
var page = $(this).parents('.page')[0]; const page = $(this).parents('.page')[0];
var node = data.node; const node = data.node;
if (node.children) { if (node.children) {
loadNodesToLoad(page, node); loadNodesToLoad(page, node);
} }
@ -222,8 +222,8 @@ import 'material-icons';
} }
function onNodeLoad(event, data) { function onNodeLoad(event, data) {
var page = $(this).parents('.page')[0]; const page = $(this).parents('.page')[0];
var node = data.node; const node = data.node;
if (node.children) { if (node.children) {
loadNodesToLoad(page, node); loadNodesToLoad(page, node);
} }
@ -252,9 +252,9 @@ import 'material-icons';
} }
function loadNodesToLoad(page, node) { function loadNodesToLoad(page, node) {
var children = node.children; const children = node.children;
for (var i = 0, length = children.length; i < length; i++) { for (let i = 0, length = children.length; i < length; i++) {
var child = children[i]; const child = children[i];
if (nodesToLoad.indexOf(child) != -1) { if (nodesToLoad.indexOf(child) != -1) {
nodesToLoad = nodesToLoad.filter(function (n) { nodesToLoad = nodesToLoad.filter(function (n) {
return n != child; return n != child;
@ -273,15 +273,15 @@ import 'material-icons';
} }
function updateEditorNode(page, item) { function updateEditorNode(page, item) {
var elem = $('#' + item.Id + '>a', page)[0]; const elem = $('#' + item.Id + '>a', page)[0];
if (elem == null) { if (elem == null) {
return; return;
} }
$('.editorNode', elem).remove(); $('.editorNode', elem).remove();
$(elem).append(getNodeInnerHtml(item)); $(elem).append(getNodeInnerHtml(item));
if (item.IsFolder) { if (item.IsFolder) {
var tree = jQuery.jstree._reference('.libraryTree'); const tree = jQuery.jstree._reference('.libraryTree');
var currentNode = tree._get_node(null, false); const currentNode = tree._get_node(null, false);
tree.refresh(currentNode); tree.refresh(currentNode);
} }
} }
@ -294,23 +294,23 @@ import 'material-icons';
if (itemId) { if (itemId) {
return itemId; return itemId;
} }
var url = window.location.hash || window.location.href; const url = window.location.hash || window.location.href;
return getParameterByName('id', url); return getParameterByName('id', url);
} }
var nodesToLoad = []; let nodesToLoad = [];
var selectedNodeId; let selectedNodeId;
$(document).on('itemsaved', '.metadataEditorPage', function (e, item) { $(document).on('itemsaved', '.metadataEditorPage', function (e, item) {
updateEditorNode(this, item); updateEditorNode(this, item);
}).on('pagebeforeshow', '.metadataEditorPage', function () { }).on('pagebeforeshow', '.metadataEditorPage', function () {
/* eslint-disable-next-line @babel/no-unused-expressions */ /* eslint-disable-next-line @babel/no-unused-expressions */
import('css!assets/css/metadataeditor.css'); import('css!assets/css/metadataeditor.css');
}).on('pagebeforeshow', '.metadataEditorPage', function () { }).on('pagebeforeshow', '.metadataEditorPage', function () {
var page = this; const page = this;
Dashboard.getCurrentUser().then(function (user) { Dashboard.getCurrentUser().then(function (user) {
var id = getCurrentItemId(); const id = getCurrentItemId();
if (id) { if (id) {
ApiClient.getAncestorItems(id, user.Id).then(function (ancestors) { ApiClient.getAncestorItems(id, user.Id).then(function (ancestors) {
var ids = ancestors.map(function (i) { const ids = ancestors.map(function (i) {
return i.Id; return i.Id;
}); });
initializeTree(page, user, ids, id); initializeTree(page, user, ids, id);
@ -320,13 +320,13 @@ import 'material-icons';
} }
}); });
}).on('pagebeforehide', '.metadataEditorPage', function () { }).on('pagebeforehide', '.metadataEditorPage', function () {
var page = this; const page = this;
$('.libraryTree', page).off('select_node.jstree', onNodeSelect).off('open_node.jstree', onNodeOpen).off('load_node.jstree', onNodeLoad); $('.libraryTree', page).off('select_node.jstree', onNodeSelect).off('open_node.jstree', onNodeOpen).off('load_node.jstree', onNodeLoad);
}); });
var itemId; let itemId;
window.MetadataEditor = { window.MetadataEditor = {
getItemPromise: function () { getItemPromise: function () {
var currentItemId = getCurrentItemId(); const currentItemId = getCurrentItemId();
if (currentItemId) { if (currentItemId) {
return ApiClient.getItem(Dashboard.getCurrentUserId(), currentItemId); return ApiClient.getItem(Dashboard.getCurrentUserId(), currentItemId);
} }

View file

@ -1,11 +1,8 @@
import multiDownload from 'multi-download'; import multiDownload from 'multi-download';
import shell from 'shell';
export function download(items) { export function download(items) {
if (window.NativeShell) { if (!shell.downloadFiles(items)) {
items.map(function (item) {
window.NativeShell.downloadFile(item);
});
} else {
multiDownload(items.map(function (item) { multiDownload(items.map(function (item) {
return item.url; return item.url;
})); }));

View file

@ -22,47 +22,47 @@
import appHost from 'apphost'; import appHost from 'apphost';
var _GAMEPAD_A_BUTTON_INDEX = 0; const _GAMEPAD_A_BUTTON_INDEX = 0;
var _GAMEPAD_B_BUTTON_INDEX = 1; const _GAMEPAD_B_BUTTON_INDEX = 1;
var _GAMEPAD_DPAD_UP_BUTTON_INDEX = 12; const _GAMEPAD_DPAD_UP_BUTTON_INDEX = 12;
var _GAMEPAD_DPAD_DOWN_BUTTON_INDEX = 13; const _GAMEPAD_DPAD_DOWN_BUTTON_INDEX = 13;
var _GAMEPAD_DPAD_LEFT_BUTTON_INDEX = 14; const _GAMEPAD_DPAD_LEFT_BUTTON_INDEX = 14;
var _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX = 15; const _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX = 15;
var _GAMEPAD_A_KEY = 'GamepadA'; const _GAMEPAD_A_KEY = 'GamepadA';
var _GAMEPAD_B_KEY = 'GamepadB'; const _GAMEPAD_B_KEY = 'GamepadB';
var _GAMEPAD_DPAD_UP_KEY = 'GamepadDPadUp'; const _GAMEPAD_DPAD_UP_KEY = 'GamepadDPadUp';
var _GAMEPAD_DPAD_DOWN_KEY = 'GamepadDPadDown'; const _GAMEPAD_DPAD_DOWN_KEY = 'GamepadDPadDown';
var _GAMEPAD_DPAD_LEFT_KEY = 'GamepadDPadLeft'; const _GAMEPAD_DPAD_LEFT_KEY = 'GamepadDPadLeft';
var _GAMEPAD_DPAD_RIGHT_KEY = 'GamepadDPadRight'; const _GAMEPAD_DPAD_RIGHT_KEY = 'GamepadDPadRight';
var _GAMEPAD_LEFT_THUMBSTICK_UP_KEY = 'GamepadLeftThumbStickUp'; const _GAMEPAD_LEFT_THUMBSTICK_UP_KEY = 'GamepadLeftThumbStickUp';
var _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEY = 'GamepadLeftThumbStickDown'; const _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEY = 'GamepadLeftThumbStickDown';
var _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEY = 'GamepadLeftThumbStickLeft'; const _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEY = 'GamepadLeftThumbStickLeft';
var _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEY = 'GamepadLeftThumbStickRight'; const _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEY = 'GamepadLeftThumbStickRight';
var _GAMEPAD_A_KEYCODE = 0; const _GAMEPAD_A_KEYCODE = 0;
var _GAMEPAD_B_KEYCODE = 27; const _GAMEPAD_B_KEYCODE = 27;
var _GAMEPAD_DPAD_UP_KEYCODE = 38; const _GAMEPAD_DPAD_UP_KEYCODE = 38;
var _GAMEPAD_DPAD_DOWN_KEYCODE = 40; const _GAMEPAD_DPAD_DOWN_KEYCODE = 40;
var _GAMEPAD_DPAD_LEFT_KEYCODE = 37; const _GAMEPAD_DPAD_LEFT_KEYCODE = 37;
var _GAMEPAD_DPAD_RIGHT_KEYCODE = 39; const _GAMEPAD_DPAD_RIGHT_KEYCODE = 39;
var _GAMEPAD_LEFT_THUMBSTICK_UP_KEYCODE = 38; const _GAMEPAD_LEFT_THUMBSTICK_UP_KEYCODE = 38;
var _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEYCODE = 40; const _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEYCODE = 40;
var _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEYCODE = 37; const _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEYCODE = 37;
var _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEYCODE = 39; const _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEYCODE = 39;
var _THUMB_STICK_THRESHOLD = 0.75; const _THUMB_STICK_THRESHOLD = 0.75;
var _leftThumbstickUpPressed = false; let _leftThumbstickUpPressed = false;
var _leftThumbstickDownPressed = false; let _leftThumbstickDownPressed = false;
var _leftThumbstickLeftPressed = false; let _leftThumbstickLeftPressed = false;
var _leftThumbstickRightPressed = false; let _leftThumbstickRightPressed = false;
var _dPadUpPressed = false; let _dPadUpPressed = false;
var _dPadDownPressed = false; let _dPadDownPressed = false;
var _dPadLeftPressed = false; let _dPadLeftPressed = false;
var _dPadRightPressed = false; let _dPadRightPressed = false;
var _gamepadAPressed = false; let _gamepadAPressed = false;
var _gamepadBPressed = false; let _gamepadBPressed = false;
// The set of buttons on the gamepad we listen for. // The set of buttons on the gamepad we listen for.
var ProcessedButtons = [ const ProcessedButtons = [
_GAMEPAD_DPAD_UP_BUTTON_INDEX, _GAMEPAD_DPAD_UP_BUTTON_INDEX,
_GAMEPAD_DPAD_DOWN_BUTTON_INDEX, _GAMEPAD_DPAD_DOWN_BUTTON_INDEX,
_GAMEPAD_DPAD_LEFT_BUTTON_INDEX, _GAMEPAD_DPAD_LEFT_BUTTON_INDEX,
@ -71,7 +71,7 @@ var ProcessedButtons = [
_GAMEPAD_B_BUTTON_INDEX _GAMEPAD_B_BUTTON_INDEX
]; ];
var _ButtonPressedState = {}; const _ButtonPressedState = {};
_ButtonPressedState.getgamepadA = function () { _ButtonPressedState.getgamepadA = function () {
return _gamepadAPressed; return _gamepadAPressed;
}; };
@ -162,11 +162,11 @@ _ButtonPressedState.setdPadRight = function (newPressedState) {
_dPadRightPressed = newPressedState; _dPadRightPressed = newPressedState;
}; };
var times = {}; const times = {};
function throttle(key) { function throttle(key) {
var time = times[key] || 0; const time = times[key] || 0;
var now = new Date().getTime(); const now = new Date().getTime();
if ((now - time) >= 200) { if ((now - time) >= 200) {
//times[key] = now; //times[key] = now;
@ -180,7 +180,7 @@ function resetThrottle(key) {
times[key] = new Date().getTime(); times[key] = new Date().getTime();
} }
var isElectron = navigator.userAgent.toLowerCase().indexOf('electron') !== -1; const isElectron = navigator.userAgent.toLowerCase().indexOf('electron') !== -1;
function allowInput() { function allowInput() {
// This would be nice but always seems to return true with electron // This would be nice but always seems to return true with electron
if (!isElectron && document.hidden) { /* eslint-disable-line compat/compat */ if (!isElectron && document.hidden) { /* eslint-disable-line compat/compat */
@ -199,7 +199,7 @@ function raiseEvent(name, key, keyCode) {
return; return;
} }
var event = document.createEvent('Event'); const event = document.createEvent('Event');
event.initEvent(name, true, true); event.initEvent(name, true, true);
event.key = key; event.key = key;
event.keyCode = keyCode; event.keyCode = keyCode;
@ -218,7 +218,7 @@ function raiseKeyEvent(oldPressedState, newPressedState, key, keyCode, enableRep
// No-op if oldPressedState === newPressedState // No-op if oldPressedState === newPressedState
if (newPressedState === true) { if (newPressedState === true) {
// button down // button down
var fire = false; let fire = false;
// always fire if this is the initial down press // always fire if this is the initial down press
if (oldPressedState === false) { if (oldPressedState === false) {
@ -244,19 +244,19 @@ function raiseKeyEvent(oldPressedState, newPressedState, key, keyCode, enableRep
} }
} }
var inputLoopTimer; let inputLoopTimer;
function runInputLoop() { function runInputLoop() {
// Get the latest gamepad state. // Get the latest gamepad state.
var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */ const gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */
for (var i = 0, len = gamepads.length; i < len; i++) { for (let i = 0, len = gamepads.length; i < len; i++) {
var gamepad = gamepads[i]; const gamepad = gamepads[i];
if (!gamepad) { if (!gamepad) {
continue; continue;
} }
// Iterate through the axes // Iterate through the axes
var axes = gamepad.axes; const axes = gamepad.axes;
var leftStickX = axes[0]; const leftStickX = axes[0];
var leftStickY = axes[1]; const leftStickY = axes[1];
if (leftStickX > _THUMB_STICK_THRESHOLD) { // Right if (leftStickX > _THUMB_STICK_THRESHOLD) { // Right
_ButtonPressedState.setleftThumbstickRight(true); _ButtonPressedState.setleftThumbstickRight(true);
} else if (leftStickX < -_THUMB_STICK_THRESHOLD) { // Left } else if (leftStickX < -_THUMB_STICK_THRESHOLD) { // Left
@ -272,8 +272,8 @@ function runInputLoop() {
_ButtonPressedState.setleftThumbstickDown(false); _ButtonPressedState.setleftThumbstickDown(false);
} }
// Iterate through the buttons to see if Left thumbstick, DPad, A and B are pressed. // Iterate through the buttons to see if Left thumbstick, DPad, A and B are pressed.
var buttons = gamepad.buttons; const buttons = gamepad.buttons;
for (var j = 0, len = buttons.length; j < len; j++) { for (let j = 0, len = buttons.length; j < len; j++) {
if (ProcessedButtons.indexOf(j) !== -1) { if (ProcessedButtons.indexOf(j) !== -1) {
if (buttons[j].pressed) { if (buttons[j].pressed) {
switch (j) { switch (j) {
@ -355,9 +355,9 @@ function stopInputLoop() {
} }
function isGamepadConnected() { function isGamepadConnected() {
var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */ const gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */
for (var i = 0, len = gamepads.length; i < len; i++) { for (let i = 0, len = gamepads.length; i < len; i++) {
var gamepad = gamepads[i]; const gamepad = gamepads[i];
if (gamepad && gamepad.connected) { if (gamepad && gamepad.connected) {
return true; return true;
} }

View file

@ -2,7 +2,7 @@
/* eslint-disable indent */ /* eslint-disable indent */
export function getDeviceIcon(device) { export function getDeviceIcon(device) {
var baseUrl = 'assets/img/devices/'; const baseUrl = 'assets/img/devices/';
switch (device.AppName || device.Client) { switch (device.AppName || device.Client) {
case 'Samsung Smart TV': case 'Samsung Smart TV':
return baseUrl + 'samsung.svg'; return baseUrl + 'samsung.svg';

View file

@ -6,7 +6,7 @@ export function getSavedQueryKey(modifier) {
} }
export function loadSavedQueryValues(key, query) { export function loadSavedQueryValues(key, query) {
var values = userSettings.get(key); let values = userSettings.get(key);
if (values) { if (values) {
values = JSON.parse(values); values = JSON.parse(values);
@ -17,7 +17,7 @@ export function loadSavedQueryValues(key, query) {
} }
export function saveQueryValues(key, query) { export function saveQueryValues(key, query) {
var values = {}; const values = {};
if (query.SortBy) { if (query.SortBy) {
values.SortBy = query.SortBy; values.SortBy = query.SortBy;
@ -39,7 +39,7 @@ export function getSavedView (key) {
} }
export function showLayoutMenu (button, currentLayout, views) { export function showLayoutMenu (button, currentLayout, views) {
var dispatchEvent = true; let dispatchEvent = true;
if (!views) { if (!views) {
dispatchEvent = false; dispatchEvent = false;
@ -47,7 +47,7 @@ export function showLayoutMenu (button, currentLayout, views) {
views = views ? views.split(',') : ['List', 'Poster', 'PosterCard', 'Thumb', 'ThumbCard']; views = views ? views.split(',') : ['List', 'Poster', 'PosterCard', 'Thumb', 'ThumbCard'];
} }
var menuItems = views.map(function (v) { const menuItems = views.map(function (v) {
return { return {
name: globalize.translate(v), name: globalize.translate(v),
id: v, id: v,
@ -79,12 +79,12 @@ export function showLayoutMenu (button, currentLayout, views) {
} }
export function getQueryPagingHtml (options) { export function getQueryPagingHtml (options) {
var startIndex = options.startIndex; const startIndex = options.startIndex;
var limit = options.limit; const limit = options.limit;
var totalRecordCount = options.totalRecordCount; const totalRecordCount = options.totalRecordCount;
var html = ''; let html = '';
var recordsEnd = Math.min(startIndex + limit, totalRecordCount); const recordsEnd = Math.min(startIndex + limit, totalRecordCount);
var showControls = limit < totalRecordCount; const showControls = limit < totalRecordCount;
if (html += '<div class="listPaging">', showControls) { if (html += '<div class="listPaging">', showControls) {
html += '<span style="vertical-align:middle;">'; html += '<span style="vertical-align:middle;">';
@ -124,10 +124,10 @@ export function showSortMenu (options) {
import('emby-radio') import('emby-radio')
]).then(([{default: dialogHelper}]) => { ]).then(([{default: dialogHelper}]) => {
function onSortByChange() { function onSortByChange() {
var newValue = this.value; const newValue = this.value;
if (this.checked) { if (this.checked) {
var changed = options.query.SortBy != newValue; const changed = options.query.SortBy != newValue;
options.query.SortBy = newValue.replace('_', ','); options.query.SortBy = newValue.replace('_', ',');
options.query.StartIndex = 0; options.query.StartIndex = 0;
@ -138,10 +138,10 @@ export function showSortMenu (options) {
} }
function onSortOrderChange() { function onSortOrderChange() {
var newValue = this.value; const newValue = this.value;
if (this.checked) { if (this.checked) {
var changed = options.query.SortOrder != newValue; const changed = options.query.SortOrder != newValue;
options.query.SortOrder = newValue; options.query.SortOrder = newValue;
options.query.StartIndex = 0; options.query.StartIndex = 0;
@ -151,7 +151,7 @@ export function showSortMenu (options) {
} }
} }
var dlg = dialogHelper.createDialog({ const dlg = dialogHelper.createDialog({
removeOnClose: true, removeOnClose: true,
modal: false, modal: false,
entryAnimationDuration: 160, entryAnimationDuration: 160,
@ -160,18 +160,18 @@ export function showSortMenu (options) {
dlg.classList.add('ui-body-a'); dlg.classList.add('ui-body-a');
dlg.classList.add('background-theme-a'); dlg.classList.add('background-theme-a');
dlg.classList.add('formDialog'); dlg.classList.add('formDialog');
var html = ''; let html = '';
html += '<div style="margin:0;padding:1.25em 1.5em 1.5em;">'; html += '<div style="margin:0;padding:1.25em 1.5em 1.5em;">';
html += '<h2 style="margin:0 0 .5em;">'; html += '<h2 style="margin:0 0 .5em;">';
html += globalize.translate('HeaderSortBy'); html += globalize.translate('HeaderSortBy');
html += '</h2>'; html += '</h2>';
var i; let i;
var length; let length;
var isChecked; let isChecked;
html += '<div>'; html += '<div>';
for (i = 0, length = options.items.length; i < length; i++) { for (i = 0, length = options.items.length; i < length; i++) {
var option = options.items[i]; const option = options.items[i];
var radioValue = option.id.replace(',', '_'); const radioValue = option.id.replace(',', '_');
isChecked = (options.query.SortBy || '').replace(',', '_') == radioValue ? ' checked' : ''; isChecked = (options.query.SortBy || '').replace(',', '_') == radioValue ? ' checked' : '';
html += '<label class="radio-label-block"><input type="radio" is="emby-radio" name="SortBy" data-id="' + option.id + '" value="' + radioValue + '" class="menuSortBy" ' + isChecked + ' /><span>' + option.name + '</span></label>'; html += '<label class="radio-label-block"><input type="radio" is="emby-radio" name="SortBy" data-id="' + option.id + '" value="' + radioValue + '" class="menuSortBy" ' + isChecked + ' /><span>' + option.name + '</span></label>';
} }
@ -189,13 +189,13 @@ export function showSortMenu (options) {
html += '</div>'; html += '</div>';
dlg.innerHTML = html; dlg.innerHTML = html;
dialogHelper.open(dlg); dialogHelper.open(dlg);
var sortBys = dlg.querySelectorAll('.menuSortBy'); const sortBys = dlg.querySelectorAll('.menuSortBy');
for (i = 0, length = sortBys.length; i < length; i++) { for (i = 0, length = sortBys.length; i < length; i++) {
sortBys[i].addEventListener('change', onSortByChange); sortBys[i].addEventListener('change', onSortByChange);
} }
var sortOrders = dlg.querySelectorAll('.menuSortOrder'); const sortOrders = dlg.querySelectorAll('.menuSortOrder');
for (i = 0, length = sortOrders.length; i < length; i++) { for (i = 0, length = sortOrders.length; i < length; i++) {
sortOrders[i].addEventListener('change', onSortOrderChange); sortOrders[i].addEventListener('change', onSortOrderChange);

View file

@ -29,10 +29,10 @@ import 'flexStyles';
html += '</div>'; html += '</div>';
html += '<div class="headerRight">'; html += '<div class="headerRight">';
html += '<span class="headerSelectedPlayer"></span>'; html += '<span class="headerSelectedPlayer"></span>';
html += `<button is="paper-icon-button-light" class="headerSyncButton syncButton headerButton headerButtonRight hide" title="${globalize.translate('ButtonSyncPlay')}"><span class="material-icons sync_disabled"></span></button>`; html += '<button is="paper-icon-button-light" class="headerSyncButton syncButton headerButton headerButtonRight hide"><span class="material-icons sync_disabled"></span></button>';
html += `<button is="paper-icon-button-light" class="headerAudioPlayerButton audioPlayerButton headerButton headerButtonRight hide" title="${globalize.translate('ButtonPlayer')}"><span class="material-icons music_note"></span></button>`; html += '<button is="paper-icon-button-light" class="headerAudioPlayerButton audioPlayerButton headerButton headerButtonRight hide"><span class="material-icons music_note"></span></button>';
html += `<button is="paper-icon-button-light" class="headerCastButton castButton headerButton headerButtonRight hide" title="${globalize.translate('ButtonCast')}"><span class="material-icons cast"></span></button>`; html += '<button is="paper-icon-button-light" class="headerCastButton castButton headerButton headerButtonRight hide"><span class="material-icons cast"></span></button>';
html += `<button type="button" is="paper-icon-button-light" class="headerButton headerButtonRight headerSearchButton hide" title="${globalize.translate('Search')}"><span class="material-icons search"></span></button>`; html += '<button type="button" is="paper-icon-button-light" class="headerButton headerButtonRight headerSearchButton hide"><span class="material-icons search"></span></button>';
html += '<button is="paper-icon-button-light" class="headerButton headerButtonRight headerUserButton hide"><span class="material-icons person"></span></button>'; html += '<button is="paper-icon-button-light" class="headerButton headerButtonRight headerUserButton hide"><span class="material-icons person"></span></button>';
html += '</div>'; html += '</div>';
html += '</div>'; html += '</div>';
@ -43,13 +43,16 @@ import 'flexStyles';
skinHeader.classList.add('skinHeader-blurred'); skinHeader.classList.add('skinHeader-blurred');
skinHeader.innerHTML = html; skinHeader.innerHTML = html;
headerBackButton = skinHeader.querySelector('.headerBackButton');
headerHomeButton = skinHeader.querySelector('.headerHomeButton'); headerHomeButton = skinHeader.querySelector('.headerHomeButton');
mainDrawerButton = skinHeader.querySelector('.mainDrawerButton');
headerUserButton = skinHeader.querySelector('.headerUserButton'); headerUserButton = skinHeader.querySelector('.headerUserButton');
headerCastButton = skinHeader.querySelector('.headerCastButton'); headerCastButton = skinHeader.querySelector('.headerCastButton');
headerAudioPlayerButton = skinHeader.querySelector('.headerAudioPlayerButton'); headerAudioPlayerButton = skinHeader.querySelector('.headerAudioPlayerButton');
headerSearchButton = skinHeader.querySelector('.headerSearchButton'); headerSearchButton = skinHeader.querySelector('.headerSearchButton');
headerSyncButton = skinHeader.querySelector('.headerSyncButton'); headerSyncButton = skinHeader.querySelector('.headerSyncButton');
retranslateUi();
lazyLoadViewMenuBarImages(); lazyLoadViewMenuBarImages();
bindMenuEvents(); bindMenuEvents();
updateCastIcon(); updateCastIcon();
@ -73,8 +76,26 @@ import 'flexStyles';
appRouter.back(); appRouter.back();
} }
function retranslateUi() {
if (headerSyncButton) {
headerSyncButton.title = globalize.translate('ButtonSyncPlay');
}
if (headerAudioPlayerButton) {
headerAudioPlayerButton.title = globalize.translate('ButtonPlayer');
}
if (headerCastButton) {
headerCastButton.title = globalize.translate('ButtonCast');
}
if (headerSearchButton) {
headerSearchButton.title = globalize.translate('Search');
}
}
function updateUserInHeader(user) { function updateUserInHeader(user) {
renderHeader(); retranslateUi();
let hasImage; let hasImage;
@ -153,14 +174,10 @@ import 'flexStyles';
} }
function bindMenuEvents() { function bindMenuEvents() {
mainDrawerButton = document.querySelector('.mainDrawerButton');
if (mainDrawerButton) { if (mainDrawerButton) {
mainDrawerButton.addEventListener('click', toggleMainDrawer); mainDrawerButton.addEventListener('click', toggleMainDrawer);
} }
const headerBackButton = skinHeader.querySelector('.headerBackButton');
if (headerBackButton) { if (headerBackButton) {
headerBackButton.addEventListener('click', onBackClick); headerBackButton.addEventListener('click', onBackClick);
} }
@ -772,10 +789,6 @@ import 'flexStyles';
} }
function updateBackButton(page) { function updateBackButton(page) {
if (!headerBackButton) {
headerBackButton = document.querySelector('.headerBackButton');
}
if (headerBackButton) { if (headerBackButton) {
if (page.getAttribute('data-backbutton') !== 'false' && appRouter.canGoBack()) { if (page.getAttribute('data-backbutton') !== 'false' && appRouter.canGoBack()) {
headerBackButton.classList.remove('hide'); headerBackButton.classList.remove('hide');

View file

@ -1,16 +1,16 @@
import browser from 'browser'; import browser from 'browser';
function fallback(urls) { function fallback(urls) {
var i = 0; let i = 0;
(function createIframe() { (function createIframe() {
var frame = document.createElement('iframe'); const frame = document.createElement('iframe');
frame.style.display = 'none'; frame.style.display = 'none';
frame.src = urls[i++]; frame.src = urls[i++];
document.documentElement.appendChild(frame); document.documentElement.appendChild(frame);
// the download init has to be sequential otherwise IE only use the first // the download init has to be sequential otherwise IE only use the first
var interval = setInterval(function () { const interval = setInterval(function () {
if (frame.contentWindow.document.readyState === 'complete' || frame.contentWindow.document.readyState === 'interactive') { if (frame.contentWindow.document.readyState === 'complete' || frame.contentWindow.document.readyState === 'interactive') {
clearInterval(interval); clearInterval(interval);
@ -28,14 +28,14 @@ function fallback(urls) {
} }
function sameDomain(url) { function sameDomain(url) {
var a = document.createElement('a'); const a = document.createElement('a');
a.href = url; a.href = url;
return window.location.hostname === a.hostname && window.location.protocol === a.protocol; return window.location.hostname === a.hostname && window.location.protocol === a.protocol;
} }
function download(url) { function download(url) {
var a = document.createElement('a'); const a = document.createElement('a');
a.download = ''; a.download = '';
a.href = url; a.href = url;
// firefox doesn't support `a.click()`... // firefox doesn't support `a.click()`...
@ -51,7 +51,7 @@ export default function (urls) {
return fallback(urls); return fallback(urls);
} }
var delay = 0; let delay = 0;
urls.forEach(function (url) { urls.forEach(function (url) {
// the download init has to be sequential for firefox if the urls are not on the same domain // the download init has to be sequential for firefox if the urls are not on the same domain

View file

@ -3,7 +3,7 @@ define(['listView'], function (listView) {
function getFetchPlaylistItemsFn(itemId) { function getFetchPlaylistItemsFn(itemId) {
return function () { return function () {
var query = { const query = {
Fields: 'PrimaryImageAspectRatio,UserData', Fields: 'PrimaryImageAspectRatio,UserData',
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
UserId: ApiClient.getCurrentUserId() UserId: ApiClient.getCurrentUserId()
@ -28,7 +28,7 @@ define(['listView'], function (listView) {
} }
function init(page, item) { function init(page, item) {
var elem = page.querySelector('#childrenContent .itemsContainer'); const elem = page.querySelector('#childrenContent .itemsContainer');
elem.classList.add('vertical-list'); elem.classList.add('vertical-list');
elem.classList.remove('vertical-wrap'); elem.classList.remove('vertical-wrap');
elem.enableDragReordering(true); elem.enableDragReordering(true);

View file

@ -17,7 +17,7 @@ import 'detailtablecss';
console.groupCollapsed('defining core routes'); console.groupCollapsed('defining core routes');
function defineRoute(newRoute) { function defineRoute(newRoute) {
var path = newRoute.alias ? newRoute.alias : newRoute.path; const path = newRoute.alias ? newRoute.alias : newRoute.path;
console.debug('defining route: ' + path); console.debug('defining route: ' + path);
newRoute.dictionary = 'core'; newRoute.dictionary = 'core';
Emby.Page.addRoute(path, newRoute); Emby.Page.addRoute(path, newRoute);
@ -159,10 +159,11 @@ import 'detailtablecss';
}); });
defineRoute({ defineRoute({
path: '/quickconnect.html', alias: '/quickConnect.html',
path: '/controllers/dashboard/quickConnect.html',
autoFocus: false, autoFocus: false,
roles: 'admin', roles: 'admin',
controller: 'dashboard/quickconnect' controller: 'dashboard/quickConnect'
}); });
defineRoute({ defineRoute({

View file

@ -209,7 +209,7 @@ export class UserSettings {
} }
val = this.get('enableBackdrops', false); val = this.get('enableBackdrops', false);
return val !== 'false'; return val === 'true';
} }
/** /**

View file

@ -1,9 +1,48 @@
let data; let data;
const urlResolver = document.createElement('a');
// `fetch` with `file:` support
// Recent browsers seem to support `file` protocol under some conditions.
// Based on https://github.com/github/fetch/pull/92#issuecomment-174730593
// https://github.com/github/fetch/pull/92#issuecomment-512187452
async function fetchLocal(url, options) {
urlResolver.href = url;
const requestURL = urlResolver.href;
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest;
xhr.onload = () => {
// `file` protocol has invalid OK status
let status = xhr.status;
if (requestURL.startsWith('file:') && status === 0) {
status = 200;
}
/* eslint-disable-next-line compat/compat */
resolve(new Response(xhr.responseText, {status: status}));
};
xhr.onerror = () => {
reject(new TypeError('Local request failed'));
};
xhr.open('GET', url);
if (options && options.cache) {
xhr.setRequestHeader('Cache-Control', options.cache);
}
xhr.send(null);
});
}
async function getConfig() { async function getConfig() {
if (data) return Promise.resolve(data); if (data) return Promise.resolve(data);
try { try {
const response = await fetch('config.json', { const response = await fetchLocal('config.json', {
cache: 'no-cache' cache: 'no-cache'
}); });
@ -22,7 +61,7 @@ async function getConfig() {
async function getDefaultConfig() { async function getDefaultConfig() {
try { try {
const response = await fetch('config.template.json', { const response = await fetchLocal('config.template.json', {
cache: 'no-cache' cache: 'no-cache'
}); });
@ -63,3 +102,12 @@ export function getPlugins() {
return []; return [];
}); });
} }
export function getFonts() {
return getConfig().then(config => {
return config.fonts;
}).catch(error => {
console.log('cannot get web config:', error);
return [];
});
}

View file

@ -1,20 +1,43 @@
// TODO: This seems like a good candidate for deprecation // TODO: This seems like a good candidate for deprecation
export default { export default {
openUrl: function (url, target) { enableFullscreen: function() {
window.NativeShell?.enableFullscreen();
},
disableFullscreen: function() {
window.NativeShell?.disableFullscreen();
},
openUrl: function(url, target) {
if (window.NativeShell) { if (window.NativeShell) {
window.NativeShell.openUrl(url, target); window.NativeShell.openUrl(url, target);
} else { } else {
window.open(url, target || '_blank'); window.open(url, target || '_blank');
} }
}, },
enableFullscreen: function () { updateMediaSession(mediaInfo) {
if (window.NativeShell) { window.NativeShell?.updateMediaSession(mediaInfo);
window.NativeShell.enableFullscreen();
}
}, },
disableFullscreen: function () { hideMediaSession() {
window.NativeShell?.hideMediaSession();
},
/**
* Notify the NativeShell about volume level changes.
* Useful for e.g. remote playback.
*/
updateVolumeLevel(volume) {
window.NativeShell?.updateVolumeLevel(volume);
},
/**
* Download specified files with NativeShell if possible
*
* @returns true on success
*/
downloadFiles(items) {
if (window.NativeShell) { if (window.NativeShell) {
window.NativeShell.disableFullscreen(); items.map(function(item) {
window.NativeShell.downloadFile(item);
});
return true;
} }
return false;
} }
}; };

View file

@ -1,10 +1,10 @@
window.getWindowLocationSearch = function(win) { window.getWindowLocationSearch = function(win) {
'use strict'; 'use strict';
var search = (win || window).location.search; let search = (win || window).location.search;
if (!search) { if (!search) {
var index = window.location.href.indexOf('?'); const index = window.location.href.indexOf('?');
if (index != -1) { if (index != -1) {
search = window.location.href.substring(index); search = window.location.href.substring(index);
@ -18,9 +18,9 @@ window.getParameterByName = function(name, url) {
'use strict'; 'use strict';
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regexS = '[\\?&]' + name + '=([^&#]*)'; const regexS = '[\\?&]' + name + '=([^&#]*)';
var regex = new RegExp(regexS, 'i'); const regex = new RegExp(regexS, 'i');
var results = regex.exec(url || getWindowLocationSearch()); const results = regex.exec(url || getWindowLocationSearch());
if (results == null) { if (results == null) {
return ''; return '';
@ -33,7 +33,7 @@ window.pageClassOn = function(eventName, className, fn) {
'use strict'; 'use strict';
document.addEventListener(eventName, function (event) { document.addEventListener(eventName, function (event) {
var target = event.target; const target = event.target;
if (target.classList.contains(className)) { if (target.classList.contains(className)) {
fn.call(target, event); fn.call(target, event);
@ -45,7 +45,7 @@ window.pageIdOn = function(eventName, id, fn) {
'use strict'; 'use strict';
document.addEventListener(eventName, function (event) { document.addEventListener(eventName, function (event) {
var target = event.target; const target = event.target;
if (target.id === id) { if (target.id === id) {
fn.call(target, event); fn.call(target, event);
@ -53,7 +53,7 @@ window.pageIdOn = function(eventName, id, fn) {
}); });
}; };
var AppInfo = {}; const AppInfo = {};
function initClient() { function initClient() {
function bindConnectionManagerEvents(connectionManager, events, userSettings) { function bindConnectionManagerEvents(connectionManager, events, userSettings) {
@ -61,7 +61,7 @@ function initClient() {
window.connectionManager.currentApiClient = function () { window.connectionManager.currentApiClient = function () {
if (!localApiClient) { if (!localApiClient) {
var server = window.connectionManager.getLastUsedServer(); const server = window.connectionManager.getLastUsedServer();
if (server) { if (server) {
localApiClient = window.connectionManager.getApiClient(server.Id); localApiClient = window.connectionManager.getApiClient(server.Id);
@ -86,11 +86,11 @@ function initClient() {
return require(['connectionManagerFactory', 'apphost', 'credentialprovider', 'events', 'userSettings'], function (ConnectionManager, appHost, credentialProvider, events, userSettings) { return require(['connectionManagerFactory', 'apphost', 'credentialprovider', 'events', 'userSettings'], function (ConnectionManager, appHost, credentialProvider, events, userSettings) {
appHost = appHost.default || appHost; appHost = appHost.default || appHost;
var credentialProviderInstance = new credentialProvider(); const credentialProviderInstance = new credentialProvider();
var promises = [appHost.init()]; const promises = [appHost.init()];
return Promise.all(promises).then(function (responses) { return Promise.all(promises).then(function (responses) {
var capabilities = Dashboard.capabilities(appHost); const capabilities = Dashboard.capabilities(appHost);
window.connectionManager = new ConnectionManager(credentialProviderInstance, appHost.appName(), appHost.appVersion(), appHost.deviceName(), appHost.deviceId(), capabilities); window.connectionManager = new ConnectionManager(credentialProviderInstance, appHost.appName(), appHost.appVersion(), appHost.deviceName(), appHost.deviceId(), capabilities);
@ -102,7 +102,7 @@ function initClient() {
return require(['apiclient', 'clientUtils'], function (apiClientFactory, clientUtils) { return require(['apiclient', 'clientUtils'], function (apiClientFactory, clientUtils) {
console.debug('creating ApiClient singleton'); console.debug('creating ApiClient singleton');
var apiClient = new apiClientFactory(Dashboard.serverAddress(), appHost.appName(), appHost.appVersion(), appHost.deviceName(), appHost.deviceId()); const apiClient = new apiClientFactory(Dashboard.serverAddress(), appHost.appName(), appHost.appVersion(), appHost.deviceName(), appHost.deviceId());
apiClient.enableAutomaticNetworking = false; apiClient.enableAutomaticNetworking = false;
apiClient.manualAddressOnly = true; apiClient.manualAddressOnly = true;
@ -194,7 +194,7 @@ function initClient() {
require(['clientUtils']); require(['clientUtils']);
var promises = []; const promises = [];
if (!window.fetch) { if (!window.fetch) {
promises.push(require(['fetch'])); promises.push(require(['fetch']));
} }
@ -203,7 +203,7 @@ function initClient() {
createConnectionManager().then(function () { createConnectionManager().then(function () {
console.debug('initAfterDependencies promises resolved'); console.debug('initAfterDependencies promises resolved');
require(['globalize', 'browser'], function (globalize, browser) { require(['globalize', 'browser'], function (globalize, {default: browser}) {
window.Globalize = globalize; window.Globalize = globalize;
loadCoreDictionary(globalize).then(function () { loadCoreDictionary(globalize).then(function () {
onGlobalizeInit(browser, globalize); onGlobalizeInit(browser, globalize);
@ -226,8 +226,8 @@ function initClient() {
} }
function loadCoreDictionary(globalize) { function loadCoreDictionary(globalize) {
var languages = ['ar', 'be-by', 'bg-bg', 'ca', 'cs', 'da', 'de', 'el', 'en-gb', 'en-us', 'es', 'es-ar', 'es-mx', 'fa', 'fi', 'fr', 'fr-ca', 'gsw', 'he', 'hi-in', 'hr', 'hu', 'id', 'it', 'kk', 'ko', 'lt-lt', 'ms', 'nb', 'nl', 'pl', 'pt-br', 'pt-pt', 'ro', 'ru', 'sk', 'sl-si', 'sv', 'tr', 'uk', 'vi', 'zh-cn', 'zh-hk', 'zh-tw']; const languages = ['ar', 'be-by', 'bg-bg', 'ca', 'cs', 'da', 'de', 'el', 'en-gb', 'en-us', 'es', 'es-ar', 'es-mx', 'fa', 'fi', 'fr', 'fr-ca', 'gsw', 'he', 'hi-in', 'hr', 'hu', 'id', 'it', 'ja', 'kk', 'ko', 'lt-lt', 'ms', 'nb', 'nl', 'pl', 'pt-br', 'pt-pt', 'ro', 'ru', 'sk', 'sl-si', 'sv', 'tr', 'uk', 'vi', 'zh-cn', 'zh-hk', 'zh-tw'];
var translations = languages.map(function (language) { const translations = languages.map(function (language) {
return { return {
lang: language, lang: language,
path: 'strings/' + language + '.json' path: 'strings/' + language + '.json'
@ -367,7 +367,7 @@ function initClient() {
require(['playerSelectionMenu']); require(['playerSelectionMenu']);
var apiClient = window.connectionManager && window.connectionManager.currentApiClient(); const apiClient = window.connectionManager && window.connectionManager.currentApiClient();
if (apiClient) { if (apiClient) {
fetch(apiClient.getUrl('Branding/Css')) fetch(apiClient.getUrl('Branding/Css'))
.then(function(response) { .then(function(response) {
@ -410,8 +410,8 @@ function initClient() {
} }
function onWebComponentsReady() { function onWebComponentsReady() {
var componentsPath = getComponentsPath(); const componentsPath = getComponentsPath();
var scriptsPath = getScriptsPath(); const scriptsPath = getScriptsPath();
define('filesystem', [scriptsPath + '/filesystem'], returnFirstDependency); define('filesystem', [scriptsPath + '/filesystem'], returnFirstDependency);
@ -441,18 +441,18 @@ function initClient() {
init(); init();
} }
var promise; let promise;
var localApiClient; let localApiClient;
function initRequireJs() { function initRequireJs() {
var urlArgs = 'v=' + (window.dashboardVersion || new Date().getDate()); const urlArgs = 'v=' + (window.dashboardVersion || new Date().getDate());
var bowerPath = getBowerPath(); const bowerPath = getBowerPath();
var componentsPath = getComponentsPath(); const componentsPath = getComponentsPath();
var elementsPath = getElementsPath(); const elementsPath = getElementsPath();
var scriptsPath = getScriptsPath(); const scriptsPath = getScriptsPath();
var paths = { const paths = {
browserdeviceprofile: 'scripts/browserDeviceProfile', browserdeviceprofile: 'scripts/browserDeviceProfile',
browser: 'scripts/browser', browser: 'scripts/browser',
libraryBrowser: 'scripts/libraryBrowser', libraryBrowser: 'scripts/libraryBrowser',
@ -495,6 +495,7 @@ function initClient() {
'flvjs', 'flvjs',
'jstree', 'jstree',
'epubjs', 'epubjs',
'pdfjs',
'jQuery', 'jQuery',
'hlsjs', 'hlsjs',
'howler', 'howler',
@ -505,7 +506,6 @@ function initClient() {
'sortable', 'sortable',
'webcomponents', 'webcomponents',
'material-icons', 'material-icons',
'jellyfin-noto',
'date-fns', 'date-fns',
'page', 'page',
'polyfill', 'polyfill',
@ -528,7 +528,7 @@ function initClient() {
}); });
promise = require(['fetch']) promise = require(['fetch'])
.then(() => require(['jQuery', 'polyfill', 'fast-text-encoding', 'intersection-observer', 'classlist-polyfill', 'css!assets/css/site', 'jellyfin-noto'], (jQuery) => { .then(() => require(['jQuery', 'polyfill', 'fast-text-encoding', 'intersection-observer', 'classlist-polyfill', 'css!assets/css/site'], (jQuery) => {
// Expose jQuery globally // Expose jQuery globally
window.$ = jQuery; window.$ = jQuery;
window.jQuery = jQuery; window.jQuery = jQuery;

View file

@ -13,7 +13,7 @@ export default function (options) {
function updateTasks(tasks) { function updateTasks(tasks) {
const task = tasks.filter(function (t) { const task = tasks.filter(function (t) {
return t.ScheduledTask.Key == options.taskKey; return t.Key == options.taskKey;
})[0]; })[0];
if (options.panel) { if (options.panel) {

Some files were not shown because too many files have changed in this diff Show more