mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge branch 'master' into fix-another-usersettings
This commit is contained in:
commit
c4614f085e
109 changed files with 4670 additions and 3143 deletions
|
@ -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'
|
||||||
|
|
||||||
|
|
43
.eslintrc.js
43
.eslintrc.js
|
@ -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: [
|
||||||
|
|
36
gulpfile.js
36
gulpfile.js
|
@ -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);
|
|
||||||
|
|
47
package.json
47
package.json
|
@ -5,21 +5,23 @@
|
||||||
"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.20.2",
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
"file-loader": "^6.0.0",
|
"file-loader": "^6.0.0",
|
||||||
|
@ -47,18 +49,17 @@
|
||||||
"stylelint-no-browser-hacks": "^1.2.1",
|
"stylelint-no-browser-hacks": "^1.2.1",
|
||||||
"stylelint-order": "^4.0.0",
|
"stylelint-order": "^4.0.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",
|
||||||
|
@ -76,7 +77,7 @@
|
||||||
"query-string": "^6.11.1",
|
"query-string": "^6.11.1",
|
||||||
"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.1",
|
||||||
"webcomponents.js": "^0.7.24",
|
"webcomponents.js": "^0.7.24",
|
||||||
|
@ -89,34 +90,47 @@
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"test": [
|
"test": [
|
||||||
|
"src/components/actionSheet/actionSheet.js",
|
||||||
"src/components/autoFocuser.js",
|
"src/components/autoFocuser.js",
|
||||||
"src/components/cardbuilder/cardBuilder.js",
|
"src/components/cardbuilder/cardBuilder.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/syncplay/groupSelectionMenu.js",
|
"src/components/syncplay/groupSelectionMenu.js",
|
||||||
"src/components/syncplay/timeSyncManager.js",
|
"src/components/syncplay/playbackPermissionManager.js",
|
||||||
"src/components/syncplay/syncPlayManager.js",
|
"src/components/syncplay/syncPlayManager.js",
|
||||||
|
"src/components/syncplay/timeSyncManager.js",
|
||||||
|
"src/plugins/bookPlayer/plugin.js",
|
||||||
|
"src/plugins/bookPlayer/tableOfContent.js",
|
||||||
|
"src/plugins/photoPlayer/plugin.js",
|
||||||
|
"src/scripts/deleteHelper.js",
|
||||||
"src/scripts/dfnshelper.js",
|
"src/scripts/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/components/actionSheet/actionSheet.js",
|
|
||||||
"src/components/playmenu.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"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -141,7 +155,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\""
|
||||||
}
|
}
|
||||||
|
|
|
@ -1144,3 +1144,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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -72,12 +72,12 @@ define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-butt
|
||||||
reject();
|
reject();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
|
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||||
dialogHelper.close(dlg);
|
dialogHelper.close(dlg);
|
||||||
});
|
});
|
||||||
dlg.querySelector('form').addEventListener('submit', function (e) {
|
dlg.querySelector('form').addEventListener('submit', function (event) {
|
||||||
submitSchedule(dlg, options);
|
submitSchedule(dlg, options);
|
||||||
e.preventDefault();
|
event.preventDefault();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -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>';
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>';
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,6 +181,7 @@ 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('#chkDetailsBanner').checked = userSettings.detailsBanner();
|
||||||
|
|
||||||
|
@ -223,6 +224,7 @@ 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);
|
userSettingsInstance.detailsBanner(context.querySelector('#chkDetailsBanner').checked);
|
||||||
|
|
||||||
|
|
|
@ -143,20 +143,28 @@
|
||||||
<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>
|
||||||
|
|
||||||
<div class="checkboxContainer checkboxContainer-withDescription fldDetailsBanner">
|
<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>
|
<label>
|
||||||
<input type="checkbox" is="emby-checkbox" id="chkDetailsBanner" />
|
<input type="checkbox" is="emby-checkbox" id="chkDetailsBanner" />
|
||||||
<span>${EnableDetailsBanner}</span>
|
<span>${EnableDetailsBanner}</span>
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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>';
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 + '">';
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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');
|
||||||
});
|
});
|
||||||
|
|
|
@ -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
|
||||||
|
};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -2187,7 +2185,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 +2214,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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -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
|
||||||
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
};
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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).checked = profile.EnableAlbumArtInDidl;
|
||||||
$('#chkEnableSingleImageLimit', page).checked(profile.EnableSingleAlbumArtLimit);
|
$('#chkEnableSingleImageLimit', page).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).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).checked = profile.RequiresPlainFolders;
|
||||||
$('#chkRequiresPlainVideoItems', page).checked(profile.RequiresPlainVideoItems);
|
$('#chkRequiresPlainVideoItems', page).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).checked = transcodingProfile.EnableMpegtsM2TsMode || false;
|
||||||
$('#chkEstimateContentLength', popup).checked(transcodingProfile.EstimateContentLength || false);
|
$('#chkEstimateContentLength', popup).checked = transcodingProfile.EstimateContentLength || false;
|
||||||
$('#chkReportByteRangeRequests', popup).checked('Bytes' == transcodingProfile.TranscodeSeekInfo);
|
$('#chkReportByteRangeRequests', popup).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).checked;
|
||||||
currentSubProfile.EstimateContentLength = $('#chkEstimateContentLength', page).checked();
|
currentSubProfile.EstimateContentLength = $('#chkEstimateContentLength', page).checked;
|
||||||
currentSubProfile.TranscodeSeekInfo = $('#chkReportByteRangeRequests', page).checked() ? 'Bytes' : 'Auto';
|
currentSubProfile.TranscodeSeekInfo = $('#chkReportByteRangeRequests', page).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).checked;
|
||||||
profile.EnableSingleAlbumArtLimit = $('#chkEnableSingleImageLimit', page).checked();
|
profile.EnableSingleAlbumArtLimit = $('#chkEnableSingleImageLimit', page).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).checked;
|
||||||
profile.RequiresPlainVideoItems = $('#chkRequiresPlainVideoItems', page).checked();
|
profile.RequiresPlainVideoItems = $('#chkRequiresPlainVideoItems', page).checked;
|
||||||
profile.IgnoreTranscodeByteRangeRequests = $('#chkIgnoreTranscodeByteRangeRequests', page).checked();
|
profile.IgnoreTranscodeByteRangeRequests = $('#chkIgnoreTranscodeByteRangeRequests', page).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();
|
||||||
|
|
|
@ -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).checked = config.EnableServer;
|
||||||
$('#chkBlastAliveMessages', page).checked(config.BlastAliveMessages);
|
$('#chkBlastAliveMessages', page).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).checked;
|
||||||
config.BlastAliveMessages = $('#chkBlastAliveMessages', form).checked();
|
config.BlastAliveMessages = $('#chkBlastAliveMessages', form).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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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).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).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;
|
||||||
|
|
|
@ -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).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).checked = user.Policy.IsAdministrator;
|
||||||
$('#chkDisabled', page).checked(user.Policy.IsDisabled);
|
$('#chkDisabled', page).checked = user.Policy.IsDisabled;
|
||||||
$('#chkIsHidden', page).checked(user.Policy.IsHidden);
|
$('#chkIsHidden', page).checked = user.Policy.IsHidden;
|
||||||
$('#chkRemoteControlSharedDevices', page).checked(user.Policy.EnableSharedDeviceControl);
|
$('#chkRemoteControlSharedDevices', page).checked = user.Policy.EnableSharedDeviceControl;
|
||||||
$('#chkEnableRemoteControlOtherUsers', page).checked(user.Policy.EnableRemoteControlOfOtherUsers);
|
$('#chkEnableRemoteControlOtherUsers', page).checked = user.Policy.EnableRemoteControlOfOtherUsers;
|
||||||
$('#chkEnableDownloading', page).checked(user.Policy.EnableContentDownloading);
|
$('#chkEnableDownloading', page).checked = user.Policy.EnableContentDownloading;
|
||||||
$('#chkManageLiveTv', page).checked(user.Policy.EnableLiveTvManagement);
|
$('#chkManageLiveTv', page).checked = user.Policy.EnableLiveTvManagement;
|
||||||
$('#chkEnableLiveTvAccess', page).checked(user.Policy.EnableLiveTvAccess);
|
$('#chkEnableLiveTvAccess', page).checked = user.Policy.EnableLiveTvAccess;
|
||||||
$('#chkEnableMediaPlayback', page).checked(user.Policy.EnableMediaPlayback);
|
$('#chkEnableMediaPlayback', page).checked = user.Policy.EnableMediaPlayback;
|
||||||
$('#chkEnableAudioPlaybackTranscoding', page).checked(user.Policy.EnableAudioPlaybackTranscoding);
|
$('#chkEnableAudioPlaybackTranscoding', page).checked = user.Policy.EnableAudioPlaybackTranscoding;
|
||||||
$('#chkEnableVideoPlaybackTranscoding', page).checked(user.Policy.EnableVideoPlaybackTranscoding);
|
$('#chkEnableVideoPlaybackTranscoding', page).checked = user.Policy.EnableVideoPlaybackTranscoding;
|
||||||
$('#chkEnableVideoPlaybackRemuxing', page).checked(user.Policy.EnablePlaybackRemuxing);
|
$('#chkEnableVideoPlaybackRemuxing', page).checked = user.Policy.EnablePlaybackRemuxing;
|
||||||
$('#chkForceRemoteSourceTranscoding', page).checked(user.Policy.ForceRemoteSourceTranscoding);
|
$('#chkForceRemoteSourceTranscoding', page).checked = user.Policy.ForceRemoteSourceTranscoding;
|
||||||
$('#chkRemoteAccess', page).checked(null == user.Policy.EnableRemoteAccess || user.Policy.EnableRemoteAccess);
|
$('#chkRemoteAccess', page).checked = null == user.Policy.EnableRemoteAccess || user.Policy.EnableRemoteAccess;
|
||||||
$('#chkEnableSyncTranscoding', page).checked(user.Policy.EnableSyncTranscoding);
|
$('#chkEnableSyncTranscoding', page).checked = user.Policy.EnableSyncTranscoding;
|
||||||
$('#chkEnableConversion', page).checked(user.Policy.EnableMediaConversion || false);
|
$('#chkEnableConversion', page).checked = user.Policy.EnableMediaConversion || false;
|
||||||
$('#chkEnableSharing', page).checked(user.Policy.EnablePublicSharing);
|
$('#chkEnableSharing', page).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).checked;
|
||||||
user.Policy.IsHidden = $('#chkIsHidden', page).checked();
|
user.Policy.IsHidden = $('#chkIsHidden', page).checked;
|
||||||
user.Policy.IsDisabled = $('#chkDisabled', page).checked();
|
user.Policy.IsDisabled = $('#chkDisabled', page).checked;
|
||||||
user.Policy.EnableRemoteControlOfOtherUsers = $('#chkEnableRemoteControlOtherUsers', page).checked();
|
user.Policy.EnableRemoteControlOfOtherUsers = $('#chkEnableRemoteControlOtherUsers', page).checked;
|
||||||
user.Policy.EnableLiveTvManagement = $('#chkManageLiveTv', page).checked();
|
user.Policy.EnableLiveTvManagement = $('#chkManageLiveTv', page).checked;
|
||||||
user.Policy.EnableLiveTvAccess = $('#chkEnableLiveTvAccess', page).checked();
|
user.Policy.EnableLiveTvAccess = $('#chkEnableLiveTvAccess', page).checked;
|
||||||
user.Policy.EnableSharedDeviceControl = $('#chkRemoteControlSharedDevices', page).checked();
|
user.Policy.EnableSharedDeviceControl = $('#chkRemoteControlSharedDevices', page).checked;
|
||||||
user.Policy.EnableMediaPlayback = $('#chkEnableMediaPlayback', page).checked();
|
user.Policy.EnableMediaPlayback = $('#chkEnableMediaPlayback', page).checked;
|
||||||
user.Policy.EnableAudioPlaybackTranscoding = $('#chkEnableAudioPlaybackTranscoding', page).checked();
|
user.Policy.EnableAudioPlaybackTranscoding = $('#chkEnableAudioPlaybackTranscoding', page).checked;
|
||||||
user.Policy.EnableVideoPlaybackTranscoding = $('#chkEnableVideoPlaybackTranscoding', page).checked();
|
user.Policy.EnableVideoPlaybackTranscoding = $('#chkEnableVideoPlaybackTranscoding', page).checked;
|
||||||
user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).checked();
|
user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).checked;
|
||||||
user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).checked();
|
user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).checked;
|
||||||
user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).checked();
|
user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).checked;
|
||||||
user.Policy.EnableSyncTranscoding = $('#chkEnableSyncTranscoding', page).checked();
|
user.Policy.EnableSyncTranscoding = $('#chkEnableSyncTranscoding', page).checked;
|
||||||
user.Policy.EnableMediaConversion = $('#chkEnableConversion', page).checked();
|
user.Policy.EnableMediaConversion = $('#chkEnableConversion', page).checked;
|
||||||
user.Policy.EnablePublicSharing = $('#chkEnableSharing', page).checked();
|
user.Policy.EnablePublicSharing = $('#chkEnableSharing', page).checked;
|
||||||
user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).checked();
|
user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).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).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) {
|
||||||
|
|
|
@ -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).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).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).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).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).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) {
|
||||||
|
|
|
@ -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).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).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).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).checked;
|
||||||
user.Policy.EnabledChannels = [];
|
user.Policy.EnabledChannels = [];
|
||||||
|
|
||||||
if (!user.Policy.EnableAllChannels) {
|
if (!user.Policy.EnableAllChannels) {
|
||||||
|
|
|
@ -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
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
278
src/plugins/bookPlayer/plugin.js
Normal file
278
src/plugins/bookPlayer/plugin.js
Normal file
|
@ -0,0 +1,278 @@
|
||||||
|
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 TableOfContent from './tableOfContent';
|
||||||
|
|
||||||
|
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 TableOfContent(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(() => {
|
||||||
|
if (cancellationToken.shouldCancel) {
|
||||||
|
return reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
39
src/plugins/bookPlayer/style.css
Normal file
39
src/plugins/bookPlayer/style.css
Normal 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;
|
||||||
|
}
|
90
src/plugins/bookPlayer/tableOfContent.js
Normal file
90
src/plugins/bookPlayer/tableOfContent.js
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
import dialogHelper from 'dialogHelper';
|
||||||
|
|
||||||
|
export default class TableOfContent {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,
|
|
@ -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');
|
|
@ -1,23 +1,18 @@
|
||||||
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) {
|
||||||
|
|
||||||
require(['slideshow'], function (slideshow) {
|
import('slideshow').then(({default: slideshow}) => {
|
||||||
|
|
||||||
var index = options.startIndex || 0;
|
var index = options.startIndex || 0;
|
||||||
|
|
||||||
|
@ -41,12 +36,10 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
PhotoPlayer.prototype.canPlayMediaType = function (mediaType) {
|
canPlayMediaType(mediaType) {
|
||||||
|
|
||||||
return (mediaType || '').toLowerCase() === 'photo';
|
return (mediaType || '').toLowerCase() === 'photo';
|
||||||
};
|
}
|
||||||
|
}
|
||||||
return PhotoPlayer;
|
|
||||||
});
|
|
|
@ -14,10 +14,6 @@ define([], function () {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userAgent.indexOf('nintendo') !== -1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userAgent.indexOf('viera') !== -1) {
|
if (userAgent.indexOf('viera') !== -1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -93,7 +89,7 @@ define([], function () {
|
||||||
var _supportsCssAnimation;
|
var _supportsCssAnimation;
|
||||||
var _supportsCssAnimationWithPrefix;
|
var _supportsCssAnimationWithPrefix;
|
||||||
function supportsCssAnimation(allowPrefix) {
|
function supportsCssAnimation(allowPrefix) {
|
||||||
|
// TODO: Assess if this is still needed, as all of our targets should natively support CSS animations.
|
||||||
if (allowPrefix) {
|
if (allowPrefix) {
|
||||||
if (_supportsCssAnimationWithPrefix === true || _supportsCssAnimationWithPrefix === false) {
|
if (_supportsCssAnimationWithPrefix === true || _supportsCssAnimationWithPrefix === false) {
|
||||||
return _supportsCssAnimationWithPrefix;
|
return _supportsCssAnimationWithPrefix;
|
||||||
|
@ -145,7 +141,6 @@ define([], function () {
|
||||||
/(chrome)[ \/]([\w.]+)/.exec(ua) ||
|
/(chrome)[ \/]([\w.]+)/.exec(ua) ||
|
||||||
/(safari)[ \/]([\w.]+)/.exec(ua) ||
|
/(safari)[ \/]([\w.]+)/.exec(ua) ||
|
||||||
/(firefox)[ \/]([\w.]+)/.exec(ua) ||
|
/(firefox)[ \/]([\w.]+)/.exec(ua) ||
|
||||||
/(msie) ([\w.]+)/.exec(ua) ||
|
|
||||||
ua.indexOf('compatible') < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
|
ua.indexOf('compatible') < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
|
||||||
[];
|
[];
|
||||||
|
|
||||||
|
@ -161,14 +156,6 @@ define([], function () {
|
||||||
|
|
||||||
if (browser === 'edge') {
|
if (browser === 'edge') {
|
||||||
platform_match = [''];
|
platform_match = [''];
|
||||||
} else {
|
|
||||||
if (ua.indexOf('windows phone') !== -1 || ua.indexOf('iemobile') !== -1) {
|
|
||||||
|
|
||||||
// http://www.neowin.net/news/ie11-fakes-user-agent-to-fool-gmail-in-windows-phone-81-gdr1-update
|
|
||||||
browser = 'msie';
|
|
||||||
} else if (ua.indexOf('like gecko') !== -1 && ua.indexOf('webkit') === -1 && ua.indexOf('opera') === -1 && ua.indexOf('chrome') === -1 && ua.indexOf('safari') === -1) {
|
|
||||||
browser = 'msie';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (browser === 'opr') {
|
if (browser === 'opr') {
|
||||||
|
@ -211,7 +198,7 @@ define([], function () {
|
||||||
browser[matched.platform] = true;
|
browser[matched.platform] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!browser.chrome && !browser.msie && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf('webkit') !== -1) {
|
if (!browser.chrome && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf('webkit') !== -1) {
|
||||||
browser.safari = true;
|
browser.safari = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +211,10 @@ define([], function () {
|
||||||
browser.mobile = true;
|
browser.mobile = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
browser.xboxOne = userAgent.toLowerCase().indexOf('xbox') !== -1;
|
if (userAgent.toLowerCase().indexOf('xbox') !== -1) {
|
||||||
|
browser.xboxOne = true;
|
||||||
|
browser.tv = true;
|
||||||
|
}
|
||||||
browser.animate = typeof document !== 'undefined' && document.documentElement.animate != null;
|
browser.animate = typeof document !== 'undefined' && document.documentElement.animate != null;
|
||||||
browser.tizen = userAgent.toLowerCase().indexOf('tizen') !== -1 || self.tizen != null;
|
browser.tizen = userAgent.toLowerCase().indexOf('tizen') !== -1 || self.tizen != null;
|
||||||
browser.web0s = userAgent.toLowerCase().indexOf('Web0S'.toLowerCase()) !== -1;
|
browser.web0s = userAgent.toLowerCase().indexOf('Web0S'.toLowerCase()) !== -1;
|
||||||
|
|
|
@ -188,20 +188,6 @@ define(['browser'], function (browser) {
|
||||||
return browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
return browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFlvMseDirectPlayProfile() {
|
|
||||||
var videoAudioCodecs = ['aac'];
|
|
||||||
if (!browser.edge && !browser.msie) {
|
|
||||||
videoAudioCodecs.push('mp3');
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
Container: 'flv',
|
|
||||||
Type: 'Video',
|
|
||||||
VideoCodec: 'h264',
|
|
||||||
AudioCodec: videoAudioCodecs.join(',')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDirectPlayProfileForVideoContainer(container, videoAudioCodecs, videoTestElement, options) {
|
function getDirectPlayProfileForVideoContainer(container, videoAudioCodecs, videoTestElement, options) {
|
||||||
var supported = false;
|
var supported = false;
|
||||||
var profileContainer = container;
|
var profileContainer = container;
|
||||||
|
@ -230,9 +216,6 @@ define(['browser'], function (browser) {
|
||||||
break;
|
break;
|
||||||
case 'flv':
|
case 'flv':
|
||||||
supported = browser.tizen || browser.orsay;
|
supported = browser.tizen || browser.orsay;
|
||||||
//if (!supported && window.MediaSource != null && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"')) {
|
|
||||||
// return getFlvMseDirectPlayProfile();
|
|
||||||
//}
|
|
||||||
break;
|
break;
|
||||||
case '3gp':
|
case '3gp':
|
||||||
case 'mts':
|
case 'mts':
|
||||||
|
|
|
@ -209,7 +209,7 @@ define(['datetime', 'jQuery', 'globalize', 'material-icons'], function (datetime
|
||||||
function onNodeOpen(event, data) {
|
function onNodeOpen(event, data) {
|
||||||
var page = $(this).parents('.page')[0];
|
var page = $(this).parents('.page')[0];
|
||||||
var node = data.node;
|
var node = data.node;
|
||||||
if (node.children && node.children) {
|
if (node.children) {
|
||||||
loadNodesToLoad(page, node);
|
loadNodesToLoad(page, node);
|
||||||
}
|
}
|
||||||
if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) {
|
if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) {
|
||||||
|
@ -221,7 +221,7 @@ define(['datetime', 'jQuery', 'globalize', 'material-icons'], function (datetime
|
||||||
function onNodeLoad(event, data) {
|
function onNodeLoad(event, data) {
|
||||||
var page = $(this).parents('.page')[0];
|
var page = $(this).parents('.page')[0];
|
||||||
var node = data.node;
|
var node = data.node;
|
||||||
if (node.children && node.children) {
|
if (node.children) {
|
||||||
loadNodesToLoad(page, node);
|
loadNodesToLoad(page, node);
|
||||||
}
|
}
|
||||||
if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) {
|
if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) {
|
||||||
|
|
|
@ -602,27 +602,25 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
if (libraryMenuOptions) {
|
if (libraryMenuOptions) {
|
||||||
getUserViews(apiClient, userId).then(function (result) {
|
getUserViews(apiClient, userId).then(function (result) {
|
||||||
var items = result;
|
var items = result;
|
||||||
var html = '';
|
var html = `<h3 class="sidebarHeader">${globalize.translate('HeaderMedia')}</h3>`;
|
||||||
html += '<h3 class="sidebarHeader">';
|
|
||||||
html += globalize.translate('HeaderMedia');
|
|
||||||
html += '</h3>';
|
|
||||||
html += items.map(function (i) {
|
html += items.map(function (i) {
|
||||||
var icon = i.icon || imageHelper.getLibraryIcon(i.CollectionType);
|
var icon = i.icon || imageHelper.getLibraryIcon(i.CollectionType);
|
||||||
var itemId = i.Id;
|
var itemId = i.Id;
|
||||||
|
|
||||||
if (i.onclick) {
|
const linkHtml = `<a is="emby-linkbutton" data-itemid="${itemId}" class="lnkMediaFolder navMenuOption" href="${getItemHref(i, i.CollectionType)}">
|
||||||
i.onclick;
|
<span class="material-icons navMenuOptionIcon ${icon}"></span>
|
||||||
}
|
<span class="sectionName navMenuOptionText">${i.Name}</span>
|
||||||
|
</a>`;
|
||||||
|
|
||||||
return '<a is="emby-linkbutton" data-itemid="' + itemId + '" class="lnkMediaFolder navMenuOption" href="' + getItemHref(i, i.CollectionType) + '"><span class="material-icons navMenuOptionIcon ' + icon + '"></span><span class="sectionName navMenuOptionText">' + i.Name + '</span></a>';
|
return linkHtml;
|
||||||
}).join('');
|
}).join('');
|
||||||
libraryMenuOptions.innerHTML = html;
|
libraryMenuOptions.innerHTML = html;
|
||||||
var elem = libraryMenuOptions;
|
var elem = libraryMenuOptions;
|
||||||
var sidebarLinks = elem.querySelectorAll('.navMenuOption');
|
var sidebarLinks = elem.querySelectorAll('.navMenuOption');
|
||||||
|
|
||||||
for (var i = 0, length = sidebarLinks.length; i < length; i++) {
|
for (const sidebarLink of sidebarLinks) {
|
||||||
sidebarLinks[i].removeEventListener('click', onSidebarLinkClick);
|
sidebarLink.removeEventListener('click', onSidebarLinkClick);
|
||||||
sidebarLinks[i].addEventListener('click', onSidebarLinkClick);
|
sidebarLink.addEventListener('click', onSidebarLinkClick);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -936,6 +934,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
|
|
||||||
updateMenuForPageType(isDashboardPage, isLibraryPage);
|
updateMenuForPageType(isDashboardPage, isLibraryPage);
|
||||||
|
|
||||||
|
// TODO: Seems to do nothing? Check if needed (also in other views).
|
||||||
if (!e.detail.isRestored) {
|
if (!e.detail.isRestored) {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,10 +69,11 @@ define(['loading', 'listView', 'cardBuilder', 'libraryMenu', 'libraryBrowser', '
|
||||||
showLoadingMessage();
|
showLoadingMessage();
|
||||||
var query = getQuery(view);
|
var query = getQuery(view);
|
||||||
var promise1 = ApiClient.getItems(Dashboard.getCurrentUserId(), query);
|
var promise1 = ApiClient.getItems(Dashboard.getCurrentUserId(), query);
|
||||||
|
// TODO: promise2 is unused, check if necessary.
|
||||||
var promise2 = Dashboard.getCurrentUser();
|
var promise2 = Dashboard.getCurrentUser();
|
||||||
Promise.all([promise1, promise2]).then(function (responses) {
|
Promise.all([promise1, promise2]).then(function (responses) {
|
||||||
var result = responses[0];
|
var result = responses[0];
|
||||||
responses[1];
|
// TODO: Is the scroll necessary?
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
var html = '';
|
var html = '';
|
||||||
var viewStyle = getPageData(view).view;
|
var viewStyle = getPageData(view).view;
|
||||||
|
|
|
@ -180,6 +180,20 @@ export class UserSettings {
|
||||||
return val !== 'false';
|
return val !== 'false';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or set 'Blurhash' state.
|
||||||
|
* @param {boolean|undefined} val - Flag to enable 'Blurhash' or undefined.
|
||||||
|
* @return {boolean} 'Blurhash' state.
|
||||||
|
*/
|
||||||
|
enableBlurhash(val) {
|
||||||
|
if (val !== undefined) {
|
||||||
|
return this.set('blurhash', val.toString(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = this.get('blurhash', false);
|
||||||
|
return val !== 'false';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get or set 'Backdrops' state.
|
* Get or set 'Backdrops' state.
|
||||||
* @param {boolean|undefined} val - Flag to enable 'Backdrops' or undefined.
|
* @param {boolean|undefined} val - Flag to enable 'Backdrops' or undefined.
|
||||||
|
@ -444,6 +458,7 @@ export const enableNextVideoInfoOverlay = currentSettings.enableNextVideoInfoOve
|
||||||
export const enableThemeSongs = currentSettings.enableThemeSongs.bind(currentSettings);
|
export const enableThemeSongs = currentSettings.enableThemeSongs.bind(currentSettings);
|
||||||
export const enableThemeVideos = currentSettings.enableThemeVideos.bind(currentSettings);
|
export const enableThemeVideos = currentSettings.enableThemeVideos.bind(currentSettings);
|
||||||
export const enableFastFadein = currentSettings.enableFastFadein.bind(currentSettings);
|
export const enableFastFadein = currentSettings.enableFastFadein.bind(currentSettings);
|
||||||
|
export const enableBlurhash = currentSettings.enableBlurhash.bind(currentSettings);
|
||||||
export const enableBackdrops = currentSettings.enableBackdrops.bind(currentSettings);
|
export const enableBackdrops = currentSettings.enableBackdrops.bind(currentSettings);
|
||||||
export const detailsBanner = currentSettings.detailsBanner.bind(currentSettings);
|
export const detailsBanner = currentSettings.detailsBanner.bind(currentSettings);
|
||||||
export const language = currentSettings.language.bind(currentSettings);
|
export const language = currentSettings.language.bind(currentSettings);
|
||||||
|
|
|
@ -375,8 +375,7 @@ var AppInfo = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initRequireWithBrowser(browser) {
|
function initRequireWithBrowser() {
|
||||||
var bowerPath = getBowerPath();
|
|
||||||
var componentsPath = getComponentsPath();
|
var componentsPath = getComponentsPath();
|
||||||
var scriptsPath = getScriptsPath();
|
var scriptsPath = getScriptsPath();
|
||||||
|
|
||||||
|
@ -385,13 +384,7 @@ var AppInfo = {};
|
||||||
define('lazyLoader', [componentsPath + '/lazyLoader/lazyLoaderIntersectionObserver'], returnFirstDependency);
|
define('lazyLoader', [componentsPath + '/lazyLoader/lazyLoaderIntersectionObserver'], returnFirstDependency);
|
||||||
define('shell', [scriptsPath + '/shell'], returnFirstDependency);
|
define('shell', [scriptsPath + '/shell'], returnFirstDependency);
|
||||||
|
|
||||||
if ('registerElement' in document) {
|
define('registerElement', ['document-register-element'], returnFirstDependency);
|
||||||
define('registerElement', []);
|
|
||||||
} else if (browser.msie) {
|
|
||||||
define('registerElement', ['webcomponents'], returnFirstDependency);
|
|
||||||
} else {
|
|
||||||
define('registerElement', ['document-register-element'], returnFirstDependency);
|
|
||||||
}
|
|
||||||
|
|
||||||
define('alert', [componentsPath + '/alert'], returnFirstDependency);
|
define('alert', [componentsPath + '/alert'], returnFirstDependency);
|
||||||
|
|
||||||
|
@ -486,21 +479,22 @@ var AppInfo = {};
|
||||||
function loadPlugins(appHost, browser, shell) {
|
function loadPlugins(appHost, browser, shell) {
|
||||||
console.debug('loading installed plugins');
|
console.debug('loading installed plugins');
|
||||||
var list = [
|
var list = [
|
||||||
'components/playback/playaccessvalidation',
|
'plugins/playAccessValidation/plugin',
|
||||||
'components/playback/experimentalwarnings',
|
'plugins/experimentalWarnings/plugin',
|
||||||
'components/htmlAudioPlayer/plugin',
|
'plugins/htmlAudioPlayer/plugin',
|
||||||
'components/htmlVideoPlayer/plugin',
|
'plugins/htmlVideoPlayer/plugin',
|
||||||
'components/photoPlayer/plugin',
|
'plugins/photoPlayer/plugin',
|
||||||
'components/youtubeplayer/plugin',
|
'plugins/bookPlayer/plugin',
|
||||||
'components/backdropScreensaver/plugin',
|
'plugins/youtubePlayer/plugin',
|
||||||
'components/logoScreensaver/plugin'
|
'plugins/backdropScreensaver/plugin',
|
||||||
|
'plugins/logoScreensaver/plugin'
|
||||||
];
|
];
|
||||||
|
|
||||||
if (appHost.supports('remotecontrol')) {
|
if (appHost.supports('remotecontrol')) {
|
||||||
list.push('components/sessionPlayer');
|
list.push('plugins/sessionPlayer/plugin');
|
||||||
|
|
||||||
if (browser.chrome || browser.opera) {
|
if (browser.chrome || browser.opera) {
|
||||||
list.push('components/chromecast/chromecastplayer');
|
list.push('plugins/chromecastPlayer/plugin');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,6 +555,7 @@ var AppInfo = {};
|
||||||
require(['components/playback/volumeosd']);
|
require(['components/playback/volumeosd']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* eslint-disable-next-line compat/compat */
|
||||||
if (navigator.mediaSession || window.NativeShell) {
|
if (navigator.mediaSession || window.NativeShell) {
|
||||||
require(['mediaSession']);
|
require(['mediaSession']);
|
||||||
}
|
}
|
||||||
|
@ -616,8 +611,8 @@ var AppInfo = {};
|
||||||
/* eslint-enable compat/compat */
|
/* eslint-enable compat/compat */
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWebComponentsReady(browser) {
|
function onWebComponentsReady() {
|
||||||
initRequireWithBrowser(browser);
|
initRequireWithBrowser();
|
||||||
|
|
||||||
if (self.appMode === 'cordova' || self.appMode === 'android' || self.appMode === 'standalone') {
|
if (self.appMode === 'cordova' || self.appMode === 'android' || self.appMode === 'standalone') {
|
||||||
AppInfo.isNativeApp = true;
|
AppInfo.isNativeApp = true;
|
||||||
|
@ -659,7 +654,8 @@ var AppInfo = {};
|
||||||
nowPlayingHelper: componentsPath + '/playback/nowplayinghelper',
|
nowPlayingHelper: componentsPath + '/playback/nowplayinghelper',
|
||||||
pluginManager: componentsPath + '/pluginManager',
|
pluginManager: componentsPath + '/pluginManager',
|
||||||
packageManager: componentsPath + '/packagemanager',
|
packageManager: componentsPath + '/packagemanager',
|
||||||
screensaverManager: componentsPath + '/screensavermanager'
|
screensaverManager: componentsPath + '/screensavermanager',
|
||||||
|
chromecastHelper: 'plugins/chromecastPlayer/chromecastHelpers'
|
||||||
};
|
};
|
||||||
|
|
||||||
requirejs.onError = onRequireJsError;
|
requirejs.onError = onRequireJsError;
|
||||||
|
@ -677,6 +673,7 @@ var AppInfo = {};
|
||||||
'fetch',
|
'fetch',
|
||||||
'flvjs',
|
'flvjs',
|
||||||
'jstree',
|
'jstree',
|
||||||
|
'epubjs',
|
||||||
'jQuery',
|
'jQuery',
|
||||||
'hlsjs',
|
'hlsjs',
|
||||||
'howler',
|
'howler',
|
||||||
|
@ -778,7 +775,6 @@ var AppInfo = {};
|
||||||
define('appSettings', [scriptsPath + '/settings/appSettings'], returnFirstDependency);
|
define('appSettings', [scriptsPath + '/settings/appSettings'], returnFirstDependency);
|
||||||
define('userSettings', [scriptsPath + '/settings/userSettings'], returnFirstDependency);
|
define('userSettings', [scriptsPath + '/settings/userSettings'], returnFirstDependency);
|
||||||
|
|
||||||
define('chromecastHelper', [componentsPath + '/chromecast/chromecasthelpers'], returnFirstDependency);
|
|
||||||
define('mediaSession', [componentsPath + '/playback/mediasession'], returnFirstDependency);
|
define('mediaSession', [componentsPath + '/playback/mediasession'], returnFirstDependency);
|
||||||
define('actionsheet', [componentsPath + '/actionSheet/actionSheet'], returnFirstDependency);
|
define('actionsheet', [componentsPath + '/actionSheet/actionSheet'], returnFirstDependency);
|
||||||
define('tunerPicker', [componentsPath + '/tunerPicker'], returnFirstDependency);
|
define('tunerPicker', [componentsPath + '/tunerPicker'], returnFirstDependency);
|
||||||
|
@ -1137,7 +1133,7 @@ var AppInfo = {};
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return require(['browser'], onWebComponentsReady);
|
return onWebComponentsReady();
|
||||||
}();
|
}();
|
||||||
|
|
||||||
pageClassOn('viewshow', 'standalonePage', function () {
|
pageClassOn('viewshow', 'standalonePage', function () {
|
||||||
|
|
|
@ -1540,8 +1540,6 @@
|
||||||
"CopyStreamURLError": "Při kopírování URL došlo k chybě.",
|
"CopyStreamURLError": "Při kopírování URL došlo k chybě.",
|
||||||
"LabelVideoResolution": "Rozlišení videa:",
|
"LabelVideoResolution": "Rozlišení videa:",
|
||||||
"LabelStreamType": "Typ streamu:",
|
"LabelStreamType": "Typ streamu:",
|
||||||
"EnableFastImageFadeInHelp": "Zobrazí plakáty a další obrázky s rychlejší animací přechodu po dokončení načítání.",
|
|
||||||
"EnableFastImageFadeIn": "Rychlé animace přechodů obrazu",
|
|
||||||
"LabelPlayerDimensions": "Zobrazené rozlišení:",
|
"LabelPlayerDimensions": "Zobrazené rozlišení:",
|
||||||
"LabelDroppedFrames": "Vynechané snímky:",
|
"LabelDroppedFrames": "Vynechané snímky:",
|
||||||
"LabelCorruptedFrames": "Poškozené snímky:",
|
"LabelCorruptedFrames": "Poškozené snímky:",
|
||||||
|
@ -1603,7 +1601,7 @@
|
||||||
"HeaderDVR": "Nahrávání",
|
"HeaderDVR": "Nahrávání",
|
||||||
"SaveChanges": "Uložit změny",
|
"SaveChanges": "Uložit změny",
|
||||||
"LabelSyncPlayPlaybackDiff": "Rozdíl v době přehrávání:",
|
"LabelSyncPlayPlaybackDiff": "Rozdíl v době přehrávání:",
|
||||||
"SyncPlayAccessHelp": "Určuje úroveň přístupu k synchronizaci přehrávání, kterou tento uživatel bude mít. Tato funkce umožňuje synchronizovat přehrávání s dalšími uživateli.",
|
"SyncPlayAccessHelp": "Určuje úroveň přístupu k synchronizaci přehrávání, kterou tento uživatel bude mít. Tato funkce umožňuje synchronizovat přehrávání s dalšími zařízeními.",
|
||||||
"MessageSyncPlayErrorMedia": "Zapnutí synchronizace přehrávání se nezdařilo. Chyba média.",
|
"MessageSyncPlayErrorMedia": "Zapnutí synchronizace přehrávání se nezdařilo. Chyba média.",
|
||||||
"MessageSyncPlayErrorMissingSession": "Zapnutí synchronizace přehrávání se nezdařilo. Nebyla nalezena relace.",
|
"MessageSyncPlayErrorMissingSession": "Zapnutí synchronizace přehrávání se nezdařilo. Nebyla nalezena relace.",
|
||||||
"MessageSyncPlayErrorNoActivePlayer": "Nebyl nalezen žádný aktivní přehrávač. Synchronizace přehrávání byla vypnuta.",
|
"MessageSyncPlayErrorNoActivePlayer": "Nebyl nalezen žádný aktivní přehrávač. Synchronizace přehrávání byla vypnuta.",
|
||||||
|
@ -1633,5 +1631,7 @@
|
||||||
"HeaderSyncPlayEnabled": "Synchronizace přehrávání povolena",
|
"HeaderSyncPlayEnabled": "Synchronizace přehrávání povolena",
|
||||||
"HeaderSyncPlaySelectGroup": "Připojit ke skupině",
|
"HeaderSyncPlaySelectGroup": "Připojit ke skupině",
|
||||||
"EnableDetailsBannerHelp": "Zobrazí obrázek ve vrchní části detailu položky.",
|
"EnableDetailsBannerHelp": "Zobrazí obrázek ve vrchní části detailu položky.",
|
||||||
"EnableDetailsBanner": "Obrázek detailu"
|
"EnableDetailsBanner": "Obrázek detailu",
|
||||||
|
"ShowMore": "Zobrazit více",
|
||||||
|
"ShowLess": "Zobrazit méně"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1569,8 +1569,6 @@
|
||||||
"LabelStreamType": "Stream type:",
|
"LabelStreamType": "Stream type:",
|
||||||
"LabelSonyAggregationFlags": "Sony aggregering flag:",
|
"LabelSonyAggregationFlags": "Sony aggregering flag:",
|
||||||
"LabelSize": "Størrelse:",
|
"LabelSize": "Størrelse:",
|
||||||
"EnableFastImageFadeInHelp": "Aktivér hurtigere fade-in-animation til indlæste billeder",
|
|
||||||
"EnableFastImageFadeIn": "Hurtigt billede indtoning",
|
|
||||||
"LabelPleaseRestart": "Ændringer vil træde i kraft efter web klienten er blevet genindlæst manuelt.",
|
"LabelPleaseRestart": "Ændringer vil træde i kraft efter web klienten er blevet genindlæst manuelt.",
|
||||||
"LabelPlayMethod": "Afspilnings metode:",
|
"LabelPlayMethod": "Afspilnings metode:",
|
||||||
"LabelPlayerDimensions": "Afspillerdimensioner:",
|
"LabelPlayerDimensions": "Afspillerdimensioner:",
|
||||||
|
|
|
@ -1478,8 +1478,6 @@
|
||||||
"MessageConfirmAppExit": "Wirklich verlassen?",
|
"MessageConfirmAppExit": "Wirklich verlassen?",
|
||||||
"LabelVideoResolution": "Videoauflösung:",
|
"LabelVideoResolution": "Videoauflösung:",
|
||||||
"LabelStreamType": "Streamtyp:",
|
"LabelStreamType": "Streamtyp:",
|
||||||
"EnableFastImageFadeInHelp": "Aktiviere schnellere Einblendeanimation für geladene Bilder",
|
|
||||||
"EnableFastImageFadeIn": "Schnelle Bildeinblendung",
|
|
||||||
"LabelPlayerDimensions": "Playerabmessungen:",
|
"LabelPlayerDimensions": "Playerabmessungen:",
|
||||||
"LabelDroppedFrames": "Verlorene Frames:",
|
"LabelDroppedFrames": "Verlorene Frames:",
|
||||||
"LabelCorruptedFrames": "Fehlerhafte Frames:",
|
"LabelCorruptedFrames": "Fehlerhafte Frames:",
|
||||||
|
@ -1540,7 +1538,7 @@
|
||||||
"HeaderServerAddressSettings": "Server-Adresseinstellungen",
|
"HeaderServerAddressSettings": "Server-Adresseinstellungen",
|
||||||
"HeaderRemoteAccessSettings": "Fernzugriffs-Einstellungen",
|
"HeaderRemoteAccessSettings": "Fernzugriffs-Einstellungen",
|
||||||
"HeaderHttpsSettings": "HTTPS-Einstellungen",
|
"HeaderHttpsSettings": "HTTPS-Einstellungen",
|
||||||
"SyncPlayAccessHelp": "Wähle die Berechtigungsstufe, die dieser Benutzer auf das SyncPlay-Feature hat. SyncPlay ermöglicht die Synchronisierung der Wiedergabe mit anderen Benutzern.",
|
"SyncPlayAccessHelp": "Wähle die Berechtigungsstufe, die dieser Benutzer auf das SyncPlay-Feature hat. SyncPlay ermöglicht die Synchronisierung der Wiedergabe mit anderen Geräten.",
|
||||||
"MessageSyncPlayErrorMedia": "SyncPlay konnte nicht aktiviert werden! Medienfehler.",
|
"MessageSyncPlayErrorMedia": "SyncPlay konnte nicht aktiviert werden! Medienfehler.",
|
||||||
"MessageSyncPlayErrorMissingSession": "SyncPlay konnte nicht aktiviert werden! Fehlende Sitzung.",
|
"MessageSyncPlayErrorMissingSession": "SyncPlay konnte nicht aktiviert werden! Fehlende Sitzung.",
|
||||||
"MessageSyncPlayErrorNoActivePlayer": "Keine aktive Wiedergabe gefunden. SyncPlay wurde deaktiviert.",
|
"MessageSyncPlayErrorNoActivePlayer": "Keine aktive Wiedergabe gefunden. SyncPlay wurde deaktiviert.",
|
||||||
|
@ -1569,5 +1567,9 @@
|
||||||
"MillisecondsUnit": "ms",
|
"MillisecondsUnit": "ms",
|
||||||
"LabelSyncPlayTimeOffset": "Zeitversatz mit dem Server:",
|
"LabelSyncPlayTimeOffset": "Zeitversatz mit dem Server:",
|
||||||
"HeaderSyncPlayEnabled": "SyncPlay aktiviert",
|
"HeaderSyncPlayEnabled": "SyncPlay aktiviert",
|
||||||
"HeaderSyncPlaySelectGroup": "Tritt einer Gruppe bei"
|
"HeaderSyncPlaySelectGroup": "Tritt einer Gruppe bei",
|
||||||
|
"EnableDetailsBannerHelp": "Zeigt ein Bannerbild im oberen Bereich der Seite Item-Details.",
|
||||||
|
"EnableDetailsBanner": "Detailbanner",
|
||||||
|
"ShowMore": "Mehr anzeigen",
|
||||||
|
"ShowLess": "Weniger anzeigen"
|
||||||
}
|
}
|
||||||
|
|
|
@ -837,8 +837,8 @@
|
||||||
"LabelSecureConnectionsMode": "Secure connection mode:",
|
"LabelSecureConnectionsMode": "Secure connection mode:",
|
||||||
"LabelSeasonNumber": "Season number:",
|
"LabelSeasonNumber": "Season number:",
|
||||||
"LabelScreensaver": "Screensaver:",
|
"LabelScreensaver": "Screensaver:",
|
||||||
"EnableFastImageFadeIn": "Fast image fade-in",
|
"EnableFasterAnimations": "Faster animations",
|
||||||
"EnableFastImageFadeInHelp": "Enable faster fade-in animation for loaded images",
|
"EnableFasterAnimationsHelp": "Use faster animations and transitions",
|
||||||
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
|
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
|
||||||
"LabelSaveLocalMetadataHelp": "Saving artwork into media folders will put them in a place where they can be easily edited.",
|
"LabelSaveLocalMetadataHelp": "Saving artwork into media folders will put them in a place where they can be easily edited.",
|
||||||
"LabelRuntimeMinutes": "Run time (minutes):",
|
"LabelRuntimeMinutes": "Run time (minutes):",
|
||||||
|
|
|
@ -826,8 +826,8 @@
|
||||||
"LabelSaveLocalMetadataHelp": "Saving artwork into media folders will put them in a place where they can be easily edited.",
|
"LabelSaveLocalMetadataHelp": "Saving artwork into media folders will put them in a place where they can be easily edited.",
|
||||||
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
|
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
|
||||||
"LabelScreensaver": "Screensaver:",
|
"LabelScreensaver": "Screensaver:",
|
||||||
"EnableFastImageFadeIn": "Fast Image Fade Animations",
|
"EnableFasterAnimations": "Faster animations",
|
||||||
"EnableFastImageFadeInHelp": "Show posters and other images with a quicker fade animation when they finish loading.",
|
"EnableFasterAnimationsHelp": "Use faster animations and transitions",
|
||||||
"LabelSeasonNumber": "Season number:",
|
"LabelSeasonNumber": "Season number:",
|
||||||
"LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:",
|
"LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:",
|
||||||
"LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.",
|
"LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.",
|
||||||
|
@ -1373,6 +1373,8 @@
|
||||||
"Share": "Share",
|
"Share": "Share",
|
||||||
"ShowAdvancedSettings": "Show advanced settings",
|
"ShowAdvancedSettings": "Show advanced settings",
|
||||||
"ShowIndicatorsFor": "Show indicators for:",
|
"ShowIndicatorsFor": "Show indicators for:",
|
||||||
|
"ShowLess": "Show less",
|
||||||
|
"ShowMore": "Show more",
|
||||||
"ShowTitle": "Show title",
|
"ShowTitle": "Show title",
|
||||||
"ShowYear": "Show year",
|
"ShowYear": "Show year",
|
||||||
"Shows": "Shows",
|
"Shows": "Shows",
|
||||||
|
@ -1403,7 +1405,7 @@
|
||||||
"Suggestions": "Suggestions",
|
"Suggestions": "Suggestions",
|
||||||
"Sunday": "Sunday",
|
"Sunday": "Sunday",
|
||||||
"Sync": "Sync",
|
"Sync": "Sync",
|
||||||
"SyncPlayAccessHelp": "Select the level of access this user has to the SyncPlay feature. SyncPlay enables to sync playback with other users.",
|
"SyncPlayAccessHelp": "Select the level of access this user has to the SyncPlay feature. SyncPlay enables to sync playback with other devices.",
|
||||||
"SystemDlnaProfilesHelp": "System profiles are read-only. Changes to a system profile will be saved to a new custom profile.",
|
"SystemDlnaProfilesHelp": "System profiles are read-only. Changes to a system profile will be saved to a new custom profile.",
|
||||||
"TV": "TV",
|
"TV": "TV",
|
||||||
"TabAccess": "Access",
|
"TabAccess": "Access",
|
||||||
|
@ -1546,5 +1548,7 @@
|
||||||
"EveryHour": "Every hour",
|
"EveryHour": "Every hour",
|
||||||
"EveryXHours": "Every {0} hours",
|
"EveryXHours": "Every {0} hours",
|
||||||
"OnApplicationStartup": "On application startup",
|
"OnApplicationStartup": "On application startup",
|
||||||
"UnsupportedPlayback": "Jellyfin cannot decrypt content protected by DRM but all content will be attempted regardless, including protected titles. Some files may appear completely black due to encryption or other unsupported features, such as interactive titles."
|
"UnsupportedPlayback": "Jellyfin cannot decrypt content protected by DRM but all content will be attempted regardless, including protected titles. Some files may appear completely black due to encryption or other unsupported features, such as interactive titles.",
|
||||||
|
"EnableBlurhash": "Enable blurred placeholders for images",
|
||||||
|
"EnableBlurhashHelp": "Images that are still being loaded will be displayed with a blurred placeholder"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"AddToCollection": "Aldoni al kolekto",
|
"AddToCollection": "Aldoni al kolekto",
|
||||||
"Actor": "Aktoro",
|
"Actor": "Aktoro",
|
||||||
"Absolute": "Absoluto"
|
"Absolute": "Absoluta"
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
"AnamorphicVideoNotSupported": "Video anamorfico no soportado",
|
"AnamorphicVideoNotSupported": "Video anamorfico no soportado",
|
||||||
"AnyLanguage": "Cualquier idioma",
|
"AnyLanguage": "Cualquier idioma",
|
||||||
"Anytime": "En cualquier momento",
|
"Anytime": "En cualquier momento",
|
||||||
"AroundTime": "Alrededor de {0}",
|
"AroundTime": "Alrededor de",
|
||||||
"Art": "Arte",
|
"Art": "Arte",
|
||||||
"Artists": "Artistas",
|
"Artists": "Artistas",
|
||||||
"AsManyAsPossible": "Tantos como sea posible",
|
"AsManyAsPossible": "Tantos como sea posible",
|
||||||
|
@ -103,7 +103,7 @@
|
||||||
"ButtonRemove": "Remover",
|
"ButtonRemove": "Remover",
|
||||||
"ButtonRename": "Renombrar",
|
"ButtonRename": "Renombrar",
|
||||||
"ButtonRepeat": "Repetir",
|
"ButtonRepeat": "Repetir",
|
||||||
"ButtonResetEasyPassword": "Reiniciar el código pin sencillo",
|
"ButtonResetEasyPassword": "Restablecer código PIN sencillo",
|
||||||
"ButtonResetPassword": "Restablecer contraseña",
|
"ButtonResetPassword": "Restablecer contraseña",
|
||||||
"ButtonRestart": "Reiniciar",
|
"ButtonRestart": "Reiniciar",
|
||||||
"ButtonResume": "Continuar",
|
"ButtonResume": "Continuar",
|
||||||
|
@ -203,7 +203,7 @@
|
||||||
"EnableBackdrops": "Imágenes de fondo",
|
"EnableBackdrops": "Imágenes de fondo",
|
||||||
"EnableBackdropsHelp": "Muestra imágenes de fondo en el fondo de algunas páginas mientras se navega por la biblioteca.",
|
"EnableBackdropsHelp": "Muestra imágenes de fondo en el fondo de algunas páginas mientras se navega por la biblioteca.",
|
||||||
"EnableCinemaMode": "Modo cine",
|
"EnableCinemaMode": "Modo cine",
|
||||||
"EnableColorCodedBackgrounds": "Fondos de color codificados",
|
"EnableColorCodedBackgrounds": "Fondos de colores codificados",
|
||||||
"EnableDisplayMirroring": "Duplicado de pantalla",
|
"EnableDisplayMirroring": "Duplicado de pantalla",
|
||||||
"EnableExternalVideoPlayers": "Reproductores de video externos",
|
"EnableExternalVideoPlayers": "Reproductores de video externos",
|
||||||
"EnableExternalVideoPlayersHelp": "Un menú de reproductor externo se mostrara cuando inicie la reproducción de un video.",
|
"EnableExternalVideoPlayersHelp": "Un menú de reproductor externo se mostrara cuando inicie la reproducción de un video.",
|
||||||
|
@ -410,8 +410,8 @@
|
||||||
"HeaderRecordingOptions": "Opciones de grabación",
|
"HeaderRecordingOptions": "Opciones de grabación",
|
||||||
"HeaderRecordingPostProcessing": "Post procesado de las grabaciones",
|
"HeaderRecordingPostProcessing": "Post procesado de las grabaciones",
|
||||||
"HeaderRemoteControl": "Control remoto",
|
"HeaderRemoteControl": "Control remoto",
|
||||||
"HeaderRemoveMediaFolder": "Eliminar carpeta de medios",
|
"HeaderRemoveMediaFolder": "Remover carpeta de medios",
|
||||||
"HeaderRemoveMediaLocation": "Eliminar ubicación de medios",
|
"HeaderRemoveMediaLocation": "Remover ubicación de medios",
|
||||||
"HeaderResponseProfile": "Perfil de respuesta",
|
"HeaderResponseProfile": "Perfil de respuesta",
|
||||||
"HeaderResponseProfileHelp": "Los perfiles de respuesta proporcionan un medio para personalizar la información enviada al dispositivo cuando se reproducen ciertos tipos de medios.",
|
"HeaderResponseProfileHelp": "Los perfiles de respuesta proporcionan un medio para personalizar la información enviada al dispositivo cuando se reproducen ciertos tipos de medios.",
|
||||||
"HeaderRestart": "Reiniciar",
|
"HeaderRestart": "Reiniciar",
|
||||||
|
@ -697,7 +697,7 @@
|
||||||
"LabelNumberOfGuideDays": "Número de días de datos de la programación a descargar:",
|
"LabelNumberOfGuideDays": "Número de días de datos de la programación a descargar:",
|
||||||
"LabelNumberOfGuideDaysHelp": "Descargar más días de datos de programación permite programar con mayor anticipación y ver más listados, pero tomará más tiempo en descargar. Auto hará la selección basada en el número de canales.",
|
"LabelNumberOfGuideDaysHelp": "Descargar más días de datos de programación permite programar con mayor anticipación y ver más listados, pero tomará más tiempo en descargar. Auto hará la selección basada en el número de canales.",
|
||||||
"LabelOptionalNetworkPath": "(Opcional) Carpeta de red compartida:",
|
"LabelOptionalNetworkPath": "(Opcional) Carpeta de red compartida:",
|
||||||
"LabelOptionalNetworkPathHelp": "Si esta carpeta es compartida en su red, proveer la ruta del recurso compartido de red puede permitir a las aplicaciones Jellyfin en otros dispositivos acceder a los archivos de medios directamente.",
|
"LabelOptionalNetworkPathHelp": "Si esta carpeta es compartida en su red, proveer la ruta del recurso compartido de red puede permitir a las aplicaciones Jellyfin en otros dispositivos acceder a los archivos de medios directamente. Por ejemplo, {0} o {1}.",
|
||||||
"LabelOriginalAspectRatio": "Relación de aspecto original:",
|
"LabelOriginalAspectRatio": "Relación de aspecto original:",
|
||||||
"LabelOriginalTitle": "Título original:",
|
"LabelOriginalTitle": "Título original:",
|
||||||
"LabelOverview": "Resumen:",
|
"LabelOverview": "Resumen:",
|
||||||
|
@ -878,7 +878,7 @@
|
||||||
"MessageConfirmDeleteTunerDevice": "¿Estás seguro de querer eliminar este dispositivo?",
|
"MessageConfirmDeleteTunerDevice": "¿Estás seguro de querer eliminar este dispositivo?",
|
||||||
"MessageConfirmProfileDeletion": "¿Estás seguro de querer eliminar este perfil?",
|
"MessageConfirmProfileDeletion": "¿Estás seguro de querer eliminar este perfil?",
|
||||||
"MessageConfirmRecordingCancellation": "¿Cancelar grabación?",
|
"MessageConfirmRecordingCancellation": "¿Cancelar grabación?",
|
||||||
"MessageConfirmRemoveMediaLocation": "¿Estás seguro de querer eliminar esta ubicación?",
|
"MessageConfirmRemoveMediaLocation": "¿Estás seguro de querer remover esta ubicación?",
|
||||||
"MessageConfirmRestart": "¿Estás seguro de que deseas reiniciar el servidor Jellyfin?",
|
"MessageConfirmRestart": "¿Estás seguro de que deseas reiniciar el servidor Jellyfin?",
|
||||||
"MessageConfirmRevokeApiKey": "¿Estás seguro de querer revocar esta clave API? La conexión de la aplicación con el servidor Jellyfin será terminada abruptamente.",
|
"MessageConfirmRevokeApiKey": "¿Estás seguro de querer revocar esta clave API? La conexión de la aplicación con el servidor Jellyfin será terminada abruptamente.",
|
||||||
"MessageConfirmShutdown": "¿Estás seguro de que deseas apagar el servidor?",
|
"MessageConfirmShutdown": "¿Estás seguro de que deseas apagar el servidor?",
|
||||||
|
@ -912,7 +912,7 @@
|
||||||
"MessagePluginInstallDisclaimer": "Los complementos desarrollados por miembros de la comunidad Jellyfin son una gran forma de mejorar tu experiencia con Jellyfin con características y beneficios adicionales. Antes de instalar, por favor, conoce el impacto que pueden ocasionar en tu servidor Jellyfin, tales como escaneo más largo de bibliotecas, procesamiento en segundo plano adicional y reducción de la estabilidad del sistema.",
|
"MessagePluginInstallDisclaimer": "Los complementos desarrollados por miembros de la comunidad Jellyfin son una gran forma de mejorar tu experiencia con Jellyfin con características y beneficios adicionales. Antes de instalar, por favor, conoce el impacto que pueden ocasionar en tu servidor Jellyfin, tales como escaneo más largo de bibliotecas, procesamiento en segundo plano adicional y reducción de la estabilidad del sistema.",
|
||||||
"MessageReenableUser": "Ver abajo para volver a habilitar",
|
"MessageReenableUser": "Ver abajo para volver a habilitar",
|
||||||
"MessageSettingsSaved": "Configuraciones guardadas.",
|
"MessageSettingsSaved": "Configuraciones guardadas.",
|
||||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "Las siguientes ubicaciones de medios se eliminarán de tu biblioteca:",
|
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "Las siguientes ubicaciones de medios se removerán de tu biblioteca:",
|
||||||
"MessageUnableToConnectToServer": "No podemos conectarnos al servidor seleccionado en este momento. Por favor, asegúrate de que está funcionando e inténtalo de nuevo.",
|
"MessageUnableToConnectToServer": "No podemos conectarnos al servidor seleccionado en este momento. Por favor, asegúrate de que está funcionando e inténtalo de nuevo.",
|
||||||
"MessageUnsetContentHelp": "El contenido será mostrado como carpetas simples. Para mejores resultados utiliza el administrador de metadatos para establecer los tipos de contenido para las subcarpetas.",
|
"MessageUnsetContentHelp": "El contenido será mostrado como carpetas simples. Para mejores resultados utiliza el administrador de metadatos para establecer los tipos de contenido para las subcarpetas.",
|
||||||
"MessageYouHaveVersionInstalled": "Actualmente cuentas con la versión {0} instalada.",
|
"MessageYouHaveVersionInstalled": "Actualmente cuentas con la versión {0} instalada.",
|
||||||
|
@ -1453,7 +1453,6 @@
|
||||||
"LabelTranscodingFramerate": "Velocidad de cuadros de la transcodificación:",
|
"LabelTranscodingFramerate": "Velocidad de cuadros de la transcodificación:",
|
||||||
"LabelSize": "Tamaño:",
|
"LabelSize": "Tamaño:",
|
||||||
"SelectAdminUsername": "Por favor, selecciona un nombre de usuario para la cuenta de administrador.",
|
"SelectAdminUsername": "Por favor, selecciona un nombre de usuario para la cuenta de administrador.",
|
||||||
"EnableFastImageFadeInHelp": "Habilita una animación más rápida de desvanecimiento para las imágenes cargadas",
|
|
||||||
"LabelDroppedFrames": "Cuadros saltados:",
|
"LabelDroppedFrames": "Cuadros saltados:",
|
||||||
"CopyStreamURLError": "Hubo un error al copiar la URL.",
|
"CopyStreamURLError": "Hubo un error al copiar la URL.",
|
||||||
"ButtonSplit": "Dividir",
|
"ButtonSplit": "Dividir",
|
||||||
|
@ -1484,7 +1483,6 @@
|
||||||
"MessageConfirmAppExit": "¿Deseas salir?",
|
"MessageConfirmAppExit": "¿Deseas salir?",
|
||||||
"LabelVideoResolution": "Resolución de video:",
|
"LabelVideoResolution": "Resolución de video:",
|
||||||
"LabelStreamType": "Tipo de transmisión:",
|
"LabelStreamType": "Tipo de transmisión:",
|
||||||
"EnableFastImageFadeIn": "Desvanecimiento rápido de las imágenes",
|
|
||||||
"LabelPlayerDimensions": "Dimensiones del reproductor:",
|
"LabelPlayerDimensions": "Dimensiones del reproductor:",
|
||||||
"LabelCorruptedFrames": "Cuadros corruptos:",
|
"LabelCorruptedFrames": "Cuadros corruptos:",
|
||||||
"HeaderNavigation": "Navegación",
|
"HeaderNavigation": "Navegación",
|
||||||
|
@ -1524,5 +1522,37 @@
|
||||||
"HeaderRemoteAccessSettings": "Opciones de acceso remoto",
|
"HeaderRemoteAccessSettings": "Opciones de acceso remoto",
|
||||||
"HeaderHttpsSettings": "Opciones HTTPS",
|
"HeaderHttpsSettings": "Opciones HTTPS",
|
||||||
"HeaderDVR": "DVR",
|
"HeaderDVR": "DVR",
|
||||||
"ApiKeysCaption": "Lista de claves API actualmente habilitadas"
|
"ApiKeysCaption": "Lista de claves API actualmente habilitadas",
|
||||||
|
"SyncPlayAccessHelp": "Selecciona el nivel de acceso que este usuario tiene a la función SyncPlay. SyncPlay permite sincronizar la reproducción con otros dispositivos.",
|
||||||
|
"MessageSyncPlayErrorMedia": "¡Fallo al activar SyncPlay! Error en el archivo de medios.",
|
||||||
|
"MessageSyncPlayErrorMissingSession": "¡Fallo al activar SyncPlay! Falta la sesión.",
|
||||||
|
"MessageSyncPlayErrorNoActivePlayer": "No se ha encontrado ningún reproductor activo. SyncPlay ha sido desactivado.",
|
||||||
|
"MessageSyncPlayErrorAccessingGroups": "Se produjo un error al acceder a la lista de grupos.",
|
||||||
|
"MessageSyncPlayLibraryAccessDenied": "El acceso a este contenido está restringido.",
|
||||||
|
"MessageSyncPlayJoinGroupDenied": "Permiso requerido para usar SyncPlay.",
|
||||||
|
"MessageSyncPlayCreateGroupDenied": "Permiso requerido para crear un grupo.",
|
||||||
|
"MessageSyncPlayGroupDoesNotExist": "Fallo al unirse al grupo porque éste no existe.",
|
||||||
|
"MessageSyncPlayPlaybackPermissionRequired": "Permiso de reproducción requerido.",
|
||||||
|
"MessageSyncPlayNoGroupsAvailable": "No hay grupos disponibles. Empieza a reproducir algo primero.",
|
||||||
|
"MessageSyncPlayGroupWait": "<b>{0}</b> está cargando...",
|
||||||
|
"MessageSyncPlayUserLeft": "<b>{0}</b> abandonó el grupo.",
|
||||||
|
"MessageSyncPlayUserJoined": "<b>{0}</b> se ha unido al grupo.",
|
||||||
|
"MessageSyncPlayDisabled": "SyncPlay deshabilitado.",
|
||||||
|
"MessageSyncPlayEnabled": "SyncPlay habilitado.",
|
||||||
|
"LabelSyncPlayAccess": "Acceso a SyncPlay",
|
||||||
|
"LabelSyncPlayAccessNone": "Deshabilitado para este usuario",
|
||||||
|
"LabelSyncPlayAccessJoinGroups": "Permitir al usuario unirse a grupos",
|
||||||
|
"LabelSyncPlayAccessCreateAndJoinGroups": "Permitir al usuario crear y unirse a grupos",
|
||||||
|
"LabelSyncPlayLeaveGroupDescription": "Deshabilitar SyncPlay",
|
||||||
|
"LabelSyncPlayLeaveGroup": "Abandonar grupo",
|
||||||
|
"LabelSyncPlayNewGroupDescription": "Crear un nuevo grupo",
|
||||||
|
"LabelSyncPlayNewGroup": "Nuevo grupo",
|
||||||
|
"LabelSyncPlaySyncMethod": "Método de sincronización:",
|
||||||
|
"LabelSyncPlayPlaybackDiff": "Diferencia de tiempo de reproducción:",
|
||||||
|
"MillisecondsUnit": "ms",
|
||||||
|
"LabelSyncPlayTimeOffset": "Tiempo compensado respecto al servidor:",
|
||||||
|
"HeaderSyncPlayEnabled": "SyncPlay habilitado",
|
||||||
|
"HeaderSyncPlaySelectGroup": "Unirse a un grupo",
|
||||||
|
"EnableDetailsBannerHelp": "Mostrar una imagen banner en la parte superior de la página de detalles del elemento.",
|
||||||
|
"EnableDetailsBanner": "Banner de detalles"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"AccessRestrictedTryAgainLater": "El acceso está restringido actualmente. Por favor, inténtalo más tarde.",
|
"AccessRestrictedTryAgainLater": "Actualmente el acceso está restringido. Por favor, inténtalo de nuevo más tarde.",
|
||||||
"Add": "Añadir",
|
"Add": "Añadir",
|
||||||
"AddItemToCollectionHelp": "Agregue elementos a las colecciones buscándolos y haciendo clic con el botón derecho o tocando los menús para agregarlos a una colección.",
|
"AddItemToCollectionHelp": "Agregue elementos a las colecciones buscándolos y haciendo clic con el botón derecho o tocando los menús para agregarlos a una colección.",
|
||||||
"AddToCollection": "Añadir a la colección",
|
"AddToCollection": "Añadir a la colección",
|
||||||
|
@ -1458,8 +1458,8 @@
|
||||||
"ButtonSplit": "Dividir",
|
"ButtonSplit": "Dividir",
|
||||||
"HeaderNavigation": "Navegación",
|
"HeaderNavigation": "Navegación",
|
||||||
"MessageConfirmAppExit": "¿Quieres salir?",
|
"MessageConfirmAppExit": "¿Quieres salir?",
|
||||||
"EnableFastImageFadeInHelp": "Mostrar carteles y otras imágenes con difuminado rápido cuando termine la carga.",
|
"EnableFasterAnimationsHelp": "Las animaciones y transiciones durarán menos tiempo",
|
||||||
"EnableFastImageFadeIn": "Difuminado rápido de imágenes",
|
"EnableFasterAnimations": "Animaciones más rápidas",
|
||||||
"CopyStreamURLError": "Ha habido un error copiando la dirección.",
|
"CopyStreamURLError": "Ha habido un error copiando la dirección.",
|
||||||
"AllowFfmpegThrottlingHelp": "Cuando una transcodificación o un remux se adelanta lo suficiente desde la posición de reproducción actual, pause el proceso para que consuma menos recursos. Esto es más útil cuando se reproduce de forma linear, sin saltar de posición de reproducción a menudo. Desactívelo si experimenta problemas de reproducción.",
|
"AllowFfmpegThrottlingHelp": "Cuando una transcodificación o un remux se adelanta lo suficiente desde la posición de reproducción actual, pause el proceso para que consuma menos recursos. Esto es más útil cuando se reproduce de forma linear, sin saltar de posición de reproducción a menudo. Desactívelo si experimenta problemas de reproducción.",
|
||||||
"PlaybackErrorNoCompatibleStream": "Este contenido no es compatible con este dispositivo y no se puede reproducir: No se puede obtener del servidor en un formato compatible.",
|
"PlaybackErrorNoCompatibleStream": "Este contenido no es compatible con este dispositivo y no se puede reproducir: No se puede obtener del servidor en un formato compatible.",
|
||||||
|
@ -1524,8 +1524,10 @@
|
||||||
"LabelEnableHttps": "Activar HTTPS",
|
"LabelEnableHttps": "Activar HTTPS",
|
||||||
"TabDVR": "DVR",
|
"TabDVR": "DVR",
|
||||||
"SaveChanges": "Guardar cambios",
|
"SaveChanges": "Guardar cambios",
|
||||||
|
"EnableBlurhash": "Mostrar una representación de las imágenes mientras cargan",
|
||||||
|
"EnableBlurhashHelp": "Aparecerá una representación de los colores de las imágenes antes de que terminen de cargar",
|
||||||
"HeaderDVR": "DVR",
|
"HeaderDVR": "DVR",
|
||||||
"SyncPlayAccessHelp": "Selecciona el nivel de acceso que posee este usuario al SyncPlay. SyncPlay permite sincronizar reproductores con otros usuarios.",
|
"SyncPlayAccessHelp": "Selecciona los permisos de este usuario para utilizar SyncPlay. SyncPlay te permite sincronizar la reproducción entre varios dispositivos.",
|
||||||
"MessageSyncPlayErrorMedia": "¡No se pudo activar SyncPlay! Error de medio.",
|
"MessageSyncPlayErrorMedia": "¡No se pudo activar SyncPlay! Error de medio.",
|
||||||
"MessageSyncPlayErrorMissingSession": "¡No se pudo activar SyncPlay! Sesión desconectada.",
|
"MessageSyncPlayErrorMissingSession": "¡No se pudo activar SyncPlay! Sesión desconectada.",
|
||||||
"MessageSyncPlayErrorNoActivePlayer": "No hay reproductor activo. SyncPlay ha sido desactivado.",
|
"MessageSyncPlayErrorNoActivePlayer": "No hay reproductor activo. SyncPlay ha sido desactivado.",
|
||||||
|
@ -1556,5 +1558,7 @@
|
||||||
"HeaderSyncPlayEnabled": "Syncplay activo",
|
"HeaderSyncPlayEnabled": "Syncplay activo",
|
||||||
"HeaderSyncPlaySelectGroup": "Unirse a un grupo",
|
"HeaderSyncPlaySelectGroup": "Unirse a un grupo",
|
||||||
"EnableDetailsBannerHelp": "Mostrar imagen de banner en el tope de la página de detalles del elemento.",
|
"EnableDetailsBannerHelp": "Mostrar imagen de banner en el tope de la página de detalles del elemento.",
|
||||||
"EnableDetailsBanner": "Barra de Detalles"
|
"EnableDetailsBanner": "Barra de Detalles",
|
||||||
|
"ShowMore": "Mostrar más",
|
||||||
|
"ShowLess": "Mostrar menos"
|
||||||
}
|
}
|
||||||
|
|
1550
src/strings/es_419.json
Normal file
1550
src/strings/es_419.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -612,7 +612,7 @@
|
||||||
"ConfirmDeleteItem": "حذف این مورد، آن را هم از فایل سیستمی و هم از کتابخانه رسانه شما حذف می کند. آیا اطمینان دارید که میخواهید ادامه دهید؟",
|
"ConfirmDeleteItem": "حذف این مورد، آن را هم از فایل سیستمی و هم از کتابخانه رسانه شما حذف می کند. آیا اطمینان دارید که میخواهید ادامه دهید؟",
|
||||||
"AlwaysPlaySubtitlesHelp": "زیرنویسهای متناسب با توجه به اولویت زبان بدون در نظر گرفتن زبان صوتی ویدیو پخش می شوند.",
|
"AlwaysPlaySubtitlesHelp": "زیرنویسهای متناسب با توجه به اولویت زبان بدون در نظر گرفتن زبان صوتی ویدیو پخش می شوند.",
|
||||||
"AllowedRemoteAddressesHelp": "لیستی از آدرس های IP یا ورودیهای IP/netmask برای شبکه هایی که به آنها امکان ارتباط از راه دور داده میشود ، با کاما از هم جدا شدند. در صورت خالی ماندن ، تمام آدرسهای راه دور مجاز خواهند بود.",
|
"AllowedRemoteAddressesHelp": "لیستی از آدرس های IP یا ورودیهای IP/netmask برای شبکه هایی که به آنها امکان ارتباط از راه دور داده میشود ، با کاما از هم جدا شدند. در صورت خالی ماندن ، تمام آدرسهای راه دور مجاز خواهند بود.",
|
||||||
"AllowOnTheFlySubtitleExtractionHelp": "زیرنویس های جاسازی شده را میتوان از فیلمها استخراج کرد و به منظور جلوگیری از کدگذاری فیلم ، به صورت متن ساده به بازدید کننده ارسال کرد. در بعضی از سیستمها این میتواند مدت زیادی طول بکشد و باعث شود پخش فیلم در طول فرآیند استخراج متوقف شود. این گزینه را غیرفعال کنید تا زیرنویسهای جاسازی شده با استفاده از رمزگذاری ویدیو در حالی که به طور محلی توسط دستگاه بازدیدکننده پشتیبانی نمیشوند ارسال شود.",
|
"AllowOnTheFlySubtitleExtractionHelp": "زیرنویس های جاسازی شده را میتوان از ویدئو ها استخراج کرد و به منظور جلوگیری از کدگذاری فیلم ، به صورت متن ساده به بازدید کننده ارسال کرد. در بعضی از سیستمها این میتواند مدت زیادی طول بکشد و باعث شود پخش فیلم در طول فرآیند استخراج متوقف شود. این گزینه را غیرفعال کنید تا زیرنویسهای جاسازی شده با استفاده از رمزگذاری ویدیو در حالی که به طور محلی توسط دستگاه بازدیدکننده پشتیبانی نمیشوند ارسال شود.",
|
||||||
"AdditionalNotificationServices": "برای نصب سرویسهای اعلان اضافی، در فروشگاه افزونهها جستجو کنید.",
|
"AdditionalNotificationServices": "برای نصب سرویسهای اعلان اضافی، در فروشگاه افزونهها جستجو کنید.",
|
||||||
"OptionThumbCard": "کارت بندانگشتی",
|
"OptionThumbCard": "کارت بندانگشتی",
|
||||||
"OptionThumb": "بندانگشتی",
|
"OptionThumb": "بندانگشتی",
|
||||||
|
@ -702,5 +702,102 @@
|
||||||
"MessageUnauthorizedUser": "در حال حاضر مجاز به دسترسی به سرور نیستید. لطفا برای اطلاعات بیشتر با مدیر سرور خود تماس بگیرید.",
|
"MessageUnauthorizedUser": "در حال حاضر مجاز به دسترسی به سرور نیستید. لطفا برای اطلاعات بیشتر با مدیر سرور خود تماس بگیرید.",
|
||||||
"MessageInvalidUser": "نام کاربری یا گذرواژه نامعتبر است. لطفا دوباره تلاش کنید.",
|
"MessageInvalidUser": "نام کاربری یا گذرواژه نامعتبر است. لطفا دوباره تلاش کنید.",
|
||||||
"MessageInvalidForgotPasswordPin": "کد پین نامعتبر یا منقضی شده وارد شد. لطفا دوباره تلاش کنید.",
|
"MessageInvalidForgotPasswordPin": "کد پین نامعتبر یا منقضی شده وارد شد. لطفا دوباره تلاش کنید.",
|
||||||
"MessageInstallPluginFromApp": "این افزونه باید از داخل برنامهای که قصد استفاده از آن را دارید نصب شود."
|
"MessageInstallPluginFromApp": "این افزونه باید از داخل برنامهای که قصد استفاده از آن را دارید نصب شود.",
|
||||||
|
"PasswordResetHeader": "بازنشانی گذرواژه",
|
||||||
|
"PasswordResetConfirmation": "آیا واقعا تمایل به بازنشانی گذرواژه دارید؟",
|
||||||
|
"PasswordResetComplete": "گذرواژه بازنشانی شد.",
|
||||||
|
"PasswordMatchError": "گذرواژه و تکرار گذرواژه باید یکسان باشند.",
|
||||||
|
"PackageInstallFailed": "{0} (نسخه {1}) نصب به مشکل برخورد.",
|
||||||
|
"PackageInstallCompleted": "{0} (نسخه {1})نصب به پایان رسید.",
|
||||||
|
"PackageInstallCancelled": "{0} ( نسخه {1})نصب لغو شد.",
|
||||||
|
"Overview": "بررسی اجمالی",
|
||||||
|
"OtherArtist": "هنرمند دیگر",
|
||||||
|
"OriginalAirDateValue": "زمان پخش اصلی : {0}",
|
||||||
|
"OptionWeekly": "هفتگی",
|
||||||
|
"OptionWeekends": "آخر هفته ها",
|
||||||
|
"OptionWeekdays": "روز های هفته",
|
||||||
|
"OptionWednesday": "چهارشنبه",
|
||||||
|
"OptionWakeFromSleep": "از خواب بیدار شدن",
|
||||||
|
"OptionUnairedEpisode": "قسمت های پخش نشده",
|
||||||
|
"OptionTvdbRating": "نمره TVDB",
|
||||||
|
"OptionTuesday": "سه شنبه",
|
||||||
|
"OptionTrackName": "نام ترک",
|
||||||
|
"OptionRequirePerfectSubtitleMatchHelp": "نتیجه کامل زیرنویس ها را به صورتی فیلتر می کند که فقط مواردی را که دقیقا با فایل تصویری شما آزمایش و تأیید شده اند ،شامل شود. حذف این گزینه احتمال بارگیری زیرنویس ها را افزایش می دهد ، اما شانس متن زیرنویس ناهماهنگ یا غلط نیز افزایش می یابد.",
|
||||||
|
"ServerNameIsShuttingDown": "سرور جلی فین - {0} در حال خاموش شدن می باشد.",
|
||||||
|
"ServerNameIsRestarting": "سرور جلی فین - {0} در حال راه اندازی مجدد می باشد.",
|
||||||
|
"SeriesYearToPresent": "{0}- در حال حاضر",
|
||||||
|
"SeriesSettings": "تنظیمات سریال",
|
||||||
|
"SeriesRecordingScheduled": "ضبط کردن سریال زمانبندی شد.",
|
||||||
|
"SeriesDisplayOrderHelp": "قسمت ها را بر اساس تاریخ پخش شدن، ترتیب دی وی دی یا فقط شماره مرتب کنید.",
|
||||||
|
"SeriesCancelled": "سریال متوقف شده است.",
|
||||||
|
"Series": "سریال ها",
|
||||||
|
"SelectAdminUsername": "لطفا یک نام کاربری برای حساب مدیر انتخاب کنید.",
|
||||||
|
"Season": "فصل",
|
||||||
|
"SearchResults": "نتایج جستجو",
|
||||||
|
"SearchForSubtitles": "زیرنویس ها را جستجو کنید",
|
||||||
|
"SearchForMissingMetadata": "فراداده های گم شده را جستجو کنید",
|
||||||
|
"SearchForCollectionInternetMetadata": "در اینترنت برای پیدا کردن فراداده و عکس جستجو کنید",
|
||||||
|
"Search": "جستجو کردن",
|
||||||
|
"Screenshots": "نماگرفت ها",
|
||||||
|
"Screenshot": "نماگرفت",
|
||||||
|
"Schedule": "برنامه زمانی",
|
||||||
|
"ScanLibrary": "کتابخانه را اسکن کنید",
|
||||||
|
"ScanForNewAndUpdatedFiles": "فایل های جدید و به روز رسانی شده را اسکن کنید",
|
||||||
|
"ChannelAccessHelp": "کانال هایی که قصد اشتراک گذاری با این کاربر را دارید انتخاب کنید. مدیران توانایی ویرایش همه ی کانال ها را با استفاده از مدیریت فراداده دارند.",
|
||||||
|
"ChangingMetadataImageSettingsNewContent": "تغییر تنظیمات دانلود فراداده ها و عکس ها فقط بر روی محتواهای جدیدی که به کتابخانه اضافه می شوند، اعمال می شوند. برای اعمال تغییرات بر روی محتوای موجود، شما باید فراداده را به صورت دستی به روزرسانی کنید.",
|
||||||
|
"Refresh": "بهروزرسانی",
|
||||||
|
"Recordings": "ضبط شده ها",
|
||||||
|
"RecordingScheduled": "ضبط برنامه ریزی شد.",
|
||||||
|
"RecordingPathChangeMessage": "با تغییر محل ذخیره فایل های ضبط شده، فایل های موجود به صورت خودکار منتقل نمی شوند. در صورت نیاز، شما باید خودتان این کار را انجام دهید.",
|
||||||
|
"RecordingCancelled": "ضبط شدن لغو شد.",
|
||||||
|
"RecordSeries": "ضبط کردن سریال ها",
|
||||||
|
"Record": "ضبط کردن",
|
||||||
|
"RecommendationStarring": "با هنرمندی {0}",
|
||||||
|
"RecommendationDirectedBy": "کارگردانی شده توسط {0}",
|
||||||
|
"RecommendationBecauseYouWatched": "برای اینکه تو {0} مشاهده کردی",
|
||||||
|
"RecommendationBecauseYouLike": "برای اینکه تو {0} را نیز دوست داری",
|
||||||
|
"RecentlyWatched": "اخیرا مشاهده شده",
|
||||||
|
"Rate": "ارزیابی کن",
|
||||||
|
"Raised": "مطرح شده",
|
||||||
|
"QueueAllFromHere": "همه را از اینجا در صف قرار بده",
|
||||||
|
"Quality": "کیفیت",
|
||||||
|
"Programs": "برنامه ها",
|
||||||
|
"ProductionLocations": "محل تولید",
|
||||||
|
"Producer": "تولید کننده",
|
||||||
|
"Primary": "اصلی",
|
||||||
|
"Previous": "قبلی",
|
||||||
|
"Premieres": "برتر ها",
|
||||||
|
"Premiere": "برتر",
|
||||||
|
"PreferEmbeddedEpisodeInfosOverFileNames": "اطلاعات تعبیه شده در فراداده را به اسم فایل ترجیح بده",
|
||||||
|
"PreferEmbeddedEpisodeInfosOverFileNamesHelp": "این از اطلاعات قسمت در فراداده های تعبیه شده در صورت موجود استفاده می کند.",
|
||||||
|
"PreferEmbeddedTitlesOverFileNamesHelp": "این عنوان نمایش را به صورت پیش فرض تعیین می کند، زمانی که فراداده اینترنتی یا محلی موجود نباشند.",
|
||||||
|
"PreferEmbeddedTitlesOverFileNames": "عنوان های تعبیه شده را به نام فایل ترجیح بده",
|
||||||
|
"PluginInstalledMessage": "افزونه با موفقیت نصب شد. برای اعمال تغییرات سرور جلیفین نیاز به بارگذاری مجدد دارد.",
|
||||||
|
"PleaseSelectTwoItems": "لطفا حداقل دو مورد را انتخاب کنید.",
|
||||||
|
"PleaseRestartServerName": "لطفا سرور جلیفین را دوباره بارگذاری کنید - {0}.",
|
||||||
|
"PleaseEnterNameOrId": "لطفا یک نام یا شناسه خارجی را وارد کنید.",
|
||||||
|
"PleaseConfirmPluginInstallation": "لطفا با کلیک بر روی OK تایید کنید که شما متن بالا را خوانده اید و می خواهید که افزونه را نصب کنید.",
|
||||||
|
"PleaseAddAtLeastOneFolder": "لطفا حداقل یک پوشه به این کتابخانه با کلیک بر روی \"افزودن\" اضافه کنید.",
|
||||||
|
"Played": "اجرا شده",
|
||||||
|
"PlaybackErrorNoCompatibleStream": "سرویس گیرنده با مدیا سازگاری ندارد و سرور یک فرمت سازگار را ارسال نمی کند.",
|
||||||
|
"PlayNextEpisodeAutomatically": "قسمت بعدی را به صورت خودکار اجرا کن",
|
||||||
|
"PlayNext": "بعدی را اجرا کن",
|
||||||
|
"PlayFromBeginning": "از ابتدا اجرا کن",
|
||||||
|
"PlaybackData": "اجرای مجدد داده",
|
||||||
|
"PlayAllFromHere": "همه را از اینجا اجرا کن",
|
||||||
|
"Play": "اجرا کردن",
|
||||||
|
"PinCodeResetConfirmation": "آیا مطمئن هستید که می خواهید کد پین را باز نشانی کنید؟",
|
||||||
|
"PinCodeResetComplete": "کد پین بازنشانی شد.",
|
||||||
|
"PictureInPicture": "تصویر در تصویر",
|
||||||
|
"Person": "فرد",
|
||||||
|
"PerfectMatch": "همتای کامل",
|
||||||
|
"People": "افراد",
|
||||||
|
"MillisecondsUnit": "میلیثانیه",
|
||||||
|
"LabelSyncPlayTimeOffset": "اختلاف زمانی با سرور:",
|
||||||
|
"LabelSeriesRecordingPath": "مسیر ضبط سریالها (اختیاری):",
|
||||||
|
"LabelSelectFolderGroups": "به طور خودکار محتواهای پوشههای زیر را به فیلم ، موسیقی و تلویزیون گروه بندی شود:",
|
||||||
|
"LabelSeasonNumber": "شماره فصل:",
|
||||||
|
"ConfigureDateAdded": "تنظیم کنید که چگونه تاریخ اضافه شده در داشبورد سرور Jellyfin تحت تنظیمات کتابخانه تعیین میشود",
|
||||||
|
"CinemaModeConfigurationHelp": "حالت سینما تجربه تئاتر گونه را مستقیم به اتاق نشیمن شما میآورد با قابلیت پخش تریلرها و پیش نمایشها قبل از سایر ویژگیهای اصلی.",
|
||||||
|
"LaunchWebAppOnStartup": "نمای وب هنگامی که سرور آغاز به کار میکند باز بشود"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1458,8 +1458,6 @@
|
||||||
"MessageConfirmAppExit": "Voulez-vous quitter ?",
|
"MessageConfirmAppExit": "Voulez-vous quitter ?",
|
||||||
"LabelVideoResolution": "Résolution vidéo :",
|
"LabelVideoResolution": "Résolution vidéo :",
|
||||||
"LabelStreamType": "Type de flux :",
|
"LabelStreamType": "Type de flux :",
|
||||||
"EnableFastImageFadeInHelp": "Activer un fondu plus rapide pour l'animation des images chargées.",
|
|
||||||
"EnableFastImageFadeIn": "Fondu d'image rapide",
|
|
||||||
"LabelPlayerDimensions": "Dimension du lecteur :",
|
"LabelPlayerDimensions": "Dimension du lecteur :",
|
||||||
"LabelDroppedFrames": "Images perdues :",
|
"LabelDroppedFrames": "Images perdues :",
|
||||||
"LabelCorruptedFrames": "Images corrompues :",
|
"LabelCorruptedFrames": "Images corrompues :",
|
||||||
|
|
|
@ -1393,8 +1393,6 @@
|
||||||
"ButtonSplit": "Szétvág",
|
"ButtonSplit": "Szétvág",
|
||||||
"Absolute": "Abszolút",
|
"Absolute": "Abszolút",
|
||||||
"LabelSkipIfAudioTrackPresentHelp": "Vedd ki a pipát, ha minden videóhoz szeretnél feliratot az audio nyelvétől függetlenül.",
|
"LabelSkipIfAudioTrackPresentHelp": "Vedd ki a pipát, ha minden videóhoz szeretnél feliratot az audio nyelvétől függetlenül.",
|
||||||
"EnableFastImageFadeInHelp": "Gyorsabb előtűnés animáció a betöltött képekhez",
|
|
||||||
"EnableFastImageFadeIn": "Gyors kép-előtűnés",
|
|
||||||
"SubtitleOffset": "Felirat eltolása",
|
"SubtitleOffset": "Felirat eltolása",
|
||||||
"SeriesDisplayOrderHelp": "Rakd sorba az epizódokat az adásba kerülésük dátuma, a DVD sorszám, vagy az abszolút számozás szerint.",
|
"SeriesDisplayOrderHelp": "Rakd sorba az epizódokat az adásba kerülésük dátuma, a DVD sorszám, vagy az abszolút számozás szerint.",
|
||||||
"SelectAdminUsername": "Kérjük válassz felhasználónevet az adminisztrátor fiók számára.",
|
"SelectAdminUsername": "Kérjük válassz felhasználónevet az adminisztrátor fiók számára.",
|
||||||
|
@ -1539,5 +1537,22 @@
|
||||||
"LabelSyncPlaySyncMethod": "Szinkronizálási mód:",
|
"LabelSyncPlaySyncMethod": "Szinkronizálási mód:",
|
||||||
"MillisecondsUnit": "ms",
|
"MillisecondsUnit": "ms",
|
||||||
"HeaderSyncPlayEnabled": "SyncPlay engedélyezve",
|
"HeaderSyncPlayEnabled": "SyncPlay engedélyezve",
|
||||||
"HeaderSyncPlaySelectGroup": "Csatlakozás csoporthoz"
|
"HeaderSyncPlaySelectGroup": "Csatlakozás csoporthoz",
|
||||||
|
"SyncPlayAccessHelp": "Válaszd ki, hogy ez a felhasználó milyen szinten férhet hozzá a SyncPlay funkcióhoz. A SyncPlay lehetőséget biztosít a lejátszások közötti szinkronizációra.",
|
||||||
|
"MessageSyncPlayErrorMedia": "Nem sikerült a SyncPlay engedélyezése! Média hiba.",
|
||||||
|
"MessageSyncPlayErrorMissingSession": "A SyncPlay lejátszása sikertelen! Hiányzó munkamenet.",
|
||||||
|
"MessageSyncPlayErrorNoActivePlayer": "Nem található aktív lejátszó. A SyncPlay letiltásra került.",
|
||||||
|
"MessageSyncPlayErrorAccessingGroups": "Hiba történt a csoportok listájának betöltésekor.",
|
||||||
|
"MessageSyncPlayLibraryAccessDenied": "A tartalomhoz való hozzáférés korlátozva van.",
|
||||||
|
"MessageSyncPlayJoinGroupDenied": "A SyncPlay használatához jogosultság szükséges.",
|
||||||
|
"MessageSyncPlayCreateGroupDenied": "Jogosultság szükséges a csoportok létrehozásához.",
|
||||||
|
"MessageSyncPlayGroupDoesNotExist": "Nem sikerült csatlakozni a csoporthoz, mivel az nem létezik.",
|
||||||
|
"MessageSyncPlayPlaybackPermissionRequired": "Lejátszási jogosultság szükséges.",
|
||||||
|
"MessageSyncPlayNoGroupsAvailable": "Nincsenek elérhető csoportok. Először kezdj el lejátszani valamit.",
|
||||||
|
"LabelSyncPlayAccessNone": "Letiltva ennél a felhasználónál",
|
||||||
|
"LabelSyncPlayAccessJoinGroups": "A felhasználó csoportokhoz való csatlakozásának engedélyezése",
|
||||||
|
"LabelSyncPlayPlaybackDiff": "Lejátszási időkülönbség:",
|
||||||
|
"LabelSyncPlayTimeOffset": "Időeltolás a szerverhez képest:",
|
||||||
|
"EnableDetailsBannerHelp": "Megjelenít egy banner képet a részletes információoldal tetején.",
|
||||||
|
"EnableDetailsBanner": "Banner a részletes oldalon"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1455,8 +1455,6 @@
|
||||||
"MessageConfirmAppExit": "Vuoi uscire?",
|
"MessageConfirmAppExit": "Vuoi uscire?",
|
||||||
"HeaderNavigation": "Navigazione",
|
"HeaderNavigation": "Navigazione",
|
||||||
"CopyStreamURLError": "Si è verificato un errore nel copiare l'indirizzo.",
|
"CopyStreamURLError": "Si è verificato un errore nel copiare l'indirizzo.",
|
||||||
"EnableFastImageFadeInHelp": "Abilita la dissolvenza veloce per le immagini caricate",
|
|
||||||
"EnableFastImageFadeIn": "Dissolvenza immagine veloce",
|
|
||||||
"PlaybackErrorNoCompatibleStream": "Il client è incompatibile con il media e il server non sta inviando un formato compatibile.",
|
"PlaybackErrorNoCompatibleStream": "Il client è incompatibile con il media e il server non sta inviando un formato compatibile.",
|
||||||
"OptionForceRemoteSourceTranscoding": "Forza la transcodifica da fonti di media remoti (come LiveTV)",
|
"OptionForceRemoteSourceTranscoding": "Forza la transcodifica da fonti di media remoti (come LiveTV)",
|
||||||
"NoCreatedLibraries": "Sembra che tu non abbia ancora creato delle librerie. {0}Vuoi crearne una adesso?{1}",
|
"NoCreatedLibraries": "Sembra che tu non abbia ancora creato delle librerie. {0}Vuoi crearne una adesso?{1}",
|
||||||
|
@ -1520,5 +1518,37 @@
|
||||||
"TabDVR": "DVR",
|
"TabDVR": "DVR",
|
||||||
"SaveChanges": "Salva modifiche",
|
"SaveChanges": "Salva modifiche",
|
||||||
"HeaderDVR": "DVR",
|
"HeaderDVR": "DVR",
|
||||||
"LabelNightly": "Nightly"
|
"LabelNightly": "Nightly",
|
||||||
|
"SyncPlayAccessHelp": "Scegli il livello d'accesso di questo utente a SyncPlay. SyncPlay ti permette di riprodurre contemporaneamente su diversi dispositivi.",
|
||||||
|
"MessageSyncPlayErrorMedia": "Impossibile abilitare SyncPlay! Errore media.",
|
||||||
|
"MessageSyncPlayErrorMissingSession": "Impossibile abilitare SyncPlay! Sessione mancante.",
|
||||||
|
"MessageSyncPlayErrorNoActivePlayer": "Nessun player attivo. SyncPlay è stato disabilitato.",
|
||||||
|
"MessageSyncPlayErrorAccessingGroups": "Errore durante l'accesso alla lista dei gruppi.",
|
||||||
|
"MessageSyncPlayLibraryAccessDenied": "L'accesso a questo contenuto è negato.",
|
||||||
|
"MessageSyncPlayJoinGroupDenied": "E' Necessario il permesso per l'utilizzo di SyncPlay.",
|
||||||
|
"MessageSyncPlayCreateGroupDenied": "E' necessario il permesso di creazione di un gruppo.",
|
||||||
|
"MessageSyncPlayGroupDoesNotExist": "Impossibile unirsi al gruppo perchè non esiste.",
|
||||||
|
"MessageSyncPlayPlaybackPermissionRequired": "Permesso di riproduzione necessario.",
|
||||||
|
"MessageSyncPlayNoGroupsAvailable": "Nessun gruppo disponibile. Inizia a riprodurre qualcosa.",
|
||||||
|
"MessageSyncPlayGroupWait": "<b>{0}</b> sta bufferizzando...",
|
||||||
|
"MessageSyncPlayUserLeft": "<b>{0}</b> ha lasciato il gruppo.",
|
||||||
|
"MessageSyncPlayUserJoined": "<b>{0}</b> si è unito al gruppo.",
|
||||||
|
"MessageSyncPlayDisabled": "SyncPlay disabilitato.",
|
||||||
|
"MessageSyncPlayEnabled": "SyncPlay abilitato.",
|
||||||
|
"LabelSyncPlayAccess": "Accesso SyncPlay",
|
||||||
|
"LabelSyncPlayAccessNone": "Disabilitato per questo utente",
|
||||||
|
"LabelSyncPlayAccessJoinGroups": "Permetti all'utente di unirsi ai gruppi",
|
||||||
|
"LabelSyncPlayAccessCreateAndJoinGroups": "Permetti all'utente di creare e unirsi ai gruppi",
|
||||||
|
"LabelSyncPlayLeaveGroupDescription": "Disabilita SyncPlay",
|
||||||
|
"LabelSyncPlayLeaveGroup": "Lascia il gruppo",
|
||||||
|
"LabelSyncPlayNewGroupDescription": "Crea un nuovo gruppo",
|
||||||
|
"LabelSyncPlayNewGroup": "Nuovo gruppo",
|
||||||
|
"LabelSyncPlaySyncMethod": "Metodo Sync:",
|
||||||
|
"LabelSyncPlayPlaybackDiff": "Differenza oraria nella riproduzione:",
|
||||||
|
"MillisecondsUnit": "ms",
|
||||||
|
"LabelSyncPlayTimeOffset": "Differenza temporale con il server:",
|
||||||
|
"HeaderSyncPlayEnabled": "SyncPlay abilitato",
|
||||||
|
"HeaderSyncPlaySelectGroup": "Unisciti a un gruppo",
|
||||||
|
"EnableDetailsBannerHelp": "Mostra il banner nella parte superiore della pagina di dettaglio dell'elemento.",
|
||||||
|
"EnableDetailsBanner": "Banner Dettagli"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1484,8 +1484,6 @@
|
||||||
"MessageConfirmAppExit": "Shyǵýdy qalaısyz ba?",
|
"MessageConfirmAppExit": "Shyǵýdy qalaısyz ba?",
|
||||||
"LabelVideoResolution": "Beıne ajyratymdylyǵy:",
|
"LabelVideoResolution": "Beıne ajyratymdylyǵy:",
|
||||||
"LabelStreamType": "Aǵyn túri:",
|
"LabelStreamType": "Aǵyn túri:",
|
||||||
"EnableFastImageFadeInHelp": "Júktelgen sýretter úshin shapshan kórsetilýin qosý",
|
|
||||||
"EnableFastImageFadeIn": "Sýrettiń shapshan kórsetilýi",
|
|
||||||
"LabelPlayerDimensions": "Oınatqysh ólshemderi:",
|
"LabelPlayerDimensions": "Oınatqysh ólshemderi:",
|
||||||
"LabelDroppedFrames": "Ótkizilgen kadrlar:",
|
"LabelDroppedFrames": "Ótkizilgen kadrlar:",
|
||||||
"LabelCorruptedFrames": "Búlingen kadrlar:",
|
"LabelCorruptedFrames": "Búlingen kadrlar:",
|
||||||
|
|
|
@ -1343,8 +1343,6 @@
|
||||||
"LabelSkipIfAudioTrackPresentHelp": "오디오 언어와 상관없이 모든 비디오가 자막을 갖추도록 하려면 이 항목을 체크하지 마십시오.",
|
"LabelSkipIfAudioTrackPresentHelp": "오디오 언어와 상관없이 모든 비디오가 자막을 갖추도록 하려면 이 항목을 체크하지 마십시오.",
|
||||||
"LabelSelectFolderGroupsHelp": "체크되지 않은 폴더는 폴더 고유의 보기 방식으로 표시됩니다.",
|
"LabelSelectFolderGroupsHelp": "체크되지 않은 폴더는 폴더 고유의 보기 방식으로 표시됩니다.",
|
||||||
"LabelSelectFolderGroups": "자동으로 이하의 폴더의 항목을 영화, 음악, TV 와 같은 보기 방식으로 그룹화:",
|
"LabelSelectFolderGroups": "자동으로 이하의 폴더의 항목을 영화, 음악, TV 와 같은 보기 방식으로 그룹화:",
|
||||||
"EnableFastImageFadeInHelp": "로드된 이미지에 더 빠른 페이드 인 효과를 적용",
|
|
||||||
"EnableFastImageFadeIn": "빠른 이미지 페이드 인 효과",
|
|
||||||
"LabelScheduledTaskLastRan": "최근 실행: {0}, 소모시간: {1}.",
|
"LabelScheduledTaskLastRan": "최근 실행: {0}, 소모시간: {1}.",
|
||||||
"LabelRemoteClientBitrateLimitHelp": "(선택) 모든 외부 네트워크로 접속된 장치들에 적용되는 각 스트리밍별 비트레이트 제한입니다. 이는 서버의 인터넷이 처리할 수 있는 한계보다 더 높은 비트레이트를 요청하는 것을 방지할 수 있습니다. 비디오를 더 낮은 비트레이트로 트랜스코딩하기 위해 서버에 높은 CPU 부하를 줄 수 있습니다.",
|
"LabelRemoteClientBitrateLimitHelp": "(선택) 모든 외부 네트워크로 접속된 장치들에 적용되는 각 스트리밍별 비트레이트 제한입니다. 이는 서버의 인터넷이 처리할 수 있는 한계보다 더 높은 비트레이트를 요청하는 것을 방지할 수 있습니다. 비디오를 더 낮은 비트레이트로 트랜스코딩하기 위해 서버에 높은 CPU 부하를 줄 수 있습니다.",
|
||||||
"LabelReasonForTranscoding": "트랜스코딩 원인:",
|
"LabelReasonForTranscoding": "트랜스코딩 원인:",
|
||||||
|
|
|
@ -1232,7 +1232,5 @@
|
||||||
"MessageUnauthorizedUser": "Jūs neesat autorizēti lai piekļūtu serverim šajā brīdī. Lūdzu sazinieties ar savu servera administratoru priekš papildus informācijas.",
|
"MessageUnauthorizedUser": "Jūs neesat autorizēti lai piekļūtu serverim šajā brīdī. Lūdzu sazinieties ar savu servera administratoru priekš papildus informācijas.",
|
||||||
"MessageInstallPluginFromApp": "Šis paplašinājums ir jāuzstāda no lietotnes, kurā jūs to vēlaties izmantot.",
|
"MessageInstallPluginFromApp": "Šis paplašinājums ir jāuzstāda no lietotnes, kurā jūs to vēlaties izmantot.",
|
||||||
"LabelEmbedAlbumArtDidl": "Ievietot albumu vākus iekš Didl",
|
"LabelEmbedAlbumArtDidl": "Ievietot albumu vākus iekš Didl",
|
||||||
"EnableFastImageFadeIn": "Ātra attēlu ieplūšana",
|
|
||||||
"EnableFastImageFadeInHelp": "Iespējot ātrāku ieplūšanas animāciju priekš ielādētiem attēliem",
|
|
||||||
"LabelSelectFolderGroups": "Automātiski grupēt saturu no sekojošām datnēm skatos kā Filmas, Mūzika un TV:"
|
"LabelSelectFolderGroups": "Automātiski grupēt saturu no sekojošām datnēm skatos kā Filmas, Mūzika un TV:"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1454,8 +1454,6 @@
|
||||||
"SelectAdminUsername": "Vennligst velg et brukernavn for administrator kontoen. ",
|
"SelectAdminUsername": "Vennligst velg et brukernavn for administrator kontoen. ",
|
||||||
"HeaderNavigation": "Navigering",
|
"HeaderNavigation": "Navigering",
|
||||||
"MessageConfirmAppExit": "Vil du avslutte?",
|
"MessageConfirmAppExit": "Vil du avslutte?",
|
||||||
"EnableFastImageFadeInHelp": "Bruk rask inntoning av animasjon for lastede bilder",
|
|
||||||
"EnableFastImageFadeIn": "Rask bilde inntoning",
|
|
||||||
"CopyStreamURLError": "Det var en feil under kopiering av URL'en.",
|
"CopyStreamURLError": "Det var en feil under kopiering av URL'en.",
|
||||||
"LabelVideoResolution": "Oppløsning på video:",
|
"LabelVideoResolution": "Oppløsning på video:",
|
||||||
"LabelPlayerDimensions": "Dimensjoner på avspiller:",
|
"LabelPlayerDimensions": "Dimensjoner på avspiller:",
|
||||||
|
|
|
@ -1471,8 +1471,6 @@
|
||||||
"Artist": "Artiest",
|
"Artist": "Artiest",
|
||||||
"AllowFfmpegThrottlingHelp": "Wanneer een transcode of remux ver genoeg voorloopt op de huidige afspeelpositie, pauzeer het proces, zodat het minder middelen verbruikt. Dit is vooral handig wanneer u kijkt zonder vaak te zoeken. Schakel dit uit als u afspeelproblemen ondervindt.",
|
"AllowFfmpegThrottlingHelp": "Wanneer een transcode of remux ver genoeg voorloopt op de huidige afspeelpositie, pauzeer het proces, zodat het minder middelen verbruikt. Dit is vooral handig wanneer u kijkt zonder vaak te zoeken. Schakel dit uit als u afspeelproblemen ondervindt.",
|
||||||
"AllowFfmpegThrottling": "Throttle Transcodes",
|
"AllowFfmpegThrottling": "Throttle Transcodes",
|
||||||
"EnableFastImageFadeInHelp": "Toon posters en andere afbeeldingen met een snellere fade-animatie wanneer ze klaar zijn met laden.",
|
|
||||||
"EnableFastImageFadeIn": "Fast Image Fade Animaties",
|
|
||||||
"LabelPlayerDimensions": "Afspeellengte:",
|
"LabelPlayerDimensions": "Afspeellengte:",
|
||||||
"LabelLibraryPageSizeHelp": "Kies het aantal artikelen dat wordt weergegeven op een bibliotheekpagina. Kies 0 om dit te verbergen.",
|
"LabelLibraryPageSizeHelp": "Kies het aantal artikelen dat wordt weergegeven op een bibliotheekpagina. Kies 0 om dit te verbergen.",
|
||||||
"LabelLibraryPageSize": "Bibliotheekpagina grootte:",
|
"LabelLibraryPageSize": "Bibliotheekpagina grootte:",
|
||||||
|
|
|
@ -1466,8 +1466,6 @@
|
||||||
"NoCreatedLibraries": "Wygląda na to, że nie utworzyłeś jeszcze żadnych bibliotek. {0}Czy chcesz utworzyć jedną teraz?{1}",
|
"NoCreatedLibraries": "Wygląda na to, że nie utworzyłeś jeszcze żadnych bibliotek. {0}Czy chcesz utworzyć jedną teraz?{1}",
|
||||||
"LabelVideoResolution": "Rozdzielczość wideo:",
|
"LabelVideoResolution": "Rozdzielczość wideo:",
|
||||||
"LabelStreamType": "Typ transmisji:",
|
"LabelStreamType": "Typ transmisji:",
|
||||||
"EnableFastImageFadeInHelp": "Włącz szybszą animację pojawiania się dla załadowanych obrazów",
|
|
||||||
"EnableFastImageFadeIn": "Szybkie pojawianie się obrazów",
|
|
||||||
"Artist": "Artysta",
|
"Artist": "Artysta",
|
||||||
"AlbumArtist": "Album artysty",
|
"AlbumArtist": "Album artysty",
|
||||||
"Album": "Album",
|
"Album": "Album",
|
||||||
|
|
|
@ -1456,7 +1456,6 @@
|
||||||
"MessageConfirmAppExit": "Você quer sair?",
|
"MessageConfirmAppExit": "Você quer sair?",
|
||||||
"LabelVideoResolution": "Resolução de vídeo:",
|
"LabelVideoResolution": "Resolução de vídeo:",
|
||||||
"LabelStreamType": "Tipo de stream:",
|
"LabelStreamType": "Tipo de stream:",
|
||||||
"EnableFastImageFadeIn": "Fade-in rápido da imagem",
|
|
||||||
"LabelPlayerDimensions": "Dimensões do player:",
|
"LabelPlayerDimensions": "Dimensões do player:",
|
||||||
"LabelCorruptedFrames": "Quadros corrompidos:",
|
"LabelCorruptedFrames": "Quadros corrompidos:",
|
||||||
"HeaderNavigation": "Navegação",
|
"HeaderNavigation": "Navegação",
|
||||||
|
@ -1465,7 +1464,6 @@
|
||||||
"AskAdminToCreateLibrary": "Peça a um administrador para criar uma biblioteca.",
|
"AskAdminToCreateLibrary": "Peça a um administrador para criar uma biblioteca.",
|
||||||
"AllowFfmpegThrottling": "Transcodes do Acelerador",
|
"AllowFfmpegThrottling": "Transcodes do Acelerador",
|
||||||
"PlaybackErrorNoCompatibleStream": "Este cliente não é compatível com a media e o servidor não está enviando um formato de mídia compatível.",
|
"PlaybackErrorNoCompatibleStream": "Este cliente não é compatível com a media e o servidor não está enviando um formato de mídia compatível.",
|
||||||
"EnableFastImageFadeInHelp": "Mostrar pôsteres e outras imagens com uma animação mais rápida ao terminar de carregar.",
|
|
||||||
"LabelDroppedFrames": "Quadros caídos:",
|
"LabelDroppedFrames": "Quadros caídos:",
|
||||||
"AllowFfmpegThrottlingHelp": "Quando uma transcodificação ou remux estiver suficientemente avançada da posição atual de reprodução, pause o processo para que consuma menos recursos. Isso é mais proveitoso para quando não há avanço ou retrocesso do vídeo com frequência. Desative se tiver problemas de reprodução.",
|
"AllowFfmpegThrottlingHelp": "Quando uma transcodificação ou remux estiver suficientemente avançada da posição atual de reprodução, pause o processo para que consuma menos recursos. Isso é mais proveitoso para quando não há avanço ou retrocesso do vídeo com frequência. Desative se tiver problemas de reprodução.",
|
||||||
"PreferEmbeddedEpisodeInfosOverFileNames": "Preferir informações dos episódios incorporadas nos arquivos ao invés dos nomes",
|
"PreferEmbeddedEpisodeInfosOverFileNames": "Preferir informações dos episódios incorporadas nos arquivos ao invés dos nomes",
|
||||||
|
|
|
@ -1102,13 +1102,13 @@
|
||||||
"AllowedRemoteAddressesHelp": "Lista separada por vírgula de endereços IP ou entradas de máscara de IP/rede para redes que terão permissão para se conectar remotamente. Se deixado em branco, todos os endereços remotos serão permitidos.",
|
"AllowedRemoteAddressesHelp": "Lista separada por vírgula de endereços IP ou entradas de máscara de IP/rede para redes que terão permissão para se conectar remotamente. Se deixado em branco, todos os endereços remotos serão permitidos.",
|
||||||
"AllowRemoteAccessHelp": "Se desmarcada, todas as conexões remotas serão bloqueadas.",
|
"AllowRemoteAccessHelp": "Se desmarcada, todas as conexões remotas serão bloqueadas.",
|
||||||
"AllowRemoteAccess": "Permitir ligações remotas a este Servidor Jellyfin.",
|
"AllowRemoteAccess": "Permitir ligações remotas a este Servidor Jellyfin.",
|
||||||
"AllowOnTheFlySubtitleExtractionHelp": "Legendas integradas podem ser extraídas do vídeo e enviadas como texto simples para os clientes para evitar transcodificação. Em certos dispositivos, é uma operação demorada e pode causar paragens de reprodução durante o processo de extracção. Desactive esta opção para que as legendas sejam integradas no vídeo durante a conversão para um formato suportado pelo dispositivo de destino.",
|
"AllowOnTheFlySubtitleExtractionHelp": "Legendas integradas podem ser extraídas do vídeo e enviadas como texto simples para os clientes de forma a evitar transcodificação. Em certos dispositivos, esta operação pode demorar algum tempo e causar paragens de reprodução durante o processo de extração. Desative esta opção para que as legendas sejam integradas no vídeo durante a conversão para um formato suportado pelo dispositivo de destino.",
|
||||||
"AllowOnTheFlySubtitleExtraction": "Permitir a extração de legendas em tempo real",
|
"AllowOnTheFlySubtitleExtraction": "Permitir a extração de legendas em tempo real",
|
||||||
"AllowHWTranscodingHelp": "Permita que o sintonizador transcodifique os fluxos em tempo real. Isso pode ajudar a reduzir a transcodificação exigida pelo servidor.",
|
"AllowHWTranscodingHelp": "Permita que o sintonizador transcodifique os fluxos em tempo real. Isso pode ajudar a reduzir a transcodificação exigida pelo servidor.",
|
||||||
"AllLibraries": "Todas as bibliotecas",
|
"AllLibraries": "Todas as bibliotecas",
|
||||||
"AllLanguages": "Todos os idiomas",
|
"AllLanguages": "Todos os idiomas",
|
||||||
"AllEpisodes": "Todos os episódios",
|
"AllEpisodes": "Todos os episódios",
|
||||||
"AllComplexFormats": "Todos os formatos complexos (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)",
|
"AllComplexFormats": "Todos os formatos complexos (ASS, SSA, VOBSUB, PGS, SUB, IDX, etc.)",
|
||||||
"AllChannels": "Todos os canais",
|
"AllChannels": "Todos os canais",
|
||||||
"All": "Todos",
|
"All": "Todos",
|
||||||
"Alerts": "Alertas",
|
"Alerts": "Alertas",
|
||||||
|
@ -1314,8 +1314,6 @@
|
||||||
"LabelSortOrder": "Ordem de classificação:",
|
"LabelSortOrder": "Ordem de classificação:",
|
||||||
"LabelSortBy": "Ordenar por:",
|
"LabelSortBy": "Ordenar por:",
|
||||||
"LabelSkin": "Pele:",
|
"LabelSkin": "Pele:",
|
||||||
"EnableFastImageFadeInHelp": "Habilite uma animação mais rápida para imagens carregadas",
|
|
||||||
"EnableFastImageFadeIn": "Efeito de imagem fade-in rápido",
|
|
||||||
"LabelRemoteClientBitrateLimitHelp": "Um limite opcional de taxa de bits por fluxo para todos os dispositivos fora da rede. Isso é útil para impedir que os dispositivos solicitem uma taxa de bits mais alta do que a sua conexão à Internet pode suportar. Isso pode resultar no aumento da carga da CPU no servidor para transcodificar vídeos em tempo real para uma taxa de bits mais baixa.",
|
"LabelRemoteClientBitrateLimitHelp": "Um limite opcional de taxa de bits por fluxo para todos os dispositivos fora da rede. Isso é útil para impedir que os dispositivos solicitem uma taxa de bits mais alta do que a sua conexão à Internet pode suportar. Isso pode resultar no aumento da carga da CPU no servidor para transcodificar vídeos em tempo real para uma taxa de bits mais baixa.",
|
||||||
"LabelPlayerDimensions": "Dimensões do reprodutor:",
|
"LabelPlayerDimensions": "Dimensões do reprodutor:",
|
||||||
"LabelParentNumber": "Número pai:",
|
"LabelParentNumber": "Número pai:",
|
||||||
|
|
|
@ -250,7 +250,7 @@
|
||||||
"ButtonSubmit": "Trimite",
|
"ButtonSubmit": "Trimite",
|
||||||
"Collections": "Colecții",
|
"Collections": "Colecții",
|
||||||
"AllowRemoteAccess": "Permite conexiuni externe către acest server Jellyfin.",
|
"AllowRemoteAccess": "Permite conexiuni externe către acest server Jellyfin.",
|
||||||
"AllowRemoteAccessHelp": "Dacă este nebifat, toate conexiunile externe vor fi blocate.",
|
"AllowRemoteAccessHelp": "Dacă este neselectat, toate conexiunile externe vor fi blocate.",
|
||||||
"AlwaysPlaySubtitles": "Întotdeauna arată",
|
"AlwaysPlaySubtitles": "Întotdeauna arată",
|
||||||
"AnyLanguage": "Orice Limbă",
|
"AnyLanguage": "Orice Limbă",
|
||||||
"Anytime": "Oricând",
|
"Anytime": "Oricând",
|
||||||
|
@ -1238,7 +1238,7 @@
|
||||||
"Repeat": "Repetă",
|
"Repeat": "Repetă",
|
||||||
"RemoveFromPlaylist": "Scoateți din lista de redare",
|
"RemoveFromPlaylist": "Scoateți din lista de redare",
|
||||||
"RemoveFromCollection": "Scoateți din colecție",
|
"RemoveFromCollection": "Scoateți din colecție",
|
||||||
"RememberMe": "Ține-mă minte",
|
"RememberMe": "Ține-mă Minte",
|
||||||
"ReleaseDate": "Data lansării",
|
"ReleaseDate": "Data lansării",
|
||||||
"RefreshQueued": "Actualizare adăugată în coadă.",
|
"RefreshQueued": "Actualizare adăugată în coadă.",
|
||||||
"RefreshMetadata": "Actualizați metadatele",
|
"RefreshMetadata": "Actualizați metadatele",
|
||||||
|
@ -1454,8 +1454,6 @@
|
||||||
"HeaderNavigation": "Navigare",
|
"HeaderNavigation": "Navigare",
|
||||||
"MessageConfirmAppExit": "Vrei să ieși?",
|
"MessageConfirmAppExit": "Vrei să ieși?",
|
||||||
"CopyStreamURLError": "A apărut o eroare la copierea adresei URL.",
|
"CopyStreamURLError": "A apărut o eroare la copierea adresei URL.",
|
||||||
"EnableFastImageFadeInHelp": "Activați animația mai rapidă de tranziție pentru imaginile încărcate",
|
|
||||||
"EnableFastImageFadeIn": "Tranziție a imaginii rapidă",
|
|
||||||
"LabelVideoResolution": "Rezoluția video:",
|
"LabelVideoResolution": "Rezoluția video:",
|
||||||
"LabelStreamType": "Tipul streamului:",
|
"LabelStreamType": "Tipul streamului:",
|
||||||
"LabelPlayerDimensions": "Dimensiunile soft redare:",
|
"LabelPlayerDimensions": "Dimensiunile soft redare:",
|
||||||
|
@ -1519,5 +1517,37 @@
|
||||||
"HeaderHttpsSettings": "Setări https",
|
"HeaderHttpsSettings": "Setări https",
|
||||||
"TabDVR": "DVR",
|
"TabDVR": "DVR",
|
||||||
"SaveChanges": "Salvează modificările",
|
"SaveChanges": "Salvează modificările",
|
||||||
"HeaderDVR": "DVR"
|
"HeaderDVR": "DVR",
|
||||||
|
"SyncPlayAccessHelp": "Selectați nivelul de acces pe care îl are acest utilizator la funcția SyncPlay. SyncPlay permite sincronizarea redării cu alte dispozitive.",
|
||||||
|
"MessageSyncPlayErrorMedia": "Eroare la activarea SyncPlay! Eroare media.",
|
||||||
|
"MessageSyncPlayErrorMissingSession": "Eroare la activarea SyncPlay! Sesiune lipsă.",
|
||||||
|
"MessageSyncPlayErrorNoActivePlayer": "Nu a fost găsit niciun soft de redare activ. SyncPlay a fost dezactivat.",
|
||||||
|
"MessageSyncPlayErrorAccessingGroups": "A apărut o eroare la accesarea listei de grupuri.",
|
||||||
|
"MessageSyncPlayLibraryAccessDenied": "Accesul la acest conținut este restricționat.",
|
||||||
|
"MessageSyncPlayJoinGroupDenied": "Permisiune necesară pentru a utiliza SyncPlay.",
|
||||||
|
"MessageSyncPlayCreateGroupDenied": "Permisiune necesară pentru crearea unui grup.",
|
||||||
|
"MessageSyncPlayGroupDoesNotExist": "Nu a reușit să se alăture grupului, deoarece nu există.",
|
||||||
|
"MessageSyncPlayPlaybackPermissionRequired": "Este necesară permisiunea de redare.",
|
||||||
|
"MessageSyncPlayNoGroupsAvailable": "Nu există grupuri disponibile. Începe să redai ceva mai întâi.",
|
||||||
|
"MessageSyncPlayGroupWait": "<b>{0}</b> se încarcă...",
|
||||||
|
"MessageSyncPlayUserLeft": "<b>{0}</b> a părăsit grupul.",
|
||||||
|
"MessageSyncPlayUserJoined": "<b>{0}</b> s-a alăturat grupului.",
|
||||||
|
"MessageSyncPlayDisabled": "SyncPlay dezactivat.",
|
||||||
|
"MessageSyncPlayEnabled": "SyncPlay activat.",
|
||||||
|
"LabelSyncPlayAccess": "Acces SyncPlay",
|
||||||
|
"LabelSyncPlayAccessNone": "Dezactivat pentru acest utilizator",
|
||||||
|
"LabelSyncPlayAccessJoinGroups": "Permiteți utilizatorului să se alăture grupurilor",
|
||||||
|
"LabelSyncPlayAccessCreateAndJoinGroups": "Permiteți utilizatorului să creeze și să se alăture grupurilor",
|
||||||
|
"LabelSyncPlayLeaveGroupDescription": "Dezactivează SyncPlay",
|
||||||
|
"LabelSyncPlayLeaveGroup": "Parăsește grup",
|
||||||
|
"LabelSyncPlayNewGroupDescription": "Crează un grup nou",
|
||||||
|
"LabelSyncPlayNewGroup": "Grup nou",
|
||||||
|
"LabelSyncPlaySyncMethod": "Metoda de sincronizare:",
|
||||||
|
"LabelSyncPlayPlaybackDiff": "Diferența de timp de redare:",
|
||||||
|
"MillisecondsUnit": "ms",
|
||||||
|
"LabelSyncPlayTimeOffset": "Decalare de timp cu serverul:",
|
||||||
|
"HeaderSyncPlayEnabled": "SyncPlay activat",
|
||||||
|
"HeaderSyncPlaySelectGroup": "Alăturați-vă unui grup",
|
||||||
|
"EnableDetailsBannerHelp": "Afișați o imagine de bandou în partea de sus a paginii cu detalii ale articolului.",
|
||||||
|
"EnableDetailsBanner": "Detalii Bandou"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1460,8 +1460,6 @@
|
||||||
"HeaderNavigation": "Навигация",
|
"HeaderNavigation": "Навигация",
|
||||||
"LabelVideoResolution": "Разрешение видео:",
|
"LabelVideoResolution": "Разрешение видео:",
|
||||||
"LabelStreamType": "Тип потока:",
|
"LabelStreamType": "Тип потока:",
|
||||||
"EnableFastImageFadeInHelp": "Включить быстрое появление анимации для загруженных изображений",
|
|
||||||
"EnableFastImageFadeIn": "Быстрое появление изображения",
|
|
||||||
"LabelPlayerDimensions": "Размеры проигрывателя:",
|
"LabelPlayerDimensions": "Размеры проигрывателя:",
|
||||||
"LabelDroppedFrames": "Пропущенные кадры:",
|
"LabelDroppedFrames": "Пропущенные кадры:",
|
||||||
"LabelCorruptedFrames": "Испорченные кадры:",
|
"LabelCorruptedFrames": "Испорченные кадры:",
|
||||||
|
@ -1520,5 +1518,39 @@
|
||||||
"HeaderServerAddressSettings": "Параметры адреса сервера",
|
"HeaderServerAddressSettings": "Параметры адреса сервера",
|
||||||
"HeaderRemoteAccessSettings": "Параметры удалённого доступа",
|
"HeaderRemoteAccessSettings": "Параметры удалённого доступа",
|
||||||
"HeaderHttpsSettings": "Параметры HTTPS",
|
"HeaderHttpsSettings": "Параметры HTTPS",
|
||||||
"HeaderDVR": "DVR"
|
"HeaderDVR": "DVR",
|
||||||
|
"MessageSyncPlayJoinGroupDenied": "Требуется разрешение для использования SyncPlay.",
|
||||||
|
"MessageSyncPlayDisabled": "SyncPlay отключен.",
|
||||||
|
"MessageSyncPlayEnabled": "SyncPlay включён.",
|
||||||
|
"LabelSyncPlayAccess": "Доступ к SyncPlay",
|
||||||
|
"LabelSyncPlayLeaveGroupDescription": "Отключить SyncPlay",
|
||||||
|
"HeaderSyncPlayEnabled": "SyncPlay включён",
|
||||||
|
"HeaderSyncPlaySelectGroup": "Присоединить группу",
|
||||||
|
"EnableDetailsBanner": "Баннер подробностей",
|
||||||
|
"EnableDetailsBannerHelp": "Отображает рисунок баннера вверху страницы подробностей элемента.",
|
||||||
|
"MessageSyncPlayErrorAccessingGroups": "Произошла ошибка при попытке доступа к списку групп.",
|
||||||
|
"MessageSyncPlayLibraryAccessDenied": "Доступ к данному содержанию ограничен.",
|
||||||
|
"MessageSyncPlayCreateGroupDenied": "Требуется разрешение для создания группы.",
|
||||||
|
"MessageSyncPlayGroupDoesNotExist": "Не удалось присоединиться к группе, поскольку она не существует.",
|
||||||
|
"MessageSyncPlayPlaybackPermissionRequired": "Требуется разрешение на воспроизведение.",
|
||||||
|
"MessageSyncPlayNoGroupsAvailable": "Никакие группы не доступны. Сначала начните воспроизводить что-нибудь.",
|
||||||
|
"MessageSyncPlayGroupWait": "<b>{0}</b> буферизуется...",
|
||||||
|
"MessageSyncPlayUserLeft": "<b>{0}</b> покинул группу.",
|
||||||
|
"MessageSyncPlayUserJoined": "<b>{0}</b> присоединил группу.",
|
||||||
|
"LabelSyncPlayAccessNone": "Отключено для данного пользователя",
|
||||||
|
"LabelSyncPlayAccessJoinGroups": "Разрешить пользователю присоединяться к группам",
|
||||||
|
"LabelSyncPlayAccessCreateAndJoinGroups": "Разрешить пользователю создавать и присоединять группы",
|
||||||
|
"LabelSyncPlayLeaveGroup": "Покинуть группу",
|
||||||
|
"LabelSyncPlayNewGroupDescription": "Создание новой группы",
|
||||||
|
"LabelSyncPlayNewGroup": "Новая группа",
|
||||||
|
"LabelSyncPlaySyncMethod": "Метод синхронизации:",
|
||||||
|
"LabelSyncPlayPlaybackDiff": "Разница времени воспроизведения:",
|
||||||
|
"MillisecondsUnit": "мс",
|
||||||
|
"LabelSyncPlayTimeOffset": "Сдвиг времени относительно сервера:",
|
||||||
|
"SyncPlayAccessHelp": "Выберите уровень доступа данного пользователя к функциональности SyncPlay. SyncPlay позволяет синхронизировать воспроизведение с другими устройствами.",
|
||||||
|
"MessageSyncPlayErrorMedia": "Не удалось включить SyncPlay! Ошибка медиаданных.",
|
||||||
|
"MessageSyncPlayErrorMissingSession": "Не удалось включить SyncPlay! Отсутствует сеанс.",
|
||||||
|
"MessageSyncPlayErrorNoActivePlayer": "Активный проигрыватель не найден. SyncPlay был отключен.",
|
||||||
|
"ShowMore": "Показать больше",
|
||||||
|
"ShowLess": "Показать меньше"
|
||||||
}
|
}
|
||||||
|
|
|
@ -721,7 +721,7 @@
|
||||||
"Refresh": "Obnoviť",
|
"Refresh": "Obnoviť",
|
||||||
"RefreshMetadata": "Obnoviť metadáta",
|
"RefreshMetadata": "Obnoviť metadáta",
|
||||||
"ReleaseDate": "Dátum vydania",
|
"ReleaseDate": "Dátum vydania",
|
||||||
"RememberMe": "Zapamätať si ma",
|
"RememberMe": "Zapamätaj si ma",
|
||||||
"RemoveFromCollection": "Odobrať z kolekcie",
|
"RemoveFromCollection": "Odobrať z kolekcie",
|
||||||
"Repeat": "Opakovať",
|
"Repeat": "Opakovať",
|
||||||
"RepeatAll": "Opakovať všetko",
|
"RepeatAll": "Opakovať všetko",
|
||||||
|
@ -1457,8 +1457,6 @@
|
||||||
"MessageConfirmAppExit": "Chceli by ste odísiť?",
|
"MessageConfirmAppExit": "Chceli by ste odísiť?",
|
||||||
"LabelVideoResolution": "Rozlíšenie videa:",
|
"LabelVideoResolution": "Rozlíšenie videa:",
|
||||||
"LabelStreamType": "Typ streamu:",
|
"LabelStreamType": "Typ streamu:",
|
||||||
"EnableFastImageFadeInHelp": "Povoliť animáciu rýchleho rozjasnenia pre nahrané obrázky",
|
|
||||||
"EnableFastImageFadeIn": "Rýchle rozjasnenie obrázku",
|
|
||||||
"LabelPlayerDimensions": "Rozmery prehrávača:",
|
"LabelPlayerDimensions": "Rozmery prehrávača:",
|
||||||
"LabelDroppedFrames": "Vynechané snímky:",
|
"LabelDroppedFrames": "Vynechané snímky:",
|
||||||
"LabelCorruptedFrames": "Poškodené snímky:",
|
"LabelCorruptedFrames": "Poškodené snímky:",
|
||||||
|
@ -1550,5 +1548,8 @@
|
||||||
"MillisecondsUnit": "ms",
|
"MillisecondsUnit": "ms",
|
||||||
"LabelSyncPlayTimeOffset": "Časový rozdiel so serverom:",
|
"LabelSyncPlayTimeOffset": "Časový rozdiel so serverom:",
|
||||||
"HeaderSyncPlayEnabled": "Synchronizácia prehrávania je povolená",
|
"HeaderSyncPlayEnabled": "Synchronizácia prehrávania je povolená",
|
||||||
"HeaderSyncPlaySelectGroup": "Pripojiť sa k skupine"
|
"HeaderSyncPlaySelectGroup": "Pripojiť sa k skupine",
|
||||||
|
"SyncPlayAccessHelp": "Vyberte úroveň prístupu pre tohto používateľa k funkcií synchronizácie prehrávania. Synchronizácia prehrávania umožňuje zosynchronizovať prehrávanie s ostatnými zariadeniami.",
|
||||||
|
"EnableDetailsBannerHelp": "Zobrazí banner na vrchnej časti detailu položky.",
|
||||||
|
"EnableDetailsBanner": "Detail banneru"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1344,8 +1344,6 @@
|
||||||
"LabelSize": "Storlek:",
|
"LabelSize": "Storlek:",
|
||||||
"LabelServerName": "Servernamn:",
|
"LabelServerName": "Servernamn:",
|
||||||
"LabelSecureConnectionsMode": "Säker uppkopplings läge:",
|
"LabelSecureConnectionsMode": "Säker uppkopplings läge:",
|
||||||
"EnableFastImageFadeInHelp": "Aktivera snabbare fade-in animationer för laddade bilder",
|
|
||||||
"EnableFastImageFadeIn": "Snabb bild fade-in",
|
|
||||||
"LabelPostProcessorArgumentsHelp": "Använd {path} som sökväg till inspelade filen.",
|
"LabelPostProcessorArgumentsHelp": "Använd {path} som sökväg till inspelade filen.",
|
||||||
"LabelPostProcessorArguments": "Post-processor kommandoradsargument:",
|
"LabelPostProcessorArguments": "Post-processor kommandoradsargument:",
|
||||||
"LabelDroppedFrames": "Tappade ramar:",
|
"LabelDroppedFrames": "Tappade ramar:",
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue