Merge branch 'master' into es6-subtitlesettings

This commit is contained in:
Dmitry Lyzo 2020-06-10 11:06:38 +03:00 committed by GitHub
commit 17f04b8042
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
146 changed files with 5890 additions and 3909 deletions

View file

@ -21,8 +21,6 @@ jobs:
BuildConfiguration: development BuildConfiguration: development
Production: Production:
BuildConfiguration: production BuildConfiguration: production
Standalone:
BuildConfiguration: standalone
pool: pool:
vmImage: 'ubuntu-latest' vmImage: 'ubuntu-latest'
@ -49,13 +47,9 @@ jobs:
condition: eq(variables['BuildConfiguration'], 'development') condition: eq(variables['BuildConfiguration'], 'development')
- script: 'yarn build:production' - script: 'yarn build:production'
displayName: 'Build Bundle' displayName: 'Build Production'
condition: eq(variables['BuildConfiguration'], 'production') condition: eq(variables['BuildConfiguration'], 'production')
- script: 'yarn build:standalone'
displayName: 'Build Standalone'
condition: eq(variables['BuildConfiguration'], 'standalone')
- script: 'test -d dist' - script: 'test -d dist'
displayName: 'Check Build' displayName: 'Check Build'

View file

@ -27,29 +27,30 @@ module.exports = {
'plugin:compat/recommended' 'plugin:compat/recommended'
], ],
rules: { rules: {
'block-spacing': ["error"], 'block-spacing': ['error'],
'brace-style': ["error"], 'brace-style': ['error'],
'comma-dangle': ["error", "never"], 'comma-dangle': ['error', 'never'],
'comma-spacing': ["error"], 'comma-spacing': ['error'],
'eol-last': ["error"], 'eol-last': ['error'],
'indent': ["error", 4, { "SwitchCase": 1 }], 'indent': ['error', 4, { 'SwitchCase': 1 }],
'keyword-spacing': ["error"], 'keyword-spacing': ['error'],
'max-statements-per-line': ["error"], 'max-statements-per-line': ['error'],
'no-floating-decimal': ["error"], 'no-floating-decimal': ['error'],
'no-multi-spaces': ["error"], 'no-multi-spaces': ['error'],
'no-multiple-empty-lines': ["error", { "max": 1 }], 'no-multiple-empty-lines': ['error', { 'max': 1 }],
'no-trailing-spaces': ["error"], 'no-trailing-spaces': ['error'],
'one-var': ["error", "never"], 'one-var': ['error', 'never'],
'quotes': ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": false }], 'quotes': ['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': false }],
'semi': ["error"], 'semi': ['error'],
'space-before-blocks': ["error"], 'space-before-blocks': ['error'],
"space-infix-ops": "error" 'space-infix-ops': 'error'
}, },
overrides: [ overrides: [
{ {
files: [ files: [
'./src/**/*.js' './src/**/*.js'
], ],
parser: 'babel-eslint',
env: { env: {
node: false, node: false,
amd: true, amd: true,
@ -97,11 +98,11 @@ module.exports = {
}, },
rules: { rules: {
// TODO: Fix warnings and remove these rules // TODO: Fix warnings and remove these rules
'no-redeclare': ["warn"], 'no-redeclare': ['warn'],
'no-unused-vars': ["warn"], 'no-unused-vars': ['warn'],
'no-useless-escape': ["warn"], 'no-useless-escape': ['warn'],
// TODO: Remove after ES6 migration is complete // TODO: Remove after ES6 migration is complete
'import/no-unresolved': ["off"] 'import/no-unresolved': ['off']
}, },
settings: { settings: {
polyfills: [ polyfills: [
@ -131,6 +132,7 @@ module.exports = {
'Object.getOwnPropertyDescriptor', 'Object.getOwnPropertyDescriptor',
'Object.getPrototypeOf', 'Object.getPrototypeOf',
'Object.keys', 'Object.keys',
'Object.entries',
'Object.getOwnPropertyNames', 'Object.getOwnPropertyNames',
'Function.name', 'Function.name',
'Function.hasInstance', 'Function.hasInstance',

5
.gitignore vendored
View file

@ -1,6 +1,3 @@
# config
config.json
# npm # npm
dist dist
web web
@ -10,5 +7,5 @@ node_modules
.idea .idea
.vscode .vscode
#log # log
yarn-error.log yarn-error.log

View file

@ -16,7 +16,6 @@ const stream = require('webpack-stream');
const inject = require('gulp-inject'); const inject = require('gulp-inject');
const postcss = require('gulp-postcss'); const postcss = require('gulp-postcss');
const sass = require('gulp-sass'); const sass = require('gulp-sass');
const gulpif = require('gulp-if');
const lazypipe = require('lazypipe'); const lazypipe = require('lazypipe');
sass.compiler = require('node-sass'); sass.compiler = require('node-sass');
@ -68,7 +67,7 @@ function serve() {
} }
}); });
watch(options.apploader.query, apploader(true)); watch(options.apploader.query, apploader());
watch('src/bundle.js', webpack); watch('src/bundle.js', webpack);
@ -131,18 +130,12 @@ function javascript(query) {
.pipe(browserSync.stream()); .pipe(browserSync.stream());
} }
function apploader(standalone) { function apploader() {
function task() { return src(options.apploader.query, { base: './src/' })
return src(options.apploader.query, { base: './src/' }) .pipe(concat('scripts/apploader.js'))
.pipe(gulpif(standalone, concat('scripts/apploader.js'))) .pipe(pipelineJavascript())
.pipe(pipelineJavascript()) .pipe(dest('dist/'))
.pipe(dest('dist/')) .pipe(browserSync.stream());
.pipe(browserSync.stream());
}
task.displayName = 'apploader';
return task;
} }
function webpack() { function webpack() {
@ -181,12 +174,6 @@ function copy(query) {
.pipe(browserSync.stream()); .pipe(browserSync.stream());
} }
function copyIndex() {
return src(options.injectBundle.query, { base: './src/' })
.pipe(dest('dist/'))
.pipe(browserSync.stream());
}
function injectBundle() { function injectBundle() {
return src(options.injectBundle.query, { base: './src/' }) return src(options.injectBundle.query, { base: './src/' })
.pipe(inject( .pipe(inject(
@ -196,10 +183,5 @@ function injectBundle() {
.pipe(browserSync.stream()); .pipe(browserSync.stream());
} }
function build(standalone) { exports.default = series(clean, parallel(javascript, apploader, webpack, css, html, images, copy), injectBundle);
return series(clean, parallel(javascript, apploader(standalone), webpack, css, html, images, copy)); exports.serve = series(exports.default, serve);
}
exports.default = series(build(false), copyIndex);
exports.standalone = series(build(true), injectBundle);
exports.serve = series(exports.standalone, serve);

View file

@ -5,27 +5,29 @@
"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.9.6", "@babel/core": "^7.10.2",
"@babel/plugin-proposal-class-properties": "^7.10.1",
"@babel/plugin-proposal-private-methods": "^7.10.1",
"@babel/plugin-transform-modules-amd": "^7.9.6", "@babel/plugin-transform-modules-amd": "^7.9.6",
"@babel/polyfill": "^7.8.7", "@babel/polyfill": "^7.8.7",
"@babel/preset-env": "^7.8.6", "@babel/preset-env": "^7.10.2",
"autoprefixer": "^9.8.0", "autoprefixer": "^9.8.0",
"babel-eslint": "^11.0.0-beta.2",
"babel-loader": "^8.0.6", "babel-loader": "^8.0.6",
"browser-sync": "^2.26.7", "browser-sync": "^2.26.7",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^5.1.1", "copy-webpack-plugin": "^5.1.1",
"css-loader": "^3.4.2", "css-loader": "^3.4.2",
"cssnano": "^4.1.10", "cssnano": "^4.1.10",
"del": "^5.1.0", "del": "^5.1.0",
"eslint": "^6.8.0", "eslint": "^6.8.0",
"eslint-plugin-compat": "^3.5.1", "eslint-plugin-compat": "^3.5.1",
"eslint-plugin-eslint-comments": "^3.1.2", "eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.20.2", "eslint-plugin-import": "^2.21.1",
"eslint-plugin-promise": "^4.2.1", "eslint-plugin-promise": "^4.2.1",
"file-loader": "^6.0.0", "file-loader": "^6.0.0",
"gulp": "^4.0.2", "gulp": "^4.0.2",
"gulp-babel": "^8.0.0", "gulp-babel": "^8.0.0",
"gulp-cli": "^2.2.1", "gulp-cli": "^2.3.0",
"gulp-concat": "^2.6.1", "gulp-concat": "^2.6.1",
"gulp-htmlmin": "^5.0.1", "gulp-htmlmin": "^5.0.1",
"gulp-if": "^3.0.0", "gulp-if": "^3.0.0",
@ -42,30 +44,29 @@
"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": "^1.1.3",
"stylelint": "^13.5.0", "stylelint": "^13.6.0",
"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.0.0", "stylelint-order": "^4.1.0",
"webpack": "^4.41.5", "webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-concat-plugin": "^3.0.0",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^4.2.2", "webpack-merge": "^4.2.2",
"webpack-stream": "^5.2.1" "webpack-stream": "^5.2.1"
}, },
"dependencies": { "dependencies": {
"alameda": "^1.4.0", "alameda": "^1.4.0",
"blurhash": "^1.1.3",
"classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz", "classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"date-fns": "^2.14.0", "date-fns": "^2.14.0",
"document-register-element": "^1.14.3", "document-register-element": "^1.14.3",
"epubjs": "^0.3.85",
"fast-text-encoding": "^1.0.1", "fast-text-encoding": "^1.0.1",
"flv.js": "^1.5.0", "flv.js": "^1.5.0",
"headroom.js": "^0.11.0", "headroom.js": "^0.11.0",
"hls.js": "^0.13.1", "hls.js": "^0.13.1",
"howler": "^2.2.0", "howler": "^2.2.0",
"intersection-observer": "^0.10.0", "intersection-observer": "^0.10.0",
"jellyfin-apiclient": "^1.1.2", "jellyfin-apiclient": "^1.2.2",
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto", "jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
"jquery": "^3.5.1", "jquery": "^3.5.1",
"jstree": "^3.3.7", "jstree": "^3.3.7",
@ -73,12 +74,12 @@
"material-design-icons-iconfont": "^5.0.1", "material-design-icons-iconfont": "^5.0.1",
"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.11.1", "query-string": "^6.13.0",
"resize-observer-polyfill": "^1.5.1", "resize-observer-polyfill": "^1.5.1",
"screenfull": "^5.0.2", "screenfull": "^5.0.2",
"shaka-player": "^2.5.11", "shaka-player": "^2.5.12",
"sortablejs": "^1.10.2", "sortablejs": "^1.10.2",
"swiper": "^5.4.1", "swiper": "^5.4.2",
"webcomponents.js": "^0.7.24", "webcomponents.js": "^0.7.24",
"whatwg-fetch": "^3.0.0" "whatwg-fetch": "^3.0.0"
}, },
@ -89,38 +90,58 @@
"overrides": [ "overrides": [
{ {
"test": [ "test": [
"src/components/accessSchedule/accessSchedule.js",
"src/components/actionSheet/actionSheet.js",
"src/components/autoFocuser.js", "src/components/autoFocuser.js",
"src/components/cardbuilder/cardBuilder.js", "src/components/cardbuilder/cardBuilder.js",
"src/components/subtitlesettings/subtitlesettings.js", "src/components/cardbuilder/chaptercardbuilder.js",
"src/components/subtitlesettings/subtitleappearancehelper.js", "src/components/cardbuilder/peoplecardbuilder.js",
"src/components/settingshelper.js",
"src/controllers/user/subtitles.js",
"src/scripts/fileDownloader.js",
"src/components/images/imageLoader.js", "src/components/images/imageLoader.js",
"src/components/indicators/indicators.js",
"src/components/lazyLoader/lazyLoaderIntersectionObserver.js", "src/components/lazyLoader/lazyLoaderIntersectionObserver.js",
"src/components/playback/brightnessosd.js",
"src/components/playback/mediasession.js", "src/components/playback/mediasession.js",
"src/components/playback/nowplayinghelper.js",
"src/components/playback/playbackorientation.js",
"src/components/playback/playerSelectionMenu.js",
"src/components/playback/playersettingsmenu.js",
"src/components/playback/playmethodhelper.js",
"src/components/playback/remotecontrolautoplay.js",
"src/components/playback/volumeosd.js",
"src/components/playmenu.js",
"src/components/sanatizefilename.js", "src/components/sanatizefilename.js",
"src/components/scrollManager.js", "src/components/scrollManager.js",
"src/components/syncplay/playbackPermissionManager.js", "src/components/settingshelper.js",
"src/components/syncplay/groupSelectionMenu.js", "src/components/subtitlesettings/subtitlesettings.js",
"src/components/syncplay/timeSyncManager.js", "src/components/subtitlesettings/subtitleappearancehelper.js",
"src/components/syncplay/syncPlayManager.js", "src/components/syncPlay/groupSelectionMenu.js",
"src/components/syncPlay/playbackPermissionManager.js",
"src/components/syncPlay/syncPlayManager.js",
"src/components/syncPlay/timeSyncManager.js",
"src/controllers/dashboard/logs.js",
"src/controllers/user/subtitles.js",
"src/plugins/bookPlayer/plugin.js",
"src/plugins/bookPlayer/tableOfContents.js",
"src/plugins/photoPlayer/plugin.js",
"src/scripts/deleteHelper.js",
"src/scripts/dfnshelper.js", "src/scripts/dfnshelper.js",
"src/scripts/dom.js", "src/scripts/dom.js",
"src/scripts/fileDownloader.js",
"src/scripts/filesystem.js", "src/scripts/filesystem.js",
"src/scripts/imagehelper.js", "src/scripts/imagehelper.js",
"src/scripts/inputManager.js", "src/scripts/inputManager.js",
"src/scripts/deleteHelper.js", "src/plugins/backdropScreensaver/plugin.js",
"src/components/actionSheet/actionSheet.js", "src/components/filterdialog/filterdialog.js",
"src/components/playmenu.js", "src/components/fetchhelper.js",
"src/components/indicators/indicators.js",
"src/scripts/keyboardNavigation.js", "src/scripts/keyboardNavigation.js",
"src/scripts/settings/appSettings.js", "src/scripts/settings/appSettings.js",
"src/scripts/settings/userSettings.js", "src/scripts/settings/userSettings.js",
"src/scripts/settings/webSettings.js" "src/scripts/settings/webSettings.js"
], ],
"plugins": [ "plugins": [
"@babel/plugin-transform-modules-amd" "@babel/plugin-transform-modules-amd",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-private-methods"
] ]
} }
] ]
@ -145,7 +166,6 @@
"prepare": "gulp --production", "prepare": "gulp --production",
"build:development": "gulp --development", "build:development": "gulp --development",
"build:production": "gulp --production", "build:production": "gulp --production",
"build:standalone": "gulp standalone --development",
"lint": "eslint \".\"", "lint": "eslint \".\"",
"stylelint": "stylelint \"src/**/*.css\"" "stylelint": "stylelint \"src/**/*.css\""
} }

View file

@ -597,6 +597,7 @@
.detailImageContainer { .detailImageContainer {
position: relative; position: relative;
margin-top: -25vh; margin-top: -25vh;
margin-bottom: 10vh;
float: left; float: left;
width: 25vw; width: 25vw;
z-index: 3; z-index: 3;
@ -641,7 +642,8 @@ div.itemDetailGalleryLink.defaultCardBackground {
} }
.itemDetailGalleryLink.defaultCardBackground { .itemDetailGalleryLink.defaultCardBackground {
height: 23vw; /* Dirty hack to get it to look somewhat square. Less than ideal. */ /* Dirty hack to get it to look somewhat square. Less than ideal. */
height: 23vw;
} }
.itemDetailGalleryLink.defaultCardBackground > .material-icons { .itemDetailGalleryLink.defaultCardBackground > .material-icons {
@ -1144,3 +1146,21 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards {
margin-top: 0; margin-top: 0;
font-size: 1.4em; font-size: 1.4em;
} }
.overview-controls {
display: flex;
justify-content: flex-end;
}
.detail-clamp-text {
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 12;
-webkit-box-orient: vertical;
}
@media all and (min-width: 40em) {
.detail-clamp-text {
-webkit-line-clamp: 6;
}
}

View file

@ -16,6 +16,12 @@ _define('fetch', function() {
return fetch; return fetch;
}); });
// Blurhash
var blurhash = require('blurhash');
_define('blurhash', function() {
return blurhash;
});
// query-string // query-string
var query = require('query-string'); var query = require('query-string');
_define('queryString', function() { _define('queryString', function() {
@ -102,6 +108,11 @@ _define('jellyfin-noto', function () {
return noto; return noto;
}); });
var epubjs = require('epubjs');
_define('epubjs', function () {
return epubjs;
});
// page.js // page.js
var page = require('page'); var page = require('page');
_define('page', function() { _define('page', function() {

View file

@ -1,9 +1,20 @@
define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-button-light', 'formDialogStyle'], function (dialogHelper, datetime, globalize) { /* eslint-disable indent */
'use strict';
/**
* Module for controlling user parental control from.
* @module components/accessSchedule/accessSchedule
*/
import dialogHelper from 'dialogHelper';
import datetime from 'datetime';
import globalize from 'globalize';
import 'emby-select';
import 'paper-icon-button-light';
import 'formDialogStyle';
function getDisplayTime(hours) { function getDisplayTime(hours) {
var minutes = 0; let minutes = 0;
var pct = hours % 1; const pct = hours % 1;
if (pct) { if (pct) {
minutes = parseInt(60 * pct); minutes = parseInt(60 * pct);
@ -13,25 +24,25 @@ define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-butt
} }
function populateHours(context) { function populateHours(context) {
var html = ''; let html = '';
for (var i = 0; i < 24; i++) { for (let i = 0; i < 24; i++) {
html += '<option value="' + i + '">' + getDisplayTime(i) + '</option>'; html += `<option value="${i}">${getDisplayTime(i)}</option>`;
} }
html += '<option value="24">' + getDisplayTime(0) + '</option>'; html += `<option value="24">${getDisplayTime(0)}</option>`;
context.querySelector('#selectStart').innerHTML = html; context.querySelector('#selectStart').innerHTML = html;
context.querySelector('#selectEnd').innerHTML = html; context.querySelector('#selectEnd').innerHTML = html;
} }
function loadSchedule(context, schedule) { function loadSchedule(context, {DayOfWeek, StartHour, EndHour}) {
context.querySelector('#selectDay').value = schedule.DayOfWeek || 'Sunday'; context.querySelector('#selectDay').value = DayOfWeek || 'Sunday';
context.querySelector('#selectStart').value = schedule.StartHour || 0; context.querySelector('#selectStart').value = StartHour || 0;
context.querySelector('#selectEnd').value = schedule.EndHour || 0; context.querySelector('#selectEnd').value = EndHour || 0;
} }
function submitSchedule(context, options) { function submitSchedule(context, options) {
var updatedSchedule = { const updatedSchedule = {
DayOfWeek: context.querySelector('#selectDay').value, DayOfWeek: context.querySelector('#selectDay').value,
StartHour: context.querySelector('#selectStart').value, StartHour: context.querySelector('#selectStart').value,
EndHour: context.querySelector('#selectEnd').value EndHour: context.querySelector('#selectEnd').value
@ -46,44 +57,42 @@ define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-butt
dialogHelper.close(context); dialogHelper.close(context);
} }
return { export function show(options) {
show: function (options) { return new Promise((resolve, reject) => {
return new Promise(function (resolve, reject) { // TODO: remove require
var xhr = new XMLHttpRequest(); require(['text!./components/accessSchedule/accessSchedule.template.html'], template => {
xhr.open('GET', 'components/accessSchedule/accessSchedule.template.html', true); const dlg = dialogHelper.createDialog({
removeOnClose: true,
xhr.onload = function (e) { size: 'small'
var template = this.response; });
var dlg = dialogHelper.createDialog({ dlg.classList.add('formDialog');
removeOnClose: true, let html = '';
size: 'small' html += globalize.translateDocument(template);
}); dlg.innerHTML = html;
dlg.classList.add('formDialog'); populateHours(dlg);
var html = ''; loadSchedule(dlg, options.schedule);
html += globalize.translateDocument(template); dialogHelper.open(dlg);
dlg.innerHTML = html; dlg.addEventListener('close', () => {
populateHours(dlg); if (dlg.submitted) {
loadSchedule(dlg, options.schedule); resolve(options.schedule);
dialogHelper.open(dlg); } else {
dlg.addEventListener('close', function () { reject();
if (dlg.submitted) { }
resolve(options.schedule); });
} else { dlg.querySelector('.btnCancel').addEventListener('click', () => {
reject(); dialogHelper.close(dlg);
} });
}); dlg.querySelector('form').addEventListener('submit', event => {
dlg.querySelector('.btnCancel').addEventListener('click', function (e) { submitSchedule(dlg, options);
dialogHelper.close(dlg); event.preventDefault();
}); return false;
dlg.querySelector('form').addEventListener('submit', function (e) { });
submitSchedule(dlg, options);
e.preventDefault();
return false;
});
};
xhr.send();
}); });
} });
}; }
});
/* eslint-enable indent */
export default {
show: show
};

View file

@ -16,15 +16,8 @@ function getOffsets(elems) {
return results; return results;
} }
let box;
for (let elem of elems) { for (let elem of elems) {
// Support: BlackBerry 5, iOS 3 (original iPhone) let box = elem.getBoundingClientRect();
// If we don't have gBCR, just use 0,0 rather than error
if (elem.getBoundingClientRect) {
box = elem.getBoundingClientRect();
} else {
box = { top: 0, left: 0 };
}
results.push({ results.push({
top: box.top, top: box.top,
@ -153,7 +146,9 @@ export function show(options) {
} }
if (layoutManager.tv) { if (layoutManager.tv) {
html += '<button is="paper-icon-button-light" class="btnCloseActionSheet hide-mouse-idle-tv" tabindex="-1"><span class="material-icons arrow_back"></span></button>'; html += `<button is="paper-icon-button-light" class="btnCloseActionSheet hide-mouse-idle-tv" tabindex="-1">
<span class="material-icons arrow_back"></span>
</button>`;
} }
// If any items have an icon, give them all an icon just to make sure they're all lined up evenly // If any items have an icon, give them all an icon just to make sure they're all lined up evenly
@ -216,7 +211,7 @@ export function show(options) {
itemIcon = icons[i]; itemIcon = icons[i];
if (itemIcon) { if (itemIcon) {
html += '<span class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons ' + itemIcon + '"></span>'; html += `<span class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons ${itemIcon}"></span>`;
} else if (renderIcon && !center) { } else if (renderIcon && !center) {
html += '<span class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons check" style="visibility:hidden;"></span>'; html += '<span class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons check" style="visibility:hidden;"></span>';
} }
@ -228,13 +223,13 @@ export function show(options) {
html += '</div>'; html += '</div>';
if (item.secondaryText) { if (item.secondaryText) {
html += '<div class="listItemBodyText secondary">' + item.secondaryText + '</div>'; html += `<div class="listItemBodyText secondary">${item.secondaryText}</div>`;
} }
html += '</div>'; html += '</div>';
if (item.asideText) { if (item.asideText) {
html += '<div class="listItemAside actionSheetItemAsideText">' + item.asideText + '</div>'; html += `<div class="listItemAside actionSheetItemAsideText">${item.asideText}</div>`;
} }
html += '</button>'; html += '</button>';
@ -242,7 +237,7 @@ export function show(options) {
if (options.showCancel) { if (options.showCancel) {
html += '<div class="buttons">'; html += '<div class="buttons">';
html += '<button is="emby-button" type="button" class="btnCloseActionSheet">' + globalize.translate('ButtonCancel') + '</button>'; html += `<button is="emby-button" type="button" class="btnCloseActionSheet">${globalize.translate('ButtonCancel')}</button>`;
html += '</div>'; html += '</div>';
} }
html += '</div>'; html += '</div>';

View file

@ -34,10 +34,14 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
html += '</div>'; html += '</div>';
if (entry.Overview) { if (entry.Overview) {
html += '<button type="button" is="paper-icon-button-light" class="btnEntryInfo" data-id="' + entry.Id + '" title="' + globalize.translate('Info') + '"><span class="material-icons info"></span></button>'; html += `<button type="button" is="paper-icon-button-light" class="btnEntryInfo" data-id="${entry.Id}" title="${globalize.translate('Info')}">
<span class="material-icons info"></span>
</button>`;
} }
return html += '</div>'; html += '</div>';
return html;
} }
function renderList(elem, apiClient, result, startIndex, limit) { function renderList(elem, apiClient, result, startIndex, limit) {

View file

@ -26,11 +26,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro
connectionManager.connect({ connectionManager.connect({
enableAutoLogin: appSettings.enableAutoLogin() enableAutoLogin: appSettings.enableAutoLogin()
}).then(function (result) { }).then(function (result) {
handleConnectionResult(result, loading); handleConnectionResult(result);
}); });
} }
function handleConnectionResult(result, loading) { function handleConnectionResult(result) {
switch (result.State) { switch (result.State) {
case 'SignedIn': case 'SignedIn':
loading.hide(); loading.hide();
@ -246,13 +246,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro
} }
if (setQuality) { if (setQuality) {
var quality;
var quality = 100;
var type = options.type || 'Primary'; var type = options.type || 'Primary';
if (browser.tv || browser.slow) { if (browser.tv || browser.slow) {
// TODO: wtf
if (browser.chrome) { if (browser.chrome) {
// webp support // webp support
quality = type === 'Primary' ? 40 : 50; quality = type === 'Primary' ? 40 : 50;
@ -384,7 +382,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro
if (firstResult.State !== 'SignedIn' && !route.anonymous) { if (firstResult.State !== 'SignedIn' && !route.anonymous) {
handleConnectionResult(firstResult, loading); handleConnectionResult(firstResult);
return; return;
} }
} }
@ -463,7 +461,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro
return Promise.resolve(); return Promise.resolve();
} }
var isHandlingBackToDefault;
var isDummyBackToHome; var isDummyBackToHome;
function loadContent(ctx, route, html, request) { function loadContent(ctx, route, html, request) {
@ -589,8 +586,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro
path = '/' + path; path = '/' + path;
} }
var baseRoute = baseUrl(); path = path.replace(baseUrl(), '');
path = path.replace(baseRoute, '');
if (currentRouteInfo && currentRouteInfo.path === path) { if (currentRouteInfo && currentRouteInfo.path === path) {
// can't use this with home right now due to the back menu // can't use this with home right now due to the back menu
@ -621,10 +617,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro
} }
function showItem(item, serverId, options) { function showItem(item, serverId, options) {
// TODO: Refactor this so it only gets items, not strings.
if (typeof (item) === 'string') { if (typeof (item) === 'string') {
var apiClient = serverId ? connectionManager.getApiClient(serverId) : connectionManager.currentApiClient(); var apiClient = serverId ? connectionManager.getApiClient(serverId) : connectionManager.currentApiClient();
apiClient.getItem(apiClient.getCurrentUserId(), item).then(function (item) { apiClient.getItem(apiClient.getCurrentUserId(), item).then(function (itemObject) {
appRouter.showItem(item, options); appRouter.showItem(itemObject, options);
}); });
} else { } else {
if (arguments.length === 2) { if (arguments.length === 2) {

View file

@ -5,7 +5,7 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
var disableHlsVideoAudioCodecs = []; var disableHlsVideoAudioCodecs = [];
if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) { if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) {
if (browser.edge || browser.msie) { if (browser.edge) {
disableHlsVideoAudioCodecs.push('mp3'); disableHlsVideoAudioCodecs.push('mp3');
} }
@ -93,18 +93,36 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
function getDeviceName() { function getDeviceName() {
var deviceName; var deviceName;
deviceName = browser.tizen ? 'Samsung Smart TV' : browser.web0s ? 'LG Smart TV' : browser.operaTv ? 'Opera TV' : browser.xboxOne ? 'Xbox One' : browser.ps4 ? 'Sony PS4' : browser.chrome ? 'Chrome' : browser.edge ? 'Edge' : browser.firefox ? 'Firefox' : browser.msie ? 'Internet Explorer' : browser.opera ? 'Opera' : browser.safari ? 'Safari' : 'Web Browser'; if (browser.tizen) {
deviceName = 'Samsung Smart TV';
} else if (browser.web0s) {
deviceName = 'LG Smart TV';
} else if (browser.operaTv) {
deviceName = 'Opera TV';
} else if (browser.xboxOne) {
deviceName = 'Xbox One';
} else if (browser.ps4) {
deviceName = 'Sony PS4';
} else if (browser.chrome) {
deviceName = 'Chrome';
} else if (browser.edge) {
deviceName = 'Edge';
} else if (browser.firefox) {
deviceName = 'Firefox';
} else if (browser.opera) {
deviceName = 'Opera';
} else if (browser.safari) {
deviceName = 'Safari';
} else {
deviceName = 'Web Browser';
}
if (browser.ipad) { if (browser.ipad) {
deviceName += ' iPad'; deviceName += ' iPad';
} else { } else if (browser.iphone) {
if (browser.iphone) { deviceName += ' iPhone';
deviceName += ' iPhone'; } else if (browser.android) {
} else { deviceName += ' Android';
if (browser.android) {
deviceName += ' Android';
}
}
} }
return deviceName; return deviceName;
@ -267,7 +285,7 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
if (enabled) features.push('multiserver'); if (enabled) features.push('multiserver');
}); });
if (!browser.orsay && !browser.msie && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) { if (!browser.orsay && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) {
features.push('subtitleappearancesettings'); features.push('subtitleappearancesettings');
} }

View file

@ -1,56 +0,0 @@
define(['connectionManager'], function (connectionManager) {
return function () {
var self = this;
self.name = 'Backdrop ScreenSaver';
self.type = 'screensaver';
self.id = 'backdropscreensaver';
self.supportsAnonymous = false;
var currentSlideshow;
self.show = function () {
var query = {
ImageTypes: 'Backdrop',
EnableImageTypes: 'Backdrop',
IncludeItemTypes: 'Movie,Series,MusicArtist',
SortBy: 'Random',
Recursive: true,
Fields: 'Taglines',
ImageTypeLimit: 1,
StartIndex: 0,
Limit: 200
};
var apiClient = connectionManager.currentApiClient();
apiClient.getItems(apiClient.getCurrentUserId(), query).then(function (result) {
if (result.Items.length) {
require(['slideshow'], function (slideshow) {
var newSlideShow = new slideshow({
showTitle: true,
cover: true,
items: result.Items
});
newSlideShow.show();
currentSlideshow = newSlideShow;
});
}
});
};
self.hide = function () {
if (currentSlideshow) {
currentSlideshow.hide();
currentSlideshow = null;
}
};
};
});

View file

@ -503,94 +503,49 @@ import 'programStyles';
const primaryImageAspectRatio = item.PrimaryImageAspectRatio; const primaryImageAspectRatio = item.PrimaryImageAspectRatio;
let forceName = false; let forceName = false;
let imgUrl = null; let imgUrl = null;
let imgTag = null;
let coverImage = false; let coverImage = false;
let uiAspect = null; let uiAspect = null;
let imgType = null;
let itemId = null;
if (options.preferThumb && item.ImageTags && item.ImageTags.Thumb) { if (options.preferThumb && item.ImageTags && item.ImageTags.Thumb) {
imgType = 'Thumb';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.ImageTags.Thumb;
type: 'Thumb',
maxWidth: width,
tag: item.ImageTags.Thumb
});
} else if ((options.preferBanner || shape === 'banner') && item.ImageTags && item.ImageTags.Banner) { } else if ((options.preferBanner || shape === 'banner') && item.ImageTags && item.ImageTags.Banner) {
imgType = 'Banner';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.ImageTags.Banner;
type: 'Banner',
maxWidth: width,
tag: item.ImageTags.Banner
});
} else if (options.preferDisc && item.ImageTags && item.ImageTags.Disc) { } else if (options.preferDisc && item.ImageTags && item.ImageTags.Disc) {
imgType = 'Disc';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.ImageTags.Disc;
type: 'Disc',
maxWidth: width,
tag: item.ImageTags.Disc
});
} else if (options.preferLogo && item.ImageTags && item.ImageTags.Logo) { } else if (options.preferLogo && item.ImageTags && item.ImageTags.Logo) {
imgType = 'Logo';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.ImageTags.Logo;
type: 'Logo',
maxWidth: width,
tag: item.ImageTags.Logo
});
} else if (options.preferLogo && item.ParentLogoImageTag && item.ParentLogoItemId) { } else if (options.preferLogo && item.ParentLogoImageTag && item.ParentLogoItemId) {
imgType = 'Logo';
imgUrl = apiClient.getScaledImageUrl(item.ParentLogoItemId, { imgTag = item.ParentLogoImageTag;
type: 'Logo', itemId = item.ParentLogoItemId;
maxWidth: width,
tag: item.ParentLogoImageTag
});
} else if (options.preferThumb && item.SeriesThumbImageTag && options.inheritThumb !== false) { } else if (options.preferThumb && item.SeriesThumbImageTag && options.inheritThumb !== false) {
imgType = 'Thumb';
imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { imgTag = item.SeriesThumbImageTag;
type: 'Thumb', itemId = item.SeriesId;
maxWidth: width,
tag: item.SeriesThumbImageTag
});
} else if (options.preferThumb && item.ParentThumbItemId && options.inheritThumb !== false && item.MediaType !== 'Photo') { } else if (options.preferThumb && item.ParentThumbItemId && options.inheritThumb !== false && item.MediaType !== 'Photo') {
imgType = 'Thumb';
imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, { imgTag = item.ParentThumbImageTag;
type: 'Thumb', itemId = item.ParentThumbItemId;
maxWidth: width,
tag: item.ParentThumbImageTag
});
} else if (options.preferThumb && item.BackdropImageTags && item.BackdropImageTags.length) { } else if (options.preferThumb && item.BackdropImageTags && item.BackdropImageTags.length) {
imgType = 'Backdrop';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.BackdropImageTags[0];
type: 'Backdrop',
maxWidth: width,
tag: item.BackdropImageTags[0]
});
forceName = true; forceName = true;
} else if (options.preferThumb && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false && item.Type === 'Episode') { } else if (options.preferThumb && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false && item.Type === 'Episode') {
imgType = 'Backdrop';
imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { imgTag = item.ParentBackdropImageTags[0];
type: 'Backdrop', itemId = item.ParentBackdropItemId;
maxWidth: width,
tag: item.ParentBackdropImageTags[0]
});
} else if (item.ImageTags && item.ImageTags.Primary) { } else if (item.ImageTags && item.ImageTags.Primary) {
imgType = 'Primary';
imgTag = item.ImageTags.Primary;
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
imgUrl = apiClient.getScaledImageUrl(item.Id, {
type: 'Primary',
maxHeight: height,
maxWidth: width,
tag: item.ImageTags.Primary
});
if (options.preferThumb && options.showTitle !== false) { if (options.preferThumb && options.showTitle !== false) {
forceName = true; forceName = true;
} }
@ -603,16 +558,11 @@ import 'programStyles';
} }
} else if (item.PrimaryImageTag) { } else if (item.PrimaryImageTag) {
imgType = 'Primary';
imgTag = item.PrimaryImageTag;
itemId = item.PrimaryImageItemId;
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
imgUrl = apiClient.getScaledImageUrl(item.PrimaryImageItemId || item.Id || item.ItemId, {
type: 'Primary',
maxHeight: height,
maxWidth: width,
tag: item.PrimaryImageTag
});
if (options.preferThumb && options.showTitle !== false) { if (options.preferThumb && options.showTitle !== false) {
forceName = true; forceName = true;
} }
@ -624,30 +574,19 @@ import 'programStyles';
} }
} }
} else if (item.ParentPrimaryImageTag) { } else if (item.ParentPrimaryImageTag) {
imgType = 'Primary';
imgUrl = apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, { imgTag = item.ParentPrimaryImageTag;
type: 'Primary', itemId = item.ParentPrimaryImageItemId;
maxWidth: width,
tag: item.ParentPrimaryImageTag
});
} else if (item.SeriesPrimaryImageTag) { } else if (item.SeriesPrimaryImageTag) {
imgType = 'Primary';
imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { imgTag = item.SeriesPrimaryImageTag;
type: 'Primary', itemId = item.SeriesId;
maxWidth: width,
tag: item.SeriesPrimaryImageTag
});
} else if (item.AlbumId && item.AlbumPrimaryImageTag) { } else if (item.AlbumId && item.AlbumPrimaryImageTag) {
imgType = 'Primary';
imgTag = item.AlbumPrimaryImageTag;
itemId = item.AlbumId;
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
imgUrl = apiClient.getScaledImageUrl(item.AlbumId, {
type: 'Primary',
maxHeight: height,
maxWidth: width,
tag: item.AlbumPrimaryImageTag
});
if (primaryImageAspectRatio) { if (primaryImageAspectRatio) {
uiAspect = getDesiredAspect(shape); uiAspect = getDesiredAspect(shape);
if (uiAspect) { if (uiAspect) {
@ -655,57 +594,46 @@ import 'programStyles';
} }
} }
} else if (item.Type === 'Season' && item.ImageTags && item.ImageTags.Thumb) { } else if (item.Type === 'Season' && item.ImageTags && item.ImageTags.Thumb) {
imgType = 'Thumb';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.ImageTags.Thumb;
type: 'Thumb',
maxWidth: width,
tag: item.ImageTags.Thumb
});
} else if (item.BackdropImageTags && item.BackdropImageTags.length) { } else if (item.BackdropImageTags && item.BackdropImageTags.length) {
imgType = 'Backdrop';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.BackdropImageTags[0];
type: 'Backdrop',
maxWidth: width,
tag: item.BackdropImageTags[0]
});
} else if (item.ImageTags && item.ImageTags.Thumb) { } else if (item.ImageTags && item.ImageTags.Thumb) {
imgType = 'Thumb';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.ImageTags.Thumb;
type: 'Thumb',
maxWidth: width,
tag: item.ImageTags.Thumb
});
} else if (item.SeriesThumbImageTag && options.inheritThumb !== false) { } else if (item.SeriesThumbImageTag && options.inheritThumb !== false) {
imgType = 'Thumb';
imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { imgTag = item.SeriesThumbImageTag;
type: 'Thumb', itemId = item.SeriesId;
maxWidth: width,
tag: item.SeriesThumbImageTag
});
} else if (item.ParentThumbItemId && options.inheritThumb !== false) { } else if (item.ParentThumbItemId && options.inheritThumb !== false) {
imgType = 'Thumb';
imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, { imgTag = item.ParentThumbImageTag;
type: 'Thumb', itemId = item.ParentThumbItemId;
maxWidth: width,
tag: item.ParentThumbImageTag
});
} else if (item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false) { } else if (item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false) {
imgType = 'Backdrop';
imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { imgTag = item.ParentBackdropImageTags[0];
type: 'Backdrop', itemId = item.ParentBackdropItemId;
maxWidth: width,
tag: item.ParentBackdropImageTags[0]
});
} }
if (!itemId) {
itemId = item.Id;
}
if (imgTag && imgType) {
imgUrl = apiClient.getScaledImageUrl(itemId, {
type: imgType,
maxHeight: height,
maxWidth: width,
tag: imgTag
});
}
let blurHashes = options.imageBlurhashes || item.ImageBlurHashes || {};
return { return {
imgUrl: imgUrl, imgUrl: imgUrl,
blurhash: (blurHashes[imgType] || {})[imgTag],
forceName: forceName, forceName: forceName,
coverImage: coverImage coverImage: coverImage
}; };
@ -1321,6 +1249,7 @@ import 'programStyles';
const imgInfo = getCardImageUrl(item, apiClient, options, shape); const imgInfo = getCardImageUrl(item, apiClient, options, shape);
const imgUrl = imgInfo.imgUrl; const imgUrl = imgInfo.imgUrl;
const blurhash = imgInfo.blurhash;
const forceName = imgInfo.forceName; const forceName = imgInfo.forceName;
@ -1445,15 +1374,20 @@ import 'programStyles';
cardContentClass += ' cardContent-shadow'; cardContentClass += ' cardContent-shadow';
} }
let blurhashAttrib = '';
if (blurhash && blurhash.length > 0) {
blurhashAttrib = 'data-blurhash="' + blurhash + '"';
}
if (layoutManager.tv) { if (layoutManager.tv) {
// Don't use the IMG tag with safari because it puts a white border around it // Don't use the IMG tag with safari because it puts a white border around it
cardImageContainerOpen = imgUrl ? ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + ' lazy" data-src="' + imgUrl + '">') : ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + '">'); cardImageContainerOpen = imgUrl ? ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + ' lazy" data-src="' + imgUrl + '" ' + blurhashAttrib + '>') : ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + '">');
cardImageContainerClose = '</div>'; cardImageContainerClose = '</div>';
} else { } else {
// Don't use the IMG tag with safari because it puts a white border around it // Don't use the IMG tag with safari because it puts a white border around it
cardImageContainerOpen = imgUrl ? ('<button data-action="' + action + '" class="cardContent-button ' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction lazy" data-src="' + imgUrl + '">') : ('<button data-action="' + action + '" class="cardContent-button ' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction">'); cardImageContainerOpen = imgUrl ? ('<button data-action="' + action + '" class="cardContent-button ' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction lazy" data-src="' + imgUrl + '" ' + blurhashAttrib + '>') : ('<button data-action="' + action + '" class="cardContent-button ' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction">');
cardImageContainerClose = '</button>'; cardImageContainerClose = '</button>';
} }

View file

@ -1,13 +1,23 @@
define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browser'], function (datetime, imageLoader, connectionManager, layoutManager, browser) { /* eslint-disable indent */
'use strict';
var enableFocusTransform = !browser.slow && !browser.edge; /**
* Module for building cards from item data.
* @module components/cardBuilder/chaptercardbuilder
*/
function buildChapterCardsHtml(item, chapters, options) { import datetime from 'datetime';
import imageLoader from 'imageLoader';
import connectionManager from 'connectionManager';
import layoutManager from 'layoutManager';
import browser from 'browser';
const enableFocusTransform = !browser.slow && !browser.edge;
function buildChapterCardsHtml(item, chapters, options) {
// TODO move card creation code to Card component // TODO move card creation code to Card component
var className = 'card itemAction chapterCard'; let className = 'card itemAction chapterCard';
if (layoutManager.tv) { if (layoutManager.tv) {
className += ' show-focus'; className += ' show-focus';
@ -17,12 +27,12 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
} }
} }
var mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || []; const mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || [];
var videoStream = mediaStreams.filter(function (i) { const videoStream = mediaStreams.filter(({Type}) => {
return i.Type === 'Video'; return Type === 'Video';
})[0] || {}; })[0] || {};
var shape = (options.backdropShape || 'backdrop'); let shape = (options.backdropShape || 'backdrop');
if (videoStream.Width && videoStream.Height) { if (videoStream.Width && videoStream.Height) {
@ -31,24 +41,24 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
} }
} }
className += ' ' + shape + 'Card'; className += ` ${shape}Card`;
if (options.block || options.rows) { if (options.block || options.rows) {
className += ' block'; className += ' block';
} }
var html = ''; let html = '';
var itemsInRow = 0; let itemsInRow = 0;
var apiClient = connectionManager.getApiClient(item.ServerId); const apiClient = connectionManager.getApiClient(item.ServerId);
for (var i = 0, length = chapters.length; i < length; i++) { for (let i = 0, length = chapters.length; i < length; i++) {
if (options.rows && itemsInRow === 0) { if (options.rows && itemsInRow === 0) {
html += '<div class="cardColumn">'; html += '<div class="cardColumn">';
} }
var chapter = chapters[i]; const chapter = chapters[i];
html += buildChapterCard(item, apiClient, chapter, i, options, className, shape); html += buildChapterCard(item, apiClient, chapter, i, options, className, shape);
itemsInRow++; itemsInRow++;
@ -62,50 +72,50 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
return html; return html;
} }
function getImgUrl(item, chapter, index, maxWidth, apiClient) { function getImgUrl({Id}, {ImageTag}, index, maxWidth, apiClient) {
if (chapter.ImageTag) { if (ImageTag) {
return apiClient.getScaledImageUrl(item.Id, { return apiClient.getScaledImageUrl(Id, {
maxWidth: maxWidth * 2, maxWidth: maxWidth * 2,
tag: chapter.ImageTag, tag: ImageTag,
type: 'Chapter', type: 'Chapter',
index: index index
}); });
} }
return null; return null;
} }
function buildChapterCard(item, apiClient, chapter, index, options, className, shape) { function buildChapterCard(item, apiClient, chapter, index, {width, coverImage}, className, shape) {
var imgUrl = getImgUrl(item, chapter, index, options.width || 400, apiClient); const imgUrl = getImgUrl(item, chapter, index, width || 400, apiClient);
var cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer'; let cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer';
if (options.coverImage) { if (coverImage) {
cardImageContainerClass += ' coveredImage'; cardImageContainerClass += ' coveredImage';
} }
var dataAttributes = ' data-action="play" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-positionticks="' + chapter.StartPositionTicks + '"'; const dataAttributes = ` data-action="play" data-isfolder="${item.IsFolder}" data-id="${item.Id}" data-serverid="${item.ServerId}" data-type="${item.Type}" data-mediatype="${item.MediaType}" data-positionticks="${chapter.StartPositionTicks}"`;
var cardImageContainer = imgUrl ? ('<div class="' + cardImageContainerClass + ' lazy" data-src="' + imgUrl + '">') : ('<div class="' + cardImageContainerClass + '">'); let cardImageContainer = imgUrl ? (`<div class="${cardImageContainerClass} lazy" data-src="${imgUrl}">`) : (`<div class="${cardImageContainerClass}">`);
if (!imgUrl) { if (!imgUrl) {
cardImageContainer += '<span class="material-icons cardImageIcon local_movies"></span>'; cardImageContainer += '<span class="material-icons cardImageIcon local_movies"></span>';
} }
var nameHtml = ''; let nameHtml = '';
nameHtml += '<div class="cardText">' + chapter.Name + '</div>'; nameHtml += `<div class="cardText">${chapter.Name}</div>`;
nameHtml += '<div class="cardText">' + datetime.getDisplayRunningTime(chapter.StartPositionTicks) + '</div>'; nameHtml += `<div class="cardText">${datetime.getDisplayRunningTime(chapter.StartPositionTicks)}</div>`;
var cardBoxCssClass = 'cardBox'; const cardBoxCssClass = 'cardBox';
var cardScalableClass = 'cardScalable'; const cardScalableClass = 'cardScalable';
var html = '<button type="button" class="' + className + '"' + dataAttributes + '><div class="' + cardBoxCssClass + '"><div class="' + cardScalableClass + '"><div class="cardPadder-' + shape + '"></div>' + cardImageContainer + '</div><div class="innerCardFooter">' + nameHtml + '</div></div></div></button>'; const html = `<button type="button" class="${className}"${dataAttributes}><div class="${cardBoxCssClass}"><div class="${cardScalableClass}"><div class="cardPadder-${shape}"></div>${cardImageContainer}</div><div class="innerCardFooter">${nameHtml}</div></div></div></button>`;
return html; return html;
} }
function buildChapterCards(item, chapters, options) { export function buildChapterCards(item, chapters, options) {
if (options.parentContainer) { if (options.parentContainer) {
// Abort if the container has been disposed // Abort if the container has been disposed
@ -121,15 +131,16 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
} }
} }
var html = buildChapterCardsHtml(item, chapters, options); const html = buildChapterCardsHtml(item, chapters, options);
options.itemsContainer.innerHTML = html; options.itemsContainer.innerHTML = html;
imageLoader.lazyChildren(options.itemsContainer); imageLoader.lazyChildren(options.itemsContainer);
} }
return { /* eslint-enable indent */
buildChapterCards: buildChapterCards
}; export default {
buildChapterCards: buildChapterCards
};
});

View file

@ -1,7 +1,13 @@
define(['cardBuilder'], function (cardBuilder) { /* eslint-disable indent */
'use strict';
function buildPeopleCards(items, options) { /**
* Module for building cards from item data.
* @module components/cardBuilder/peoplecardbuilder
*/
import cardBuilder from 'cardBuilder';
export function buildPeopleCards(items, options) {
options = Object.assign(options || {}, { options = Object.assign(options || {}, {
cardLayout: false, cardLayout: false,
@ -15,8 +21,8 @@ define(['cardBuilder'], function (cardBuilder) {
cardBuilder.buildCards(items, options); cardBuilder.buildCards(items, options);
} }
return { /* eslint-enable indent */
buildPeopleCards: buildPeopleCards
};
}); export default {
buildPeopleCards: buildPeopleCards
};

View file

@ -181,7 +181,9 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
context.querySelector('#chkThemeSong').checked = userSettings.enableThemeSongs(); context.querySelector('#chkThemeSong').checked = userSettings.enableThemeSongs();
context.querySelector('#chkThemeVideo').checked = userSettings.enableThemeVideos(); context.querySelector('#chkThemeVideo').checked = userSettings.enableThemeVideos();
context.querySelector('#chkFadein').checked = userSettings.enableFastFadein(); context.querySelector('#chkFadein').checked = userSettings.enableFastFadein();
context.querySelector('#chkBlurhash').checked = userSettings.enableBlurhash();
context.querySelector('#chkBackdrops').checked = userSettings.enableBackdrops(); context.querySelector('#chkBackdrops').checked = userSettings.enableBackdrops();
context.querySelector('#chkDetailsBanner').checked = userSettings.detailsBanner();
context.querySelector('#selectLanguage').value = userSettings.language() || ''; context.querySelector('#selectLanguage').value = userSettings.language() || '';
context.querySelector('.selectDateTimeLocale').value = userSettings.dateTimeLocale() || ''; context.querySelector('.selectDateTimeLocale').value = userSettings.dateTimeLocale() || '';
@ -222,7 +224,9 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
userSettingsInstance.skin(context.querySelector('.selectSkin').value); userSettingsInstance.skin(context.querySelector('.selectSkin').value);
userSettingsInstance.enableFastFadein(context.querySelector('#chkFadein').checked); userSettingsInstance.enableFastFadein(context.querySelector('#chkFadein').checked);
userSettingsInstance.enableBlurhash(context.querySelector('#chkBlurhash').checked);
userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked); userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked);
userSettingsInstance.detailsBanner(context.querySelector('#chkDetailsBanner').checked);
if (user.Id === apiClient.getCurrentUserId()) { if (user.Id === apiClient.getCurrentUserId()) {
skinManager.setTheme(userSettingsInstance.theme()); skinManager.setTheme(userSettingsInstance.theme());

View file

@ -143,17 +143,33 @@
<select is="emby-select" class="selectSoundEffects" label="${LabelSoundEffects}"></select> <select is="emby-select" class="selectSoundEffects" label="${LabelSoundEffects}"></select>
</div> </div>
<div class="inputContainer inputContainer-withDescription fldFadein"> <div class="inputContainer inputContainer-withDescription">
<input is="emby-input" type="number" id="txtLibraryPageSize" pattern="[0-9]*" required="required" min="0" max="1000" step="1" label="${LabelLibraryPageSize}" /> <input is="emby-input" type="number" id="txtLibraryPageSize" pattern="[0-9]*" required="required" min="0" max="1000" step="1" label="${LabelLibraryPageSize}" />
<div class="fieldDescription">${LabelLibraryPageSizeHelp}</div> <div class="fieldDescription">${LabelLibraryPageSizeHelp}</div>
</div> </div>
<div class="checkboxContainer checkboxContainer-withDescription fldFadein"> <div class="checkboxContainer checkboxContainer-withDescription">
<label> <label>
<input type="checkbox" is="emby-checkbox" id="chkFadein" /> <input type="checkbox" is="emby-checkbox" id="chkFadein" />
<span>${EnableFastImageFadeIn}</span> <span>${EnableFasterAnimations}</span>
</label> </label>
<div class="fieldDescription checkboxFieldDescription">${EnableFastImageFadeInHelp}</div> <div class="fieldDescription checkboxFieldDescription">${EnableFasterAnimationsHelp}</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input type="checkbox" is="emby-checkbox" id="chkBlurhash" />
<span>${EnableBlurhash}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${EnableBlurhashHelp}</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input type="checkbox" is="emby-checkbox" id="chkDetailsBanner" />
<span>${EnableDetailsBanner}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${EnableDetailsBannerHelp}</div>
</div> </div>
<div class="checkboxContainer checkboxContainer-withDescription fldBackdrops hide"> <div class="checkboxContainer checkboxContainer-withDescription fldBackdrops hide">

View file

@ -1,21 +1,19 @@
define([], function () { /* eslint-disable indent */
'use strict'; export function getFetchPromise(request) {
function getFetchPromise(request) { const headers = request.headers || {};
var headers = request.headers || {};
if (request.dataType === 'json') { if (request.dataType === 'json') {
headers.accept = 'application/json'; headers.accept = 'application/json';
} }
var fetchRequest = { const fetchRequest = {
headers: headers, headers: headers,
method: request.type, method: request.type,
credentials: 'same-origin' credentials: 'same-origin'
}; };
var contentType = request.contentType; let contentType = request.contentType;
if (request.data) { if (request.data) {
@ -33,12 +31,12 @@ define([], function () {
headers['Content-Type'] = contentType; headers['Content-Type'] = contentType;
} }
var url = request.url; let url = request.url;
if (request.query) { if (request.query) {
var paramString = paramsToString(request.query); const paramString = paramsToString(request.query);
if (paramString) { if (paramString) {
url += '?' + paramString; url += `?${paramString}`;
} }
} }
@ -51,11 +49,11 @@ define([], function () {
function fetchWithTimeout(url, options, timeoutMs) { function fetchWithTimeout(url, options, timeoutMs) {
console.debug('fetchWithTimeout: timeoutMs: ' + timeoutMs + ', url: ' + url); console.debug(`fetchWithTimeout: timeoutMs: ${timeoutMs}, url: ${url}`);
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
var timeout = setTimeout(reject, timeoutMs); const timeout = setTimeout(reject, timeoutMs);
options = options || {}; options = options || {};
options.credentials = 'same-origin'; options.credentials = 'same-origin';
@ -63,50 +61,47 @@ define([], function () {
fetch(url, options).then(function (response) { fetch(url, options).then(function (response) {
clearTimeout(timeout); clearTimeout(timeout);
console.debug('fetchWithTimeout: succeeded connecting to url: ' + url); console.debug(`fetchWithTimeout: succeeded connecting to url: ${url}`);
resolve(response); resolve(response);
}, function (error) { }, function (error) {
clearTimeout(timeout); clearTimeout(timeout);
console.debug('fetchWithTimeout: timed out connecting to url: ' + url); console.debug(`fetchWithTimeout: timed out connecting to url: ${url}`);
reject(); reject(error);
}); });
}); });
} }
/**
* @param params {Record<string, string | number | boolean>}
* @returns {string} Query string
*/
function paramsToString(params) { function paramsToString(params) {
return Object.entries(params)
var values = []; // eslint-disable-next-line no-unused-vars
.filter(([_, v]) => v !== null && v !== undefined && v !== '')
for (var key in params) { .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
.join('&');
var value = params[key];
if (value !== null && value !== undefined && value !== '') {
values.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
}
}
return values.join('&');
} }
function ajax(request) { export function ajax(request) {
if (!request) { if (!request) {
throw new Error('Request cannot be null'); throw new Error('Request cannot be null');
} }
request.headers = request.headers || {}; request.headers = request.headers || {};
console.debug('requesting url: ' + request.url); console.debug(`requesting url: ${request.url}`);
return getFetchPromise(request).then(function (response) { return getFetchPromise(request).then(function (response) {
console.debug('response status: ' + response.status + ', url: ' + request.url); console.debug(`response status: ${response.status}, url: ${request.url}`);
if (response.status < 400) { if (response.status < 400) {
if (request.dataType === 'json' || request.headers.accept === 'application/json') { if (request.dataType === 'json' || request.headers.accept === 'application/json') {
return response.json(); return response.json();
} else if (request.dataType === 'text' || (response.headers.get('Content-Type') || '').toLowerCase().indexOf('text/') === 0) { } else if (request.dataType === 'text' || (response.headers.get('Content-Type') || '').toLowerCase().startsWith('text/')) {
return response.text(); return response.text();
} else { } else {
return response; return response;
@ -115,12 +110,8 @@ define([], function () {
return Promise.reject(response); return Promise.reject(response);
} }
}, function (err) { }, function (err) {
console.error('request failed to url: ' + request.url); console.error(`request failed to url: ${request.url}`);
throw err; throw err;
}); });
} }
return { /* eslint-enable indent */
getFetchPromise: getFetchPromise,
ajax: ajax
};
});

View file

@ -1,21 +1,28 @@
define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'browser', 'require', 'emby-checkbox', 'emby-collapse', 'css!./style'], function (dom, dialogHelper, globalize, connectionManager, events, browser, require) { import dom from 'dom';
'use strict'; import dialogHelper from 'dialogHelper';
import globalize from 'globalize';
import connectionManager from 'connectionManager';
import events from 'events';
import 'emby-checkbox';
import 'emby-collapse';
import 'css!./style.css';
/* eslint-disable indent */
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');
} else { } else {
elem.classList.add('hide'); elem.classList.add('hide');
} }
var html = ''; let html = '';
html += '<div class="checkboxList">'; html += '<div class="checkboxList">';
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 + '" class="' + cssClass + '"/>'; itemHtml += `<input is="emby-checkbox" type="checkbox" ${checkedHtml} data-filter="${filter}" class="${cssClass}"/>`;
itemHtml += '<span>' + filter + '</span>'; itemHtml += `<span>${filter}</span>`;
itemHtml += '</label>'; itemHtml += '</label>';
return itemHtml; return itemHtml;
}).join(''); }).join('');
@ -24,21 +31,24 @@ define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'brow
} }
function renderFilters(context, result, query) { function renderFilters(context, result, query) {
if (result.Tags) {
result.Tags.length = Math.min(result.Tags.length, 50);
}
renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) { renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) {
var delimeter = '|'; const delimeter = '|';
return (delimeter + (query.Genres || '') + delimeter).indexOf(delimeter + i + delimeter) != -1; return (delimeter + (query.Genres || '') + delimeter).includes(delimeter + i + delimeter);
}); });
renderOptions(context, '.officialRatingFilters', 'chkOfficialRatingFilter', result.OfficialRatings, function (i) { renderOptions(context, '.officialRatingFilters', 'chkOfficialRatingFilter', result.OfficialRatings, function (i) {
var delimeter = '|'; const delimeter = '|';
return (delimeter + (query.OfficialRatings || '') + delimeter).indexOf(delimeter + i + delimeter) != -1; return (delimeter + (query.OfficialRatings || '') + delimeter).includes(delimeter + i + delimeter);
}); });
renderOptions(context, '.tagFilters', 'chkTagFilter', result.Tags, function (i) { renderOptions(context, '.tagFilters', 'chkTagFilter', result.Tags, function (i) {
var delimeter = '|'; const delimeter = '|';
return (delimeter + (query.Tags || '') + delimeter).indexOf(delimeter + i + delimeter) != -1; return (delimeter + (query.Tags || '') + delimeter).includes(delimeter + i + delimeter);
}); });
renderOptions(context, '.yearFilters', 'chkYearFilter', result.Years, function (i) { renderOptions(context, '.yearFilters', 'chkYearFilter', result.Years, function (i) {
var delimeter = ','; const delimeter = ',';
return (delimeter + (query.Years || '') + delimeter).indexOf(delimeter + i + delimeter) != -1; return (delimeter + (query.Years || '') + delimeter).includes(delimeter + i + delimeter);
}); });
} }
@ -52,59 +62,58 @@ define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'brow
}); });
} }
/**
* @param context {HTMLDivElement} Dialog
* @param options {any} Options
*/
function updateFilterControls(context, options) { function updateFilterControls(context, options) {
var elems; const query = options.query;
var i;
var length;
var query = options.query;
if (options.mode == 'livetvchannels') { if (options.mode === 'livetvchannels') {
context.querySelector('.chkFavorite').checked = query.IsFavorite == true; context.querySelector('.chkFavorite').checked = query.IsFavorite === true;
context.querySelector('.chkLikes').checked = query.IsLiked == true; context.querySelector('.chkLikes').checked = query.IsLiked === true;
context.querySelector('.chkDislikes').checked = query.IsDisliked == true; context.querySelector('.chkDislikes').checked = query.IsDisliked === true;
} else { } else {
elems = context.querySelectorAll('.chkStandardFilter'); for (const elem of context.querySelectorAll('.chkStandardFilter')) {
for (i = 0, length = elems.length; i < length; i++) { const filters = `,${query.Filters || ''}`;
var chkStandardFilter = elems[i]; const filterName = elem.getAttribute('data-filter');
var filters = ',' + (query.Filters || ''); elem.checked = filters.includes(`,${filterName}`);
var filterName = chkStandardFilter.getAttribute('data-filter');
chkStandardFilter.checked = filters.indexOf(',' + filterName) != -1;
} }
} }
elems = context.querySelectorAll('.chkVideoTypeFilter'); for (const elem of context.querySelectorAll('.chkVideoTypeFilter')) {
for (i = 0, length = elems.length; i < length; i++) { const filters = `,${query.VideoTypes || ''}`;
var chkVideoTypeFilter = elems[i]; const filterName = elem.getAttribute('data-filter');
var filters = ',' + (query.VideoTypes || ''); elem.checked = filters.includes(`,${filterName}`);
var filterName = chkVideoTypeFilter.getAttribute('data-filter');
chkVideoTypeFilter.checked = filters.indexOf(',' + filterName) != -1;
} }
context.querySelector('.chk3DFilter').checked = query.Is3D == true; context.querySelector('.chk3DFilter').checked = query.Is3D === true;
context.querySelector('.chkHDFilter').checked = query.IsHD == true; context.querySelector('.chkHDFilter').checked = query.IsHD === true;
context.querySelector('.chk4KFilter').checked = query.Is4K == true; context.querySelector('.chk4KFilter').checked = query.Is4K === true;
context.querySelector('.chkSDFilter').checked = query.IsHD == true; context.querySelector('.chkSDFilter').checked = query.IsHD === true;
context.querySelector('#chkSubtitle').checked = query.HasSubtitles == true; context.querySelector('#chkSubtitle').checked = query.HasSubtitles === true;
context.querySelector('#chkTrailer').checked = query.HasTrailer == true; context.querySelector('#chkTrailer').checked = query.HasTrailer === true;
context.querySelector('#chkThemeSong').checked = query.HasThemeSong == true; context.querySelector('#chkThemeSong').checked = query.HasThemeSong === true;
context.querySelector('#chkThemeVideo').checked = query.HasThemeVideo == true; context.querySelector('#chkThemeVideo').checked = query.HasThemeVideo === true;
context.querySelector('#chkSpecialFeature').checked = query.HasSpecialFeature == true; context.querySelector('#chkSpecialFeature').checked = query.HasSpecialFeature === true;
context.querySelector('#chkSpecialEpisode').checked = query.ParentIndexNumber == 0; context.querySelector('#chkSpecialEpisode').checked = query.ParentIndexNumber === 0;
context.querySelector('#chkMissingEpisode').checked = query.IsMissing == true; context.querySelector('#chkMissingEpisode').checked = query.IsMissing === true;
context.querySelector('#chkFutureEpisode').checked = query.IsUnaired == true; context.querySelector('#chkFutureEpisode').checked = query.IsUnaired === true;
for (i = 0, length = elems.length; i < length; i++) { for (const elem of context.querySelectorAll('.chkStatus')) {
var chkStatus = elems[i]; const filters = `,${query.SeriesStatus || ''}`;
var filters = ',' + (query.SeriesStatus || ''); const filterName = elem.getAttribute('data-filter');
var filterName = chkStatus.getAttribute('data-filter'); elem.checked = filters.includes(`,${filterName}`);
chkStatus.checked = filters.indexOf(',' + filterName) != -1;
} }
} }
/**
* @param instance {FilterDialog} An instance of FilterDialog
*/
function triggerChange(instance) { function triggerChange(instance) {
events.trigger(instance, 'filterchange'); events.trigger(instance, 'filterchange');
} }
function setVisibility(context, options) { function setVisibility(context, options) {
if (options.mode == 'livetvchannels' || options.mode == 'albums' || options.mode == 'artists' || options.mode == 'albumartists' || options.mode == 'songs') { if (options.mode === 'livetvchannels' || options.mode === 'albums' || options.mode === 'artists' || options.mode === 'albumartists' || options.mode === 'songs') {
hideByClass(context, 'videoStandard'); hideByClass(context, 'videoStandard');
} }
@ -115,263 +124,287 @@ define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'brow
context.querySelector('.yearFilters').classList.remove('hide'); context.querySelector('.yearFilters').classList.remove('hide');
} }
if (options.mode == 'movies' || options.mode == 'episodes') { if (options.mode === 'movies' || options.mode === 'episodes') {
context.querySelector('.videoTypeFilters').classList.remove('hide'); context.querySelector('.videoTypeFilters').classList.remove('hide');
} }
if (options.mode == 'movies' || options.mode == 'series' || options.mode == 'episodes') { if (options.mode === 'movies' || options.mode === 'series' || options.mode === 'episodes') {
context.querySelector('.features').classList.remove('hide'); context.querySelector('.features').classList.remove('hide');
} }
if (options.mode == 'series') { if (options.mode === 'series') {
context.querySelector('.seriesStatus').classList.remove('hide'); context.querySelector('.seriesStatus').classList.remove('hide');
} }
if (options.mode == 'episodes') { if (options.mode === 'episodes') {
showByClass(context, 'episodeFilter'); showByClass(context, 'episodeFilter');
} }
} }
function showByClass(context, className) { function showByClass(context, className) {
var elems = context.querySelectorAll('.' + className); for (const elem of context.querySelectorAll(`.${className}`)) {
elem.classList.remove('hide');
for (var i = 0, length = elems.length; i < length; i++) {
elems[i].classList.remove('hide');
} }
} }
function hideByClass(context, className) { function hideByClass(context, className) {
var elems = context.querySelectorAll('.' + className); for (const elem of context.querySelectorAll(`.${className}`)) {
elem.classList.add('hide');
for (var i = 0, length = elems.length; i < length; i++) {
elems[i].classList.add('hide');
} }
} }
function enableDynamicFilters(mode) { function enableDynamicFilters(mode) {
return mode == 'movies' || mode == 'series' || mode == 'albums' || mode == 'albumartists' || mode == 'artists' || mode == 'songs' || mode == 'episodes'; return mode === 'movies' || mode === 'series' || mode === 'albums' || mode === 'albumartists' || mode === 'artists' || mode === 'songs' || mode === 'episodes';
} }
return function (options) { class FilterDialog {
function onFavoriteChange() { constructor(options) {
var query = options.query; /**
query.StartIndex = 0; * @private
query.IsFavorite = !!this.checked || null; */
triggerChange(self); this.options = options;
} }
function onStandardFilterChange() { /**
var query = options.query; * @private
var filterName = this.getAttribute('data-filter'); */
var filters = query.Filters || ''; onFavoriteChange(elem) {
filters = (',' + filters).replace(',' + filterName, '').substring(1); const query = this.options.query;
query.StartIndex = 0;
query.IsFavorite = !!elem.checked || null;
triggerChange(this);
}
if (this.checked) { /**
filters = filters ? filters + ',' + filterName : filterName; * @private
*/
onStandardFilterChange(elem) {
const query = this.options.query;
const filterName = elem.getAttribute('data-filter');
let filters = query.Filters || '';
filters = (`,${filters}`).replace(`,${filterName}`, '').substring(1);
if (elem.checked) {
filters = filters ? `${filters},${filterName}` : filterName;
} }
query.StartIndex = 0; query.StartIndex = 0;
query.Filters = filters; query.Filters = filters;
triggerChange(self); triggerChange(this);
} }
function onVideoTypeFilterChange() { /**
var query = options.query; * @private
var filterName = this.getAttribute('data-filter'); */
var filters = query.VideoTypes || ''; onVideoTypeFilterChange(elem) {
filters = (',' + filters).replace(',' + filterName, '').substring(1); const query = this.options.query;
const filterName = elem.getAttribute('data-filter');
let filters = query.VideoTypes || '';
filters = (`,${filters}`).replace(`,${filterName}`, '').substring(1);
if (this.checked) { if (elem.checked) {
filters = filters ? filters + ',' + filterName : filterName; filters = filters ? `${filters},${filterName}` : filterName;
} }
query.StartIndex = 0; query.StartIndex = 0;
query.VideoTypes = filters; query.VideoTypes = filters;
triggerChange(self); triggerChange(this);
} }
function onStatusChange() { /**
var query = options.query; * @private
var filterName = this.getAttribute('data-filter'); */
var filters = query.SeriesStatus || ''; onStatusChange(elem) {
filters = (',' + filters).replace(',' + filterName, '').substring(1); const query = this.options.query;
const filterName = elem.getAttribute('data-filter');
let filters = query.SeriesStatus || '';
filters = (`,${filters}`).replace(`,${filterName}`, '').substring(1);
if (this.checked) { if (elem.checked) {
filters = filters ? filters + ',' + filterName : filterName; filters = filters ? `${filters},${filterName}` : filterName;
} }
query.SeriesStatus = filters; query.SeriesStatus = filters;
query.StartIndex = 0; query.StartIndex = 0;
triggerChange(self); triggerChange(this);
} }
function bindEvents(context) { /**
var elems; * @param context {HTMLDivElement} The dialog
var i; */
var length; bindEvents(context) {
var query = options.query; const query = this.options.query;
if (options.mode == 'livetvchannels') { if (this.options.mode === 'livetvchannels') {
elems = context.querySelectorAll('.chkFavorite'); for (const elem of context.querySelectorAll('.chkFavorite')) {
for (i = 0, length = elems.length; i < length; i++) { elem.addEventListener('change', () => this.onFavoriteChange(elem));
elems[i].addEventListener('change', onFavoriteChange);
} }
context.querySelector('.chkLikes').addEventListener('change', function () {
const chkLikes = context.querySelector('.chkLikes');
chkLikes.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.IsLiked = this.checked ? true : null; query.IsLiked = chkLikes.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('.chkDislikes').addEventListener('change', function () { const chkDislikes = context.querySelector('.chkDislikes');
chkDislikes.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.IsDisliked = this.checked ? true : null; query.IsDisliked = chkDislikes.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
} else { } else {
elems = context.querySelectorAll('.chkStandardFilter'); for (const elem of context.querySelectorAll('.chkStandardFilter')) {
for (i = 0, length = elems.length; i < length; i++) { elem.addEventListener('change', () => this.onStandardFilterChange(elem));
elems[i].addEventListener('change', onStandardFilterChange);
} }
} }
elems = context.querySelectorAll('.chkVideoTypeFilter');
for (i = 0, length = elems.length; i < length; i++) { for (const elem of context.querySelectorAll('.chkVideoTypeFilter')) {
elems[i].addEventListener('change', onVideoTypeFilterChange); elem.addEventListener('change', () => this.onVideoTypeFilterChange(elem));
} }
context.querySelector('.chk3DFilter').addEventListener('change', function () { const chk3DFilter = context.querySelector('.chk3DFilter');
chk3DFilter.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.Is3D = this.checked ? true : null; query.Is3D = chk3DFilter.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('.chk4KFilter').addEventListener('change', function () { const chk4KFilter = context.querySelector('.chk4KFilter');
chk4KFilter.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.Is4K = this.checked ? true : null; query.Is4K = chk4KFilter.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('.chkHDFilter').addEventListener('change', function () { const chkHDFilter = context.querySelector('.chkHDFilter');
chkHDFilter.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.IsHD = this.checked ? true : null; query.IsHD = chkHDFilter.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('.chkSDFilter').addEventListener('change', function () { const chkSDFilter = context.querySelector('.chkSDFilter');
chkSDFilter.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.IsHD = this.checked ? false : null; query.IsHD = chkSDFilter.checked ? false : null;
triggerChange(self); triggerChange(this);
}); });
elems = context.querySelectorAll('.chkStatus'); for (const elem of context.querySelectorAll('.chkStatus')) {
for (i = 0, length = elems.length; i < length; i++) { elem.addEventListener('change', () => this.onStatusChange(elem));
elems[i].addEventListener('change', onStatusChange);
} }
context.querySelector('#chkTrailer').addEventListener('change', function () { const chkTrailer = context.querySelector('#chkTrailer');
chkTrailer.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.HasTrailer = this.checked ? true : null; query.HasTrailer = chkTrailer.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('#chkThemeSong').addEventListener('change', function () { const chkThemeSong = context.querySelector('#chkThemeSong');
chkThemeSong.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.HasThemeSong = this.checked ? true : null; query.HasThemeSong = chkThemeSong.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('#chkSpecialFeature').addEventListener('change', function () { const chkSpecialFeature = context.querySelector('#chkSpecialFeature');
chkSpecialFeature.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.HasSpecialFeature = this.checked ? true : null; query.HasSpecialFeature = chkSpecialFeature.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('#chkThemeVideo').addEventListener('change', function () { const chkThemeVideo = context.querySelector('#chkThemeVideo');
chkThemeVideo.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.HasThemeVideo = this.checked ? true : null; query.HasThemeVideo = chkThemeVideo.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('#chkMissingEpisode').addEventListener('change', function () { const chkMissingEpisode = context.querySelector('#chkMissingEpisode');
chkMissingEpisode.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.IsMissing = this.checked ? true : false; query.IsMissing = !!chkMissingEpisode.checked;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('#chkSpecialEpisode').addEventListener('change', function () { const chkSpecialEpisode = context.querySelector('#chkSpecialEpisode');
chkSpecialEpisode.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.ParentIndexNumber = this.checked ? 0 : null; query.ParentIndexNumber = chkSpecialEpisode.checked ? 0 : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('#chkFutureEpisode').addEventListener('change', function () { const chkFutureEpisode = context.querySelector('#chkFutureEpisode');
chkFutureEpisode.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
if (this.checked) { if (chkFutureEpisode.checked) {
query.IsUnaired = true; query.IsUnaired = true;
query.IsVirtualUnaired = null; query.IsVirtualUnaired = null;
} else { } else {
query.IsUnaired = null; query.IsUnaired = null;
query.IsVirtualUnaired = false; query.IsVirtualUnaired = false;
} }
triggerChange(self); triggerChange(this);
}); });
context.querySelector('#chkSubtitle').addEventListener('change', function () { const chkSubtitle = context.querySelector('#chkSubtitle');
chkSubtitle.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.HasSubtitles = this.checked ? true : null; query.HasSubtitles = chkSubtitle.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.addEventListener('change', function (e) { context.addEventListener('change', (e) => {
var chkGenreFilter = dom.parentWithClass(e.target, 'chkGenreFilter'); const chkGenreFilter = dom.parentWithClass(e.target, 'chkGenreFilter');
if (chkGenreFilter) { if (chkGenreFilter) {
var filterName = chkGenreFilter.getAttribute('data-filter'); const filterName = chkGenreFilter.getAttribute('data-filter');
var filters = query.Genres || ''; let filters = query.Genres || '';
var delimiter = '|'; const delimiter = '|';
filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1); filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1);
if (chkGenreFilter.checked) { if (chkGenreFilter.checked) {
filters = filters ? (filters + delimiter + filterName) : filterName; filters = filters ? (filters + delimiter + filterName) : filterName;
} }
query.StartIndex = 0; query.StartIndex = 0;
query.Genres = filters; query.Genres = filters;
triggerChange(self); triggerChange(this);
return; return;
} }
var chkTagFilter = dom.parentWithClass(e.target, 'chkTagFilter'); const chkTagFilter = dom.parentWithClass(e.target, 'chkTagFilter');
if (chkTagFilter) { if (chkTagFilter) {
var filterName = chkTagFilter.getAttribute('data-filter'); const filterName = chkTagFilter.getAttribute('data-filter');
var filters = query.Tags || ''; let filters = query.Tags || '';
var delimiter = '|'; const delimiter = '|';
filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1); filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1);
if (chkTagFilter.checked) { if (chkTagFilter.checked) {
filters = filters ? (filters + delimiter + filterName) : filterName; filters = filters ? (filters + delimiter + filterName) : filterName;
} }
query.StartIndex = 0; query.StartIndex = 0;
query.Tags = filters; query.Tags = filters;
triggerChange(self); triggerChange(this);
return; return;
} }
var chkYearFilter = dom.parentWithClass(e.target, 'chkYearFilter'); const chkYearFilter = dom.parentWithClass(e.target, 'chkYearFilter');
if (chkYearFilter) { if (chkYearFilter) {
var filterName = chkYearFilter.getAttribute('data-filter'); const filterName = chkYearFilter.getAttribute('data-filter');
var filters = query.Years || ''; let filters = query.Years || '';
var delimiter = ','; const delimiter = ',';
filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1); filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1);
if (chkYearFilter.checked) { if (chkYearFilter.checked) {
filters = filters ? (filters + delimiter + filterName) : filterName; filters = filters ? (filters + delimiter + filterName) : filterName;
} }
query.StartIndex = 0; query.StartIndex = 0;
query.Years = filters; query.Years = filters;
triggerChange(self); triggerChange(this);
return; return;
} }
var chkOfficialRatingFilter = dom.parentWithClass(e.target, 'chkOfficialRatingFilter'); const chkOfficialRatingFilter = dom.parentWithClass(e.target, 'chkOfficialRatingFilter');
if (chkOfficialRatingFilter) { if (chkOfficialRatingFilter) {
var filterName = chkOfficialRatingFilter.getAttribute('data-filter'); const filterName = chkOfficialRatingFilter.getAttribute('data-filter');
var filters = query.OfficialRatings || ''; let filters = query.OfficialRatings || '';
var delimiter = '|'; const delimiter = '|';
filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1); filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1);
if (chkOfficialRatingFilter.checked) { if (chkOfficialRatingFilter.checked) {
filters = filters ? (filters + delimiter + filterName) : filterName; filters = filters ? (filters + delimiter + filterName) : filterName;
} }
query.StartIndex = 0; query.StartIndex = 0;
query.OfficialRatings = filters; query.OfficialRatings = filters;
triggerChange(self); triggerChange(this);
return;
} }
}); });
} }
var self = this; show() {
return import('text!./filterdialog.template.html').then(({default: template}) => {
self.show = function () { return new Promise((resolve) => {
return new Promise(function (resolve, reject) { const dlg = dialogHelper.createDialog({
require(['text!./filterdialog.template.html'], function (template) {
var dlg = dialogHelper.createDialog({
removeOnClose: true, removeOnClose: true,
modal: false modal: false
}); });
@ -380,18 +413,21 @@ define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'brow
dlg.classList.add('formDialog'); dlg.classList.add('formDialog');
dlg.classList.add('filterDialog'); dlg.classList.add('filterDialog');
dlg.innerHTML = globalize.translateDocument(template); dlg.innerHTML = globalize.translateDocument(template);
setVisibility(dlg, options); setVisibility(dlg, this.options);
dialogHelper.open(dlg); dialogHelper.open(dlg);
dlg.addEventListener('close', resolve); dlg.addEventListener('close', resolve);
updateFilterControls(dlg, options); updateFilterControls(dlg, this.options);
bindEvents(dlg); this.bindEvents(dlg);
if (enableDynamicFilters(options.mode)) { if (enableDynamicFilters(this.options.mode)) {
dlg.classList.add('dynamicFilterDialog'); dlg.classList.add('dynamicFilterDialog');
var apiClient = connectionManager.getApiClient(options.serverId); const apiClient = connectionManager.getApiClient(this.options.serverId);
loadDynamicFilters(dlg, apiClient, apiClient.getCurrentUserId(), options.query); loadDynamicFilters(dlg, apiClient, apiClient.getCurrentUserId(), this.options.query);
} }
}); });
}); });
}; }
}; }
});
/* eslint-enable indent */
export default FilterDialog;

View file

@ -229,7 +229,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
var options = { var options = {
Limit: limit, Limit: limit,
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo', Fields: 'PrimaryImageAspectRatio,BasicSyncInfo,Path',
ImageTypeLimit: 1, ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Thumb', EnableImageTypes: 'Primary,Backdrop,Thumb',
ParentId: parentId ParentId: parentId
@ -667,7 +667,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
var apiClient = connectionManager.getApiClient(serverId); var apiClient = connectionManager.getApiClient(serverId);
return apiClient.getNextUpEpisodes({ return apiClient.getNextUpEpisodes({
Limit: enableScrollX() ? 24 : 15, Limit: enableScrollX() ? 24 : 15,
Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo', Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo,Path',
UserId: apiClient.getCurrentUserId(), UserId: apiClient.getCurrentUserId(),
ImageTypeLimit: 1, ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',

View file

@ -203,9 +203,9 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
html += '<div class="cardContent">'; html += '<div class="cardContent">';
if (layoutManager.tv || !appHost.supports('externallinks')) { if (layoutManager.tv || !appHost.supports('externallinks')) {
html += '<div class="cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center bottom;"></div>'; html += '<div class="cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center center;background-size:contain;"></div>';
} else { } else {
html += '<a is="emby-linkbutton" target="_blank" href="' + getDisplayUrl(image.Url, apiClient) + '" class="button-link cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center bottom;"></a>'; html += '<a is="emby-linkbutton" target="_blank" href="' + getDisplayUrl(image.Url, apiClient) + '" class="button-link cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center center;background-size:contain"></a>';
} }
html += '</div>'; html += '</div>';

View file

@ -132,7 +132,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
var imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: imageSize }); var imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: imageSize });
html += '<div class="cardImageContainer" style="background-image:url(\'' + imageUrl + '\');background-position:center bottom;"></div>'; html += '<div class="cardImageContainer" style="background-image:url(\'' + imageUrl + '\');background-position:center center;background-size:contain;"></div>';
html += '</div>'; html += '</div>';
html += '</div>'; html += '</div>';

View file

@ -1,5 +1,6 @@
import * as lazyLoader from 'lazyLoader'; import * as lazyLoader from 'lazyLoader';
import * as userSettings from 'userSettings'; import * as userSettings from 'userSettings';
import * as blurhash from 'blurhash';
import 'css!./style'; import 'css!./style';
/* eslint-disable indent */ /* eslint-disable indent */
@ -11,47 +12,111 @@ import 'css!./style';
fillImageElement(elem, source); fillImageElement(elem, source);
} }
async function itemBlurhashing(target, blurhashstr) {
if (blurhash.isBlurhashValid(blurhashstr)) {
// Although the default values recommended by Blurhash developers is 32x32, a size of 18x18 seems to be the sweet spot for us,
// improving the performance and reducing the memory usage, while retaining almost full blur quality.
// Lower values had more visible pixelation
let width = 18;
let height = 18;
let pixels;
try {
pixels = blurhash.decode(blurhashstr, width, height);
} catch (err) {
console.error('Blurhash decode error: ', err);
target.classList.add('non-blurhashable');
return;
}
let canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext('2d');
let imgData = ctx.createImageData(width, height);
imgData.data.set(pixels);
ctx.putImageData(imgData, 0, 0);
let child = target.appendChild(canvas);
child.classList.add('blurhash-canvas');
child.style.opacity = 1;
if (userSettings.enableFastFadein()) {
child.classList.add('lazy-blurhash-fadein-fast');
} else {
child.classList.add('lazy-blurhash-fadein');
}
target.classList.add('blurhashed');
target.removeAttribute('data-blurhash');
}
}
function switchCanvas(elem) {
let child = elem.getElementsByClassName('blurhash-canvas')[0];
if (child) {
child.style.opacity = elem.getAttribute('data-src') ? 1 : 0;
}
}
export function fillImage(entry) { export function fillImage(entry) {
if (!entry) { if (!entry) {
throw new Error('entry cannot be null'); throw new Error('entry cannot be null');
} }
let target = entry.target;
var source = undefined; var source = undefined;
if (entry.target) {
source = entry.target.getAttribute('data-src'); if (target) {
source = target.getAttribute('data-src');
var blurhashstr = target.getAttribute('data-blurhash');
} else { } else {
source = entry; source = entry;
} }
if (userSettings.enableBlurhash()) {
if (!target.classList.contains('blurhashed', 'non-blurhashable') && blurhashstr) {
itemBlurhashing(target, blurhashstr);
} else if (!blurhashstr && !target.classList.contains('blurhashed')) {
target.classList.add('non-blurhashable');
}
}
if (entry.intersectionRatio > 0) { if (entry.intersectionRatio > 0) {
if (source) fillImageElement(entry.target, source); if (source) fillImageElement(target, source);
} else if (!source) { } else if (!source) {
emptyImageElement(entry.target); emptyImageElement(target);
} }
} }
function fillImageElement(elem, url) { function fillImageElement(elem, url) {
if (url === undefined) { if (url === undefined) {
throw new Error('url cannot be undefined'); throw new TypeError('url cannot be undefined');
} }
let preloaderImg = new Image(); let preloaderImg = new Image();
preloaderImg.src = url; preloaderImg.src = url;
// This is necessary here, so changing blurhash settings without reloading the page works
if (!userSettings.enableBlurhash() || elem.classList.contains('non-blurhashable')) {
elem.classList.add('lazy-hidden');
}
preloaderImg.addEventListener('load', () => { preloaderImg.addEventListener('load', () => {
if (elem.tagName !== 'IMG') { if (elem.tagName !== 'IMG') {
elem.style.backgroundImage = "url('" + url + "')"; elem.style.backgroundImage = "url('" + url + "')";
} else { } else {
elem.setAttribute('src', url); elem.setAttribute('src', url);
} }
if (userSettings.enableFastFadein()) {
elem.classList.add('lazy-image-fadein-fast');
} else {
elem.classList.add('lazy-image-fadein');
}
elem.removeAttribute('data-src'); elem.removeAttribute('data-src');
if (elem.classList.contains('non-blurhashable') || !userSettings.enableBlurhash()) {
elem.classList.remove('lazy-hidden');
if (userSettings.enableFastFadein()) {
elem.classList.add('lazy-image-fadein-fast');
} else {
elem.classList.add('lazy-image-fadein');
}
} else {
switchCanvas(elem);
}
}); });
} }
@ -65,11 +130,14 @@ import 'css!./style';
url = elem.getAttribute('src'); url = elem.getAttribute('src');
elem.setAttribute('src', ''); elem.setAttribute('src', '');
} }
elem.setAttribute('data-src', url); elem.setAttribute('data-src', url);
elem.classList.remove('lazy-image-fadein-fast'); if (elem.classList.contains('non-blurhashable') || !userSettings.enableBlurhash()) {
elem.classList.remove('lazy-image-fadein'); elem.classList.remove('lazy-image-fadein-fast', 'lazy-image-fadein');
elem.classList.add('lazy-hidden');
} else {
switchCanvas(elem);
}
} }
export function lazyChildren(elem) { export function lazyChildren(elem) {

View file

@ -1,13 +1,32 @@
.cardImageContainer.lazy { .lazy-image-fadein {
opacity: 0;
}
.cardImageContainer.lazy.lazy-image-fadein {
opacity: 1; opacity: 1;
transition: opacity 0.7s; transition: opacity 0.7s;
} }
.cardImageContainer.lazy.lazy-image-fadein-fast { .lazy-image-fadein-fast {
opacity: 1; opacity: 1;
transition: opacity 0.2s; transition: opacity 0.2s;
} }
.lazy-hidden {
opacity: 0;
}
.lazy-blurhash-fadein-fast {
transition: opacity 0.2s;
}
.lazy-blurhash-fadein {
transition: opacity 0.7s;
}
.blurhash-canvas {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
}

View file

@ -120,7 +120,12 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
html += plugin.Name; html += plugin.Name;
html += '</h3>'; html += '</h3>';
html += '</div>'; html += '</div>';
index > 0 ? html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonUp') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_up"></span></button>' : plugins.length > 1 && (html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonDown') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_down"></span></button>'), html += '</div>'; if (index > 0) {
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonUp') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_up"></span></button>';
} else if (plugins.length > 1) {
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonDown') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_down"></span></button>';
}
html += '</div>';
}); });
html += '</div>'; html += '</div>';

View file

@ -79,7 +79,7 @@
<div class="checkboxContainer checkboxContainer-withDescription chkAutomaticallyGroupSeriesContainer hide advanced"> <div class="checkboxContainer checkboxContainer-withDescription chkAutomaticallyGroupSeriesContainer hide advanced">
<label> <label>
<input type="checkbox" is="emby-checkbox" class="chkAutomaticallyGroupSeries" checked /> <input type="checkbox" is="emby-checkbox" class="chkAutomaticallyGroupSeries" />
<span>${OptionAutomaticallyGroupSeries}</span> <span>${OptionAutomaticallyGroupSeries}</span>
</label> </label>
<div class="fieldDescription checkboxFieldDescription">${OptionAutomaticallyGroupSeriesHelp}</div> <div class="fieldDescription checkboxFieldDescription">${OptionAutomaticallyGroupSeriesHelp}</div>

View file

@ -70,6 +70,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
function getImageUrl(item, width) { function getImageUrl(item, width) {
var apiClient = connectionManager.getApiClient(item.ServerId); var apiClient = connectionManager.getApiClient(item.ServerId);
let itemId;
var options = { var options = {
maxWidth: width * 2, maxWidth: width * 2,
@ -77,45 +78,45 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
}; };
if (item.ImageTags && item.ImageTags.Primary) { if (item.ImageTags && item.ImageTags.Primary) {
options.tag = item.ImageTags.Primary; options.tag = item.ImageTags.Primary;
return apiClient.getScaledImageUrl(item.Id, options); itemId = item.Id;
} }
if (item.AlbumId && item.AlbumPrimaryImageTag) { if (item.AlbumId && item.AlbumPrimaryImageTag) {
options.tag = item.AlbumPrimaryImageTag; options.tag = item.AlbumPrimaryImageTag;
return apiClient.getScaledImageUrl(item.AlbumId, options); itemId = item.AlbumId;
} else if (item.SeriesId && item.SeriesPrimaryImageTag) { } else if (item.SeriesId && item.SeriesPrimaryImageTag) {
options.tag = item.SeriesPrimaryImageTag; options.tag = item.SeriesPrimaryImageTag;
return apiClient.getScaledImageUrl(item.SeriesId, options); itemId = item.SeriesId;
} else if (item.ParentPrimaryImageTag) { } else if (item.ParentPrimaryImageTag) {
options.tag = item.ParentPrimaryImageTag; options.tag = item.ParentPrimaryImageTag;
return apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, options); itemId = item.ParentPrimaryImageItemId;
} }
let blurHashes = item.ImageBlurHashes || {};
let blurhashstr = (blurHashes[options.type] || {})[options.tag];
return null; if (itemId) {
return { url: apiClient.getScaledImageUrl(itemId, options), blurhash: blurhashstr };
}
} }
function getChannelImageUrl(item, width) { function getChannelImageUrl(item, width) {
var apiClient = connectionManager.getApiClient(item.ServerId); var apiClient = connectionManager.getApiClient(item.ServerId);
var options = { var options = {
maxWidth: width * 2, maxWidth: width * 2,
type: 'Primary' type: 'Primary'
}; };
if (item.ChannelId && item.ChannelPrimaryImageTag) { if (item.ChannelId && item.ChannelPrimaryImageTag) {
options.tag = item.ChannelPrimaryImageTag; options.tag = item.ChannelPrimaryImageTag;
return apiClient.getScaledImageUrl(item.ChannelId, options);
} }
let blurHashes = item.ImageBlurHashes || {};
let blurhashstr = (blurHashes[options.type])[options.tag];
return null; if (item.ChannelId) {
return { url: apiClient.getScaledImageUrl(item.ChannelId, options), blurhash: blurhashstr };
}
} }
function getTextLinesHtml(textlines, isLargeStyle) { function getTextLinesHtml(textlines, isLargeStyle) {
@ -268,8 +269,10 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
} }
if (options.image !== false) { if (options.image !== false) {
var imgUrl = options.imageSource === 'channel' ? getChannelImageUrl(item, downloadWidth) : getImageUrl(item, downloadWidth); let imgData = options.imageSource === 'channel' ? getChannelImageUrl(item, downloadWidth) : getImageUrl(item, downloadWidth);
var imageClass = isLargeStyle ? 'listItemImage listItemImage-large' : 'listItemImage'; let imgUrl = imgData.url;
let blurhash = imgData.blurhash;
let imageClass = isLargeStyle ? 'listItemImage listItemImage-large' : 'listItemImage';
if (isLargeStyle && layoutManager.tv) { if (isLargeStyle && layoutManager.tv) {
imageClass += ' listItemImage-large-tv'; imageClass += ' listItemImage-large-tv';
@ -283,8 +286,13 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
var imageAction = playOnImageClick ? 'resume' : action; var imageAction = playOnImageClick ? 'resume' : action;
let blurhashAttrib = '';
if (blurhash && blurhash.length > 0) {
blurhashAttrib = 'data-blurhash="' + blurhash + '"';
}
if (imgUrl) { if (imgUrl) {
html += '<div data-action="' + imageAction + '" class="' + imageClass + ' lazy" data-src="' + imgUrl + '" item-icon>'; html += '<div data-action="' + imageAction + '" class="' + imageClass + ' lazy" data-src="' + imgUrl + '" ' + blurhashAttrib + ' item-icon>';
} else { } else {
html += '<div class="' + imageClass + '">'; html += '<div class="' + imageClass + '">';
} }

View file

@ -273,7 +273,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
} }
} }
if (item.RunTimeTicks && item.Type !== 'Series' && item.Type !== 'Program' && !showFolderRuntime && options.runtime !== false) { if (item.RunTimeTicks && item.Type !== 'Series' && item.Type !== 'Program' && item.Type !== 'Book' && !showFolderRuntime && options.runtime !== false) {
if (item.Type === 'Audio') { if (item.Type === 'Audio') {

View file

@ -46,7 +46,7 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
function showNonPersistentNotification(title, options, timeoutMs) { function showNonPersistentNotification(title, options, timeoutMs) {
try { try {
var notif = new Notification(title, options); var notif = new Notification(title, options); /* eslint-disable-line compat/compat */
if (notif.show) { if (notif.show) {
notif.show(); notif.show();

View file

@ -1,171 +1,171 @@
define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'material-icons'], function (events, playbackManager, dom, browser) { import events from 'events';
'use strict'; import playbackManager from 'playbackManager';
import dom from 'dom';
import browser from 'browser';
import 'css!./iconosd';
import 'material-icons';
var currentPlayer; var currentPlayer;
var osdElement; var osdElement;
var iconElement; var iconElement;
var progressElement; var progressElement;
var enableAnimation; var enableAnimation;
function getOsdElementHtml() { function getOsdElementHtml() {
var html = ''; var html = '';
html += '<span class="material-icons iconOsdIcon brightness_high"></span>'; html += '<span class="material-icons iconOsdIcon brightness_high"></span>';
html += '<div class="iconOsdProgressOuter"><div class="iconOsdProgressInner brightnessOsdProgressInner"></div></div>'; html += '<div class="iconOsdProgressOuter"><div class="iconOsdProgressInner brightnessOsdProgressInner"></div></div>';
return html; return html;
}
function ensureOsdElement() {
var elem = osdElement;
if (!elem) {
enableAnimation = browser.supportsCssAnimation();
elem = document.createElement('div');
elem.classList.add('hide');
elem.classList.add('iconOsd');
elem.classList.add('iconOsd-hidden');
elem.classList.add('brightnessOsd');
elem.innerHTML = getOsdElementHtml();
iconElement = elem.querySelector('.material-icons');
progressElement = elem.querySelector('.iconOsdProgressInner');
document.body.appendChild(elem);
osdElement = elem;
} }
}
function ensureOsdElement() { function onHideComplete() {
this.classList.add('hide');
}
var elem = osdElement; var hideTimeout;
if (!elem) { function showOsd() {
enableAnimation = browser.supportsCssAnimation(); clearHideTimeout();
elem = document.createElement('div'); var elem = osdElement;
elem.classList.add('hide');
elem.classList.add('iconOsd');
elem.classList.add('iconOsd-hidden');
elem.classList.add('brightnessOsd');
elem.innerHTML = getOsdElementHtml();
iconElement = elem.querySelector('.material-icons'); dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
progressElement = elem.querySelector('.iconOsdProgressInner'); once: true
document.body.appendChild(elem);
osdElement = elem;
}
}
function onHideComplete() {
this.classList.add('hide');
}
var hideTimeout;
function showOsd() {
clearHideTimeout();
var elem = osdElement;
dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
once: true
});
elem.classList.remove('hide');
// trigger reflow
void elem.offsetWidth;
requestAnimationFrame(function () {
elem.classList.remove('iconOsd-hidden');
hideTimeout = setTimeout(hideOsd, 3000);
});
}
function clearHideTimeout() {
if (hideTimeout) {
clearTimeout(hideTimeout);
hideTimeout = null;
}
}
function hideOsd() {
clearHideTimeout();
var elem = osdElement;
if (elem) {
if (enableAnimation) {
// trigger reflow
void elem.offsetWidth;
requestAnimationFrame(function () {
elem.classList.add('iconOsd-hidden');
dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
once: true
});
});
} else {
onHideComplete.call(elem);
}
}
}
function setIcon(iconElement, icon) {
iconElement.classList.remove('brightness_high');
iconElement.classList.remove('brightness_medium');
iconElement.classList.remove('brightness_low');
iconElement.classList.add(icon);
}
function updateElementsFromPlayer(brightness) {
if (iconElement) {
if (brightness >= 80) {
setIcon(iconElement, 'brightness_high');
} else if (brightness >= 20) {
setIcon(iconElement, 'brightness_medium');
} else {
setIcon(iconElement, 'brightness_low');
}
}
if (progressElement) {
progressElement.style.width = (brightness || 0) + '%';
}
}
function releaseCurrentPlayer() {
var player = currentPlayer;
if (player) {
events.off(player, 'brightnesschange', onBrightnessChanged);
events.off(player, 'playbackstop', hideOsd);
currentPlayer = null;
}
}
function onBrightnessChanged(e) {
var player = this;
ensureOsdElement();
updateElementsFromPlayer(playbackManager.getBrightness(player));
showOsd();
}
function bindToPlayer(player) {
if (player === currentPlayer) {
return;
}
releaseCurrentPlayer();
currentPlayer = player;
if (!player) {
return;
}
hideOsd();
events.on(player, 'brightnesschange', onBrightnessChanged);
events.on(player, 'playbackstop', hideOsd);
}
events.on(playbackManager, 'playerchange', function () {
bindToPlayer(playbackManager.getCurrentPlayer());
}); });
bindToPlayer(playbackManager.getCurrentPlayer()); elem.classList.remove('hide');
// trigger reflow
void elem.offsetWidth;
requestAnimationFrame(function () {
elem.classList.remove('iconOsd-hidden');
hideTimeout = setTimeout(hideOsd, 3000);
});
}
function clearHideTimeout() {
if (hideTimeout) {
clearTimeout(hideTimeout);
hideTimeout = null;
}
}
function hideOsd() {
clearHideTimeout();
var elem = osdElement;
if (elem) {
if (enableAnimation) {
// trigger reflow
void elem.offsetWidth;
requestAnimationFrame(function () {
elem.classList.add('iconOsd-hidden');
dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
once: true
});
});
} else {
onHideComplete.call(elem);
}
}
}
function setIcon(iconElement, icon) {
iconElement.classList.remove('brightness_high', 'brightness_medium', 'brightness_low');
iconElement.classList.add(icon);
}
function updateElementsFromPlayer(brightness) {
if (iconElement) {
if (brightness >= 80) {
setIcon(iconElement, 'brightness_high');
} else if (brightness >= 20) {
setIcon(iconElement, 'brightness_medium');
} else {
setIcon(iconElement, 'brightness_low');
}
}
if (progressElement) {
progressElement.style.width = (brightness || 0) + '%';
}
}
function releaseCurrentPlayer() {
var player = currentPlayer;
if (player) {
events.off(player, 'brightnesschange', onBrightnessChanged);
events.off(player, 'playbackstop', hideOsd);
currentPlayer = null;
}
}
function onBrightnessChanged(e) {
var player = this;
ensureOsdElement();
updateElementsFromPlayer(playbackManager.getBrightness(player));
showOsd();
}
function bindToPlayer(player) {
if (player === currentPlayer) {
return;
}
releaseCurrentPlayer();
currentPlayer = player;
if (!player) {
return;
}
hideOsd();
events.on(player, 'brightnesschange', onBrightnessChanged);
events.on(player, 'playbackstop', hideOsd);
}
events.on(playbackManager, 'playerchange', function () {
bindToPlayer(playbackManager.getCurrentPlayer());
}); });
bindToPlayer(playbackManager.getCurrentPlayer());

View file

@ -119,6 +119,7 @@ import connectionManager from 'connectionManager';
const canSeek = playState.CanSeek || false; const canSeek = playState.CanSeek || false;
if ('mediaSession' in navigator) { if ('mediaSession' in navigator) {
/* eslint-disable-next-line compat/compat */
navigator.mediaSession.metadata = new MediaMetadata({ navigator.mediaSession.metadata = new MediaMetadata({
title: title, title: title,
artist: artist, artist: artist,
@ -179,6 +180,7 @@ import connectionManager from 'connectionManager';
function hideMediaControls() { function hideMediaControls() {
if ('mediaSession' in navigator) { if ('mediaSession' in navigator) {
/* eslint-disable-next-line compat/compat */
navigator.mediaSession.metadata = null; navigator.mediaSession.metadata = null;
} else { } else {
window.NativeShell.hideMediaSession(); window.NativeShell.hideMediaSession();
@ -210,26 +212,32 @@ import connectionManager from 'connectionManager';
} }
if ('mediaSession' in navigator) { if ('mediaSession' in navigator) {
/* eslint-disable-next-line compat/compat */
navigator.mediaSession.setActionHandler('previoustrack', function () { navigator.mediaSession.setActionHandler('previoustrack', function () {
execute('previousTrack'); execute('previousTrack');
}); });
/* eslint-disable-next-line compat/compat */
navigator.mediaSession.setActionHandler('nexttrack', function () { navigator.mediaSession.setActionHandler('nexttrack', function () {
execute('nextTrack'); execute('nextTrack');
}); });
/* eslint-disable-next-line compat/compat */
navigator.mediaSession.setActionHandler('play', function () { navigator.mediaSession.setActionHandler('play', function () {
execute('unpause'); execute('unpause');
}); });
/* eslint-disable-next-line compat/compat */
navigator.mediaSession.setActionHandler('pause', function () { navigator.mediaSession.setActionHandler('pause', function () {
execute('pause'); execute('pause');
}); });
/* eslint-disable-next-line compat/compat */
navigator.mediaSession.setActionHandler('seekbackward', function () { navigator.mediaSession.setActionHandler('seekbackward', function () {
execute('rewind'); execute('rewind');
}); });
/* eslint-disable-next-line compat/compat */
navigator.mediaSession.setActionHandler('seekforward', function () { navigator.mediaSession.setActionHandler('seekforward', function () {
execute('fastForward'); execute('fastForward');
}); });

View file

@ -1,86 +1,82 @@
define([], function () { export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
'use strict';
function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) { var topItem = nowPlayingItem;
var bottomItem = null;
var topText = nowPlayingItem.Name;
var topItem = nowPlayingItem; if (nowPlayingItem.AlbumId && nowPlayingItem.MediaType === 'Audio') {
var bottomItem = null; topItem = {
var topText = nowPlayingItem.Name; Id: nowPlayingItem.AlbumId,
Name: nowPlayingItem.Album,
if (nowPlayingItem.AlbumId && nowPlayingItem.MediaType === 'Audio') { Type: 'MusicAlbum',
topItem = { IsFolder: true
Id: nowPlayingItem.AlbumId, };
Name: nowPlayingItem.Album,
Type: 'MusicAlbum',
IsFolder: true
};
}
if (nowPlayingItem.MediaType === 'Video') {
if (nowPlayingItem.IndexNumber != null) {
topText = nowPlayingItem.IndexNumber + ' - ' + topText;
}
if (nowPlayingItem.ParentIndexNumber != null) {
topText = nowPlayingItem.ParentIndexNumber + '.' + topText;
}
}
var bottomText = '';
if (nowPlayingItem.ArtistItems && nowPlayingItem.ArtistItems.length) {
bottomItem = {
Id: nowPlayingItem.ArtistItems[0].Id,
Name: nowPlayingItem.ArtistItems[0].Name,
Type: 'MusicArtist',
IsFolder: true
};
bottomText = nowPlayingItem.ArtistItems.map(function (a) {
return a.Name;
}).join(', ');
} else if (nowPlayingItem.Artists && nowPlayingItem.Artists.length) {
bottomText = nowPlayingItem.Artists.join(', ');
} else if (nowPlayingItem.SeriesName || nowPlayingItem.Album) {
bottomText = topText;
topText = nowPlayingItem.SeriesName || nowPlayingItem.Album;
bottomItem = topItem;
if (nowPlayingItem.SeriesId) {
topItem = {
Id: nowPlayingItem.SeriesId,
Name: nowPlayingItem.SeriesName,
Type: 'Series',
IsFolder: true
};
} else {
topItem = null;
}
} else if (nowPlayingItem.ProductionYear && includeNonNameInfo !== false) {
bottomText = nowPlayingItem.ProductionYear;
}
var list = [];
list.push({
text: topText,
item: topItem
});
if (bottomText) {
list.push({
text: bottomText,
item: bottomItem
});
}
return list;
} }
return { if (nowPlayingItem.MediaType === 'Video') {
getNowPlayingNames: getNowPlayingNames if (nowPlayingItem.IndexNumber != null) {
}; topText = nowPlayingItem.IndexNumber + ' - ' + topText;
}); }
if (nowPlayingItem.ParentIndexNumber != null) {
topText = nowPlayingItem.ParentIndexNumber + '.' + topText;
}
}
var bottomText = '';
if (nowPlayingItem.ArtistItems && nowPlayingItem.ArtistItems.length) {
bottomItem = {
Id: nowPlayingItem.ArtistItems[0].Id,
Name: nowPlayingItem.ArtistItems[0].Name,
Type: 'MusicArtist',
IsFolder: true
};
bottomText = nowPlayingItem.ArtistItems.map(function (a) {
return a.Name;
}).join(', ');
} else if (nowPlayingItem.Artists && nowPlayingItem.Artists.length) {
bottomText = nowPlayingItem.Artists.join(', ');
} else if (nowPlayingItem.SeriesName || nowPlayingItem.Album) {
bottomText = topText;
topText = nowPlayingItem.SeriesName || nowPlayingItem.Album;
bottomItem = topItem;
if (nowPlayingItem.SeriesId) {
topItem = {
Id: nowPlayingItem.SeriesId,
Name: nowPlayingItem.SeriesName,
Type: 'Series',
IsFolder: true
};
} else {
topItem = null;
}
} else if (nowPlayingItem.ProductionYear && includeNonNameInfo !== false) {
bottomText = nowPlayingItem.ProductionYear;
}
var list = [];
list.push({
text: topText,
item: topItem
});
if (bottomText) {
list.push({
text: bottomText,
item: bottomItem
});
}
return list;
}
export default {
getNowPlayingNames: getNowPlayingNames
};

View file

@ -1129,7 +1129,6 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
} }
self.canPlay = function (item) { self.canPlay = function (item) {
var itemType = item.Type; var itemType = item.Type;
if (itemType === 'PhotoAlbum' || itemType === 'MusicGenre' || itemType === 'Season' || itemType === 'Series' || itemType === 'BoxSet' || itemType === 'MusicAlbum' || itemType === 'MusicArtist' || itemType === 'Playlist') { if (itemType === 'PhotoAlbum' || itemType === 'MusicGenre' || itemType === 'Season' || itemType === 'Series' || itemType === 'BoxSet' || itemType === 'MusicAlbum' || itemType === 'MusicArtist' || itemType === 'Playlist') {
@ -1143,7 +1142,6 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
} }
if (itemType === 'Program') { if (itemType === 'Program') {
if (!item.EndDate || !item.StartDate) { if (!item.EndDate || !item.StartDate) {
return false; return false;
} }
@ -1909,11 +1907,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
// Setting this to true may cause some incorrect sorting // Setting this to true may cause some incorrect sorting
Recursive: false, Recursive: false,
SortBy: options.shuffle ? 'Random' : 'SortName', SortBy: options.shuffle ? 'Random' : 'SortName',
MediaTypes: 'Photo,Video', MediaTypes: 'Photo,Video'
Limit: 500
}).then(function (result) { }).then(function (result) {
var items = result.Items; var items = result.Items;
var index = items.map(function (i) { var index = items.map(function (i) {
@ -2187,7 +2182,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
// Only used internally // Only used internally
self.getCurrentTicks = getCurrentTicks; self.getCurrentTicks = getCurrentTicks;
function playPhotos(items, options, user) { function playOther(items, options, user) {
var playStartIndex = options.startIndex || 0; var playStartIndex = options.startIndex || 0;
var player = getPlayer(items[playStartIndex], options); var player = getPlayer(items[playStartIndex], options);
@ -2216,9 +2211,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
return Promise.reject(); return Promise.reject();
} }
if (firstItem.MediaType === 'Photo') { if (firstItem.MediaType === 'Photo' || firstItem.MediaType === 'Book') {
return playPhotos(items, options, user); return playOther(items, options, user);
} }
var apiClient = connectionManager.getApiClient(firstItem.ServerId); var apiClient = connectionManager.getApiClient(firstItem.ServerId);

View file

@ -1,57 +1,57 @@
define(['playbackManager', 'layoutManager', 'events'], function (playbackManager, layoutManager, events) { import playbackManager from 'playbackManager';
'use strict'; import layoutManager from 'layoutManager';
import events from 'events';
var orientationLocked; var orientationLocked;
function onOrientationChangeSuccess() { function onOrientationChangeSuccess() {
orientationLocked = true; orientationLocked = true;
} }
function onOrientationChangeError(err) { function onOrientationChangeError(err) {
orientationLocked = false; orientationLocked = false;
console.error('error locking orientation: ' + err); console.error('error locking orientation: ' + err);
} }
events.on(playbackManager, 'playbackstart', function (e, player, state) { events.on(playbackManager, 'playbackstart', function (e, player, state) {
var isLocalVideo = player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player); var isLocalVideo = player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player);
if (isLocalVideo && layoutManager.mobile) { if (isLocalVideo && layoutManager.mobile) {
/* eslint-disable-next-line compat/compat */ /* eslint-disable-next-line compat/compat */
var lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation || (screen.orientation && screen.orientation.lock); var lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation || (screen.orientation && screen.orientation.lock);
if (lockOrientation) { if (lockOrientation) {
try { try {
var promise = lockOrientation('landscape'); var promise = lockOrientation('landscape');
if (promise.then) { if (promise.then) {
promise.then(onOrientationChangeSuccess, onOrientationChangeError); promise.then(onOrientationChangeSuccess, onOrientationChangeError);
} else { } else {
// returns a boolean // returns a boolean
orientationLocked = promise; orientationLocked = promise;
}
} catch (err) {
onOrientationChangeError(err);
} }
} catch (err) {
onOrientationChangeError(err);
} }
} }
}); }
});
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 */
var unlockOrientation = screen.unlockOrientation || screen.mozUnlockOrientation || screen.msUnlockOrientation || (screen.orientation && screen.orientation.unlock); /* eslint-disable-next-line compat/compat */
var unlockOrientation = screen.unlockOrientation || screen.mozUnlockOrientation || screen.msUnlockOrientation || (screen.orientation && screen.orientation.unlock);
if (unlockOrientation) {
try { if (unlockOrientation) {
unlockOrientation(); try {
} catch (err) { unlockOrientation();
console.error('error unlocking orientation: ' + err); } catch (err) {
} console.error('error unlocking orientation: ' + err);
orientationLocked = false; }
} orientationLocked = false;
} }
}); }
}); });

View file

@ -1,320 +1,325 @@
define(['appSettings', 'events', 'browser', 'loading', 'playbackManager', 'appRouter', 'globalize', 'apphost'], function (appSettings, events, browser, loading, playbackManager, appRouter, globalize, appHost) { import appSettings from 'appSettings';
'use strict'; import events from 'events';
import browser from 'browser';
import loading from 'loading';
import playbackManager from 'playbackManager';
import appRouter from 'appRouter';
import globalize from 'globalize';
import appHost from 'apphost';
function mirrorItem(info, player) { function mirrorItem(info, player) {
var item = info.item; var item = info.item;
playbackManager.displayContent({ playbackManager.displayContent({
ItemName: item.Name, ItemName: item.Name,
ItemId: item.Id, ItemId: item.Id,
ItemType: item.Type, ItemType: item.Type,
Context: info.context Context: info.context
}, player); }, player);
} }
function mirrorIfEnabled(info) { function mirrorIfEnabled(info) {
if (info && playbackManager.enableDisplayMirroring()) { if (info && playbackManager.enableDisplayMirroring()) {
var getPlayerInfo = playbackManager.getPlayerInfo(); var getPlayerInfo = playbackManager.getPlayerInfo();
if (getPlayerInfo) { if (getPlayerInfo) {
if (!getPlayerInfo.isLocalPlayer && getPlayerInfo.supportedCommands.indexOf('DisplayContent') !== -1) { if (!getPlayerInfo.isLocalPlayer && getPlayerInfo.supportedCommands.indexOf('DisplayContent') !== -1) {
mirrorItem(info, playbackManager.getCurrentPlayer()); mirrorItem(info, playbackManager.getCurrentPlayer());
}
} }
} }
} }
}
function emptyCallback() { function emptyCallback() {
// avoid console logs about uncaught promises // avoid console logs about uncaught promises
}
function getTargetSecondaryText(target) {
if (target.user) {
return target.user.Name;
} }
function getTargetSecondaryText(target) { return null;
}
if (target.user) { function getIcon(target) {
return target.user.Name; var deviceType = target.deviceType;
}
return null; if (!deviceType && target.isLocalPlayer) {
} if (browser.tv) {
function getIcon(target) {
var deviceType = target.deviceType;
if (!deviceType && target.isLocalPlayer) {
if (browser.tv) {
deviceType = 'tv';
} else if (browser.mobile) {
deviceType = 'smartphone';
} else {
deviceType = 'desktop';
}
}
if (!deviceType) {
deviceType = 'tv'; deviceType = 'tv';
} } else if (browser.mobile) {
deviceType = 'smartphone';
switch (deviceType) {
case 'smartphone':
return 'smartphone';
case 'tablet':
return 'tablet';
case 'tv':
return 'tv';
case 'cast':
return 'cast';
case 'desktop':
return 'computer';
default:
return 'tv';
}
}
function showPlayerSelection(button) {
var currentPlayerInfo = playbackManager.getPlayerInfo();
if (currentPlayerInfo) {
if (!currentPlayerInfo.isLocalPlayer) {
showActivePlayerMenu(currentPlayerInfo);
return;
}
}
var currentPlayerId = currentPlayerInfo ? currentPlayerInfo.id : null;
loading.show();
playbackManager.getTargets().then(function (targets) {
var menuItems = targets.map(function (t) {
var name = t.name;
if (t.appName && t.appName !== t.name) {
name += ' - ' + t.appName;
}
return {
name: name,
id: t.id,
selected: currentPlayerId === t.id,
secondaryText: getTargetSecondaryText(t),
icon: getIcon(t)
};
});
require(['actionsheet'], function (actionsheet) {
loading.hide();
var menuOptions = {
title: globalize.translate('HeaderPlayOn'),
items: menuItems,
positionTo: button,
resolveOnClick: true,
border: true
};
// Unfortunately we can't allow the url to change or chromecast will throw a security error
// Might be able to solve this in the future by moving the dialogs to hashbangs
if (!(!browser.chrome || appHost.supports('castmenuhashchange'))) {
menuOptions.enableHistory = false;
}
actionsheet.show(menuOptions).then(function (id) {
var target = targets.filter(function (t) {
return t.id === id;
})[0];
playbackManager.trySetActivePlayer(target.playerName, target);
mirrorIfEnabled();
}, emptyCallback);
});
});
}
function showActivePlayerMenu(playerInfo) {
require(['dialogHelper', 'dialog', 'emby-checkbox', 'emby-button'], function (dialogHelper) {
showActivePlayerMenuInternal(dialogHelper, playerInfo);
});
}
function disconnectFromPlayer(currentDeviceName) {
if (playbackManager.getSupportedCommands().indexOf('EndSession') !== -1) {
require(['dialog'], function (dialog) {
var menuItems = [];
menuItems.push({
name: globalize.translate('Yes'),
id: 'yes'
});
menuItems.push({
name: globalize.translate('No'),
id: 'no'
});
dialog({
buttons: menuItems,
//positionTo: positionTo,
text: globalize.translate('ConfirmEndPlayerSession', currentDeviceName)
}).then(function (id) {
switch (id) {
case 'yes':
playbackManager.getCurrentPlayer().endSession();
playbackManager.setDefaultPlayerActive();
break;
case 'no':
playbackManager.setDefaultPlayerActive();
break;
default:
break;
}
});
});
} else { } else {
deviceType = 'desktop';
playbackManager.setDefaultPlayerActive();
} }
} }
function showActivePlayerMenuInternal(dialogHelper, playerInfo) { if (!deviceType) {
deviceType = 'tv';
var html = '';
var dialogOptions = {
removeOnClose: true
};
dialogOptions.modal = false;
dialogOptions.entryAnimationDuration = 160;
dialogOptions.exitAnimationDuration = 160;
dialogOptions.autoFocus = false;
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('promptDialog');
var currentDeviceName = (playerInfo.deviceName || playerInfo.name);
html += '<div class="promptDialogContent" style="padding:1.5em;">';
html += '<h2 style="margin-top:.5em;">';
html += currentDeviceName;
html += '</h2>';
html += '<div>';
if (playerInfo.supportedCommands.indexOf('DisplayContent') !== -1) {
html += '<label class="checkboxContainer">';
var checkedHtml = playbackManager.enableDisplayMirroring() ? ' checked' : '';
html += '<input type="checkbox" is="emby-checkbox" class="chkMirror"' + checkedHtml + '/>';
html += '<span>' + globalize.translate('EnableDisplayMirroring') + '</span>';
html += '</label>';
}
html += '</div>';
html += '<div style="margin-top:1em;display:flex;justify-content: flex-end;">';
html += '<button is="emby-button" type="button" class="button-flat btnRemoteControl promptDialogButton">' + globalize.translate('HeaderRemoteControl') + '</button>';
html += '<button is="emby-button" type="button" class="button-flat btnDisconnect promptDialogButton ">' + globalize.translate('Disconnect') + '</button>';
html += '<button is="emby-button" type="button" class="button-flat btnCancel promptDialogButton">' + globalize.translate('ButtonCancel') + '</button>';
html += '</div>';
html += '</div>';
dlg.innerHTML = html;
var chkMirror = dlg.querySelector('.chkMirror');
if (chkMirror) {
chkMirror.addEventListener('change', onMirrorChange);
}
var destination = '';
var btnRemoteControl = dlg.querySelector('.btnRemoteControl');
if (btnRemoteControl) {
btnRemoteControl.addEventListener('click', function () {
destination = 'nowplaying';
dialogHelper.close(dlg);
});
}
dlg.querySelector('.btnDisconnect').addEventListener('click', function () {
destination = 'disconnectFromPlayer';
dialogHelper.close(dlg);
});
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg);
});
dialogHelper.open(dlg).then(function () {
if (destination === 'nowplaying') {
appRouter.showNowPlaying();
} else if (destination === 'disconnectFromPlayer') {
disconnectFromPlayer(currentDeviceName);
}
}, emptyCallback);
} }
function onMirrorChange() { switch (deviceType) {
playbackManager.enableDisplayMirroring(this.checked);
case 'smartphone':
return 'smartphone';
case 'tablet':
return 'tablet';
case 'tv':
return 'tv';
case 'cast':
return 'cast';
case 'desktop':
return 'computer';
default:
return 'tv';
} }
}
document.addEventListener('viewshow', function (e) { export function show(button) {
var state = e.detail.state || {}; var currentPlayerInfo = playbackManager.getPlayerInfo();
var item = state.item;
if (item && item.ServerId) { if (currentPlayerInfo) {
mirrorIfEnabled({ if (!currentPlayerInfo.isLocalPlayer) {
item: item showActivePlayerMenu(currentPlayerInfo);
});
return; return;
} }
}); }
events.on(appSettings, 'change', function (e, name) { var currentPlayerId = currentPlayerInfo ? currentPlayerInfo.id : null;
if (name === 'displaymirror') {
mirrorIfEnabled();
}
});
events.on(playbackManager, 'pairing', function (e) { loading.show();
loading.show();
});
events.on(playbackManager, 'paired', function (e) { playbackManager.getTargets().then(function (targets) {
loading.hide();
});
events.on(playbackManager, 'pairerror', function (e) { var menuItems = targets.map(function (t) {
loading.hide();
});
return { var name = t.name;
show: showPlayerSelection
if (t.appName && t.appName !== t.name) {
name += ' - ' + t.appName;
}
return {
name: name,
id: t.id,
selected: currentPlayerId === t.id,
secondaryText: getTargetSecondaryText(t),
icon: getIcon(t)
};
});
require(['actionsheet'], function (actionsheet) {
loading.hide();
var menuOptions = {
title: globalize.translate('HeaderPlayOn'),
items: menuItems,
positionTo: button,
resolveOnClick: true,
border: true
};
// Unfortunately we can't allow the url to change or chromecast will throw a security error
// Might be able to solve this in the future by moving the dialogs to hashbangs
if (!(!browser.chrome || appHost.supports('castmenuhashchange'))) {
menuOptions.enableHistory = false;
}
actionsheet.show(menuOptions).then(function (id) {
var target = targets.filter(function (t) {
return t.id === id;
})[0];
playbackManager.trySetActivePlayer(target.playerName, target);
mirrorIfEnabled();
}, emptyCallback);
});
});
}
function showActivePlayerMenu(playerInfo) {
require(['dialogHelper', 'dialog', 'emby-checkbox', 'emby-button'], function (dialogHelper) {
showActivePlayerMenuInternal(dialogHelper, playerInfo);
});
}
function disconnectFromPlayer(currentDeviceName) {
if (playbackManager.getSupportedCommands().indexOf('EndSession') !== -1) {
require(['dialog'], function (dialog) {
var menuItems = [];
menuItems.push({
name: globalize.translate('Yes'),
id: 'yes'
});
menuItems.push({
name: globalize.translate('No'),
id: 'no'
});
dialog({
buttons: menuItems,
//positionTo: positionTo,
text: globalize.translate('ConfirmEndPlayerSession', currentDeviceName)
}).then(function (id) {
switch (id) {
case 'yes':
playbackManager.getCurrentPlayer().endSession();
playbackManager.setDefaultPlayerActive();
break;
case 'no':
playbackManager.setDefaultPlayerActive();
break;
default:
break;
}
});
});
} else {
playbackManager.setDefaultPlayerActive();
}
}
function showActivePlayerMenuInternal(dialogHelper, playerInfo) {
var html = '';
var dialogOptions = {
removeOnClose: true
}; };
dialogOptions.modal = false;
dialogOptions.entryAnimationDuration = 160;
dialogOptions.exitAnimationDuration = 160;
dialogOptions.autoFocus = false;
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('promptDialog');
var currentDeviceName = (playerInfo.deviceName || playerInfo.name);
html += '<div class="promptDialogContent" style="padding:1.5em;">';
html += '<h2 style="margin-top:.5em;">';
html += currentDeviceName;
html += '</h2>';
html += '<div>';
if (playerInfo.supportedCommands.indexOf('DisplayContent') !== -1) {
html += '<label class="checkboxContainer">';
var checkedHtml = playbackManager.enableDisplayMirroring() ? ' checked' : '';
html += '<input type="checkbox" is="emby-checkbox" class="chkMirror"' + checkedHtml + '/>';
html += '<span>' + globalize.translate('EnableDisplayMirroring') + '</span>';
html += '</label>';
}
html += '</div>';
html += '<div style="margin-top:1em;display:flex;justify-content: flex-end;">';
html += '<button is="emby-button" type="button" class="button-flat btnRemoteControl promptDialogButton">' + globalize.translate('HeaderRemoteControl') + '</button>';
html += '<button is="emby-button" type="button" class="button-flat btnDisconnect promptDialogButton ">' + globalize.translate('Disconnect') + '</button>';
html += '<button is="emby-button" type="button" class="button-flat btnCancel promptDialogButton">' + globalize.translate('ButtonCancel') + '</button>';
html += '</div>';
html += '</div>';
dlg.innerHTML = html;
var chkMirror = dlg.querySelector('.chkMirror');
if (chkMirror) {
chkMirror.addEventListener('change', onMirrorChange);
}
var destination = '';
var btnRemoteControl = dlg.querySelector('.btnRemoteControl');
if (btnRemoteControl) {
btnRemoteControl.addEventListener('click', function () {
destination = 'nowplaying';
dialogHelper.close(dlg);
});
}
dlg.querySelector('.btnDisconnect').addEventListener('click', function () {
destination = 'disconnectFromPlayer';
dialogHelper.close(dlg);
});
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg);
});
dialogHelper.open(dlg).then(function () {
if (destination === 'nowplaying') {
appRouter.showNowPlaying();
} else if (destination === 'disconnectFromPlayer') {
disconnectFromPlayer(currentDeviceName);
}
}, emptyCallback);
}
function onMirrorChange() {
playbackManager.enableDisplayMirroring(this.checked);
}
document.addEventListener('viewshow', function (e) {
var state = e.detail.state || {};
var item = state.item;
if (item && item.ServerId) {
mirrorIfEnabled({
item: item
});
return;
}
}); });
events.on(appSettings, 'change', function (e, name) {
if (name === 'displaymirror') {
mirrorIfEnabled();
}
});
events.on(playbackManager, 'pairing', function (e) {
loading.show();
});
events.on(playbackManager, 'paired', function (e) {
loading.hide();
});
events.on(playbackManager, 'pairerror', function (e) {
loading.hide();
});
export default {
show: show
};

View file

@ -1,270 +1,272 @@
define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'globalize', 'appSettings', 'qualityoptions'], function (connectionManager, actionsheet, datetime, playbackManager, globalize, appSettings, qualityoptions) { import connectionManager from 'connectionManager';
'use strict'; import actionsheet from 'actionsheet';
import playbackManager from 'playbackManager';
import globalize from 'globalize';
import qualityoptions from 'qualityoptions';
function showQualityMenu(player, btn) { function showQualityMenu(player, btn) {
var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) {
return stream.Type === 'Video'; return stream.Type === 'Video';
})[0]; })[0];
var videoWidth = videoStream ? videoStream.Width : null; var videoWidth = videoStream ? videoStream.Width : null;
var videoHeight = videoStream ? videoStream.Height : null; var videoHeight = videoStream ? videoStream.Height : null;
var options = qualityoptions.getVideoQualityOptions({ var options = qualityoptions.getVideoQualityOptions({
currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player), currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player),
isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player), isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player),
videoWidth: videoWidth, videoWidth: videoWidth,
videoHeight: videoHeight, videoHeight: videoHeight,
enableAuto: true enableAuto: true
}); });
var menuItems = options.map(function (o) { var menuItems = options.map(function (o) {
var opt = { var opt = {
name: o.name, name: o.name,
id: o.bitrate, id: o.bitrate,
asideText: o.secondaryText asideText: o.secondaryText
}; };
if (o.selected) { if (o.selected) {
opt.selected = true; opt.selected = true;
} }
return opt; return opt;
}); });
var selectedId = options.filter(function (o) { var selectedId = options.filter(function (o) {
return o.selected; return o.selected;
}); });
selectedId = selectedId.length ? selectedId[0].bitrate : null; selectedId = selectedId.length ? selectedId[0].bitrate : null;
return actionsheet.show({ return actionsheet.show({
items: menuItems, items: menuItems,
positionTo: btn positionTo: btn
}).then(function (id) { }).then(function (id) {
var bitrate = parseInt(id); var bitrate = parseInt(id);
if (bitrate !== selectedId) { if (bitrate !== selectedId) {
playbackManager.setMaxStreamingBitrate({ playbackManager.setMaxStreamingBitrate({
enableAutomaticBitrateDetection: bitrate ? false : true, enableAutomaticBitrateDetection: bitrate ? false : true,
maxBitrate: bitrate maxBitrate: bitrate
}, player); }, player);
} }
}); });
}
function showRepeatModeMenu(player, btn) {
var menuItems = [];
var currentValue = playbackManager.getRepeatMode(player);
menuItems.push({
name: globalize.translate('RepeatAll'),
id: 'RepeatAll',
selected: currentValue === 'RepeatAll'
});
menuItems.push({
name: globalize.translate('RepeatOne'),
id: 'RepeatOne',
selected: currentValue === 'RepeatOne'
});
menuItems.push({
name: globalize.translate('None'),
id: 'RepeatNone',
selected: currentValue === 'RepeatNone'
});
return actionsheet.show({
items: menuItems,
positionTo: btn
}).then(function (mode) {
if (mode) {
playbackManager.setRepeatMode(mode, player);
}
});
}
function getQualitySecondaryText(player) {
var state = playbackManager.getPlayerState(player);
var isAutoEnabled = playbackManager.enableAutomaticBitrateDetection(player);
var currentMaxBitrate = playbackManager.getMaxStreamingBitrate(player);
var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) {
return stream.Type === 'Video';
})[0];
var videoWidth = videoStream ? videoStream.Width : null;
var videoHeight = videoStream ? videoStream.Height : null;
var options = qualityoptions.getVideoQualityOptions({
currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player),
isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player),
videoWidth: videoWidth,
videoHeight: videoHeight,
enableAuto: true
});
var menuItems = options.map(function (o) {
var opt = {
name: o.name,
id: o.bitrate,
asideText: o.secondaryText
};
if (o.selected) {
opt.selected = true;
}
return opt;
});
var selectedOption = options.filter(function (o) {
return o.selected;
});
if (!selectedOption.length) {
return null;
} }
function showRepeatModeMenu(player, btn) { selectedOption = selectedOption[0];
var menuItems = []; var text = selectedOption.name;
var currentValue = playbackManager.getRepeatMode(player);
menuItems.push({ if (selectedOption.autoText) {
name: globalize.translate('RepeatAll'), if (state.PlayState && state.PlayState.PlayMethod !== 'Transcode') {
id: 'RepeatAll', text += ' - Direct';
selected: currentValue === 'RepeatAll' } else {
}); text += ' ' + selectedOption.autoText;
}
menuItems.push({
name: globalize.translate('RepeatOne'),
id: 'RepeatOne',
selected: currentValue === 'RepeatOne'
});
menuItems.push({
name: globalize.translate('None'),
id: 'RepeatNone',
selected: currentValue === 'RepeatNone'
});
return actionsheet.show({
items: menuItems,
positionTo: btn
}).then(function (mode) {
if (mode) {
playbackManager.setRepeatMode(mode, player);
}
});
} }
function getQualitySecondaryText(player) { return text;
var state = playbackManager.getPlayerState(player); }
var isAutoEnabled = playbackManager.enableAutomaticBitrateDetection(player);
var currentMaxBitrate = playbackManager.getMaxStreamingBitrate(player);
var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { function showAspectRatioMenu(player, btn) {
return stream.Type === 'Video'; // each has a name and id
})[0]; var currentId = playbackManager.getAspectRatio(player);
var menuItems = playbackManager.getSupportedAspectRatios(player).map(function (i) {
return {
id: i.id,
name: i.name,
selected: i.id === currentId
};
});
var videoWidth = videoStream ? videoStream.Width : null; return actionsheet.show({
var videoHeight = videoStream ? videoStream.Height : null; items: menuItems,
positionTo: btn
var options = qualityoptions.getVideoQualityOptions({ }).then(function (id) {
currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player), if (id) {
isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player), playbackManager.setAspectRatio(id, player);
videoWidth: videoWidth, return Promise.resolve();
videoHeight: videoHeight,
enableAuto: true
});
var menuItems = options.map(function (o) {
var opt = {
name: o.name,
id: o.bitrate,
asideText: o.secondaryText
};
if (o.selected) {
opt.selected = true;
}
return opt;
});
var selectedOption = options.filter(function (o) {
return o.selected;
});
if (!selectedOption.length) {
return null;
}
selectedOption = selectedOption[0];
var text = selectedOption.name;
if (selectedOption.autoText) {
if (state.PlayState && state.PlayState.PlayMethod !== 'Transcode') {
text += ' - Direct';
} else {
text += ' ' + selectedOption.autoText;
}
}
return text;
}
function showAspectRatioMenu(player, btn) {
// each has a name and id
var currentId = playbackManager.getAspectRatio(player);
var menuItems = playbackManager.getSupportedAspectRatios(player).map(function (i) {
return {
id: i.id,
name: i.name,
selected: i.id === currentId
};
});
return actionsheet.show({
items: menuItems,
positionTo: btn
}).then(function (id) {
if (id) {
playbackManager.setAspectRatio(id, player);
return Promise.resolve();
}
return Promise.reject();
});
}
function showWithUser(options, player, user) {
var supportedCommands = playbackManager.getSupportedCommands(player);
var mediaType = options.mediaType;
var menuItems = [];
if (supportedCommands.indexOf('SetAspectRatio') !== -1) {
var currentAspectRatioId = playbackManager.getAspectRatio(player);
var currentAspectRatio = playbackManager.getSupportedAspectRatios(player).filter(function (i) {
return i.id === currentAspectRatioId;
})[0];
menuItems.push({
name: globalize.translate('AspectRatio'),
id: 'aspectratio',
asideText: currentAspectRatio ? currentAspectRatio.name : null
});
}
if (user && user.Policy.EnableVideoPlaybackTranscoding) {
var secondaryQualityText = getQualitySecondaryText(player);
menuItems.push({
name: globalize.translate('Quality'),
id: 'quality',
asideText: secondaryQualityText
});
}
var repeatMode = playbackManager.getRepeatMode(player);
if (supportedCommands.indexOf('SetRepeatMode') !== -1 && playbackManager.currentMediaSource(player).RunTimeTicks) {
menuItems.push({
name: globalize.translate('RepeatMode'),
id: 'repeatmode',
asideText: repeatMode === 'RepeatNone' ? globalize.translate('None') : globalize.translate('' + repeatMode)
});
}
if (options.suboffset) {
menuItems.push({
name: globalize.translate('SubtitleOffset'),
id: 'suboffset',
asideText: null
});
}
if (options.stats) {
menuItems.push({
name: globalize.translate('PlaybackData'),
id: 'stats',
asideText: null
});
}
return actionsheet.show({
items: menuItems,
positionTo: options.positionTo
}).then(function (id) {
return handleSelectedOption(id, options, player);
});
}
function show(options) {
var player = options.player;
var currentItem = playbackManager.currentItem(player);
if (!currentItem || !currentItem.ServerId) {
return showWithUser(options, player, null);
}
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
return apiClient.getCurrentUser().then(function (user) {
return showWithUser(options, player, user);
});
}
function handleSelectedOption(id, options, player) {
switch (id) {
case 'quality':
return showQualityMenu(player, options.positionTo);
case 'aspectratio':
return showAspectRatioMenu(player, options.positionTo);
case 'repeatmode':
return showRepeatModeMenu(player, options.positionTo);
case 'stats':
if (options.onOption) {
options.onOption('stats');
}
return Promise.resolve();
case 'suboffset':
if (options.onOption) {
options.onOption('suboffset');
}
return Promise.resolve();
default:
break;
} }
return Promise.reject(); return Promise.reject();
});
}
function showWithUser(options, player, user) {
var supportedCommands = playbackManager.getSupportedCommands(player);
var mediaType = options.mediaType;
var menuItems = [];
if (supportedCommands.indexOf('SetAspectRatio') !== -1) {
var currentAspectRatioId = playbackManager.getAspectRatio(player);
var currentAspectRatio = playbackManager.getSupportedAspectRatios(player).filter(function (i) {
return i.id === currentAspectRatioId;
})[0];
menuItems.push({
name: globalize.translate('AspectRatio'),
id: 'aspectratio',
asideText: currentAspectRatio ? currentAspectRatio.name : null
});
} }
return { if (user && user.Policy.EnableVideoPlaybackTranscoding) {
show: show var secondaryQualityText = getQualitySecondaryText(player);
};
}); menuItems.push({
name: globalize.translate('Quality'),
id: 'quality',
asideText: secondaryQualityText
});
}
var repeatMode = playbackManager.getRepeatMode(player);
if (supportedCommands.indexOf('SetRepeatMode') !== -1 && playbackManager.currentMediaSource(player).RunTimeTicks) {
menuItems.push({
name: globalize.translate('RepeatMode'),
id: 'repeatmode',
asideText: repeatMode === 'RepeatNone' ? globalize.translate('None') : globalize.translate('' + repeatMode)
});
}
if (options.suboffset) {
menuItems.push({
name: globalize.translate('SubtitleOffset'),
id: 'suboffset',
asideText: null
});
}
if (options.stats) {
menuItems.push({
name: globalize.translate('PlaybackData'),
id: 'stats',
asideText: null
});
}
return actionsheet.show({
items: menuItems,
positionTo: options.positionTo
}).then(function (id) {
return handleSelectedOption(id, options, player);
});
}
export function show(options) {
var player = options.player;
var currentItem = playbackManager.currentItem(player);
if (!currentItem || !currentItem.ServerId) {
return showWithUser(options, player, null);
}
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
return apiClient.getCurrentUser().then(function (user) {
return showWithUser(options, player, user);
});
}
function handleSelectedOption(id, options, player) {
switch (id) {
case 'quality':
return showQualityMenu(player, options.positionTo);
case 'aspectratio':
return showAspectRatioMenu(player, options.positionTo);
case 'repeatmode':
return showRepeatModeMenu(player, options.positionTo);
case 'stats':
if (options.onOption) {
options.onOption('stats');
}
return Promise.resolve();
case 'suboffset':
if (options.onOption) {
options.onOption('suboffset');
}
return Promise.resolve();
default:
break;
}
return Promise.reject();
}
export default {
show: show
};

View file

@ -1,24 +1,20 @@
define([], function () { export function getDisplayPlayMethod(session) {
'use strict';
function getDisplayPlayMethod(session) { if (!session.NowPlayingItem) {
return null;
if (!session.NowPlayingItem) {
return null;
}
if (session.TranscodingInfo && session.TranscodingInfo.IsVideoDirect) {
return 'DirectStream';
} else if (session.PlayState.PlayMethod === 'Transcode') {
return 'Transcode';
} else if (session.PlayState.PlayMethod === 'DirectStream') {
return 'DirectPlay';
} else if (session.PlayState.PlayMethod === 'DirectPlay') {
return 'DirectPlay';
}
} }
return { if (session.TranscodingInfo && session.TranscodingInfo.IsVideoDirect) {
getDisplayPlayMethod: getDisplayPlayMethod return 'DirectStream';
}; } else if (session.PlayState.PlayMethod === 'Transcode') {
}); return 'Transcode';
} else if (session.PlayState.PlayMethod === 'DirectStream') {
return 'DirectPlay';
} else if (session.PlayState.PlayMethod === 'DirectPlay') {
return 'DirectPlay';
}
}
export default {
getDisplayPlayMethod: getDisplayPlayMethod
};

View file

@ -1,47 +1,45 @@
define(['events', 'playbackManager'], function (events, playbackManager) { import events from 'events';
'use strict'; import playbackManager from 'playbackManager';
function transferPlayback(oldPlayer, newPlayer) { function transferPlayback(oldPlayer, newPlayer) {
const state = playbackManager.getPlayerState(oldPlayer);
const item = state.NowPlayingItem;
var state = playbackManager.getPlayerState(oldPlayer); if (!item) {
return;
var item = state.NowPlayingItem;
if (!item) {
return;
}
var playState = state.PlayState || {};
var resumePositionTicks = playState.PositionTicks || 0;
playbackManager.stop(oldPlayer).then(function () {
playbackManager.play({
ids: [item.Id],
serverId: item.ServerId,
startPositionTicks: resumePositionTicks
}, newPlayer);
});
} }
events.on(playbackManager, 'playerchange', function (e, newPlayer, newTarget, oldPlayer) { playbackManager.getPlaylist(oldPlayer).then(playlist => {
const playlistIds = playlist.map(x => x.Id);
const playState = state.PlayState || {};
const resumePositionTicks = playState.PositionTicks || 0;
const playlistIndex = playlistIds.indexOf(item.Id) || 0;
if (!oldPlayer || !newPlayer) { playbackManager.stop(oldPlayer).then(() => {
return; playbackManager.play({
} ids: playlistIds,
serverId: item.ServerId,
if (!oldPlayer.isLocalPlayer) { startPositionTicks: resumePositionTicks,
console.debug('Skipping remote control autoplay because oldPlayer is not a local player'); startIndex: playlistIndex
return; }, newPlayer);
} });
if (newPlayer.isLocalPlayer) {
console.debug('Skipping remote control autoplay because newPlayer is a local player');
return;
}
transferPlayback(oldPlayer, newPlayer);
}); });
}
events.on(playbackManager, 'playerchange', (e, newPlayer, newTarget, oldPlayer) => {
if (!oldPlayer || !newPlayer) {
return;
}
if (!oldPlayer.isLocalPlayer) {
console.debug('Skipping remote control autoplay because oldPlayer is not a local player');
return;
}
if (newPlayer.isLocalPlayer) {
console.debug('Skipping remote control autoplay because newPlayer is a local player');
return;
}
transferPlayback(oldPlayer, newPlayer);
}); });

View file

@ -1,159 +1,161 @@
define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'material-icons'], function (events, playbackManager, dom, browser) { import events from 'events';
'use strict'; import playbackManager from 'playbackManager';
import dom from 'dom';
import browser from 'browser';
import 'css!./iconosd';
import 'material-icons';
var currentPlayer; var currentPlayer;
var osdElement; var osdElement;
var iconElement; var iconElement;
var progressElement; var progressElement;
var enableAnimation; var enableAnimation;
function getOsdElementHtml() { function getOsdElementHtml() {
var html = ''; var html = '';
html += '<span class="material-icons iconOsdIcon volume_up"></span>'; html += '<span class="material-icons iconOsdIcon volume_up"></span>';
html += '<div class="iconOsdProgressOuter"><div class="iconOsdProgressInner"></div></div>'; html += '<div class="iconOsdProgressOuter"><div class="iconOsdProgressInner"></div></div>';
return html; return html;
}
function ensureOsdElement() {
var elem = osdElement;
if (!elem) {
enableAnimation = browser.supportsCssAnimation();
elem = document.createElement('div');
elem.classList.add('hide');
elem.classList.add('iconOsd');
elem.classList.add('iconOsd-hidden');
elem.classList.add('volumeOsd');
elem.innerHTML = getOsdElementHtml();
iconElement = elem.querySelector('.material-icons');
progressElement = elem.querySelector('.iconOsdProgressInner');
document.body.appendChild(elem);
osdElement = elem;
} }
}
function ensureOsdElement() { function onHideComplete() {
this.classList.add('hide');
}
var elem = osdElement; var hideTimeout;
if (!elem) { function showOsd() {
enableAnimation = browser.supportsCssAnimation(); clearHideTimeout();
elem = document.createElement('div'); var elem = osdElement;
elem.classList.add('hide');
elem.classList.add('iconOsd');
elem.classList.add('iconOsd-hidden');
elem.classList.add('volumeOsd');
elem.innerHTML = getOsdElementHtml();
iconElement = elem.querySelector('.material-icons'); dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
progressElement = elem.querySelector('.iconOsdProgressInner'); once: true
document.body.appendChild(elem);
osdElement = elem;
}
}
function onHideComplete() {
this.classList.add('hide');
}
var hideTimeout;
function showOsd() {
clearHideTimeout();
var elem = osdElement;
dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
once: true
});
elem.classList.remove('hide');
// trigger reflow
void elem.offsetWidth;
requestAnimationFrame(function () {
elem.classList.remove('iconOsd-hidden');
hideTimeout = setTimeout(hideOsd, 3000);
});
}
function clearHideTimeout() {
if (hideTimeout) {
clearTimeout(hideTimeout);
hideTimeout = null;
}
}
function hideOsd() {
clearHideTimeout();
var elem = osdElement;
if (elem) {
if (enableAnimation) {
// trigger reflow
void elem.offsetWidth;
requestAnimationFrame(function () {
elem.classList.add('iconOsd-hidden');
dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
once: true
});
});
} else {
onHideComplete.call(elem);
}
}
}
function updatePlayerVolumeState(isMuted, volume) {
if (iconElement) {
iconElement.classList.remove('volume_off', 'volume_up');
iconElement.classList.add(isMuted ? 'volume_off' : 'volume_up');
}
if (progressElement) {
progressElement.style.width = (volume || 0) + '%';
}
}
function releaseCurrentPlayer() {
var player = currentPlayer;
if (player) {
events.off(player, 'volumechange', onVolumeChanged);
events.off(player, 'playbackstop', hideOsd);
currentPlayer = null;
}
}
function onVolumeChanged(e) {
var player = this;
ensureOsdElement();
updatePlayerVolumeState(player.isMuted(), player.getVolume());
showOsd();
}
function bindToPlayer(player) {
if (player === currentPlayer) {
return;
}
releaseCurrentPlayer();
currentPlayer = player;
if (!player) {
return;
}
hideOsd();
events.on(player, 'volumechange', onVolumeChanged);
events.on(player, 'playbackstop', hideOsd);
}
events.on(playbackManager, 'playerchange', function () {
bindToPlayer(playbackManager.getCurrentPlayer());
}); });
bindToPlayer(playbackManager.getCurrentPlayer()); elem.classList.remove('hide');
// trigger reflow
void elem.offsetWidth;
requestAnimationFrame(function () {
elem.classList.remove('iconOsd-hidden');
hideTimeout = setTimeout(hideOsd, 3000);
});
}
function clearHideTimeout() {
if (hideTimeout) {
clearTimeout(hideTimeout);
hideTimeout = null;
}
}
function hideOsd() {
clearHideTimeout();
var elem = osdElement;
if (elem) {
if (enableAnimation) {
// trigger reflow
void elem.offsetWidth;
requestAnimationFrame(function () {
elem.classList.add('iconOsd-hidden');
dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
once: true
});
});
} else {
onHideComplete.call(elem);
}
}
}
function updatePlayerVolumeState(isMuted, volume) {
if (iconElement) {
iconElement.classList.remove('volume_off', 'volume_up');
iconElement.classList.add(isMuted ? 'volume_off' : 'volume_up');
}
if (progressElement) {
progressElement.style.width = (volume || 0) + '%';
}
}
function releaseCurrentPlayer() {
var player = currentPlayer;
if (player) {
events.off(player, 'volumechange', onVolumeChanged);
events.off(player, 'playbackstop', hideOsd);
currentPlayer = null;
}
}
function onVolumeChanged(e) {
var player = this;
ensureOsdElement();
updatePlayerVolumeState(player.isMuted(), player.getVolume());
showOsd();
}
function bindToPlayer(player) {
if (player === currentPlayer) {
return;
}
releaseCurrentPlayer();
currentPlayer = player;
if (!player) {
return;
}
hideOsd();
events.on(player, 'volumechange', onVolumeChanged);
events.on(player, 'playbackstop', hideOsd);
}
events.on(playbackManager, 'playerchange', function () {
bindToPlayer(playbackManager.getCurrentPlayer());
}); });
bindToPlayer(playbackManager.getCurrentPlayer());

View file

@ -58,7 +58,7 @@ define(['events', 'globalize'], function (events, globalize) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
require([pluginSpec], (pluginFactory) => { require([pluginSpec], (pluginFactory) => {
var plugin = new pluginFactory(); var plugin = pluginFactory.default ? new pluginFactory.default() : new pluginFactory();
// See if it's already installed // See if it's already installed
var existing = instance.pluginsList.filter(function (p) { var existing = instance.pluginsList.filter(function (p) {

View file

@ -57,7 +57,6 @@ define(['apphost', 'userSettings', 'browser', 'events', 'backdrop', 'globalize',
var selectedTheme; var selectedTheme;
for (var i = 0, length = themes.length; i < length; i++) { for (var i = 0, length = themes.length; i < length; i++) {
var theme = themes[i]; var theme = themes[i];
if (theme[isDefaultProperty]) { if (theme[isDefaultProperty]) {
defaultTheme = theme; defaultTheme = theme;

View file

@ -1,6 +1,6 @@
/** /**
* Module that manages the SyncPlay feature. * Module that manages the SyncPlay feature.
* @module components/syncplay/syncPlayManager * @module components/syncPlay/syncPlayManager
*/ */
import events from 'events'; import events from 'events';
@ -265,10 +265,9 @@ class SyncPlayManager {
events.on(player, 'timeupdate', this._onTimeUpdate); events.on(player, 'timeupdate', this._onTimeUpdate);
events.on(player, 'playing', this._onPlaying); events.on(player, 'playing', this._onPlaying);
events.on(player, 'waiting', this._onWaiting); events.on(player, 'waiting', this._onWaiting);
this.playbackRateSupported = player.supports('PlaybackRate');
// Save player current PlaybackRate value // Save player current PlaybackRate value
if (this.playbackRateSupported) { if (player.supports && player.supports('PlaybackRate')) {
this.localPlayerPlaybackRate = player.getPlaybackRate(); this.localPlayerPlaybackRate = player.getPlaybackRate();
} }
} }

View file

@ -1,6 +1,6 @@
/** /**
* Module that manages time syncing with server. * Module that manages time syncing with server.
* @module components/syncplay/timeSyncManager * @module components/syncPlay/timeSyncManager
*/ */
import events from 'events'; import events from 'events';

View file

@ -21,14 +21,11 @@ define(['viewContainer', 'focusManager', 'queryString', 'layoutManager'], functi
if (!newView.initComplete) { if (!newView.initComplete) {
newView.initComplete = true; newView.initComplete = true;
var controller;
if (typeof options.controllerFactory === 'function') { if (typeof options.controllerFactory === 'function') {
controller = new options.controllerFactory(newView, eventDetail.detail.params);
// Use controller method } else if (options.controllerFactory && typeof options.controllerFactory.default === 'function') {
var controller = new options.controllerFactory(newView, eventDetail.detail.params); controller = new options.controllerFactory.default(newView, eventDetail.detail.params);
} else if (typeof options.controllerFactory === 'object') {
// Use controller class
var controller = new options.controllerFactory.default(newView, eventDetail.detail.params);
} }
if (!options.controllerFactory || dispatchPageEvents) { if (!options.controllerFactory || dispatchPageEvents) {

View file

@ -57,7 +57,7 @@ define(['require', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'conne
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
require(['text!./viewsettings.template.html'], function (template) { require(['text!./viewSettings.template.html'], function (template) {
var dialogOptions = { var dialogOptions = {
removeOnClose: true, removeOnClose: true,

1
src/config.json Symbolic link
View file

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

View file

@ -1,3 +1,3 @@
{ {
"multiserver": true "multiserver": false
} }

View file

@ -1,4 +1,4 @@
define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-button', 'emby-input', 'emby-checkbox', 'listViewStyle', 'emby-button'], function ($, loading, globalize) { define(['jQuery', 'loading', 'globalize', 'emby-select', 'emby-button', 'emby-input', 'emby-checkbox', 'listViewStyle', 'emby-button'], function ($, loading, globalize) {
'use strict'; 'use strict';
function loadProfile(page) { function loadProfile(page) {
@ -23,8 +23,8 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt
$('.chkMediaType', page).each(function () { $('.chkMediaType', page).each(function () {
this.checked = -1 != (profile.SupportedMediaTypes || '').split(',').indexOf(this.getAttribute('data-value')); this.checked = -1 != (profile.SupportedMediaTypes || '').split(',').indexOf(this.getAttribute('data-value'));
}); });
$('#chkEnableAlbumArtInDidl', page).checked(profile.EnableAlbumArtInDidl); $('#chkEnableAlbumArtInDidl', page).prop('checked', profile.EnableAlbumArtInDidl);
$('#chkEnableSingleImageLimit', page).checked(profile.EnableSingleAlbumArtLimit); $('#chkEnableSingleImageLimit', page).prop('checked', profile.EnableSingleAlbumArtLimit);
renderXmlDocumentAttributes(page, profile.XmlRootAttributes || []); renderXmlDocumentAttributes(page, profile.XmlRootAttributes || []);
var idInfo = profile.Identification || {}; var idInfo = profile.Identification || {};
renderIdentificationHeaders(page, idInfo.Headers || []); renderIdentificationHeaders(page, idInfo.Headers || []);
@ -51,11 +51,11 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt
$('#txtAlbumArtMaxHeight', page).val(profile.MaxAlbumArtHeight || ''); $('#txtAlbumArtMaxHeight', page).val(profile.MaxAlbumArtHeight || '');
$('#txtIconMaxWidth', page).val(profile.MaxIconWidth || ''); $('#txtIconMaxWidth', page).val(profile.MaxIconWidth || '');
$('#txtIconMaxHeight', page).val(profile.MaxIconHeight || ''); $('#txtIconMaxHeight', page).val(profile.MaxIconHeight || '');
$('#chkIgnoreTranscodeByteRangeRequests', page).checked(profile.IgnoreTranscodeByteRangeRequests); $('#chkIgnoreTranscodeByteRangeRequests', page).prop('checked', profile.IgnoreTranscodeByteRangeRequests);
$('#txtMaxAllowedBitrate', page).val(profile.MaxStreamingBitrate || ''); $('#txtMaxAllowedBitrate', page).val(profile.MaxStreamingBitrate || '');
$('#txtMusicStreamingTranscodingBitrate', page).val(profile.MusicStreamingTranscodingBitrate || ''); $('#txtMusicStreamingTranscodingBitrate', page).val(profile.MusicStreamingTranscodingBitrate || '');
$('#chkRequiresPlainFolders', page).checked(profile.RequiresPlainFolders); $('#chkRequiresPlainFolders', page).prop('checked', profile.RequiresPlainFolders);
$('#chkRequiresPlainVideoItems', page).checked(profile.RequiresPlainVideoItems); $('#chkRequiresPlainVideoItems', page).prop('checked', profile.RequiresPlainVideoItems);
$('#txtProtocolInfo', page).val(profile.ProtocolInfo || ''); $('#txtProtocolInfo', page).val(profile.ProtocolInfo || '');
$('#txtXDlnaCap', page).val(profile.XDlnaCap || ''); $('#txtXDlnaCap', page).val(profile.XDlnaCap || '');
$('#txtXDlnaDoc', page).val(profile.XDlnaDoc || ''); $('#txtXDlnaDoc', page).val(profile.XDlnaDoc || '');
@ -357,9 +357,9 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt
$('#txtTranscodingAudioCodec', popup).val(transcodingProfile.AudioCodec || ''); $('#txtTranscodingAudioCodec', popup).val(transcodingProfile.AudioCodec || '');
$('#txtTranscodingVideoCodec', popup).val(transcodingProfile.VideoCodec || ''); $('#txtTranscodingVideoCodec', popup).val(transcodingProfile.VideoCodec || '');
$('#selectTranscodingProtocol', popup).val(transcodingProfile.Protocol || 'Http'); $('#selectTranscodingProtocol', popup).val(transcodingProfile.Protocol || 'Http');
$('#chkEnableMpegtsM2TsMode', popup).checked(transcodingProfile.EnableMpegtsM2TsMode || false); $('#chkEnableMpegtsM2TsMode', popup).prop('checked', transcodingProfile.EnableMpegtsM2TsMode || false);
$('#chkEstimateContentLength', popup).checked(transcodingProfile.EstimateContentLength || false); $('#chkEstimateContentLength', popup).prop('checked', transcodingProfile.EstimateContentLength || false);
$('#chkReportByteRangeRequests', popup).checked('Bytes' == transcodingProfile.TranscodeSeekInfo); $('#chkReportByteRangeRequests', popup).prop('checked', 'Bytes' == transcodingProfile.TranscodeSeekInfo);
$('.radioTabButton:first', popup).trigger('click'); $('.radioTabButton:first', popup).trigger('click');
openPopup(popup[0]); openPopup(popup[0]);
} }
@ -376,9 +376,9 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt
currentSubProfile.VideoCodec = $('#txtTranscodingVideoCodec', page).val(); currentSubProfile.VideoCodec = $('#txtTranscodingVideoCodec', page).val();
currentSubProfile.Protocol = $('#selectTranscodingProtocol', page).val(); currentSubProfile.Protocol = $('#selectTranscodingProtocol', page).val();
currentSubProfile.Context = 'Streaming'; currentSubProfile.Context = 'Streaming';
currentSubProfile.EnableMpegtsM2TsMode = $('#chkEnableMpegtsM2TsMode', page).checked(); currentSubProfile.EnableMpegtsM2TsMode = $('#chkEnableMpegtsM2TsMode', page).is(':checked');
currentSubProfile.EstimateContentLength = $('#chkEstimateContentLength', page).checked(); currentSubProfile.EstimateContentLength = $('#chkEstimateContentLength', page).is(':checked');
currentSubProfile.TranscodeSeekInfo = $('#chkReportByteRangeRequests', page).checked() ? 'Bytes' : 'Auto'; currentSubProfile.TranscodeSeekInfo = $('#chkReportByteRangeRequests', page).is(':checked') ? 'Bytes' : 'Auto';
if (isSubProfileNew) { if (isSubProfileNew) {
currentProfile.TranscodingProfiles.push(currentSubProfile); currentProfile.TranscodingProfiles.push(currentSubProfile);
@ -647,8 +647,8 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt
function updateProfile(page, profile) { function updateProfile(page, profile) {
profile.Name = $('#txtName', page).val(); profile.Name = $('#txtName', page).val();
profile.EnableAlbumArtInDidl = $('#chkEnableAlbumArtInDidl', page).checked(); profile.EnableAlbumArtInDidl = $('#chkEnableAlbumArtInDidl', page).is(':checked');
profile.EnableSingleAlbumArtLimit = $('#chkEnableSingleImageLimit', page).checked(); profile.EnableSingleAlbumArtLimit = $('#chkEnableSingleImageLimit', page).is(':checked');
profile.SupportedMediaTypes = $('.chkMediaType:checked', page).get().map(function (c) { profile.SupportedMediaTypes = $('.chkMediaType:checked', page).get().map(function (c) {
return c.getAttribute('data-value'); return c.getAttribute('data-value');
}).join(','); }).join(',');
@ -675,9 +675,9 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt
profile.MaxAlbumArtHeight = $('#txtAlbumArtMaxHeight', page).val(); profile.MaxAlbumArtHeight = $('#txtAlbumArtMaxHeight', page).val();
profile.MaxIconWidth = $('#txtIconMaxWidth', page).val(); profile.MaxIconWidth = $('#txtIconMaxWidth', page).val();
profile.MaxIconHeight = $('#txtIconMaxHeight', page).val(); profile.MaxIconHeight = $('#txtIconMaxHeight', page).val();
profile.RequiresPlainFolders = $('#chkRequiresPlainFolders', page).checked(); profile.RequiresPlainFolders = $('#chkRequiresPlainFolders', page).is(':checked');
profile.RequiresPlainVideoItems = $('#chkRequiresPlainVideoItems', page).checked(); profile.RequiresPlainVideoItems = $('#chkRequiresPlainVideoItems', page).is(':checked');
profile.IgnoreTranscodeByteRangeRequests = $('#chkIgnoreTranscodeByteRangeRequests', page).checked(); profile.IgnoreTranscodeByteRangeRequests = $('#chkIgnoreTranscodeByteRangeRequests', page).is(':checked');
profile.MaxStreamingBitrate = $('#txtMaxAllowedBitrate', page).val(); profile.MaxStreamingBitrate = $('#txtMaxAllowedBitrate', page).val();
profile.MusicStreamingTranscodingBitrate = $('#txtMusicStreamingTranscodingBitrate', page).val(); profile.MusicStreamingTranscodingBitrate = $('#txtMusicStreamingTranscodingBitrate', page).val();
profile.ProtocolInfo = $('#txtProtocolInfo', page).val(); profile.ProtocolInfo = $('#txtProtocolInfo', page).val();

View file

@ -1,12 +1,12 @@
define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function ($, loading, libraryMenu, globalize) { define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading, libraryMenu, globalize) {
'use strict'; 'use strict';
function loadPage(page, config, users) { function loadPage(page, config, users) {
page.querySelector('#chkEnablePlayTo').checked = config.EnablePlayTo; page.querySelector('#chkEnablePlayTo').checked = config.EnablePlayTo;
page.querySelector('#chkEnableDlnaDebugLogging').checked = config.EnableDebugLog; page.querySelector('#chkEnableDlnaDebugLogging').checked = config.EnableDebugLog;
$('#txtClientDiscoveryInterval', page).val(config.ClientDiscoveryIntervalSeconds); $('#txtClientDiscoveryInterval', page).val(config.ClientDiscoveryIntervalSeconds);
$('#chkEnableServer', page).checked(config.EnableServer); $('#chkEnableServer', page).prop('checked', config.EnableServer);
$('#chkBlastAliveMessages', page).checked(config.BlastAliveMessages); $('#chkBlastAliveMessages', page).prop('checked', config.BlastAliveMessages);
$('#txtBlastInterval', page).val(config.BlastAliveMessageIntervalSeconds); $('#txtBlastInterval', page).val(config.BlastAliveMessageIntervalSeconds);
var usersHtml = users.map(function (u) { var usersHtml = users.map(function (u) {
return '<option value="' + u.Id + '">' + u.Name + '</option>'; return '<option value="' + u.Id + '">' + u.Name + '</option>';
@ -22,8 +22,8 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function
config.EnablePlayTo = form.querySelector('#chkEnablePlayTo').checked; config.EnablePlayTo = form.querySelector('#chkEnablePlayTo').checked;
config.EnableDebugLog = form.querySelector('#chkEnableDlnaDebugLogging').checked; config.EnableDebugLog = form.querySelector('#chkEnableDlnaDebugLogging').checked;
config.ClientDiscoveryIntervalSeconds = $('#txtClientDiscoveryInterval', form).val(); config.ClientDiscoveryIntervalSeconds = $('#txtClientDiscoveryInterval', form).val();
config.EnableServer = $('#chkEnableServer', form).checked(); config.EnableServer = $('#chkEnableServer', form).is(':checked');
config.BlastAliveMessages = $('#chkBlastAliveMessages', form).checked(); config.BlastAliveMessages = $('#chkBlastAliveMessages', form).is(':checked');
config.BlastAliveMessageIntervalSeconds = $('#txtBlastInterval', form).val(); config.BlastAliveMessageIntervalSeconds = $('#txtBlastInterval', form).val();
config.DefaultUserId = $('#selectUser', form).val(); config.DefaultUserId = $('#selectUser', form).val();
ApiClient.updateNamedConfiguration('dlna', config).then(Dashboard.processServerConfigurationUpdateResult); ApiClient.updateNamedConfiguration('dlna', config).then(Dashboard.processServerConfigurationUpdateResult);

View file

@ -1,16 +1,8 @@
define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox', 'emby-textarea', 'emby-input', 'emby-select', 'emby-button'], function ($, loading, globalize) { define(['jQuery', 'loading', 'globalize', 'emby-checkbox', 'emby-textarea', 'emby-input', 'emby-select', 'emby-button'], function ($, loading, globalize) {
'use strict'; 'use strict';
function loadPage(page, config, languageOptions, systemInfo) { function loadPage(page, config, languageOptions, systemInfo) {
page.querySelector('#txtServerName').value = systemInfo.ServerName; page.querySelector('#txtServerName').value = systemInfo.ServerName;
$('#chkAutoRunWebApp', page).checked(config.AutoRunWebApp);
if (systemInfo.CanLaunchWebBrowser) {
page.querySelector('#fldAutoRunWebApp').classList.remove('hide');
} else {
page.querySelector('#fldAutoRunWebApp').classList.add('hide');
}
page.querySelector('#txtCachePath').value = systemInfo.CachePath || ''; page.querySelector('#txtCachePath').value = systemInfo.CachePath || '';
$('#txtMetadataPath', page).val(systemInfo.InternalMetadataPath || ''); $('#txtMetadataPath', page).val(systemInfo.InternalMetadataPath || '');
$('#txtMetadataNetworkPath', page).val(systemInfo.MetadataNetworkPath || ''); $('#txtMetadataNetworkPath', page).val(systemInfo.MetadataNetworkPath || '');
@ -33,7 +25,6 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox', 'emby-te
config.MetadataPath = $('#txtMetadataPath', form).val(); config.MetadataPath = $('#txtMetadataPath', form).val();
config.MetadataNetworkPath = $('#txtMetadataNetworkPath', form).val(); config.MetadataNetworkPath = $('#txtMetadataNetworkPath', form).val();
var requiresReload = config.UICulture !== currentLanguage; var requiresReload = config.UICulture !== currentLanguage;
config.AutoRunWebApp = $('#chkAutoRunWebApp', form).checked();
ApiClient.updateServerConfiguration(config).then(function() { ApiClient.updateServerConfiguration(config).then(function() {
ApiClient.getNamedConfiguration(brandingConfigKey).then(function(brandingConfig) { ApiClient.getNamedConfiguration(brandingConfigKey).then(function(brandingConfig) {
brandingConfig.LoginDisclaimer = form.querySelector('#txtLoginDisclaimer').value; brandingConfig.LoginDisclaimer = form.querySelector('#txtLoginDisclaimer').value;

View file

@ -1,6 +1,12 @@
define(['datetime', 'loading', 'apphost', 'listViewStyle', 'emby-button', 'flexStyles'], function(datetime, loading, appHost) { import datetime from 'datetime';
'use strict'; import loading from 'loading';
return function(view, params) { import 'emby-button';
import 'listViewStyle';
import 'flexStyles';
/* eslint-disable indent */
export default function(view, params) {
view.addEventListener('viewbeforeshow', function() { view.addEventListener('viewbeforeshow', function() {
loading.show(); loading.show();
var apiClient = ApiClient; var apiClient = ApiClient;
@ -29,5 +35,6 @@ define(['datetime', 'loading', 'apphost', 'listViewStyle', 'emby-button', 'flexS
loading.hide(); loading.hide();
}); });
}); });
}; }
});
/* eslint-enable indent */

View file

@ -29,14 +29,18 @@ define(['jQuery', 'dom', 'loading', 'libraryMenu', 'globalize', 'listViewStyle']
var promises = [ApiClient.getServerConfiguration(), populateLanguages(page.querySelector('#selectLanguage')), populateCountries(page.querySelector('#selectCountry'))]; var promises = [ApiClient.getServerConfiguration(), populateLanguages(page.querySelector('#selectLanguage')), populateCountries(page.querySelector('#selectCountry'))];
Promise.all(promises).then(function(responses) { Promise.all(promises).then(function(responses) {
var config = responses[0]; var config = responses[0];
page.querySelector('#selectLanguage').value = config.PreferredMetadataLanguage || '', page.querySelector('#selectCountry').value = config.MetadataCountryCode || '', loading.hide(); page.querySelector('#selectLanguage').value = config.PreferredMetadataLanguage || '';
page.querySelector('#selectCountry').value = config.MetadataCountryCode || '';
loading.hide();
}); });
} }
function onSubmit() { function onSubmit() {
var form = this; var form = this;
return loading.show(), ApiClient.getServerConfiguration().then(function(config) { return loading.show(), ApiClient.getServerConfiguration().then(function(config) {
config.PreferredMetadataLanguage = form.querySelector('#selectLanguage').value, config.MetadataCountryCode = form.querySelector('#selectCountry').value, ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult); config.PreferredMetadataLanguage = form.querySelector('#selectLanguage').value;
config.MetadataCountryCode = form.querySelector('#selectCountry').value;
ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult);
}), !1; }), !1;
} }
@ -59,6 +63,8 @@ define(['jQuery', 'dom', 'loading', 'libraryMenu', 'globalize', 'listViewStyle']
$(document).on('pageinit', '#metadataImagesConfigurationPage', function() { $(document).on('pageinit', '#metadataImagesConfigurationPage', function() {
$('.metadataImagesConfigurationForm').off('submit', onSubmit).on('submit', onSubmit); $('.metadataImagesConfigurationForm').off('submit', onSubmit).on('submit', onSubmit);
}).on('pageshow', '#metadataImagesConfigurationPage', function() { }).on('pageshow', '#metadataImagesConfigurationPage', function() {
libraryMenu.setTabs('metadata', 2, getTabs), loading.show(), loadPage(this); libraryMenu.setTabs('metadata', 2, getTabs);
loading.show();
loadPage(this);
}); });
}); });

View file

@ -1,4 +1,4 @@
define(['jQuery', 'emby-checkbox', 'fnchecked'], function ($) { define(['jQuery', 'emby-checkbox'], function ($) {
'use strict'; 'use strict';
function fillItems(elem, items, cssClass, idPrefix, currentList, isEnabledList) { function fillItems(elem, items, cssClass, idPrefix, currentList, isEnabledList) {
@ -50,7 +50,7 @@ define(['jQuery', 'emby-checkbox', 'fnchecked'], function ($) {
fillItems($('.monitorUsersList', page), users, 'chkMonitor', 'chkMonitor', notificationConfig.DisabledMonitorUsers); fillItems($('.monitorUsersList', page), users, 'chkMonitor', 'chkMonitor', notificationConfig.DisabledMonitorUsers);
fillItems($('.sendToUsersList', page), users, 'chkSendTo', 'chkSendTo', notificationConfig.SendToUsers, true); fillItems($('.sendToUsersList', page), users, 'chkSendTo', 'chkSendTo', notificationConfig.SendToUsers, true);
fillItems($('.servicesList', page), services, 'chkService', 'chkService', notificationConfig.DisabledServices); fillItems($('.servicesList', page), services, 'chkService', 'chkService', notificationConfig.DisabledServices);
$('#chkEnabled', page).checked(notificationConfig.Enabled || false); $('#chkEnabled', page).prop('checked', notificationConfig.Enabled || false);
$('#selectUsers', page).val(notificationConfig.SendToUserMode).trigger('change'); $('#selectUsers', page).val(notificationConfig.SendToUserMode).trigger('change');
}); });
} }
@ -58,10 +58,10 @@ define(['jQuery', 'emby-checkbox', 'fnchecked'], function ($) {
function save(page) { function save(page) {
var type = getParameterByName('type'); var type = getParameterByName('type');
var promise1 = ApiClient.getNamedConfiguration(notificationsConfigurationKey); var promise1 = ApiClient.getNamedConfiguration(notificationsConfigurationKey);
// TODO: Check if this promise is really needed, as it's unused.
var promise2 = ApiClient.getJSON(ApiClient.getUrl('Notifications/Types')); var promise2 = ApiClient.getJSON(ApiClient.getUrl('Notifications/Types'));
Promise.all([promise1, promise2]).then(function (responses) { Promise.all([promise1, promise2]).then(function (responses) {
var notificationOptions = responses[0]; var notificationOptions = responses[0];
var types = responses[1];
var notificationConfig = notificationOptions.Options.filter(function (n) { var notificationConfig = notificationOptions.Options.filter(function (n) {
return n.Type == type; return n.Type == type;
})[0]; })[0];
@ -73,10 +73,7 @@ define(['jQuery', 'emby-checkbox', 'fnchecked'], function ($) {
notificationOptions.Options.push(notificationConfig); notificationOptions.Options.push(notificationConfig);
} }
types.filter(function (n) { notificationConfig.Enabled = $('#chkEnabled', page).is(':checked');
return n.Type == type;
})[0];
notificationConfig.Enabled = $('#chkEnabled', page).checked();
notificationConfig.SendToUserMode = $('#selectUsers', page).val(); notificationConfig.SendToUserMode = $('#selectUsers', page).val();
notificationConfig.DisabledMonitorUsers = $('.chkMonitor', page).get().filter(function (c) { notificationConfig.DisabledMonitorUsers = $('.chkMonitor', page).get().filter(function (c) {
return !c.checked; return !c.checked;

View file

@ -50,7 +50,7 @@ define(['loading', 'libraryMenu', 'dom', 'globalize', 'cardStyle', 'emby-button'
html += '<button type="button" is="paper-icon-button-light" class="btnCardMenu autoSize"><span class="material-icons more_vert"></span></button>'; html += '<button type="button" is="paper-icon-button-light" class="btnCardMenu autoSize"><span class="material-icons more_vert"></span></button>';
html += '</div>'; html += '</div>';
html += "<div class='cardText'>"; html += "<div class='cardText'>";
html += configPage.DisplayName || plugin.Name; html += configPage && configPage.DisplayName ? configPage.DisplayName : plugin.Name;
html += '</div>'; html += '</div>';
html += "<div class='cardText cardText-secondary'>"; html += "<div class='cardText cardText-secondary'>";
html += plugin.Version; html += plugin.Version;

View file

@ -1,4 +1,4 @@
define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function ($, loading, libraryMenu, globalize) { define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading, libraryMenu, globalize) {
'use strict'; 'use strict';
function loadDeleteFolders(page, user, mediaFolders) { function loadDeleteFolders(page, user, mediaFolders) {
@ -27,7 +27,7 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function
} }
$('.deleteAccess', page).html(html).trigger('create'); $('.deleteAccess', page).html(html).trigger('create');
$('#chkEnableDeleteAllFolders', page).checked(user.Policy.EnableContentDeletion).trigger('change'); $('#chkEnableDeleteAllFolders', page).prop('checked', user.Policy.EnableContentDeletion);
}); });
} }
@ -85,23 +85,23 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function
libraryMenu.setTitle(user.Name); libraryMenu.setTitle(user.Name);
page.querySelector('.username').innerHTML = user.Name; page.querySelector('.username').innerHTML = user.Name;
$('#txtUserName', page).val(user.Name); $('#txtUserName', page).val(user.Name);
$('#chkIsAdmin', page).checked(user.Policy.IsAdministrator); $('#chkIsAdmin', page).prop('checked', user.Policy.IsAdministrator);
$('#chkDisabled', page).checked(user.Policy.IsDisabled); $('#chkDisabled', page).prop('checked', user.Policy.IsDisabled);
$('#chkIsHidden', page).checked(user.Policy.IsHidden); $('#chkIsHidden', page).prop('checked', user.Policy.IsHidden);
$('#chkRemoteControlSharedDevices', page).checked(user.Policy.EnableSharedDeviceControl); $('#chkRemoteControlSharedDevices', page).prop('checked', user.Policy.EnableSharedDeviceControl);
$('#chkEnableRemoteControlOtherUsers', page).checked(user.Policy.EnableRemoteControlOfOtherUsers); $('#chkEnableRemoteControlOtherUsers', page).prop('checked', user.Policy.EnableRemoteControlOfOtherUsers);
$('#chkEnableDownloading', page).checked(user.Policy.EnableContentDownloading); $('#chkEnableDownloading', page).prop('checked', user.Policy.EnableContentDownloading);
$('#chkManageLiveTv', page).checked(user.Policy.EnableLiveTvManagement); $('#chkManageLiveTv', page).prop('checked', user.Policy.EnableLiveTvManagement);
$('#chkEnableLiveTvAccess', page).checked(user.Policy.EnableLiveTvAccess); $('#chkEnableLiveTvAccess', page).prop('checked', user.Policy.EnableLiveTvAccess);
$('#chkEnableMediaPlayback', page).checked(user.Policy.EnableMediaPlayback); $('#chkEnableMediaPlayback', page).prop('checked', user.Policy.EnableMediaPlayback);
$('#chkEnableAudioPlaybackTranscoding', page).checked(user.Policy.EnableAudioPlaybackTranscoding); $('#chkEnableAudioPlaybackTranscoding', page).prop('checked', user.Policy.EnableAudioPlaybackTranscoding);
$('#chkEnableVideoPlaybackTranscoding', page).checked(user.Policy.EnableVideoPlaybackTranscoding); $('#chkEnableVideoPlaybackTranscoding', page).prop('checked', user.Policy.EnableVideoPlaybackTranscoding);
$('#chkEnableVideoPlaybackRemuxing', page).checked(user.Policy.EnablePlaybackRemuxing); $('#chkEnableVideoPlaybackRemuxing', page).prop('checked', user.Policy.EnablePlaybackRemuxing);
$('#chkForceRemoteSourceTranscoding', page).checked(user.Policy.ForceRemoteSourceTranscoding); $('#chkForceRemoteSourceTranscoding', page).prop('checked', user.Policy.ForceRemoteSourceTranscoding);
$('#chkRemoteAccess', page).checked(null == user.Policy.EnableRemoteAccess || user.Policy.EnableRemoteAccess); $('#chkRemoteAccess', page).prop('checked', null == user.Policy.EnableRemoteAccess || user.Policy.EnableRemoteAccess);
$('#chkEnableSyncTranscoding', page).checked(user.Policy.EnableSyncTranscoding); $('#chkEnableSyncTranscoding', page).prop('checked', user.Policy.EnableSyncTranscoding);
$('#chkEnableConversion', page).checked(user.Policy.EnableMediaConversion || false); $('#chkEnableConversion', page).prop('checked', user.Policy.EnableMediaConversion || false);
$('#chkEnableSharing', page).checked(user.Policy.EnablePublicSharing); $('#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');
$('#selectSyncPlayAccess').val(user.Policy.SyncPlayAccess); $('#selectSyncPlayAccess').val(user.Policy.SyncPlayAccess);
@ -119,28 +119,28 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function
function saveUser(user, page) { function saveUser(user, page) {
user.Name = $('#txtUserName', page).val(); user.Name = $('#txtUserName', page).val();
user.Policy.IsAdministrator = $('#chkIsAdmin', page).checked(); user.Policy.IsAdministrator = $('#chkIsAdmin', page).is(':checked');
user.Policy.IsHidden = $('#chkIsHidden', page).checked(); user.Policy.IsHidden = $('#chkIsHidden', page).is(':checked');
user.Policy.IsDisabled = $('#chkDisabled', page).checked(); user.Policy.IsDisabled = $('#chkDisabled', page).is(':checked');
user.Policy.EnableRemoteControlOfOtherUsers = $('#chkEnableRemoteControlOtherUsers', page).checked(); user.Policy.EnableRemoteControlOfOtherUsers = $('#chkEnableRemoteControlOtherUsers', page).is(':checked');
user.Policy.EnableLiveTvManagement = $('#chkManageLiveTv', page).checked(); user.Policy.EnableLiveTvManagement = $('#chkManageLiveTv', page).is(':checked');
user.Policy.EnableLiveTvAccess = $('#chkEnableLiveTvAccess', page).checked(); user.Policy.EnableLiveTvAccess = $('#chkEnableLiveTvAccess', page).is(':checked');
user.Policy.EnableSharedDeviceControl = $('#chkRemoteControlSharedDevices', page).checked(); user.Policy.EnableSharedDeviceControl = $('#chkRemoteControlSharedDevices', page).is(':checked');
user.Policy.EnableMediaPlayback = $('#chkEnableMediaPlayback', page).checked(); user.Policy.EnableMediaPlayback = $('#chkEnableMediaPlayback', page).is(':checked');
user.Policy.EnableAudioPlaybackTranscoding = $('#chkEnableAudioPlaybackTranscoding', page).checked(); user.Policy.EnableAudioPlaybackTranscoding = $('#chkEnableAudioPlaybackTranscoding', page).is(':checked');
user.Policy.EnableVideoPlaybackTranscoding = $('#chkEnableVideoPlaybackTranscoding', page).checked(); user.Policy.EnableVideoPlaybackTranscoding = $('#chkEnableVideoPlaybackTranscoding', page).is(':checked');
user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).checked(); user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).is(':checked');
user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).checked(); user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).is(':checked');
user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).checked(); user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).is(':checked');
user.Policy.EnableSyncTranscoding = $('#chkEnableSyncTranscoding', page).checked(); user.Policy.EnableSyncTranscoding = $('#chkEnableSyncTranscoding', page).is(':checked');
user.Policy.EnableMediaConversion = $('#chkEnableConversion', page).checked(); user.Policy.EnableMediaConversion = $('#chkEnableConversion', page).is(':checked');
user.Policy.EnablePublicSharing = $('#chkEnableSharing', page).checked(); user.Policy.EnablePublicSharing = $('#chkEnableSharing', page).is(':checked');
user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).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.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).checked(); user.Policy.EnableContentDeletion = $('#chkEnableDeleteAllFolders', page).is(':checked');
user.Policy.EnableContentDeletionFromFolders = user.Policy.EnableContentDeletion ? [] : $('.chkFolder', page).get().filter(function (c) { user.Policy.EnableContentDeletionFromFolders = user.Policy.EnableContentDeletion ? [] : $('.chkFolder', page).get().filter(function (c) {
return c.checked; return c.checked;
}).map(function (c) { }).map(function (c) {

View file

@ -1,4 +1,4 @@
define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function ($, loading, libraryMenu, globalize) { define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading, libraryMenu, globalize) {
'use strict'; 'use strict';
function triggerChange(select) { function triggerChange(select) {
@ -47,7 +47,7 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function
$('.channelAccessContainer', page).hide(); $('.channelAccessContainer', page).hide();
} }
$('#chkEnableAllChannels', page).checked(user.Policy.EnableAllChannels).trigger('change'); $('#chkEnableAllChannels', page).prop('checked', user.Policy.EnableAllChannels);
} }
function loadDevices(page, user, devices) { function loadDevices(page, user, devices) {
@ -63,7 +63,7 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function
html += '</div>'; html += '</div>';
$('.deviceAccess', page).show().html(html); $('.deviceAccess', page).show().html(html);
$('#chkEnableAllDevices', page).checked(user.Policy.EnableAllDevices).trigger('change'); $('#chkEnableAllDevices', page).prop('checked', user.Policy.EnableAllDevices);
if (user.Policy.IsAdministrator) { if (user.Policy.IsAdministrator) {
page.querySelector('.deviceAccessContainer').classList.add('hide'); page.querySelector('.deviceAccessContainer').classList.add('hide');
@ -90,19 +90,19 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function
} }
function saveUser(user, page) { function saveUser(user, page) {
user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).checked(); user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).is(':checked');
user.Policy.EnabledFolders = user.Policy.EnableAllFolders ? [] : $('.chkFolder', page).get().filter(function (c) { user.Policy.EnabledFolders = user.Policy.EnableAllFolders ? [] : $('.chkFolder', page).get().filter(function (c) {
return c.checked; return c.checked;
}).map(function (c) { }).map(function (c) {
return c.getAttribute('data-id'); return c.getAttribute('data-id');
}); });
user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).checked(); user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).is(':checked');
user.Policy.EnabledChannels = user.Policy.EnableAllChannels ? [] : $('.chkChannel', page).get().filter(function (c) { user.Policy.EnabledChannels = user.Policy.EnableAllChannels ? [] : $('.chkChannel', page).get().filter(function (c) {
return c.checked; return c.checked;
}).map(function (c) { }).map(function (c) {
return c.getAttribute('data-id'); return c.getAttribute('data-id');
}); });
user.Policy.EnableAllDevices = $('#chkEnableAllDevices', page).checked(); user.Policy.EnableAllDevices = $('#chkEnableAllDevices', page).is(':checked');
user.Policy.EnabledDevices = user.Policy.EnableAllDevices ? [] : $('.chkDevice', page).get().filter(function (c) { user.Policy.EnabledDevices = user.Policy.EnableAllDevices ? [] : $('.chkDevice', page).get().filter(function (c) {
return c.checked; return c.checked;
}).map(function (c) { }).map(function (c) {

View file

@ -1,4 +1,4 @@
define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], function ($, loading, globalize) { define(['jQuery', 'loading', 'globalize', 'emby-checkbox'], function ($, loading, globalize) {
'use strict'; 'use strict';
function loadMediaFolders(page, mediaFolders) { function loadMediaFolders(page, mediaFolders) {
@ -13,7 +13,7 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], functio
html += '</div>'; html += '</div>';
$('.folderAccess', page).html(html).trigger('create'); $('.folderAccess', page).html(html).trigger('create');
$('#chkEnableAllFolders', page).checked(false).trigger('change'); $('#chkEnableAllFolders', page).prop('checked', false);
} }
function loadChannels(page, channels) { function loadChannels(page, channels) {
@ -35,7 +35,7 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], functio
$('.channelAccessContainer', page).hide(); $('.channelAccessContainer', page).hide();
} }
$('#chkEnableAllChannels', page).checked(false).trigger('change'); $('#chkEnableAllChannels', page).prop('checked', false);
} }
function loadUser(page) { function loadUser(page) {
@ -58,7 +58,7 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], functio
user.Name = $('#txtUsername', page).val(); user.Name = $('#txtUsername', page).val();
user.Password = $('#txtPassword', page).val(); user.Password = $('#txtPassword', page).val();
ApiClient.createUser(user).then(function (user) { ApiClient.createUser(user).then(function (user) {
user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).checked(); user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).is(':checked');
user.Policy.EnabledFolders = []; user.Policy.EnabledFolders = [];
if (!user.Policy.EnableAllFolders) { if (!user.Policy.EnableAllFolders) {
@ -69,7 +69,7 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], functio
}); });
} }
user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).checked(); user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).is(':checked');
user.Policy.EnabledChannels = []; user.Policy.EnabledChannels = [];
if (!user.Policy.EnableAllChannels) { if (!user.Policy.EnableAllChannels) {

View file

@ -475,7 +475,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
item.Type === 'MusicAlbum' || item.Type === 'MusicAlbum' ||
item.Type === 'Person'; item.Type === 'Person';
if (!layoutManager.mobile && !userSettings.enableBackdrops()) { if (!layoutManager.mobile && !userSettings.detailsBanner()) {
return false; return false;
} }
@ -972,6 +972,19 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
} }
} }
function toggleLineClamp(clampTarget, e) {
var expandButton = e.target;
var clampClassName = 'detail-clamp-text';
if (clampTarget.classList.contains(clampClassName)) {
clampTarget.classList.remove(clampClassName);
expandButton.innerHTML = globalize.translate('ShowLess');
} else {
clampTarget.classList.add(clampClassName);
expandButton.innerHTML = globalize.translate('ShowMore');
}
}
function renderOverview(elems, item) { function renderOverview(elems, item) {
for (var i = 0, length = elems.length; i < length; i++) { for (var i = 0, length = elems.length; i < length; i++) {
var elem = elems[i]; var elem = elems[i];
@ -980,6 +993,21 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
if (overview) { if (overview) {
elem.innerHTML = overview; elem.innerHTML = overview;
elem.classList.remove('hide'); elem.classList.remove('hide');
elem.classList.add('detail-clamp-text');
// Grab the sibling element to control the expand state
var expandButton = elem.parentElement.querySelector('.overview-expand');
// Detect if we have overflow of text. Based on this StackOverflow answer
// https://stackoverflow.com/a/35157976
if (Math.abs(elem.scrollHeight - elem.offsetHeight) > 2) {
expandButton.classList.remove('hide');
} else {
expandButton.classList.add('hide');
}
expandButton.addEventListener('click', toggleLineClamp.bind(null, elem));
var anchors = elem.querySelectorAll('a'); var anchors = elem.querySelectorAll('a');
for (var j = 0, length2 = anchors.length; j < length2; j++) { for (var j = 0, length2 = anchors.length; j < length2; j++) {
@ -1863,7 +1891,8 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
itemsContainer: castContent, itemsContainer: castContent,
coverImage: true, coverImage: true,
serverId: item.ServerId, serverId: item.ServerId,
shape: 'overflowPortrait' shape: 'overflowPortrait',
imageBlurhashes: item.ImageBlurHashes
}); });
}); });
} }

View file

@ -308,7 +308,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
return apiClient.getItems(apiClient.getCurrentUserId(), modifyQueryWithFilters(instance, { return apiClient.getItems(apiClient.getCurrentUserId(), modifyQueryWithFilters(instance, {
StartIndex: startIndex, StartIndex: startIndex,
Limit: limit, Limit: limit,
Fields: 'PrimaryImageAspectRatio,SortName', Fields: 'PrimaryImageAspectRatio,SortName,Path',
ImageTypeLimit: 1, ImageTypeLimit: 1,
ParentId: item.Id, ParentId: item.Id,
SortBy: sortBy SortBy: sortBy

View file

@ -86,7 +86,7 @@ define(['cardBuilder', 'imageLoader', 'libraryBrowser', 'loading', 'events', 'us
} }
function showFilterMenu(context) { function showFilterMenu(context) {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: getQuery(), query: getQuery(),
mode: 'livetvchannels', mode: 'livetvchannels',

View file

@ -1,4 +1,4 @@
define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-button'], function ($, loading, globalize) { define(['jQuery', 'loading', 'globalize', 'emby-button'], function ($, loading, globalize) {
'use strict'; 'use strict';
function loadPage(page, config) { function loadPage(page, config) {

View file

@ -171,7 +171,12 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB
} }
if (!result.Items.length) { if (!result.Items.length) {
html = '<p style="text-align:center;">' + globalize.translate('MessageNoCollectionsAvailable') + '</p>'; html = '';
html += '<div class="noItemsMessage centerMessage">';
html += '<h1>' + globalize.translate('MessageNothingHere') + '</h1>';
html += '<p>' + globalize.translate('MessageNoCollectionsAvailable') + '</p>';
html += '</div>';
} }
var itemsContainer = tabContent.querySelector('.itemsContainer'); var itemsContainer = tabContent.querySelector('.itemsContainer');

View file

@ -165,6 +165,15 @@ define(['layoutManager', 'loading', 'libraryBrowser', 'cardBuilder', 'lazyLoader
html += '</div>'; html += '</div>';
} }
if (!result.Items.length) {
html = '';
html += '<div class="noItemsMessage centerMessage">';
html += '<h1>' + globalize.translate('MessageNothingHere') + '</h1>';
html += '<p>' + globalize.translate('MessageNoGenresAvailable') + '</p>';
html += '</div>';
}
elem.innerHTML = html; elem.innerHTML = html;
lazyLoader.lazyChildren(elem, fillItemsContainer); lazyLoader.lazyChildren(elem, fillItemsContainer);
libraryBrowser.saveQueryValues(getSavedQueryKey(), query); libraryBrowser.saveQueryValues(getSavedQueryKey(), query);

View file

@ -270,7 +270,7 @@ define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser',
query = userSettings.loadQuerySettings(savedQueryKey, query); query = userSettings.loadQuerySettings(savedQueryKey, query);
self.showFilterMenu = function () { self.showFilterMenu = function () {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: query, query: query,
mode: 'movies', mode: 'movies',

View file

@ -158,7 +158,12 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
} }
if (!result.Items.length) { if (!result.Items.length) {
html = '<p style="text-align:center;">' + globalize.translate('MessageNoTrailersFound') + '</p>'; html = '';
html += '<div class="noItemsMessage centerMessage">';
html += '<h1>' + globalize.translate('MessageNothingHere') + '</h1>';
html += '<p>' + globalize.translate('MessageNoTrailersFound') + '</p>';
html += '</div>';
} }
var itemsContainer = tabContent.querySelector('.itemsContainer'); var itemsContainer = tabContent.querySelector('.itemsContainer');
@ -180,7 +185,7 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
var isLoading = false; var isLoading = false;
self.showFilterMenu = function () { self.showFilterMenu = function () {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: getQuery(tabContent), query: getQuery(tabContent),
mode: 'movies', mode: 'movies',

View file

@ -186,7 +186,7 @@ define(['layoutManager', 'playbackManager', 'loading', 'events', 'libraryBrowser
var isLoading = false; var isLoading = false;
self.showFilterMenu = function () { self.showFilterMenu = function () {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: getQuery(), query: getQuery(),
mode: 'albums', mode: 'albums',

View file

@ -170,7 +170,7 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
var isLoading = false; var isLoading = false;
self.showFilterMenu = function () { self.showFilterMenu = function () {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: getQuery(tabContent), query: getQuery(tabContent),
mode: self.mode, mode: self.mode,

View file

@ -124,7 +124,7 @@ define(['events', 'libraryBrowser', 'imageLoader', 'listView', 'loading', 'userS
var isLoading = false; var isLoading = false;
self.showFilterMenu = function () { self.showFilterMenu = function () {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: getQuery(tabContent), query: getQuery(tabContent),
mode: 'songs', mode: 'songs',

View file

@ -157,7 +157,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
}); });
if (!displayName) { if (!displayName) {
displayItem.Type; displayName = displayItem.Type;
} }
titleElement.innerHTML = displayName; titleElement.innerHTML = displayName;

View file

@ -164,7 +164,7 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB
var isLoading = false; var isLoading = false;
self.showFilterMenu = function () { self.showFilterMenu = function () {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: getQuery(tabContent), query: getQuery(tabContent),
mode: 'episodes', mode: 'episodes',

View file

@ -161,6 +161,15 @@ define(['layoutManager', 'loading', 'libraryBrowser', 'cardBuilder', 'lazyLoader
html += '</div>'; html += '</div>';
} }
if (!result.Items.length) {
html = '';
html += '<div class="noItemsMessage centerMessage">';
html += '<h1>' + globalize.translate('MessageNothingHere') + '</h1>';
html += '<p>' + globalize.translate('MessageNoGenresAvailable') + '</p>';
html += '</div>';
}
elem.innerHTML = html; elem.innerHTML = html;
lazyLoader.lazyChildren(elem, fillItemsContainer); lazyLoader.lazyChildren(elem, fillItemsContainer);
libraryBrowser.saveQueryValues(getSavedQueryKey(), query); libraryBrowser.saveQueryValues(getSavedQueryKey(), query);

View file

@ -197,7 +197,7 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
var isLoading = false; var isLoading = false;
self.showFilterMenu = function () { self.showFilterMenu = function () {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: getQuery(tabContent), query: getQuery(tabContent),
mode: 'series', mode: 'series',

View file

@ -1,6 +1,9 @@
define(['displaySettings', 'userSettings', 'autoFocuser'], function (DisplaySettings, userSettings, autoFocuser) { define(['displaySettings', 'userSettings', 'autoFocuser'], function (DisplaySettings, userSettings, autoFocuser) {
'use strict'; 'use strict';
// Shortcuts
const UserSettings = userSettings.UserSettings;
return function (view, params) { return function (view, params) {
function onBeforeUnload(e) { function onBeforeUnload(e) {
if (hasChanges) { if (hasChanges) {
@ -11,7 +14,7 @@ define(['displaySettings', 'userSettings', 'autoFocuser'], function (DisplaySett
var settingsInstance; var settingsInstance;
var hasChanges; var hasChanges;
var userId = params.userId || ApiClient.getCurrentUserId(); var userId = params.userId || ApiClient.getCurrentUserId();
var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
view.addEventListener('viewshow', function () { view.addEventListener('viewshow', function () {
window.addEventListener('beforeunload', onBeforeUnload); window.addEventListener('beforeunload', onBeforeUnload);

View file

@ -1,6 +1,9 @@
define(['homescreenSettings', 'dom', 'globalize', 'loading', 'userSettings', 'autoFocuser', 'listViewStyle'], function (HomescreenSettings, dom, globalize, loading, userSettings, autoFocuser) { define(['homescreenSettings', 'dom', 'globalize', 'loading', 'userSettings', 'autoFocuser', 'listViewStyle'], function (HomescreenSettings, dom, globalize, loading, userSettings, autoFocuser) {
'use strict'; 'use strict';
// Shortcuts
const UserSettings = userSettings.UserSettings;
return function (view, params) { return function (view, params) {
function onBeforeUnload(e) { function onBeforeUnload(e) {
if (hasChanges) { if (hasChanges) {
@ -11,7 +14,7 @@ define(['homescreenSettings', 'dom', 'globalize', 'loading', 'userSettings', 'au
var homescreenSettingsInstance; var homescreenSettingsInstance;
var hasChanges; var hasChanges;
var userId = params.userId || ApiClient.getCurrentUserId(); var userId = params.userId || ApiClient.getCurrentUserId();
var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
view.addEventListener('viewshow', function () { view.addEventListener('viewshow', function () {
window.addEventListener('beforeunload', onBeforeUnload); window.addEventListener('beforeunload', onBeforeUnload);

View file

@ -1,6 +1,9 @@
define(['playbackSettings', 'dom', 'globalize', 'loading', 'userSettings', 'autoFocuser', 'listViewStyle'], function (PlaybackSettings, dom, globalize, loading, userSettings, autoFocuser) { define(['playbackSettings', 'dom', 'globalize', 'loading', 'userSettings', 'autoFocuser', 'listViewStyle'], function (PlaybackSettings, dom, globalize, loading, userSettings, autoFocuser) {
'use strict'; 'use strict';
// Shortcuts
const UserSettings = userSettings.UserSettings;
return function (view, params) { return function (view, params) {
function onBeforeUnload(e) { function onBeforeUnload(e) {
if (hasChanges) { if (hasChanges) {
@ -11,7 +14,7 @@ define(['playbackSettings', 'dom', 'globalize', 'loading', 'userSettings', 'auto
var settingsInstance; var settingsInstance;
var hasChanges; var hasChanges;
var userId = params.userId || ApiClient.getCurrentUserId(); var userId = params.userId || ApiClient.getCurrentUserId();
var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
view.addEventListener('viewshow', function () { view.addEventListener('viewshow', function () {
window.addEventListener('beforeunload', onBeforeUnload); window.addEventListener('beforeunload', onBeforeUnload);

View file

@ -1,11 +1,11 @@
import subtitleSettings from 'subtitleSettings'; import subtitleSettings from 'subtitleSettings';
import * as userSettings from 'userSettings'; import {UserSettings, currentSettings as userSettings} from 'userSettings';
import autoFocuser from 'autoFocuser'; import autoFocuser from 'autoFocuser';
export class SubtitleController { export class SubtitleController {
constructor(view, params) { constructor(view, params) {
this.userId = params.userId || ApiClient.getCurrentUserId(); this.userId = params.userId || ApiClient.getCurrentUserId();
this.currentSettings = this.userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); this.currentSettings = this.userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
this.hasChanges = false; this.hasChanges = false;
this.subtitleSettingsInstance = null; this.subtitleSettingsInstance = null;
this.view = view; this.view = view;

View file

@ -23,13 +23,6 @@
</div> </div>
</div> </div>
</div> </div>
<div id="fldAutoRunWebApp" class="checkboxContainer checkboxContainer-withDescription hide">
<label>
<input is="emby-checkbox" type="checkbox" id="chkAutoRunWebApp" />
<span>${LaunchWebAppOnStartup}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${LaunchWebAppOnStartupHelp}</div>
</div>
</div> </div>
<div class="verticalSection verticalSection-extrabottompadding"> <div class="verticalSection verticalSection-extrabottompadding">
@ -62,7 +55,7 @@
<input is="emby-input" type="text" id="txtLoginDisclaimer" label="${LabelLoginDisclaimer}" /> <input is="emby-input" type="text" id="txtLoginDisclaimer" label="${LabelLoginDisclaimer}" />
<div class="fieldDescription">${LabelLoginDisclaimerHelp}</div> <div class="fieldDescription">${LabelLoginDisclaimerHelp}</div>
</div> </div>
<div class="inputContainer"> <div class="inputContainer customCssContainer">
<textarea is="emby-textarea" id="txtCustomCss" label="${LabelCustomCss}" class="textarea-mono"></textarea> <textarea is="emby-textarea" id="txtCustomCss" label="${LabelCustomCss}" class="textarea-mono"></textarea>
<div class="fieldDescription">${LabelCustomCssHelp}</div> <div class="fieldDescription">${LabelCustomCssHelp}</div>
</div> </div>

View file

@ -11,7 +11,7 @@
<a is="emby-linkbutton" href="dlnaprofile.html" class="fab submit" style="margin:0 0 0 1em"> <a is="emby-linkbutton" href="dlnaprofile.html" class="fab submit" style="margin:0 0 0 1em">
<span class="material-icons add"></span> <span class="material-icons add"></span>
</a> </a>
<a style="margin-left:2em!important;" is="emby-linkbutton" class="raised button-alt headerHelpButton" target="_blank" href="https://web.archive.org/web/20181216120305/https://github.com/MediaBrowser/Wiki/wiki/Dlna-profiles">${Help}</a> <a is="emby-linkbutton" style="margin-left:2em!important;" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://web.archive.org/web/20181216120305/https://github.com/MediaBrowser/Wiki/wiki/Dlna-profiles">${Help}</a>
</div> </div>
<p>${CustomDlnaProfilesHelp}</p> <p>${CustomDlnaProfilesHelp}</p>

View file

@ -148,7 +148,7 @@ define(['browser', 'dom', 'layoutManager', 'keyboardnavigation', 'css!./emby-sli
this.classList.add('mdl-slider'); this.classList.add('mdl-slider');
this.classList.add('mdl-js-slider'); this.classList.add('mdl-js-slider');
if (browser.edge || browser.msie) { if (browser.edge) {
this.classList.add('slider-browser-edge'); this.classList.add('slider-browser-edge');
} }
if (!layoutManager.mobile) { if (!layoutManager.mobile) {

View file

@ -55,6 +55,7 @@ define(['layoutManager', 'browser', 'css!./emby-textarea', 'registerElement', 'e
newHeight = textarea.scrollHeight/* - offset*/; newHeight = textarea.scrollHeight/* - offset*/;
hasGrown = true; hasGrown = true;
} }
$('.customCssContainer').css('height', newHeight + 'px');
textarea.style.height = newHeight + 'px'; textarea.style.height = newHeight + 'px';
} }

View file

@ -148,6 +148,9 @@
<p class="itemGenres"></p> <p class="itemGenres"></p>
<h3 class="tagline"></h3> <h3 class="tagline"></h3>
<p class="overview"></p> <p class="overview"></p>
<div class="overview-controls">
<a class="overview-expand hide" is="emby-linkbutton" href="#">${ShowMore}</a>
</div>
<p id="itemBirthday"></p> <p id="itemBirthday"></p>
<p id="itemBirthLocation"></p> <p id="itemBirthLocation"></p>
<p id="itemDeathDate"></p> <p id="itemDeathDate"></p>

View file

@ -1,24 +0,0 @@
Dashboard.confirm = function(message, title, callback) {
'use strict';
require(['confirm'], function(confirm) {
confirm(message, title).then(function() {
callback(!0);
}).catch(function() {
callback(!1);
});
});
};
Dashboard.showLoadingMsg = function() {
'use strict';
require(['loading'], function(loading) {
loading.show();
});
};
Dashboard.hideLoadingMsg = function() {
'use strict';
require(['loading'], function(loading) {
loading.hide();
});
};

View file

@ -0,0 +1,52 @@
/* eslint-disable indent */
import connectionManager from 'connectionManager';
class BackdropScreensaver {
constructor() {
this.name = 'Backdrop ScreenSaver';
this.type = 'screensaver';
this.id = 'backdropscreensaver';
this.supportsAnonymous = false;
}
show() {
const query = {
ImageTypes: 'Backdrop',
EnableImageTypes: 'Backdrop',
IncludeItemTypes: 'Movie,Series,MusicArtist',
SortBy: 'Random',
Recursive: true,
Fields: 'Taglines',
ImageTypeLimit: 1,
StartIndex: 0,
Limit: 200
};
const apiClient = connectionManager.currentApiClient();
apiClient.getItems(apiClient.getCurrentUserId(), query).then((result) => {
if (result.Items.length) {
import('slideshow').then(({default: Slideshow}) => {
const newSlideShow = new Slideshow({
showTitle: true,
cover: true,
items: result.Items
});
newSlideShow.show();
this.currentSlideshow = newSlideShow;
}).catch(console.error);
}
});
}
hide() {
if (this.currentSlideshow) {
this.currentSlideshow.hide();
this.currentSlideshow = null;
}
}
}
/* eslint-enable indent */
export default BackdropScreensaver;

View file

@ -0,0 +1,285 @@
import connectionManager from 'connectionManager';
import loading from 'loading';
import keyboardnavigation from 'keyboardnavigation';
import dialogHelper from 'dialogHelper';
import events from 'events';
import 'css!./style';
import 'material-icons';
import 'paper-icon-button-light';
import TableOfContents from './tableOfContents';
export class BookPlayer {
constructor() {
this.name = 'Book Player';
this.type = 'mediaplayer';
this.id = 'bookplayer';
this.priority = 1;
this.onDialogClosed = this.onDialogClosed.bind(this);
this.openTableOfContents = this.openTableOfContents.bind(this);
this.onWindowKeyUp = this.onWindowKeyUp.bind(this);
}
play(options) {
this._progress = 0;
this._loaded = false;
loading.show();
let elem = this.createMediaElement();
return this.setCurrentSrc(elem, options);
}
stop() {
this.unbindEvents();
let elem = this._mediaElement;
let tocElement = this._tocElement;
let rendition = this._rendition;
if (elem) {
dialogHelper.close(elem);
this._mediaElement = null;
}
if (tocElement) {
tocElement.destroy();
this._tocElement = null;
}
if (rendition) {
rendition.destroy();
}
// Hide loader in case player was not fully loaded yet
loading.hide();
this._cancellationToken.shouldCancel = true;
}
currentItem() {
return this._currentItem;
}
currentTime() {
return this._progress * 1000;
}
duration() {
return 1000;
}
getBufferedRanges() {
return [{
start: 0,
end: 10000000
}];
}
volume() {
return 100;
}
isMuted() {
return false;
}
paused() {
return false;
}
seekable() {
return true;
}
onWindowKeyUp(e) {
let key = keyboardnavigation.getKeyName(e);
let rendition = this._rendition;
let book = rendition.book;
switch (key) {
case 'l':
case 'ArrowRight':
case 'Right':
if (this._loaded) {
book.package.metadata.direction === 'rtl' ? rendition.prev() : rendition.next();
}
break;
case 'j':
case 'ArrowLeft':
case 'Left':
if (this._loaded) {
book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev();
}
break;
case 'Escape':
if (this._tocElement) {
// Close table of contents on ESC if it is open
this._tocElement.destroy();
} else {
// Otherwise stop the entire book player
this.stop();
}
break;
}
}
onDialogClosed() {
this.stop();
}
bindMediaElementEvents() {
let elem = this._mediaElement;
elem.addEventListener('close', this.onDialogClosed, {once: true});
elem.querySelector('.btnBookplayerExit').addEventListener('click', this.onDialogClosed, {once: true});
elem.querySelector('.btnBookplayerToc').addEventListener('click', this.openTableOfContents);
}
bindEvents() {
this.bindMediaElementEvents();
document.addEventListener('keyup', this.onWindowKeyUp);
// FIXME: I don't really get why document keyup event is not triggered when epub is in focus
this._rendition.on('keyup', this.onWindowKeyUp);
}
unbindMediaElementEvents() {
let elem = this._mediaElement;
elem.removeEventListener('close', this.onDialogClosed);
elem.querySelector('.btnBookplayerExit').removeEventListener('click', this.onDialogClosed);
elem.querySelector('.btnBookplayerToc').removeEventListener('click', this.openTableOfContents);
}
unbindEvents() {
if (this._mediaElement) {
this.unbindMediaElementEvents();
}
document.removeEventListener('keyup', this.onWindowKeyUp);
if (this._rendition) {
this._rendition.off('keyup', this.onWindowKeyUp);
}
}
openTableOfContents() {
if (this._loaded) {
this._tocElement = new TableOfContents(this);
}
}
createMediaElement() {
let elem = this._mediaElement;
if (elem) {
return elem;
}
elem = document.getElementById('bookPlayer');
if (!elem) {
elem = dialogHelper.createDialog({
exitAnimationDuration: 400,
size: 'fullscreen',
autoFocus: false,
scrollY: false,
exitAnimation: 'fadeout',
removeOnClose: true
});
elem.id = 'bookPlayer';
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>';
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>';
elem.innerHTML = html;
dialogHelper.open(elem);
}
this._mediaElement = elem;
return elem;
}
setCurrentSrc(elem, options) {
let item = options.items[0];
this._currentItem = item;
this.streamInfo = {
started: true,
ended: false,
mediaSource: {
Id: item.Id
}
};
let serverId = item.ServerId;
let apiClient = connectionManager.getApiClient(serverId);
return new Promise((resolve, reject) => {
require(['epubjs'], (epubjs) => {
let downloadHref = apiClient.getItemDownloadUrl(item.Id);
let book = epubjs.default(downloadHref, {openAs: 'epub'});
let rendition = book.renderTo(elem, {width: '100%', height: '97%'});
this._currentSrc = downloadHref;
this._rendition = rendition;
let cancellationToken = {
shouldCancel: false
};
this._cancellationToken = cancellationToken;
return rendition.display().then(() => {
let epubElem = document.querySelector('.epub-container');
epubElem.style.display = 'none';
this.bindEvents();
return this._rendition.book.locations.generate(1024).then(async () => {
if (cancellationToken.shouldCancel) {
return reject();
}
const percentageTicks = options.startPositionTicks / 10000000;
if (percentageTicks !== 0.0) {
const resumeLocation = book.locations.cfiFromPercentage(percentageTicks);
await rendition.display(resumeLocation);
}
this._loaded = true;
epubElem.style.display = 'block';
rendition.on('relocated', (locations) => {
this._progress = book.locations.percentageFromCfi(locations.start.cfi);
events.trigger(this, 'timeupdate');
});
loading.hide();
return resolve();
});
}, () => {
console.error('Failed to display epub');
return reject();
});
});
});
}
canPlayMediaType(mediaType) {
return (mediaType || '').toLowerCase() === 'book';
}
canPlayItem(item) {
if (item.Path && (item.Path.endsWith('epub'))) {
return true;
}
return false;
}
}
export default BookPlayer;

View file

@ -0,0 +1,39 @@
#bookPlayer {
position: relative;
height: 100%;
width: 100%;
overflow: auto;
z-index: 100;
background: #fff;
}
.topRightActionButtons {
right: 0.5vh;
top: 0.5vh;
z-index: 1002;
position: absolute;
}
.topLeftActionButtons {
left: 0.5vh;
top: 0.5vh;
z-index: 1002;
position: absolute;
}
.bookplayerButtonIcon {
color: black;
opacity: 0.7;
}
#dialogToc {
background-color: white;
}
.toc li {
margin-bottom: 5px;
}
.bookplayerErrorMsg {
text-align: center;
}

View file

@ -0,0 +1,91 @@
import dialogHelper from 'dialogHelper';
export default class TableOfContents {
constructor(bookPlayer) {
this._bookPlayer = bookPlayer;
this._rendition = bookPlayer._rendition;
this.onDialogClosed = this.onDialogClosed.bind(this);
this.createMediaElement();
}
destroy() {
let elem = this._elem;
if (elem) {
this.unbindEvents();
dialogHelper.close(elem);
}
this._bookPlayer._tocElement = null;
}
bindEvents() {
let elem = this._elem;
elem.addEventListener('close', this.onDialogClosed, {once: true});
elem.querySelector('.btnBookplayerTocClose').addEventListener('click', this.onDialogClosed, {once: true});
}
unbindEvents() {
let elem = this._elem;
elem.removeEventListener('close', this.onDialogClosed);
elem.querySelector('.btnBookplayerTocClose').removeEventListener('click', this.onDialogClosed);
}
onDialogClosed() {
this.destroy();
}
replaceLinks(contents, f) {
let links = contents.querySelectorAll('a[href]');
links.forEach((link) => {
let href = link.getAttribute('href');
link.onclick = () => {
f(href);
return false;
};
});
}
createMediaElement() {
let rendition = this._rendition;
let elem = dialogHelper.createDialog({
size: 'small',
autoFocus: false,
removeOnClose: true
});
elem.id = 'dialogToc';
let tocHtml = '<div class="topRightActionButtons">';
tocHtml += '<button is="paper-icon-button-light" class="autoSize bookplayerButton btnBookplayerTocClose hide-mouse-idle-tv" tabindex="-1"><span class="material-icons bookplayerButtonIcon close"></span></button>';
tocHtml += '</div>';
tocHtml += '<ul class="toc">';
rendition.book.navigation.forEach((chapter) => {
tocHtml += '<li>';
// Remove '../' from href
let link = chapter.href.startsWith('../') ? chapter.href.substr(3) : chapter.href;
tocHtml += `<a href="${rendition.book.path.directory + link}">${chapter.label}</a>`;
tocHtml += '</li>';
});
tocHtml += '</ul>';
elem.innerHTML = tocHtml;
this.replaceLinks(elem, (href) => {
let relative = rendition.book.path.relative(href);
rendition.display(relative);
this.destroy();
});
this._elem = elem;
this.bindEvents();
dialogHelper.open(elem);
}
}

View file

@ -57,11 +57,6 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
var applicationStable = 'F007D354'; var applicationStable = 'F007D354';
var applicationNightly = '6F511C87'; var applicationNightly = '6F511C87';
var applicationID = applicationStable;
if (userSettings.chromecastVersion === 'nightly') {
applicationID = applicationNightly;
}
var messageNamespace = 'urn:x-cast:com.connectsdk'; var messageNamespace = 'urn:x-cast:com.connectsdk';
var CastPlayer = function () { var CastPlayer = function () {
@ -105,6 +100,11 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
return; return;
} }
var applicationID = applicationStable;
if (userSettings.chromecastVersion() === 'nightly') {
applicationID = applicationNightly;
}
// request session // request session
var sessionRequest = new chrome.cast.SessionRequest(applicationID); var sessionRequest = new chrome.cast.SessionRequest(applicationID);
var apiConfig = new chrome.cast.ApiConfig(sessionRequest, var apiConfig = new chrome.cast.ApiConfig(sessionRequest,

View file

@ -281,14 +281,6 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
} }
self.play = function (options) { self.play = function (options) {
if (browser.msie) {
if (options.playMethod === 'Transcode' && !window.MediaSource) {
alert('Playback of this content is not supported in Internet Explorer. For a better experience, try a modern browser such as Microsoft Edge, Google Chrome, Firefox or Opera.');
return Promise.reject();
}
}
self._started = false; self._started = false;
self._timeUpdated = false; self._timeUpdated = false;
@ -1425,13 +1417,6 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
var video = document.createElement('video'); var video = document.createElement('video');
if (video.webkitSupportsPresentationMode && typeof video.webkitSetPresentationMode === 'function' || document.pictureInPictureEnabled) { if (video.webkitSupportsPresentationMode && typeof video.webkitSetPresentationMode === 'function' || document.pictureInPictureEnabled) {
list.push('PictureInPicture'); list.push('PictureInPicture');
} else if (browser.ipad) {
// Unfortunately this creates a false positive on devices where its' not actually supported
if (navigator.userAgent.toLowerCase().indexOf('os 9') === -1) {
if (video.webkitSupportsPresentationMode && video.webkitSupportsPresentationMode && typeof video.webkitSetPresentationMode === 'function') {
list.push('PictureInPicture');
}
}
} else if (window.Windows) { } else if (window.Windows) {
if (Windows.UI.ViewManagement.ApplicationView.getForCurrentView().isViewModeSupported(Windows.UI.ViewManagement.ApplicationViewMode.compactOverlay)) { if (Windows.UI.ViewManagement.ApplicationView.getForCurrentView().isViewModeSupported(Windows.UI.ViewManagement.ApplicationViewMode.compactOverlay)) {
list.push('PictureInPicture'); list.push('PictureInPicture');

View file

@ -1,30 +1,20 @@
define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackManager', 'appRouter', 'appSettings', 'connectionManager'], function (browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager) { import connectionManager from 'connectionManager';
'use strict';
function PhotoPlayer() { export default class PhotoPlayer {
constructor() {
var self = this; this.name = 'Photo Player';
this.type = 'mediaplayer';
self.name = 'Photo Player'; this.id = 'photoplayer';
self.type = 'mediaplayer'; this.priority = 1;
self.id = 'photoplayer';
// Let any players created by plugins take priority
self.priority = 1;
} }
PhotoPlayer.prototype.play = function (options) { play(options) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
import('slideshow').then(({default: slideshow}) => {
require(['slideshow'], function (slideshow) {
var index = options.startIndex || 0; var index = options.startIndex || 0;
var apiClient = connectionManager.currentApiClient(); var apiClient = connectionManager.currentApiClient();
apiClient.getCurrentUser().then(function(result) { apiClient.getCurrentUser().then(function(result) {
var newSlideShow = new slideshow({ var newSlideShow = new slideshow({
showTitle: false, showTitle: false,
cover: false, cover: false,
@ -36,17 +26,13 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
}); });
newSlideShow.show(); newSlideShow.show();
resolve(); resolve();
}); });
}); });
}); });
}; }
PhotoPlayer.prototype.canPlayMediaType = function (mediaType) {
canPlayMediaType(mediaType) {
return (mediaType || '').toLowerCase() === 'photo'; return (mediaType || '').toLowerCase() === 'photo';
}; }
}
return PhotoPlayer;
});

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