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
|
||||
Production:
|
||||
BuildConfiguration: production
|
||||
Standalone:
|
||||
BuildConfiguration: standalone
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
@ -49,13 +47,9 @@ jobs:
|
|||
condition: eq(variables['BuildConfiguration'], 'development')
|
||||
|
||||
- script: 'yarn build:production'
|
||||
displayName: 'Build Bundle'
|
||||
displayName: 'Build Production'
|
||||
condition: eq(variables['BuildConfiguration'], 'production')
|
||||
|
||||
- script: 'yarn build:standalone'
|
||||
displayName: 'Build Standalone'
|
||||
condition: eq(variables['BuildConfiguration'], 'standalone')
|
||||
|
||||
- script: 'test -d dist'
|
||||
displayName: 'Check Build'
|
||||
|
||||
|
|
43
.eslintrc.js
43
.eslintrc.js
|
@ -27,29 +27,30 @@ module.exports = {
|
|||
'plugin:compat/recommended'
|
||||
],
|
||||
rules: {
|
||||
'block-spacing': ["error"],
|
||||
'brace-style': ["error"],
|
||||
'comma-dangle': ["error", "never"],
|
||||
'comma-spacing': ["error"],
|
||||
'eol-last': ["error"],
|
||||
'indent': ["error", 4, { "SwitchCase": 1 }],
|
||||
'keyword-spacing': ["error"],
|
||||
'max-statements-per-line': ["error"],
|
||||
'no-floating-decimal': ["error"],
|
||||
'no-multi-spaces': ["error"],
|
||||
'no-multiple-empty-lines': ["error", { "max": 1 }],
|
||||
'no-trailing-spaces': ["error"],
|
||||
'one-var': ["error", "never"],
|
||||
'quotes': ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": false }],
|
||||
'semi': ["error"],
|
||||
'space-before-blocks': ["error"],
|
||||
"space-infix-ops": "error"
|
||||
'block-spacing': ['error'],
|
||||
'brace-style': ['error'],
|
||||
'comma-dangle': ['error', 'never'],
|
||||
'comma-spacing': ['error'],
|
||||
'eol-last': ['error'],
|
||||
'indent': ['error', 4, { 'SwitchCase': 1 }],
|
||||
'keyword-spacing': ['error'],
|
||||
'max-statements-per-line': ['error'],
|
||||
'no-floating-decimal': ['error'],
|
||||
'no-multi-spaces': ['error'],
|
||||
'no-multiple-empty-lines': ['error', { 'max': 1 }],
|
||||
'no-trailing-spaces': ['error'],
|
||||
'one-var': ['error', 'never'],
|
||||
'quotes': ['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': false }],
|
||||
'semi': ['error'],
|
||||
'space-before-blocks': ['error'],
|
||||
'space-infix-ops': 'error'
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
'./src/**/*.js'
|
||||
],
|
||||
parser: 'babel-eslint',
|
||||
env: {
|
||||
node: false,
|
||||
amd: true,
|
||||
|
@ -97,11 +98,11 @@ module.exports = {
|
|||
},
|
||||
rules: {
|
||||
// TODO: Fix warnings and remove these rules
|
||||
'no-redeclare': ["warn"],
|
||||
'no-unused-vars': ["warn"],
|
||||
'no-useless-escape': ["warn"],
|
||||
'no-redeclare': ['warn'],
|
||||
'no-unused-vars': ['warn'],
|
||||
'no-useless-escape': ['warn'],
|
||||
// TODO: Remove after ES6 migration is complete
|
||||
'import/no-unresolved': ["off"]
|
||||
'import/no-unresolved': ['off']
|
||||
},
|
||||
settings: {
|
||||
polyfills: [
|
||||
|
|
28
gulpfile.js
28
gulpfile.js
|
@ -16,7 +16,6 @@ const stream = require('webpack-stream');
|
|||
const inject = require('gulp-inject');
|
||||
const postcss = require('gulp-postcss');
|
||||
const sass = require('gulp-sass');
|
||||
const gulpif = require('gulp-if');
|
||||
const lazypipe = require('lazypipe');
|
||||
|
||||
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);
|
||||
|
||||
|
@ -131,18 +130,12 @@ function javascript(query) {
|
|||
.pipe(browserSync.stream());
|
||||
}
|
||||
|
||||
function apploader(standalone) {
|
||||
function task() {
|
||||
function apploader() {
|
||||
return src(options.apploader.query, { base: './src/' })
|
||||
.pipe(gulpif(standalone, concat('scripts/apploader.js')))
|
||||
.pipe(concat('scripts/apploader.js'))
|
||||
.pipe(pipelineJavascript())
|
||||
.pipe(dest('dist/'))
|
||||
.pipe(browserSync.stream());
|
||||
}
|
||||
|
||||
task.displayName = 'apploader';
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
function webpack() {
|
||||
|
@ -181,12 +174,6 @@ function copy(query) {
|
|||
.pipe(browserSync.stream());
|
||||
}
|
||||
|
||||
function copyIndex() {
|
||||
return src(options.injectBundle.query, { base: './src/' })
|
||||
.pipe(dest('dist/'))
|
||||
.pipe(browserSync.stream());
|
||||
}
|
||||
|
||||
function injectBundle() {
|
||||
return src(options.injectBundle.query, { base: './src/' })
|
||||
.pipe(inject(
|
||||
|
@ -196,10 +183,5 @@ function injectBundle() {
|
|||
.pipe(browserSync.stream());
|
||||
}
|
||||
|
||||
function build(standalone) {
|
||||
return series(clean, parallel(javascript, apploader(standalone), webpack, css, html, images, copy));
|
||||
}
|
||||
|
||||
exports.default = series(build(false), copyIndex);
|
||||
exports.standalone = series(build(true), injectBundle);
|
||||
exports.serve = series(exports.standalone, serve);
|
||||
exports.default = series(clean, parallel(javascript, apploader, webpack, css, html, images, copy), injectBundle);
|
||||
exports.serve = series(exports.default, serve);
|
||||
|
|
47
package.json
47
package.json
|
@ -5,21 +5,23 @@
|
|||
"repository": "https://github.com/jellyfin/jellyfin-web",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.9.6",
|
||||
"@babel/core": "^7.10.2",
|
||||
"@babel/plugin-proposal-class-properties": "^7.10.1",
|
||||
"@babel/plugin-proposal-private-methods": "^7.10.1",
|
||||
"@babel/plugin-transform-modules-amd": "^7.9.6",
|
||||
"@babel/polyfill": "^7.8.7",
|
||||
"@babel/preset-env": "^7.8.6",
|
||||
"@babel/preset-env": "^7.10.2",
|
||||
"autoprefixer": "^9.8.0",
|
||||
"babel-eslint": "^11.0.0-beta.2",
|
||||
"babel-loader": "^8.0.6",
|
||||
"browser-sync": "^2.26.7",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"css-loader": "^3.4.2",
|
||||
"cssnano": "^4.1.10",
|
||||
"del": "^5.1.0",
|
||||
"eslint": "^6.8.0",
|
||||
"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-promise": "^4.2.1",
|
||||
"file-loader": "^6.0.0",
|
||||
|
@ -47,18 +49,17 @@
|
|||
"stylelint-no-browser-hacks": "^1.2.1",
|
||||
"stylelint-order": "^4.0.0",
|
||||
"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-stream": "^5.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"alameda": "^1.4.0",
|
||||
"blurhash": "^1.1.3",
|
||||
"classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
|
||||
"core-js": "^3.6.5",
|
||||
"date-fns": "^2.14.0",
|
||||
"document-register-element": "^1.14.3",
|
||||
"epubjs": "^0.3.85",
|
||||
"fast-text-encoding": "^1.0.1",
|
||||
"flv.js": "^1.5.0",
|
||||
"headroom.js": "^0.11.0",
|
||||
|
@ -76,7 +77,7 @@
|
|||
"query-string": "^6.11.1",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"screenfull": "^5.0.2",
|
||||
"shaka-player": "^2.5.11",
|
||||
"shaka-player": "^2.5.12",
|
||||
"sortablejs": "^1.10.2",
|
||||
"swiper": "^5.4.1",
|
||||
"webcomponents.js": "^0.7.24",
|
||||
|
@ -89,34 +90,47 @@
|
|||
"overrides": [
|
||||
{
|
||||
"test": [
|
||||
"src/components/actionSheet/actionSheet.js",
|
||||
"src/components/autoFocuser.js",
|
||||
"src/components/cardbuilder/cardBuilder.js",
|
||||
"src/scripts/fileDownloader.js",
|
||||
"src/components/images/imageLoader.js",
|
||||
"src/components/indicators/indicators.js",
|
||||
"src/components/lazyLoader/lazyLoaderIntersectionObserver.js",
|
||||
"src/components/playback/brightnessosd.js",
|
||||
"src/components/playback/mediasession.js",
|
||||
"src/components/playback/nowplayinghelper.js",
|
||||
"src/components/playback/playbackorientation.js",
|
||||
"src/components/playback/playerSelectionMenu.js",
|
||||
"src/components/playback/playersettingsmenu.js",
|
||||
"src/components/playback/playmethodhelper.js",
|
||||
"src/components/playback/remotecontrolautoplay.js",
|
||||
"src/components/playback/volumeosd.js",
|
||||
"src/components/playmenu.js",
|
||||
"src/components/sanatizefilename.js",
|
||||
"src/components/scrollManager.js",
|
||||
"src/components/syncplay/playbackPermissionManager.js",
|
||||
"src/components/syncplay/groupSelectionMenu.js",
|
||||
"src/components/syncplay/timeSyncManager.js",
|
||||
"src/components/syncplay/playbackPermissionManager.js",
|
||||
"src/components/syncplay/syncPlayManager.js",
|
||||
"src/components/syncplay/timeSyncManager.js",
|
||||
"src/plugins/bookPlayer/plugin.js",
|
||||
"src/plugins/bookPlayer/tableOfContent.js",
|
||||
"src/plugins/photoPlayer/plugin.js",
|
||||
"src/scripts/deleteHelper.js",
|
||||
"src/scripts/dfnshelper.js",
|
||||
"src/scripts/dom.js",
|
||||
"src/scripts/fileDownloader.js",
|
||||
"src/scripts/filesystem.js",
|
||||
"src/scripts/imagehelper.js",
|
||||
"src/scripts/inputManager.js",
|
||||
"src/scripts/deleteHelper.js",
|
||||
"src/components/actionSheet/actionSheet.js",
|
||||
"src/components/playmenu.js",
|
||||
"src/components/indicators/indicators.js",
|
||||
"src/scripts/keyboardNavigation.js",
|
||||
"src/scripts/settings/appSettings.js",
|
||||
"src/scripts/settings/userSettings.js",
|
||||
"src/scripts/settings/webSettings.js"
|
||||
],
|
||||
"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",
|
||||
"build:development": "gulp --development",
|
||||
"build:production": "gulp --production",
|
||||
"build:standalone": "gulp standalone --development",
|
||||
"lint": "eslint \".\"",
|
||||
"stylelint": "stylelint \"src/**/*.css\""
|
||||
}
|
||||
|
|
|
@ -1144,3 +1144,21 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards {
|
|||
margin-top: 0;
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
.overview-controls {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.detail-clamp-text {
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 12;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
@media all and (min-width: 40em) {
|
||||
.detail-clamp-text {
|
||||
-webkit-line-clamp: 6;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,12 @@ _define('fetch', function() {
|
|||
return fetch;
|
||||
});
|
||||
|
||||
// Blurhash
|
||||
var blurhash = require('blurhash');
|
||||
_define('blurhash', function() {
|
||||
return blurhash;
|
||||
});
|
||||
|
||||
// query-string
|
||||
var query = require('query-string');
|
||||
_define('queryString', function() {
|
||||
|
@ -102,6 +108,11 @@ _define('jellyfin-noto', function () {
|
|||
return noto;
|
||||
});
|
||||
|
||||
var epubjs = require('epubjs');
|
||||
_define('epubjs', function () {
|
||||
return epubjs;
|
||||
});
|
||||
|
||||
// page.js
|
||||
var page = require('page');
|
||||
_define('page', function() {
|
||||
|
|
|
@ -72,12 +72,12 @@ define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-butt
|
|||
reject();
|
||||
}
|
||||
});
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
dlg.querySelector('form').addEventListener('submit', function (e) {
|
||||
dlg.querySelector('form').addEventListener('submit', function (event) {
|
||||
submitSchedule(dlg, options);
|
||||
e.preventDefault();
|
||||
event.preventDefault();
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
|
|
@ -16,15 +16,8 @@ function getOffsets(elems) {
|
|||
return results;
|
||||
}
|
||||
|
||||
let box;
|
||||
for (let elem of elems) {
|
||||
// Support: BlackBerry 5, iOS 3 (original iPhone)
|
||||
// If we don't have gBCR, just use 0,0 rather than error
|
||||
if (elem.getBoundingClientRect) {
|
||||
box = elem.getBoundingClientRect();
|
||||
} else {
|
||||
box = { top: 0, left: 0 };
|
||||
}
|
||||
let box = elem.getBoundingClientRect();
|
||||
|
||||
results.push({
|
||||
top: box.top,
|
||||
|
@ -153,7 +146,9 @@ export function show(options) {
|
|||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
html += '<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
|
||||
|
@ -216,7 +211,7 @@ export function show(options) {
|
|||
itemIcon = icons[i];
|
||||
|
||||
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) {
|
||||
html += '<span class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons check" style="visibility:hidden;"></span>';
|
||||
}
|
||||
|
@ -228,13 +223,13 @@ export function show(options) {
|
|||
html += '</div>';
|
||||
|
||||
if (item.secondaryText) {
|
||||
html += '<div class="listItemBodyText secondary">' + item.secondaryText + '</div>';
|
||||
html += `<div class="listItemBodyText secondary">${item.secondaryText}</div>`;
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
if (item.asideText) {
|
||||
html += '<div class="listItemAside actionSheetItemAsideText">' + item.asideText + '</div>';
|
||||
html += `<div class="listItemAside actionSheetItemAsideText">${item.asideText}</div>`;
|
||||
}
|
||||
|
||||
html += '</button>';
|
||||
|
@ -242,7 +237,7 @@ export function show(options) {
|
|||
|
||||
if (options.showCancel) {
|
||||
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>';
|
||||
|
|
|
@ -34,10 +34,14 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
|
|||
html += '</div>';
|
||||
|
||||
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) {
|
||||
|
|
|
@ -26,11 +26,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro
|
|||
connectionManager.connect({
|
||||
enableAutoLogin: appSettings.enableAutoLogin()
|
||||
}).then(function (result) {
|
||||
handleConnectionResult(result, loading);
|
||||
handleConnectionResult(result);
|
||||
});
|
||||
}
|
||||
|
||||
function handleConnectionResult(result, loading) {
|
||||
function handleConnectionResult(result) {
|
||||
switch (result.State) {
|
||||
case 'SignedIn':
|
||||
loading.hide();
|
||||
|
@ -246,13 +246,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro
|
|||
}
|
||||
|
||||
if (setQuality) {
|
||||
|
||||
var quality = 100;
|
||||
|
||||
var quality;
|
||||
var type = options.type || 'Primary';
|
||||
|
||||
if (browser.tv || browser.slow) {
|
||||
|
||||
// TODO: wtf
|
||||
if (browser.chrome) {
|
||||
// webp support
|
||||
quality = type === 'Primary' ? 40 : 50;
|
||||
|
@ -384,7 +382,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro
|
|||
|
||||
if (firstResult.State !== 'SignedIn' && !route.anonymous) {
|
||||
|
||||
handleConnectionResult(firstResult, loading);
|
||||
handleConnectionResult(firstResult);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -463,7 +461,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro
|
|||
return Promise.resolve();
|
||||
}
|
||||
|
||||
var isHandlingBackToDefault;
|
||||
var isDummyBackToHome;
|
||||
|
||||
function loadContent(ctx, route, html, request) {
|
||||
|
@ -589,8 +586,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro
|
|||
path = '/' + path;
|
||||
}
|
||||
|
||||
var baseRoute = baseUrl();
|
||||
path = path.replace(baseRoute, '');
|
||||
path = path.replace(baseUrl(), '');
|
||||
|
||||
if (currentRouteInfo && currentRouteInfo.path === path) {
|
||||
// can't use this with home right now due to the back menu
|
||||
|
@ -621,10 +617,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro
|
|||
}
|
||||
|
||||
function showItem(item, serverId, options) {
|
||||
// TODO: Refactor this so it only gets items, not strings.
|
||||
if (typeof (item) === 'string') {
|
||||
var apiClient = serverId ? connectionManager.getApiClient(serverId) : connectionManager.currentApiClient();
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), item).then(function (item) {
|
||||
appRouter.showItem(item, options);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), item).then(function (itemObject) {
|
||||
appRouter.showItem(itemObject, options);
|
||||
});
|
||||
} else {
|
||||
if (arguments.length === 2) {
|
||||
|
|
|
@ -5,7 +5,7 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
var disableHlsVideoAudioCodecs = [];
|
||||
|
||||
if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) {
|
||||
if (browser.edge || browser.msie) {
|
||||
if (browser.edge) {
|
||||
disableHlsVideoAudioCodecs.push('mp3');
|
||||
}
|
||||
|
||||
|
@ -93,19 +93,37 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
|
||||
function getDeviceName() {
|
||||
var deviceName;
|
||||
deviceName = browser.tizen ? 'Samsung Smart TV' : browser.web0s ? 'LG Smart TV' : browser.operaTv ? 'Opera TV' : browser.xboxOne ? 'Xbox One' : browser.ps4 ? 'Sony PS4' : browser.chrome ? 'Chrome' : browser.edge ? 'Edge' : browser.firefox ? 'Firefox' : browser.msie ? 'Internet Explorer' : browser.opera ? 'Opera' : browser.safari ? 'Safari' : 'Web Browser';
|
||||
if (browser.tizen) {
|
||||
deviceName = 'Samsung Smart TV';
|
||||
} else if (browser.web0s) {
|
||||
deviceName = 'LG Smart TV';
|
||||
} else if (browser.operaTv) {
|
||||
deviceName = 'Opera TV';
|
||||
} else if (browser.xboxOne) {
|
||||
deviceName = 'Xbox One';
|
||||
} else if (browser.ps4) {
|
||||
deviceName = 'Sony PS4';
|
||||
} else if (browser.chrome) {
|
||||
deviceName = 'Chrome';
|
||||
} else if (browser.edge) {
|
||||
deviceName = 'Edge';
|
||||
} else if (browser.firefox) {
|
||||
deviceName = 'Firefox';
|
||||
} else if (browser.opera) {
|
||||
deviceName = 'Opera';
|
||||
} else if (browser.safari) {
|
||||
deviceName = 'Safari';
|
||||
} else {
|
||||
deviceName = 'Web Browser';
|
||||
}
|
||||
|
||||
if (browser.ipad) {
|
||||
deviceName += ' iPad';
|
||||
} else {
|
||||
if (browser.iphone) {
|
||||
} else if (browser.iphone) {
|
||||
deviceName += ' iPhone';
|
||||
} else {
|
||||
if (browser.android) {
|
||||
} else if (browser.android) {
|
||||
deviceName += ' Android';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deviceName;
|
||||
}
|
||||
|
@ -267,7 +285,7 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
if (enabled) features.push('multiserver');
|
||||
});
|
||||
|
||||
if (!browser.orsay && !browser.msie && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) {
|
||||
if (!browser.orsay && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) {
|
||||
features.push('subtitleappearancesettings');
|
||||
}
|
||||
|
||||
|
|
|
@ -503,94 +503,49 @@ import 'programStyles';
|
|||
const primaryImageAspectRatio = item.PrimaryImageAspectRatio;
|
||||
let forceName = false;
|
||||
let imgUrl = null;
|
||||
let imgTag = null;
|
||||
let coverImage = false;
|
||||
let uiAspect = null;
|
||||
let imgType = null;
|
||||
let itemId = null;
|
||||
|
||||
if (options.preferThumb && item.ImageTags && item.ImageTags.Thumb) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Thumb',
|
||||
maxWidth: width,
|
||||
tag: item.ImageTags.Thumb
|
||||
});
|
||||
|
||||
imgType = 'Thumb';
|
||||
imgTag = item.ImageTags.Thumb;
|
||||
} else if ((options.preferBanner || shape === 'banner') && item.ImageTags && item.ImageTags.Banner) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Banner',
|
||||
maxWidth: width,
|
||||
tag: item.ImageTags.Banner
|
||||
});
|
||||
|
||||
imgType = 'Banner';
|
||||
imgTag = item.ImageTags.Banner;
|
||||
} else if (options.preferDisc && item.ImageTags && item.ImageTags.Disc) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Disc',
|
||||
maxWidth: width,
|
||||
tag: item.ImageTags.Disc
|
||||
});
|
||||
|
||||
imgType = 'Disc';
|
||||
imgTag = item.ImageTags.Disc;
|
||||
} else if (options.preferLogo && item.ImageTags && item.ImageTags.Logo) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Logo',
|
||||
maxWidth: width,
|
||||
tag: item.ImageTags.Logo
|
||||
});
|
||||
|
||||
imgType = 'Logo';
|
||||
imgTag = item.ImageTags.Logo;
|
||||
} else if (options.preferLogo && item.ParentLogoImageTag && item.ParentLogoItemId) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.ParentLogoItemId, {
|
||||
type: 'Logo',
|
||||
maxWidth: width,
|
||||
tag: item.ParentLogoImageTag
|
||||
});
|
||||
|
||||
imgType = 'Logo';
|
||||
imgTag = item.ParentLogoImageTag;
|
||||
itemId = item.ParentLogoItemId;
|
||||
} else if (options.preferThumb && item.SeriesThumbImageTag && options.inheritThumb !== false) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.SeriesId, {
|
||||
type: 'Thumb',
|
||||
maxWidth: width,
|
||||
tag: item.SeriesThumbImageTag
|
||||
});
|
||||
|
||||
imgType = 'Thumb';
|
||||
imgTag = item.SeriesThumbImageTag;
|
||||
itemId = item.SeriesId;
|
||||
} else if (options.preferThumb && item.ParentThumbItemId && options.inheritThumb !== false && item.MediaType !== 'Photo') {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, {
|
||||
type: 'Thumb',
|
||||
maxWidth: width,
|
||||
tag: item.ParentThumbImageTag
|
||||
});
|
||||
|
||||
imgType = 'Thumb';
|
||||
imgTag = item.ParentThumbImageTag;
|
||||
itemId = item.ParentThumbItemId;
|
||||
} else if (options.preferThumb && item.BackdropImageTags && item.BackdropImageTags.length) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Backdrop',
|
||||
maxWidth: width,
|
||||
tag: item.BackdropImageTags[0]
|
||||
});
|
||||
|
||||
imgType = 'Backdrop';
|
||||
imgTag = item.BackdropImageTags[0];
|
||||
forceName = true;
|
||||
|
||||
} else if (options.preferThumb && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false && item.Type === 'Episode') {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, {
|
||||
type: 'Backdrop',
|
||||
maxWidth: width,
|
||||
tag: item.ParentBackdropImageTags[0]
|
||||
});
|
||||
|
||||
imgType = 'Backdrop';
|
||||
imgTag = item.ParentBackdropImageTags[0];
|
||||
itemId = item.ParentBackdropItemId;
|
||||
} else if (item.ImageTags && item.ImageTags.Primary) {
|
||||
|
||||
imgType = 'Primary';
|
||||
imgTag = item.ImageTags.Primary;
|
||||
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Primary',
|
||||
maxHeight: height,
|
||||
maxWidth: width,
|
||||
tag: item.ImageTags.Primary
|
||||
});
|
||||
|
||||
if (options.preferThumb && options.showTitle !== false) {
|
||||
forceName = true;
|
||||
}
|
||||
|
@ -603,16 +558,11 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
} else if (item.PrimaryImageTag) {
|
||||
|
||||
imgType = 'Primary';
|
||||
imgTag = item.PrimaryImageTag;
|
||||
itemId = item.PrimaryImageItemId;
|
||||
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.PrimaryImageItemId || item.Id || item.ItemId, {
|
||||
type: 'Primary',
|
||||
maxHeight: height,
|
||||
maxWidth: width,
|
||||
tag: item.PrimaryImageTag
|
||||
});
|
||||
|
||||
if (options.preferThumb && options.showTitle !== false) {
|
||||
forceName = true;
|
||||
}
|
||||
|
@ -624,30 +574,19 @@ import 'programStyles';
|
|||
}
|
||||
}
|
||||
} else if (item.ParentPrimaryImageTag) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, {
|
||||
type: 'Primary',
|
||||
maxWidth: width,
|
||||
tag: item.ParentPrimaryImageTag
|
||||
});
|
||||
imgType = 'Primary';
|
||||
imgTag = item.ParentPrimaryImageTag;
|
||||
itemId = item.ParentPrimaryImageItemId;
|
||||
} else if (item.SeriesPrimaryImageTag) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.SeriesId, {
|
||||
type: 'Primary',
|
||||
maxWidth: width,
|
||||
tag: item.SeriesPrimaryImageTag
|
||||
});
|
||||
imgType = 'Primary';
|
||||
imgTag = item.SeriesPrimaryImageTag;
|
||||
itemId = item.SeriesId;
|
||||
} else if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
|
||||
imgType = 'Primary';
|
||||
imgTag = item.AlbumPrimaryImageTag;
|
||||
itemId = item.AlbumId;
|
||||
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.AlbumId, {
|
||||
type: 'Primary',
|
||||
maxHeight: height,
|
||||
maxWidth: width,
|
||||
tag: item.AlbumPrimaryImageTag
|
||||
});
|
||||
|
||||
if (primaryImageAspectRatio) {
|
||||
uiAspect = getDesiredAspect(shape);
|
||||
if (uiAspect) {
|
||||
|
@ -655,57 +594,46 @@ import 'programStyles';
|
|||
}
|
||||
}
|
||||
} else if (item.Type === 'Season' && item.ImageTags && item.ImageTags.Thumb) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Thumb',
|
||||
maxWidth: width,
|
||||
tag: item.ImageTags.Thumb
|
||||
});
|
||||
|
||||
imgType = 'Thumb';
|
||||
imgTag = item.ImageTags.Thumb;
|
||||
} else if (item.BackdropImageTags && item.BackdropImageTags.length) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Backdrop',
|
||||
maxWidth: width,
|
||||
tag: item.BackdropImageTags[0]
|
||||
});
|
||||
|
||||
imgType = 'Backdrop';
|
||||
imgTag = item.BackdropImageTags[0];
|
||||
} else if (item.ImageTags && item.ImageTags.Thumb) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Thumb',
|
||||
maxWidth: width,
|
||||
tag: item.ImageTags.Thumb
|
||||
});
|
||||
|
||||
imgType = 'Thumb';
|
||||
imgTag = item.ImageTags.Thumb;
|
||||
} else if (item.SeriesThumbImageTag && options.inheritThumb !== false) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.SeriesId, {
|
||||
type: 'Thumb',
|
||||
maxWidth: width,
|
||||
tag: item.SeriesThumbImageTag
|
||||
});
|
||||
|
||||
imgType = 'Thumb';
|
||||
imgTag = item.SeriesThumbImageTag;
|
||||
itemId = item.SeriesId;
|
||||
} else if (item.ParentThumbItemId && options.inheritThumb !== false) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, {
|
||||
type: 'Thumb',
|
||||
maxWidth: width,
|
||||
tag: item.ParentThumbImageTag
|
||||
});
|
||||
|
||||
imgType = 'Thumb';
|
||||
imgTag = item.ParentThumbImageTag;
|
||||
itemId = item.ParentThumbItemId;
|
||||
} else if (item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, {
|
||||
type: 'Backdrop',
|
||||
maxWidth: width,
|
||||
tag: item.ParentBackdropImageTags[0]
|
||||
});
|
||||
|
||||
imgType = 'Backdrop';
|
||||
imgTag = item.ParentBackdropImageTags[0];
|
||||
itemId = item.ParentBackdropItemId;
|
||||
}
|
||||
|
||||
if (!itemId) {
|
||||
itemId = item.Id;
|
||||
}
|
||||
|
||||
if (imgTag && imgType) {
|
||||
imgUrl = apiClient.getScaledImageUrl(itemId, {
|
||||
type: imgType,
|
||||
maxHeight: height,
|
||||
maxWidth: width,
|
||||
tag: imgTag
|
||||
});
|
||||
}
|
||||
|
||||
let blurHashes = options.imageBlurhashes || item.ImageBlurHashes || {};
|
||||
|
||||
return {
|
||||
imgUrl: imgUrl,
|
||||
blurhash: (blurHashes[imgType] || {})[imgTag],
|
||||
forceName: forceName,
|
||||
coverImage: coverImage
|
||||
};
|
||||
|
@ -1321,6 +1249,7 @@ import 'programStyles';
|
|||
|
||||
const imgInfo = getCardImageUrl(item, apiClient, options, shape);
|
||||
const imgUrl = imgInfo.imgUrl;
|
||||
const blurhash = imgInfo.blurhash;
|
||||
|
||||
const forceName = imgInfo.forceName;
|
||||
|
||||
|
@ -1445,15 +1374,20 @@ import 'programStyles';
|
|||
cardContentClass += ' cardContent-shadow';
|
||||
}
|
||||
|
||||
let blurhashAttrib = '';
|
||||
if (blurhash && blurhash.length > 0) {
|
||||
blurhashAttrib = 'data-blurhash="' + blurhash + '"';
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
|
||||
// Don't use the IMG tag with safari because it puts a white border around it
|
||||
cardImageContainerOpen = imgUrl ? ('<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>';
|
||||
} else {
|
||||
// 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>';
|
||||
}
|
||||
|
|
|
@ -181,6 +181,7 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
|||
context.querySelector('#chkThemeSong').checked = userSettings.enableThemeSongs();
|
||||
context.querySelector('#chkThemeVideo').checked = userSettings.enableThemeVideos();
|
||||
context.querySelector('#chkFadein').checked = userSettings.enableFastFadein();
|
||||
context.querySelector('#chkBlurhash').checked = userSettings.enableBlurhash();
|
||||
context.querySelector('#chkBackdrops').checked = userSettings.enableBackdrops();
|
||||
context.querySelector('#chkDetailsBanner').checked = userSettings.detailsBanner();
|
||||
|
||||
|
@ -223,6 +224,7 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
|||
userSettingsInstance.skin(context.querySelector('.selectSkin').value);
|
||||
|
||||
userSettingsInstance.enableFastFadein(context.querySelector('#chkFadein').checked);
|
||||
userSettingsInstance.enableBlurhash(context.querySelector('#chkBlurhash').checked);
|
||||
userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked);
|
||||
userSettingsInstance.detailsBanner(context.querySelector('#chkDetailsBanner').checked);
|
||||
|
||||
|
|
|
@ -143,20 +143,28 @@
|
|||
<select is="emby-select" class="selectSoundEffects" label="${LabelSoundEffects}"></select>
|
||||
</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}" />
|
||||
<div class="fieldDescription">${LabelLibraryPageSizeHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldFadein">
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkFadein" />
|
||||
<span>${EnableFastImageFadeIn}</span>
|
||||
<span>${EnableFasterAnimations}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableFastImageFadeInHelp}</div>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableFasterAnimationsHelp}</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>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkDetailsBanner" />
|
||||
<span>${EnableDetailsBanner}</span>
|
||||
|
|
|
@ -229,7 +229,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
|||
|
||||
var options = {
|
||||
Limit: limit,
|
||||
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo',
|
||||
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo,Path',
|
||||
ImageTypeLimit: 1,
|
||||
EnableImageTypes: 'Primary,Backdrop,Thumb',
|
||||
ParentId: parentId
|
||||
|
@ -667,7 +667,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
|||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
return apiClient.getNextUpEpisodes({
|
||||
Limit: enableScrollX() ? 24 : 15,
|
||||
Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo',
|
||||
Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo,Path',
|
||||
UserId: apiClient.getCurrentUserId(),
|
||||
ImageTypeLimit: 1,
|
||||
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as lazyLoader from 'lazyLoader';
|
||||
import * as userSettings from 'userSettings';
|
||||
import * as blurhash from 'blurhash';
|
||||
import 'css!./style';
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
@ -11,47 +12,111 @@ import 'css!./style';
|
|||
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) {
|
||||
if (!entry) {
|
||||
throw new Error('entry cannot be null');
|
||||
}
|
||||
|
||||
let target = entry.target;
|
||||
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 {
|
||||
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 (source) fillImageElement(entry.target, source);
|
||||
if (source) fillImageElement(target, source);
|
||||
} else if (!source) {
|
||||
emptyImageElement(entry.target);
|
||||
emptyImageElement(target);
|
||||
}
|
||||
}
|
||||
|
||||
function fillImageElement(elem, url) {
|
||||
if (url === undefined) {
|
||||
throw new Error('url cannot be undefined');
|
||||
throw new TypeError('url cannot be undefined');
|
||||
}
|
||||
|
||||
let preloaderImg = new Image();
|
||||
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', () => {
|
||||
if (elem.tagName !== 'IMG') {
|
||||
elem.style.backgroundImage = "url('" + url + "')";
|
||||
} else {
|
||||
elem.setAttribute('src', url);
|
||||
}
|
||||
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');
|
||||
}
|
||||
|
||||
elem.removeAttribute('data-src');
|
||||
} else {
|
||||
switchCanvas(elem);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -65,11 +130,14 @@ import 'css!./style';
|
|||
url = elem.getAttribute('src');
|
||||
elem.setAttribute('src', '');
|
||||
}
|
||||
|
||||
elem.setAttribute('data-src', url);
|
||||
|
||||
elem.classList.remove('lazy-image-fadein-fast');
|
||||
elem.classList.remove('lazy-image-fadein');
|
||||
if (elem.classList.contains('non-blurhashable') || !userSettings.enableBlurhash()) {
|
||||
elem.classList.remove('lazy-image-fadein-fast', 'lazy-image-fadein');
|
||||
elem.classList.add('lazy-hidden');
|
||||
} else {
|
||||
switchCanvas(elem);
|
||||
}
|
||||
}
|
||||
|
||||
export function lazyChildren(elem) {
|
||||
|
|
|
@ -1,13 +1,32 @@
|
|||
.cardImageContainer.lazy {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.cardImageContainer.lazy.lazy-image-fadein {
|
||||
.lazy-image-fadein {
|
||||
opacity: 1;
|
||||
transition: opacity 0.7s;
|
||||
}
|
||||
|
||||
.cardImageContainer.lazy.lazy-image-fadein-fast {
|
||||
.lazy-image-fadein-fast {
|
||||
opacity: 1;
|
||||
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 += '</h3>';
|
||||
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>';
|
||||
|
|
|
@ -79,7 +79,7 @@
|
|||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription chkAutomaticallyGroupSeriesContainer hide advanced">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkAutomaticallyGroupSeries" checked />
|
||||
<input type="checkbox" is="emby-checkbox" class="chkAutomaticallyGroupSeries" />
|
||||
<span>${OptionAutomaticallyGroupSeries}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${OptionAutomaticallyGroupSeriesHelp}</div>
|
||||
|
|
|
@ -70,6 +70,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
|||
function getImageUrl(item, width) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
let itemId;
|
||||
|
||||
var options = {
|
||||
maxWidth: width * 2,
|
||||
|
@ -77,45 +78,45 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
|||
};
|
||||
|
||||
if (item.ImageTags && item.ImageTags.Primary) {
|
||||
|
||||
options.tag = item.ImageTags.Primary;
|
||||
return apiClient.getScaledImageUrl(item.Id, options);
|
||||
itemId = item.Id;
|
||||
}
|
||||
|
||||
if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
|
||||
options.tag = item.AlbumPrimaryImageTag;
|
||||
return apiClient.getScaledImageUrl(item.AlbumId, options);
|
||||
itemId = item.AlbumId;
|
||||
} else if (item.SeriesId && item.SeriesPrimaryImageTag) {
|
||||
|
||||
options.tag = item.SeriesPrimaryImageTag;
|
||||
return apiClient.getScaledImageUrl(item.SeriesId, options);
|
||||
|
||||
itemId = item.SeriesId;
|
||||
} else if (item.ParentPrimaryImageTag) {
|
||||
|
||||
options.tag = item.ParentPrimaryImageTag;
|
||||
return apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, options);
|
||||
itemId = item.ParentPrimaryImageItemId;
|
||||
}
|
||||
let blurHashes = item.ImageBlurHashes || {};
|
||||
let blurhashstr = (blurHashes[options.type] || {})[options.tag];
|
||||
|
||||
return null;
|
||||
if (itemId) {
|
||||
return { url: apiClient.getScaledImageUrl(itemId, options), blurhash: blurhashstr };
|
||||
}
|
||||
}
|
||||
|
||||
function getChannelImageUrl(item, width) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
var options = {
|
||||
maxWidth: width * 2,
|
||||
type: 'Primary'
|
||||
};
|
||||
|
||||
if (item.ChannelId && item.ChannelPrimaryImageTag) {
|
||||
|
||||
options.tag = item.ChannelPrimaryImageTag;
|
||||
return apiClient.getScaledImageUrl(item.ChannelId, options);
|
||||
}
|
||||
let blurHashes = item.ImageBlurHashes || {};
|
||||
let blurhashstr = (blurHashes[options.type])[options.tag];
|
||||
|
||||
return null;
|
||||
if (item.ChannelId) {
|
||||
return { url: apiClient.getScaledImageUrl(item.ChannelId, options), blurhash: blurhashstr };
|
||||
}
|
||||
}
|
||||
|
||||
function getTextLinesHtml(textlines, isLargeStyle) {
|
||||
|
@ -268,8 +269,10 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
|||
}
|
||||
|
||||
if (options.image !== false) {
|
||||
var imgUrl = options.imageSource === 'channel' ? getChannelImageUrl(item, downloadWidth) : getImageUrl(item, downloadWidth);
|
||||
var imageClass = isLargeStyle ? 'listItemImage listItemImage-large' : 'listItemImage';
|
||||
let imgData = options.imageSource === 'channel' ? getChannelImageUrl(item, downloadWidth) : getImageUrl(item, downloadWidth);
|
||||
let imgUrl = imgData.url;
|
||||
let blurhash = imgData.blurhash;
|
||||
let imageClass = isLargeStyle ? 'listItemImage listItemImage-large' : 'listItemImage';
|
||||
|
||||
if (isLargeStyle && layoutManager.tv) {
|
||||
imageClass += ' listItemImage-large-tv';
|
||||
|
@ -283,8 +286,13 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
|||
|
||||
var imageAction = playOnImageClick ? 'resume' : action;
|
||||
|
||||
let blurhashAttrib = '';
|
||||
if (blurhash && blurhash.length > 0) {
|
||||
blurhashAttrib = 'data-blurhash="' + blurhash + '"';
|
||||
}
|
||||
|
||||
if (imgUrl) {
|
||||
html += '<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 {
|
||||
html += '<div class="' + imageClass + '">';
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
|
|||
function showNonPersistentNotification(title, options, timeoutMs) {
|
||||
|
||||
try {
|
||||
var notif = new Notification(title, options);
|
||||
var notif = new Notification(title, options); /* eslint-disable-line compat/compat */
|
||||
|
||||
if (notif.show) {
|
||||
notif.show();
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'material-icons'], function (events, playbackManager, dom, browser) {
|
||||
'use strict';
|
||||
import events from 'events';
|
||||
import playbackManager from 'playbackManager';
|
||||
import dom from 'dom';
|
||||
import browser from 'browser';
|
||||
import 'css!./iconosd';
|
||||
import 'material-icons';
|
||||
|
||||
var currentPlayer;
|
||||
var osdElement;
|
||||
var iconElement;
|
||||
var progressElement;
|
||||
var currentPlayer;
|
||||
var osdElement;
|
||||
var iconElement;
|
||||
var progressElement;
|
||||
|
||||
var enableAnimation;
|
||||
var enableAnimation;
|
||||
|
||||
function getOsdElementHtml() {
|
||||
function getOsdElementHtml() {
|
||||
var html = '';
|
||||
|
||||
html += '<span class="material-icons iconOsdIcon brightness_high"></span>';
|
||||
|
@ -16,9 +20,9 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
html += '<div class="iconOsdProgressOuter"><div class="iconOsdProgressInner brightnessOsdProgressInner"></div></div>';
|
||||
|
||||
return html;
|
||||
}
|
||||
}
|
||||
|
||||
function ensureOsdElement() {
|
||||
function ensureOsdElement() {
|
||||
|
||||
var elem = osdElement;
|
||||
if (!elem) {
|
||||
|
@ -38,14 +42,14 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
document.body.appendChild(elem);
|
||||
osdElement = elem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onHideComplete() {
|
||||
function onHideComplete() {
|
||||
this.classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
var hideTimeout;
|
||||
function showOsd() {
|
||||
var hideTimeout;
|
||||
function showOsd() {
|
||||
|
||||
clearHideTimeout();
|
||||
|
||||
|
@ -65,16 +69,16 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
|
||||
hideTimeout = setTimeout(hideOsd, 3000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function clearHideTimeout() {
|
||||
function clearHideTimeout() {
|
||||
if (hideTimeout) {
|
||||
clearTimeout(hideTimeout);
|
||||
hideTimeout = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function hideOsd() {
|
||||
function hideOsd() {
|
||||
|
||||
clearHideTimeout();
|
||||
|
||||
|
@ -96,16 +100,14 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
onHideComplete.call(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setIcon(iconElement, icon) {
|
||||
iconElement.classList.remove('brightness_high');
|
||||
iconElement.classList.remove('brightness_medium');
|
||||
iconElement.classList.remove('brightness_low');
|
||||
function setIcon(iconElement, icon) {
|
||||
iconElement.classList.remove('brightness_high', 'brightness_medium', 'brightness_low');
|
||||
iconElement.classList.add(icon);
|
||||
}
|
||||
}
|
||||
|
||||
function updateElementsFromPlayer(brightness) {
|
||||
function updateElementsFromPlayer(brightness) {
|
||||
|
||||
if (iconElement) {
|
||||
if (brightness >= 80) {
|
||||
|
@ -119,9 +121,9 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
if (progressElement) {
|
||||
progressElement.style.width = (brightness || 0) + '%';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
function releaseCurrentPlayer() {
|
||||
|
||||
var player = currentPlayer;
|
||||
|
||||
|
@ -130,9 +132,9 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
events.off(player, 'playbackstop', hideOsd);
|
||||
currentPlayer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onBrightnessChanged(e) {
|
||||
function onBrightnessChanged(e) {
|
||||
|
||||
var player = this;
|
||||
|
||||
|
@ -141,9 +143,9 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
updateElementsFromPlayer(playbackManager.getBrightness(player));
|
||||
|
||||
showOsd();
|
||||
}
|
||||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
function bindToPlayer(player) {
|
||||
|
||||
if (player === currentPlayer) {
|
||||
return;
|
||||
|
@ -160,12 +162,10 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
hideOsd();
|
||||
events.on(player, 'brightnesschange', onBrightnessChanged);
|
||||
events.on(player, 'playbackstop', hideOsd);
|
||||
}
|
||||
}
|
||||
|
||||
events.on(playbackManager, 'playerchange', function () {
|
||||
events.on(playbackManager, 'playerchange', function () {
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
});
|
||||
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
|
||||
});
|
||||
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
|
|
|
@ -119,6 +119,7 @@ import connectionManager from 'connectionManager';
|
|||
const canSeek = playState.CanSeek || false;
|
||||
|
||||
if ('mediaSession' in navigator) {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
navigator.mediaSession.metadata = new MediaMetadata({
|
||||
title: title,
|
||||
artist: artist,
|
||||
|
@ -179,6 +180,7 @@ import connectionManager from 'connectionManager';
|
|||
|
||||
function hideMediaControls() {
|
||||
if ('mediaSession' in navigator) {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
navigator.mediaSession.metadata = null;
|
||||
} else {
|
||||
window.NativeShell.hideMediaSession();
|
||||
|
@ -210,26 +212,32 @@ import connectionManager from 'connectionManager';
|
|||
}
|
||||
|
||||
if ('mediaSession' in navigator) {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
navigator.mediaSession.setActionHandler('previoustrack', function () {
|
||||
execute('previousTrack');
|
||||
});
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
navigator.mediaSession.setActionHandler('nexttrack', function () {
|
||||
execute('nextTrack');
|
||||
});
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
navigator.mediaSession.setActionHandler('play', function () {
|
||||
execute('unpause');
|
||||
});
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
navigator.mediaSession.setActionHandler('pause', function () {
|
||||
execute('pause');
|
||||
});
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
navigator.mediaSession.setActionHandler('seekbackward', function () {
|
||||
execute('rewind');
|
||||
});
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
navigator.mediaSession.setActionHandler('seekforward', function () {
|
||||
execute('fastForward');
|
||||
});
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
|
||||
export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
|
||||
|
||||
var topItem = nowPlayingItem;
|
||||
var bottomItem = null;
|
||||
|
@ -78,9 +75,8 @@ define([], function () {
|
|||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
export default {
|
||||
getNowPlayingNames: getNowPlayingNames
|
||||
};
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1129,7 +1129,6 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
}
|
||||
|
||||
self.canPlay = function (item) {
|
||||
|
||||
var itemType = item.Type;
|
||||
|
||||
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 (!item.EndDate || !item.StartDate) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2187,7 +2185,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
// Only used internally
|
||||
self.getCurrentTicks = getCurrentTicks;
|
||||
|
||||
function playPhotos(items, options, user) {
|
||||
function playOther(items, options, user) {
|
||||
|
||||
var playStartIndex = options.startIndex || 0;
|
||||
var player = getPlayer(items[playStartIndex], options);
|
||||
|
@ -2216,9 +2214,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
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);
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
define(['playbackManager', 'layoutManager', 'events'], function (playbackManager, layoutManager, events) {
|
||||
'use strict';
|
||||
import playbackManager from 'playbackManager';
|
||||
import layoutManager from 'layoutManager';
|
||||
import events from 'events';
|
||||
|
||||
var orientationLocked;
|
||||
var orientationLocked;
|
||||
|
||||
function onOrientationChangeSuccess() {
|
||||
function onOrientationChangeSuccess() {
|
||||
orientationLocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
function onOrientationChangeError(err) {
|
||||
function onOrientationChangeError(err) {
|
||||
orientationLocked = false;
|
||||
console.error('error locking orientation: ' + err);
|
||||
}
|
||||
}
|
||||
|
||||
events.on(playbackManager, 'playbackstart', function (e, player, state) {
|
||||
events.on(playbackManager, 'playbackstart', function (e, player, state) {
|
||||
|
||||
var isLocalVideo = player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player);
|
||||
|
||||
|
@ -35,9 +36,9 @@ define(['playbackManager', 'layoutManager', 'events'], function (playbackManager
|
|||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
events.on(playbackManager, 'playbackstop', function (e, playbackStopInfo) {
|
||||
events.on(playbackManager, 'playbackstop', function (e, playbackStopInfo) {
|
||||
|
||||
if (orientationLocked && !playbackStopInfo.nextMediaType) {
|
||||
|
||||
|
@ -53,5 +54,4 @@ define(['playbackManager', 'layoutManager', 'events'], function (playbackManager
|
|||
orientationLocked = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
define(['appSettings', 'events', 'browser', 'loading', 'playbackManager', 'appRouter', 'globalize', 'apphost'], function (appSettings, events, browser, loading, playbackManager, appRouter, globalize, appHost) {
|
||||
'use strict';
|
||||
import appSettings from 'appSettings';
|
||||
import events from 'events';
|
||||
import browser from 'browser';
|
||||
import loading from 'loading';
|
||||
import playbackManager from 'playbackManager';
|
||||
import appRouter from 'appRouter';
|
||||
import globalize from 'globalize';
|
||||
import appHost from 'apphost';
|
||||
|
||||
function mirrorItem(info, player) {
|
||||
function mirrorItem(info, player) {
|
||||
|
||||
var item = info.item;
|
||||
|
||||
|
@ -12,9 +18,9 @@ define(['appSettings', 'events', 'browser', 'loading', 'playbackManager', 'appRo
|
|||
ItemType: item.Type,
|
||||
Context: info.context
|
||||
}, player);
|
||||
}
|
||||
}
|
||||
|
||||
function mirrorIfEnabled(info) {
|
||||
function mirrorIfEnabled(info) {
|
||||
|
||||
if (info && playbackManager.enableDisplayMirroring()) {
|
||||
|
||||
|
@ -26,13 +32,13 @@ define(['appSettings', 'events', 'browser', 'loading', 'playbackManager', 'appRo
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emptyCallback() {
|
||||
function emptyCallback() {
|
||||
// avoid console logs about uncaught promises
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetSecondaryText(target) {
|
||||
function getTargetSecondaryText(target) {
|
||||
|
||||
if (target.user) {
|
||||
|
||||
|
@ -40,9 +46,9 @@ define(['appSettings', 'events', 'browser', 'loading', 'playbackManager', 'appRo
|
|||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getIcon(target) {
|
||||
function getIcon(target) {
|
||||
|
||||
var deviceType = target.deviceType;
|
||||
|
||||
|
@ -75,9 +81,9 @@ define(['appSettings', 'events', 'browser', 'loading', 'playbackManager', 'appRo
|
|||
default:
|
||||
return 'tv';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showPlayerSelection(button) {
|
||||
export function show(button) {
|
||||
|
||||
var currentPlayerInfo = playbackManager.getPlayerInfo();
|
||||
|
||||
|
@ -144,16 +150,16 @@ define(['appSettings', 'events', 'browser', 'loading', 'playbackManager', 'appRo
|
|||
}, emptyCallback);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showActivePlayerMenu(playerInfo) {
|
||||
function showActivePlayerMenu(playerInfo) {
|
||||
|
||||
require(['dialogHelper', 'dialog', 'emby-checkbox', 'emby-button'], function (dialogHelper) {
|
||||
showActivePlayerMenuInternal(dialogHelper, playerInfo);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function disconnectFromPlayer(currentDeviceName) {
|
||||
function disconnectFromPlayer(currentDeviceName) {
|
||||
|
||||
if (playbackManager.getSupportedCommands().indexOf('EndSession') !== -1) {
|
||||
|
||||
|
@ -196,9 +202,9 @@ define(['appSettings', 'events', 'browser', 'loading', 'playbackManager', 'appRo
|
|||
|
||||
playbackManager.setDefaultPlayerActive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showActivePlayerMenuInternal(dialogHelper, playerInfo) {
|
||||
function showActivePlayerMenuInternal(dialogHelper, playerInfo) {
|
||||
|
||||
var html = '';
|
||||
|
||||
|
@ -277,13 +283,13 @@ define(['appSettings', 'events', 'browser', 'loading', 'playbackManager', 'appRo
|
|||
disconnectFromPlayer(currentDeviceName);
|
||||
}
|
||||
}, emptyCallback);
|
||||
}
|
||||
}
|
||||
|
||||
function onMirrorChange() {
|
||||
function onMirrorChange() {
|
||||
playbackManager.enableDisplayMirroring(this.checked);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('viewshow', function (e) {
|
||||
document.addEventListener('viewshow', function (e) {
|
||||
|
||||
var state = e.detail.state || {};
|
||||
var item = state.item;
|
||||
|
@ -294,27 +300,26 @@ define(['appSettings', 'events', 'browser', 'loading', 'playbackManager', 'appRo
|
|||
});
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
events.on(appSettings, 'change', function (e, name) {
|
||||
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();
|
||||
});
|
||||
|
||||
return {
|
||||
show: showPlayerSelection
|
||||
};
|
||||
});
|
||||
|
||||
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,7 +1,10 @@
|
|||
define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'globalize', 'appSettings', 'qualityoptions'], function (connectionManager, actionsheet, datetime, playbackManager, globalize, appSettings, qualityoptions) {
|
||||
'use strict';
|
||||
import connectionManager from 'connectionManager';
|
||||
import actionsheet from 'actionsheet';
|
||||
import playbackManager from 'playbackManager';
|
||||
import globalize from 'globalize';
|
||||
import qualityoptions from 'qualityoptions';
|
||||
|
||||
function showQualityMenu(player, btn) {
|
||||
function showQualityMenu(player, btn) {
|
||||
|
||||
var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) {
|
||||
return stream.Type === 'Video';
|
||||
|
@ -49,9 +52,9 @@ define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'glob
|
|||
}, player);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showRepeatModeMenu(player, btn) {
|
||||
function showRepeatModeMenu(player, btn) {
|
||||
var menuItems = [];
|
||||
var currentValue = playbackManager.getRepeatMode(player);
|
||||
|
||||
|
@ -81,9 +84,9 @@ define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'glob
|
|||
playbackManager.setRepeatMode(mode, player);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getQualitySecondaryText(player) {
|
||||
function getQualitySecondaryText(player) {
|
||||
var state = playbackManager.getPlayerState(player);
|
||||
var isAutoEnabled = playbackManager.enableAutomaticBitrateDetection(player);
|
||||
var currentMaxBitrate = playbackManager.getMaxStreamingBitrate(player);
|
||||
|
@ -137,9 +140,9 @@ define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'glob
|
|||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
function showAspectRatioMenu(player, btn) {
|
||||
function showAspectRatioMenu(player, btn) {
|
||||
// each has a name and id
|
||||
var currentId = playbackManager.getAspectRatio(player);
|
||||
var menuItems = playbackManager.getSupportedAspectRatios(player).map(function (i) {
|
||||
|
@ -161,9 +164,9 @@ define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'glob
|
|||
|
||||
return Promise.reject();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showWithUser(options, player, user) {
|
||||
function showWithUser(options, player, user) {
|
||||
var supportedCommands = playbackManager.getSupportedCommands(player);
|
||||
var mediaType = options.mediaType;
|
||||
|
||||
|
@ -223,9 +226,9 @@ define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'glob
|
|||
}).then(function (id) {
|
||||
return handleSelectedOption(id, options, player);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function show(options) {
|
||||
export function show(options) {
|
||||
var player = options.player;
|
||||
var currentItem = playbackManager.currentItem(player);
|
||||
|
||||
|
@ -237,9 +240,9 @@ define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'glob
|
|||
return apiClient.getCurrentUser().then(function (user) {
|
||||
return showWithUser(options, player, user);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleSelectedOption(id, options, player) {
|
||||
function handleSelectedOption(id, options, player) {
|
||||
switch (id) {
|
||||
case 'quality':
|
||||
return showQualityMenu(player, options.positionTo);
|
||||
|
@ -262,9 +265,8 @@ define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'glob
|
|||
}
|
||||
|
||||
return Promise.reject();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
function getDisplayPlayMethod(session) {
|
||||
export function getDisplayPlayMethod(session) {
|
||||
|
||||
if (!session.NowPlayingItem) {
|
||||
return null;
|
||||
|
@ -16,9 +13,8 @@ define([], function () {
|
|||
} else if (session.PlayState.PlayMethod === 'DirectPlay') {
|
||||
return 'DirectPlay';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
export default {
|
||||
getDisplayPlayMethod: getDisplayPlayMethod
|
||||
};
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
define(['events', 'playbackManager'], function (events, playbackManager) {
|
||||
'use strict';
|
||||
import events from 'events';
|
||||
import playbackManager from 'playbackManager';
|
||||
|
||||
function transferPlayback(oldPlayer, newPlayer) {
|
||||
|
||||
var state = playbackManager.getPlayerState(oldPlayer);
|
||||
|
||||
var item = state.NowPlayingItem;
|
||||
function transferPlayback(oldPlayer, newPlayer) {
|
||||
const state = playbackManager.getPlayerState(oldPlayer);
|
||||
const item = state.NowPlayingItem;
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
var playState = state.PlayState || {};
|
||||
var resumePositionTicks = playState.PositionTicks || 0;
|
||||
|
||||
playbackManager.stop(oldPlayer).then(function () {
|
||||
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;
|
||||
|
||||
playbackManager.stop(oldPlayer).then(() => {
|
||||
playbackManager.play({
|
||||
ids: [item.Id],
|
||||
ids: playlistIds,
|
||||
serverId: item.ServerId,
|
||||
startPositionTicks: resumePositionTicks
|
||||
|
||||
startPositionTicks: resumePositionTicks,
|
||||
startIndex: playlistIndex
|
||||
}, newPlayer);
|
||||
});
|
||||
}
|
||||
|
||||
events.on(playbackManager, 'playerchange', function (e, newPlayer, newTarget, oldPlayer) {
|
||||
});
|
||||
}
|
||||
|
||||
events.on(playbackManager, 'playerchange', (e, newPlayer, newTarget, oldPlayer) => {
|
||||
if (!oldPlayer || !newPlayer) {
|
||||
return;
|
||||
}
|
||||
|
@ -42,6 +42,4 @@ define(['events', 'playbackManager'], function (events, playbackManager) {
|
|||
}
|
||||
|
||||
transferPlayback(oldPlayer, newPlayer);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'material-icons'], function (events, playbackManager, dom, browser) {
|
||||
'use strict';
|
||||
import events from 'events';
|
||||
import playbackManager from 'playbackManager';
|
||||
import dom from 'dom';
|
||||
import browser from 'browser';
|
||||
import 'css!./iconosd';
|
||||
import 'material-icons';
|
||||
|
||||
var currentPlayer;
|
||||
var osdElement;
|
||||
var iconElement;
|
||||
var progressElement;
|
||||
var currentPlayer;
|
||||
var osdElement;
|
||||
var iconElement;
|
||||
var progressElement;
|
||||
|
||||
var enableAnimation;
|
||||
var enableAnimation;
|
||||
|
||||
function getOsdElementHtml() {
|
||||
function getOsdElementHtml() {
|
||||
var html = '';
|
||||
|
||||
html += '<span class="material-icons iconOsdIcon volume_up"></span>';
|
||||
|
@ -16,9 +20,9 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
html += '<div class="iconOsdProgressOuter"><div class="iconOsdProgressInner"></div></div>';
|
||||
|
||||
return html;
|
||||
}
|
||||
}
|
||||
|
||||
function ensureOsdElement() {
|
||||
function ensureOsdElement() {
|
||||
|
||||
var elem = osdElement;
|
||||
if (!elem) {
|
||||
|
@ -38,14 +42,14 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
document.body.appendChild(elem);
|
||||
osdElement = elem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onHideComplete() {
|
||||
function onHideComplete() {
|
||||
this.classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
var hideTimeout;
|
||||
function showOsd() {
|
||||
var hideTimeout;
|
||||
function showOsd() {
|
||||
|
||||
clearHideTimeout();
|
||||
|
||||
|
@ -65,16 +69,16 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
|
||||
hideTimeout = setTimeout(hideOsd, 3000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function clearHideTimeout() {
|
||||
function clearHideTimeout() {
|
||||
if (hideTimeout) {
|
||||
clearTimeout(hideTimeout);
|
||||
hideTimeout = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function hideOsd() {
|
||||
function hideOsd() {
|
||||
|
||||
clearHideTimeout();
|
||||
|
||||
|
@ -96,9 +100,9 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
onHideComplete.call(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updatePlayerVolumeState(isMuted, volume) {
|
||||
function updatePlayerVolumeState(isMuted, volume) {
|
||||
|
||||
if (iconElement) {
|
||||
iconElement.classList.remove('volume_off', 'volume_up');
|
||||
|
@ -107,9 +111,9 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
if (progressElement) {
|
||||
progressElement.style.width = (volume || 0) + '%';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
function releaseCurrentPlayer() {
|
||||
|
||||
var player = currentPlayer;
|
||||
|
||||
|
@ -118,9 +122,9 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
events.off(player, 'playbackstop', hideOsd);
|
||||
currentPlayer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onVolumeChanged(e) {
|
||||
function onVolumeChanged(e) {
|
||||
|
||||
var player = this;
|
||||
|
||||
|
@ -129,9 +133,9 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
updatePlayerVolumeState(player.isMuted(), player.getVolume());
|
||||
|
||||
showOsd();
|
||||
}
|
||||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
function bindToPlayer(player) {
|
||||
|
||||
if (player === currentPlayer) {
|
||||
return;
|
||||
|
@ -148,12 +152,10 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia
|
|||
hideOsd();
|
||||
events.on(player, 'volumechange', onVolumeChanged);
|
||||
events.on(player, 'playbackstop', hideOsd);
|
||||
}
|
||||
}
|
||||
|
||||
events.on(playbackManager, 'playerchange', function () {
|
||||
events.on(playbackManager, 'playerchange', function () {
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
});
|
||||
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
|
||||
});
|
||||
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
|
|
|
@ -58,7 +58,7 @@ define(['events', 'globalize'], function (events, globalize) {
|
|||
|
||||
return new Promise(function (resolve, reject) {
|
||||
require([pluginSpec], (pluginFactory) => {
|
||||
var plugin = new pluginFactory();
|
||||
var plugin = pluginFactory.default ? new pluginFactory.default() : new pluginFactory();
|
||||
|
||||
// See if it's already installed
|
||||
var existing = instance.pluginsList.filter(function (p) {
|
||||
|
|
|
@ -57,7 +57,6 @@ define(['apphost', 'userSettings', 'browser', 'events', 'backdrop', 'globalize',
|
|||
var selectedTheme;
|
||||
|
||||
for (var i = 0, length = themes.length; i < length; i++) {
|
||||
|
||||
var theme = themes[i];
|
||||
if (theme[isDefaultProperty]) {
|
||||
defaultTheme = theme;
|
||||
|
|
|
@ -265,10 +265,9 @@ class SyncPlayManager {
|
|||
events.on(player, 'timeupdate', this._onTimeUpdate);
|
||||
events.on(player, 'playing', this._onPlaying);
|
||||
events.on(player, 'waiting', this._onWaiting);
|
||||
this.playbackRateSupported = player.supports('PlaybackRate');
|
||||
|
||||
// Save player current PlaybackRate value
|
||||
if (this.playbackRateSupported) {
|
||||
if (player.supports && player.supports('PlaybackRate')) {
|
||||
this.localPlayerPlaybackRate = player.getPlaybackRate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-button', 'emby-input', 'emby-checkbox', 'listViewStyle', 'emby-button'], function ($, loading, globalize) {
|
||||
define(['jQuery', 'loading', 'globalize', 'emby-select', 'emby-button', 'emby-input', 'emby-checkbox', 'listViewStyle', 'emby-button'], function ($, loading, globalize) {
|
||||
'use strict';
|
||||
|
||||
function loadProfile(page) {
|
||||
|
@ -23,8 +23,8 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt
|
|||
$('.chkMediaType', page).each(function () {
|
||||
this.checked = -1 != (profile.SupportedMediaTypes || '').split(',').indexOf(this.getAttribute('data-value'));
|
||||
});
|
||||
$('#chkEnableAlbumArtInDidl', page).checked(profile.EnableAlbumArtInDidl);
|
||||
$('#chkEnableSingleImageLimit', page).checked(profile.EnableSingleAlbumArtLimit);
|
||||
$('#chkEnableAlbumArtInDidl', page).checked = profile.EnableAlbumArtInDidl;
|
||||
$('#chkEnableSingleImageLimit', page).checked = profile.EnableSingleAlbumArtLimit;
|
||||
renderXmlDocumentAttributes(page, profile.XmlRootAttributes || []);
|
||||
var idInfo = profile.Identification || {};
|
||||
renderIdentificationHeaders(page, idInfo.Headers || []);
|
||||
|
@ -51,11 +51,11 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt
|
|||
$('#txtAlbumArtMaxHeight', page).val(profile.MaxAlbumArtHeight || '');
|
||||
$('#txtIconMaxWidth', page).val(profile.MaxIconWidth || '');
|
||||
$('#txtIconMaxHeight', page).val(profile.MaxIconHeight || '');
|
||||
$('#chkIgnoreTranscodeByteRangeRequests', page).checked(profile.IgnoreTranscodeByteRangeRequests);
|
||||
$('#chkIgnoreTranscodeByteRangeRequests', page).checked = profile.IgnoreTranscodeByteRangeRequests;
|
||||
$('#txtMaxAllowedBitrate', page).val(profile.MaxStreamingBitrate || '');
|
||||
$('#txtMusicStreamingTranscodingBitrate', page).val(profile.MusicStreamingTranscodingBitrate || '');
|
||||
$('#chkRequiresPlainFolders', page).checked(profile.RequiresPlainFolders);
|
||||
$('#chkRequiresPlainVideoItems', page).checked(profile.RequiresPlainVideoItems);
|
||||
$('#chkRequiresPlainFolders', page).checked = profile.RequiresPlainFolders;
|
||||
$('#chkRequiresPlainVideoItems', page).checked = profile.RequiresPlainVideoItems;
|
||||
$('#txtProtocolInfo', page).val(profile.ProtocolInfo || '');
|
||||
$('#txtXDlnaCap', page).val(profile.XDlnaCap || '');
|
||||
$('#txtXDlnaDoc', page).val(profile.XDlnaDoc || '');
|
||||
|
@ -357,9 +357,9 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt
|
|||
$('#txtTranscodingAudioCodec', popup).val(transcodingProfile.AudioCodec || '');
|
||||
$('#txtTranscodingVideoCodec', popup).val(transcodingProfile.VideoCodec || '');
|
||||
$('#selectTranscodingProtocol', popup).val(transcodingProfile.Protocol || 'Http');
|
||||
$('#chkEnableMpegtsM2TsMode', popup).checked(transcodingProfile.EnableMpegtsM2TsMode || false);
|
||||
$('#chkEstimateContentLength', popup).checked(transcodingProfile.EstimateContentLength || false);
|
||||
$('#chkReportByteRangeRequests', popup).checked('Bytes' == transcodingProfile.TranscodeSeekInfo);
|
||||
$('#chkEnableMpegtsM2TsMode', popup).checked = transcodingProfile.EnableMpegtsM2TsMode || false;
|
||||
$('#chkEstimateContentLength', popup).checked = transcodingProfile.EstimateContentLength || false;
|
||||
$('#chkReportByteRangeRequests', popup).checked = 'Bytes' == transcodingProfile.TranscodeSeekInfo;
|
||||
$('.radioTabButton:first', popup).trigger('click');
|
||||
openPopup(popup[0]);
|
||||
}
|
||||
|
@ -376,9 +376,9 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt
|
|||
currentSubProfile.VideoCodec = $('#txtTranscodingVideoCodec', page).val();
|
||||
currentSubProfile.Protocol = $('#selectTranscodingProtocol', page).val();
|
||||
currentSubProfile.Context = 'Streaming';
|
||||
currentSubProfile.EnableMpegtsM2TsMode = $('#chkEnableMpegtsM2TsMode', page).checked();
|
||||
currentSubProfile.EstimateContentLength = $('#chkEstimateContentLength', page).checked();
|
||||
currentSubProfile.TranscodeSeekInfo = $('#chkReportByteRangeRequests', page).checked() ? 'Bytes' : 'Auto';
|
||||
currentSubProfile.EnableMpegtsM2TsMode = $('#chkEnableMpegtsM2TsMode', page).checked;
|
||||
currentSubProfile.EstimateContentLength = $('#chkEstimateContentLength', page).checked;
|
||||
currentSubProfile.TranscodeSeekInfo = $('#chkReportByteRangeRequests', page).checked ? 'Bytes' : 'Auto';
|
||||
|
||||
if (isSubProfileNew) {
|
||||
currentProfile.TranscodingProfiles.push(currentSubProfile);
|
||||
|
@ -647,8 +647,8 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt
|
|||
|
||||
function updateProfile(page, profile) {
|
||||
profile.Name = $('#txtName', page).val();
|
||||
profile.EnableAlbumArtInDidl = $('#chkEnableAlbumArtInDidl', page).checked();
|
||||
profile.EnableSingleAlbumArtLimit = $('#chkEnableSingleImageLimit', page).checked();
|
||||
profile.EnableAlbumArtInDidl = $('#chkEnableAlbumArtInDidl', page).checked;
|
||||
profile.EnableSingleAlbumArtLimit = $('#chkEnableSingleImageLimit', page).checked;
|
||||
profile.SupportedMediaTypes = $('.chkMediaType:checked', page).get().map(function (c) {
|
||||
return c.getAttribute('data-value');
|
||||
}).join(',');
|
||||
|
@ -675,9 +675,9 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-butt
|
|||
profile.MaxAlbumArtHeight = $('#txtAlbumArtMaxHeight', page).val();
|
||||
profile.MaxIconWidth = $('#txtIconMaxWidth', page).val();
|
||||
profile.MaxIconHeight = $('#txtIconMaxHeight', page).val();
|
||||
profile.RequiresPlainFolders = $('#chkRequiresPlainFolders', page).checked();
|
||||
profile.RequiresPlainVideoItems = $('#chkRequiresPlainVideoItems', page).checked();
|
||||
profile.IgnoreTranscodeByteRangeRequests = $('#chkIgnoreTranscodeByteRangeRequests', page).checked();
|
||||
profile.RequiresPlainFolders = $('#chkRequiresPlainFolders', page).checked;
|
||||
profile.RequiresPlainVideoItems = $('#chkRequiresPlainVideoItems', page).checked;
|
||||
profile.IgnoreTranscodeByteRangeRequests = $('#chkIgnoreTranscodeByteRangeRequests', page).checked;
|
||||
profile.MaxStreamingBitrate = $('#txtMaxAllowedBitrate', page).val();
|
||||
profile.MusicStreamingTranscodingBitrate = $('#txtMusicStreamingTranscodingBitrate', page).val();
|
||||
profile.ProtocolInfo = $('#txtProtocolInfo', page).val();
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function ($, loading, libraryMenu, globalize) {
|
||||
define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading, libraryMenu, globalize) {
|
||||
'use strict';
|
||||
|
||||
function loadPage(page, config, users) {
|
||||
page.querySelector('#chkEnablePlayTo').checked = config.EnablePlayTo;
|
||||
page.querySelector('#chkEnableDlnaDebugLogging').checked = config.EnableDebugLog;
|
||||
$('#txtClientDiscoveryInterval', page).val(config.ClientDiscoveryIntervalSeconds);
|
||||
$('#chkEnableServer', page).checked(config.EnableServer);
|
||||
$('#chkBlastAliveMessages', page).checked(config.BlastAliveMessages);
|
||||
$('#chkEnableServer', page).checked = config.EnableServer;
|
||||
$('#chkBlastAliveMessages', page).checked = config.BlastAliveMessages;
|
||||
$('#txtBlastInterval', page).val(config.BlastAliveMessageIntervalSeconds);
|
||||
var usersHtml = users.map(function (u) {
|
||||
return '<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.EnableDebugLog = form.querySelector('#chkEnableDlnaDebugLogging').checked;
|
||||
config.ClientDiscoveryIntervalSeconds = $('#txtClientDiscoveryInterval', form).val();
|
||||
config.EnableServer = $('#chkEnableServer', form).checked();
|
||||
config.BlastAliveMessages = $('#chkBlastAliveMessages', form).checked();
|
||||
config.EnableServer = $('#chkEnableServer', form).checked;
|
||||
config.BlastAliveMessages = $('#chkBlastAliveMessages', form).checked;
|
||||
config.BlastAliveMessageIntervalSeconds = $('#txtBlastInterval', form).val();
|
||||
config.DefaultUserId = $('#selectUser', form).val();
|
||||
ApiClient.updateNamedConfiguration('dlna', config).then(Dashboard.processServerConfigurationUpdateResult);
|
||||
|
|
|
@ -1,16 +1,8 @@
|
|||
define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox', 'emby-textarea', 'emby-input', 'emby-select', 'emby-button'], function ($, loading, globalize) {
|
||||
define(['jQuery', 'loading', 'globalize', 'emby-checkbox', 'emby-textarea', 'emby-input', 'emby-select', 'emby-button'], function ($, loading, globalize) {
|
||||
'use strict';
|
||||
|
||||
function loadPage(page, config, languageOptions, systemInfo) {
|
||||
page.querySelector('#txtServerName').value = systemInfo.ServerName;
|
||||
$('#chkAutoRunWebApp', page).checked(config.AutoRunWebApp);
|
||||
|
||||
if (systemInfo.CanLaunchWebBrowser) {
|
||||
page.querySelector('#fldAutoRunWebApp').classList.remove('hide');
|
||||
} else {
|
||||
page.querySelector('#fldAutoRunWebApp').classList.add('hide');
|
||||
}
|
||||
|
||||
page.querySelector('#txtCachePath').value = systemInfo.CachePath || '';
|
||||
$('#txtMetadataPath', page).val(systemInfo.InternalMetadataPath || '');
|
||||
$('#txtMetadataNetworkPath', page).val(systemInfo.MetadataNetworkPath || '');
|
||||
|
@ -33,7 +25,6 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox', 'emby-te
|
|||
config.MetadataPath = $('#txtMetadataPath', form).val();
|
||||
config.MetadataNetworkPath = $('#txtMetadataNetworkPath', form).val();
|
||||
var requiresReload = config.UICulture !== currentLanguage;
|
||||
config.AutoRunWebApp = $('#chkAutoRunWebApp', form).checked();
|
||||
ApiClient.updateServerConfiguration(config).then(function() {
|
||||
ApiClient.getNamedConfiguration(brandingConfigKey).then(function(brandingConfig) {
|
||||
brandingConfig.LoginDisclaimer = form.querySelector('#txtLoginDisclaimer').value;
|
||||
|
|
|
@ -29,14 +29,18 @@ define(['jQuery', 'dom', 'loading', 'libraryMenu', 'globalize', 'listViewStyle']
|
|||
var promises = [ApiClient.getServerConfiguration(), populateLanguages(page.querySelector('#selectLanguage')), populateCountries(page.querySelector('#selectCountry'))];
|
||||
Promise.all(promises).then(function(responses) {
|
||||
var config = responses[0];
|
||||
page.querySelector('#selectLanguage').value = config.PreferredMetadataLanguage || '', page.querySelector('#selectCountry').value = config.MetadataCountryCode || '', loading.hide();
|
||||
page.querySelector('#selectLanguage').value = config.PreferredMetadataLanguage || '';
|
||||
page.querySelector('#selectCountry').value = config.MetadataCountryCode || '';
|
||||
loading.hide();
|
||||
});
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
var form = this;
|
||||
return loading.show(), ApiClient.getServerConfiguration().then(function(config) {
|
||||
config.PreferredMetadataLanguage = form.querySelector('#selectLanguage').value, config.MetadataCountryCode = form.querySelector('#selectCountry').value, ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult);
|
||||
config.PreferredMetadataLanguage = form.querySelector('#selectLanguage').value;
|
||||
config.MetadataCountryCode = form.querySelector('#selectCountry').value;
|
||||
ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult);
|
||||
}), !1;
|
||||
}
|
||||
|
||||
|
@ -59,6 +63,8 @@ define(['jQuery', 'dom', 'loading', 'libraryMenu', 'globalize', 'listViewStyle']
|
|||
$(document).on('pageinit', '#metadataImagesConfigurationPage', function() {
|
||||
$('.metadataImagesConfigurationForm').off('submit', onSubmit).on('submit', onSubmit);
|
||||
}).on('pageshow', '#metadataImagesConfigurationPage', function() {
|
||||
libraryMenu.setTabs('metadata', 2, getTabs), loading.show(), loadPage(this);
|
||||
libraryMenu.setTabs('metadata', 2, getTabs);
|
||||
loading.show();
|
||||
loadPage(this);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
define(['jQuery', 'emby-checkbox', 'fnchecked'], function ($) {
|
||||
define(['jQuery', 'emby-checkbox'], function ($) {
|
||||
'use strict';
|
||||
|
||||
function fillItems(elem, items, cssClass, idPrefix, currentList, isEnabledList) {
|
||||
|
@ -50,7 +50,7 @@ define(['jQuery', 'emby-checkbox', 'fnchecked'], function ($) {
|
|||
fillItems($('.monitorUsersList', page), users, 'chkMonitor', 'chkMonitor', notificationConfig.DisabledMonitorUsers);
|
||||
fillItems($('.sendToUsersList', page), users, 'chkSendTo', 'chkSendTo', notificationConfig.SendToUsers, true);
|
||||
fillItems($('.servicesList', page), services, 'chkService', 'chkService', notificationConfig.DisabledServices);
|
||||
$('#chkEnabled', page).checked(notificationConfig.Enabled || false);
|
||||
$('#chkEnabled', page).checked = notificationConfig.Enabled || false;
|
||||
$('#selectUsers', page).val(notificationConfig.SendToUserMode).trigger('change');
|
||||
});
|
||||
}
|
||||
|
@ -58,10 +58,10 @@ define(['jQuery', 'emby-checkbox', 'fnchecked'], function ($) {
|
|||
function save(page) {
|
||||
var type = getParameterByName('type');
|
||||
var promise1 = ApiClient.getNamedConfiguration(notificationsConfigurationKey);
|
||||
// TODO: Check if this promise is really needed, as it's unused.
|
||||
var promise2 = ApiClient.getJSON(ApiClient.getUrl('Notifications/Types'));
|
||||
Promise.all([promise1, promise2]).then(function (responses) {
|
||||
var notificationOptions = responses[0];
|
||||
var types = responses[1];
|
||||
var notificationConfig = notificationOptions.Options.filter(function (n) {
|
||||
return n.Type == type;
|
||||
})[0];
|
||||
|
@ -73,10 +73,7 @@ define(['jQuery', 'emby-checkbox', 'fnchecked'], function ($) {
|
|||
notificationOptions.Options.push(notificationConfig);
|
||||
}
|
||||
|
||||
types.filter(function (n) {
|
||||
return n.Type == type;
|
||||
})[0];
|
||||
notificationConfig.Enabled = $('#chkEnabled', page).checked();
|
||||
notificationConfig.Enabled = $('#chkEnabled', page).checked;
|
||||
notificationConfig.SendToUserMode = $('#selectUsers', page).val();
|
||||
notificationConfig.DisabledMonitorUsers = $('.chkMonitor', page).get().filter(function (c) {
|
||||
return !c.checked;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function ($, loading, libraryMenu, globalize) {
|
||||
define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading, libraryMenu, globalize) {
|
||||
'use strict';
|
||||
|
||||
function loadDeleteFolders(page, user, mediaFolders) {
|
||||
|
@ -27,7 +27,7 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function
|
|||
}
|
||||
|
||||
$('.deleteAccess', page).html(html).trigger('create');
|
||||
$('#chkEnableDeleteAllFolders', page).checked(user.Policy.EnableContentDeletion).trigger('change');
|
||||
$('#chkEnableDeleteAllFolders', page).checked = user.Policy.EnableContentDeletion;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -85,23 +85,23 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function
|
|||
libraryMenu.setTitle(user.Name);
|
||||
page.querySelector('.username').innerHTML = user.Name;
|
||||
$('#txtUserName', page).val(user.Name);
|
||||
$('#chkIsAdmin', page).checked(user.Policy.IsAdministrator);
|
||||
$('#chkDisabled', page).checked(user.Policy.IsDisabled);
|
||||
$('#chkIsHidden', page).checked(user.Policy.IsHidden);
|
||||
$('#chkRemoteControlSharedDevices', page).checked(user.Policy.EnableSharedDeviceControl);
|
||||
$('#chkEnableRemoteControlOtherUsers', page).checked(user.Policy.EnableRemoteControlOfOtherUsers);
|
||||
$('#chkEnableDownloading', page).checked(user.Policy.EnableContentDownloading);
|
||||
$('#chkManageLiveTv', page).checked(user.Policy.EnableLiveTvManagement);
|
||||
$('#chkEnableLiveTvAccess', page).checked(user.Policy.EnableLiveTvAccess);
|
||||
$('#chkEnableMediaPlayback', page).checked(user.Policy.EnableMediaPlayback);
|
||||
$('#chkEnableAudioPlaybackTranscoding', page).checked(user.Policy.EnableAudioPlaybackTranscoding);
|
||||
$('#chkEnableVideoPlaybackTranscoding', page).checked(user.Policy.EnableVideoPlaybackTranscoding);
|
||||
$('#chkEnableVideoPlaybackRemuxing', page).checked(user.Policy.EnablePlaybackRemuxing);
|
||||
$('#chkForceRemoteSourceTranscoding', page).checked(user.Policy.ForceRemoteSourceTranscoding);
|
||||
$('#chkRemoteAccess', page).checked(null == user.Policy.EnableRemoteAccess || user.Policy.EnableRemoteAccess);
|
||||
$('#chkEnableSyncTranscoding', page).checked(user.Policy.EnableSyncTranscoding);
|
||||
$('#chkEnableConversion', page).checked(user.Policy.EnableMediaConversion || false);
|
||||
$('#chkEnableSharing', page).checked(user.Policy.EnablePublicSharing);
|
||||
$('#chkIsAdmin', page).checked = user.Policy.IsAdministrator;
|
||||
$('#chkDisabled', page).checked = user.Policy.IsDisabled;
|
||||
$('#chkIsHidden', page).checked = user.Policy.IsHidden;
|
||||
$('#chkRemoteControlSharedDevices', page).checked = user.Policy.EnableSharedDeviceControl;
|
||||
$('#chkEnableRemoteControlOtherUsers', page).checked = user.Policy.EnableRemoteControlOfOtherUsers;
|
||||
$('#chkEnableDownloading', page).checked = user.Policy.EnableContentDownloading;
|
||||
$('#chkManageLiveTv', page).checked = user.Policy.EnableLiveTvManagement;
|
||||
$('#chkEnableLiveTvAccess', page).checked = user.Policy.EnableLiveTvAccess;
|
||||
$('#chkEnableMediaPlayback', page).checked = user.Policy.EnableMediaPlayback;
|
||||
$('#chkEnableAudioPlaybackTranscoding', page).checked = user.Policy.EnableAudioPlaybackTranscoding;
|
||||
$('#chkEnableVideoPlaybackTranscoding', page).checked = user.Policy.EnableVideoPlaybackTranscoding;
|
||||
$('#chkEnableVideoPlaybackRemuxing', page).checked = user.Policy.EnablePlaybackRemuxing;
|
||||
$('#chkForceRemoteSourceTranscoding', page).checked = user.Policy.ForceRemoteSourceTranscoding;
|
||||
$('#chkRemoteAccess', page).checked = null == user.Policy.EnableRemoteAccess || user.Policy.EnableRemoteAccess;
|
||||
$('#chkEnableSyncTranscoding', page).checked = user.Policy.EnableSyncTranscoding;
|
||||
$('#chkEnableConversion', page).checked = user.Policy.EnableMediaConversion || false;
|
||||
$('#chkEnableSharing', page).checked = user.Policy.EnablePublicSharing;
|
||||
$('#txtRemoteClientBitrateLimit', page).val(user.Policy.RemoteClientBitrateLimit / 1e6 || '');
|
||||
$('#txtLoginAttemptsBeforeLockout', page).val(user.Policy.LoginAttemptsBeforeLockout || '0');
|
||||
$('#selectSyncPlayAccess').val(user.Policy.SyncPlayAccess);
|
||||
|
@ -119,28 +119,28 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function
|
|||
|
||||
function saveUser(user, page) {
|
||||
user.Name = $('#txtUserName', page).val();
|
||||
user.Policy.IsAdministrator = $('#chkIsAdmin', page).checked();
|
||||
user.Policy.IsHidden = $('#chkIsHidden', page).checked();
|
||||
user.Policy.IsDisabled = $('#chkDisabled', page).checked();
|
||||
user.Policy.EnableRemoteControlOfOtherUsers = $('#chkEnableRemoteControlOtherUsers', page).checked();
|
||||
user.Policy.EnableLiveTvManagement = $('#chkManageLiveTv', page).checked();
|
||||
user.Policy.EnableLiveTvAccess = $('#chkEnableLiveTvAccess', page).checked();
|
||||
user.Policy.EnableSharedDeviceControl = $('#chkRemoteControlSharedDevices', page).checked();
|
||||
user.Policy.EnableMediaPlayback = $('#chkEnableMediaPlayback', page).checked();
|
||||
user.Policy.EnableAudioPlaybackTranscoding = $('#chkEnableAudioPlaybackTranscoding', page).checked();
|
||||
user.Policy.EnableVideoPlaybackTranscoding = $('#chkEnableVideoPlaybackTranscoding', page).checked();
|
||||
user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).checked();
|
||||
user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).checked();
|
||||
user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).checked();
|
||||
user.Policy.EnableSyncTranscoding = $('#chkEnableSyncTranscoding', page).checked();
|
||||
user.Policy.EnableMediaConversion = $('#chkEnableConversion', page).checked();
|
||||
user.Policy.EnablePublicSharing = $('#chkEnableSharing', page).checked();
|
||||
user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).checked();
|
||||
user.Policy.IsAdministrator = $('#chkIsAdmin', page).checked;
|
||||
user.Policy.IsHidden = $('#chkIsHidden', page).checked;
|
||||
user.Policy.IsDisabled = $('#chkDisabled', page).checked;
|
||||
user.Policy.EnableRemoteControlOfOtherUsers = $('#chkEnableRemoteControlOtherUsers', page).checked;
|
||||
user.Policy.EnableLiveTvManagement = $('#chkManageLiveTv', page).checked;
|
||||
user.Policy.EnableLiveTvAccess = $('#chkEnableLiveTvAccess', page).checked;
|
||||
user.Policy.EnableSharedDeviceControl = $('#chkRemoteControlSharedDevices', page).checked;
|
||||
user.Policy.EnableMediaPlayback = $('#chkEnableMediaPlayback', page).checked;
|
||||
user.Policy.EnableAudioPlaybackTranscoding = $('#chkEnableAudioPlaybackTranscoding', page).checked;
|
||||
user.Policy.EnableVideoPlaybackTranscoding = $('#chkEnableVideoPlaybackTranscoding', page).checked;
|
||||
user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).checked;
|
||||
user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).checked;
|
||||
user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).checked;
|
||||
user.Policy.EnableSyncTranscoding = $('#chkEnableSyncTranscoding', page).checked;
|
||||
user.Policy.EnableMediaConversion = $('#chkEnableConversion', page).checked;
|
||||
user.Policy.EnablePublicSharing = $('#chkEnableSharing', page).checked;
|
||||
user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).checked;
|
||||
user.Policy.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($('#txtRemoteClientBitrateLimit', page).val() || '0'));
|
||||
user.Policy.LoginAttemptsBeforeLockout = parseInt($('#txtLoginAttemptsBeforeLockout', page).val() || '0');
|
||||
user.Policy.AuthenticationProviderId = page.querySelector('.selectLoginProvider').value;
|
||||
user.Policy.PasswordResetProviderId = page.querySelector('.selectPasswordResetProvider').value;
|
||||
user.Policy.EnableContentDeletion = $('#chkEnableDeleteAllFolders', page).checked();
|
||||
user.Policy.EnableContentDeletion = $('#chkEnableDeleteAllFolders', page).checked;
|
||||
user.Policy.EnableContentDeletionFromFolders = user.Policy.EnableContentDeletion ? [] : $('.chkFolder', page).get().filter(function (c) {
|
||||
return c.checked;
|
||||
}).map(function (c) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function ($, loading, libraryMenu, globalize) {
|
||||
define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading, libraryMenu, globalize) {
|
||||
'use strict';
|
||||
|
||||
function triggerChange(select) {
|
||||
|
@ -47,7 +47,7 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function
|
|||
$('.channelAccessContainer', page).hide();
|
||||
}
|
||||
|
||||
$('#chkEnableAllChannels', page).checked(user.Policy.EnableAllChannels).trigger('change');
|
||||
$('#chkEnableAllChannels', page).checked = user.Policy.EnableAllChannels;
|
||||
}
|
||||
|
||||
function loadDevices(page, user, devices) {
|
||||
|
@ -63,7 +63,7 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function
|
|||
|
||||
html += '</div>';
|
||||
$('.deviceAccess', page).show().html(html);
|
||||
$('#chkEnableAllDevices', page).checked(user.Policy.EnableAllDevices).trigger('change');
|
||||
$('#chkEnableAllDevices', page).checked = user.Policy.EnableAllDevices;
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
page.querySelector('.deviceAccessContainer').classList.add('hide');
|
||||
|
@ -90,19 +90,19 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function
|
|||
}
|
||||
|
||||
function saveUser(user, page) {
|
||||
user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).checked();
|
||||
user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).checked;
|
||||
user.Policy.EnabledFolders = user.Policy.EnableAllFolders ? [] : $('.chkFolder', page).get().filter(function (c) {
|
||||
return c.checked;
|
||||
}).map(function (c) {
|
||||
return c.getAttribute('data-id');
|
||||
});
|
||||
user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).checked();
|
||||
user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).checked;
|
||||
user.Policy.EnabledChannels = user.Policy.EnableAllChannels ? [] : $('.chkChannel', page).get().filter(function (c) {
|
||||
return c.checked;
|
||||
}).map(function (c) {
|
||||
return c.getAttribute('data-id');
|
||||
});
|
||||
user.Policy.EnableAllDevices = $('#chkEnableAllDevices', page).checked();
|
||||
user.Policy.EnableAllDevices = $('#chkEnableAllDevices', page).checked;
|
||||
user.Policy.EnabledDevices = user.Policy.EnableAllDevices ? [] : $('.chkDevice', page).get().filter(function (c) {
|
||||
return c.checked;
|
||||
}).map(function (c) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], function ($, loading, globalize) {
|
||||
define(['jQuery', 'loading', 'globalize', 'emby-checkbox'], function ($, loading, globalize) {
|
||||
'use strict';
|
||||
|
||||
function loadMediaFolders(page, mediaFolders) {
|
||||
|
@ -13,7 +13,7 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], functio
|
|||
|
||||
html += '</div>';
|
||||
$('.folderAccess', page).html(html).trigger('create');
|
||||
$('#chkEnableAllFolders', page).checked(false).trigger('change');
|
||||
$('#chkEnableAllFolders', page).checked = false;
|
||||
}
|
||||
|
||||
function loadChannels(page, channels) {
|
||||
|
@ -35,7 +35,7 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], functio
|
|||
$('.channelAccessContainer', page).hide();
|
||||
}
|
||||
|
||||
$('#chkEnableAllChannels', page).checked(false).trigger('change');
|
||||
$('#chkEnableAllChannels', page).checked = false;
|
||||
}
|
||||
|
||||
function loadUser(page) {
|
||||
|
@ -58,7 +58,7 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], functio
|
|||
user.Name = $('#txtUsername', page).val();
|
||||
user.Password = $('#txtPassword', page).val();
|
||||
ApiClient.createUser(user).then(function (user) {
|
||||
user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).checked();
|
||||
user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).checked;
|
||||
user.Policy.EnabledFolders = [];
|
||||
|
||||
if (!user.Policy.EnableAllFolders) {
|
||||
|
@ -69,7 +69,7 @@ define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], functio
|
|||
});
|
||||
}
|
||||
|
||||
user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).checked();
|
||||
user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).checked;
|
||||
user.Policy.EnabledChannels = [];
|
||||
|
||||
if (!user.Policy.EnableAllChannels) {
|
||||
|
|
|
@ -972,6 +972,19 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
}
|
||||
}
|
||||
|
||||
function toggleLineClamp(clampTarget, e) {
|
||||
var expandButton = e.target;
|
||||
var clampClassName = 'detail-clamp-text';
|
||||
|
||||
if (clampTarget.classList.contains(clampClassName)) {
|
||||
clampTarget.classList.remove(clampClassName);
|
||||
expandButton.innerHTML = globalize.translate('ShowLess');
|
||||
} else {
|
||||
clampTarget.classList.add(clampClassName);
|
||||
expandButton.innerHTML = globalize.translate('ShowMore');
|
||||
}
|
||||
}
|
||||
|
||||
function renderOverview(elems, item) {
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
var elem = elems[i];
|
||||
|
@ -980,6 +993,21 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
if (overview) {
|
||||
elem.innerHTML = overview;
|
||||
elem.classList.remove('hide');
|
||||
elem.classList.add('detail-clamp-text');
|
||||
|
||||
// Grab the sibling element to control the expand state
|
||||
var expandButton = elem.parentElement.querySelector('.overview-expand');
|
||||
|
||||
// Detect if we have overflow of text. Based on this StackOverflow answer
|
||||
// https://stackoverflow.com/a/35157976
|
||||
if (Math.abs(elem.scrollHeight - elem.offsetHeight) > 2) {
|
||||
expandButton.classList.remove('hide');
|
||||
} else {
|
||||
expandButton.classList.add('hide');
|
||||
}
|
||||
|
||||
expandButton.addEventListener('click', toggleLineClamp.bind(null, elem));
|
||||
|
||||
var anchors = elem.querySelectorAll('a');
|
||||
|
||||
for (var j = 0, length2 = anchors.length; j < length2; j++) {
|
||||
|
@ -1863,7 +1891,8 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
itemsContainer: castContent,
|
||||
coverImage: true,
|
||||
serverId: item.ServerId,
|
||||
shape: 'overflowPortrait'
|
||||
shape: 'overflowPortrait',
|
||||
imageBlurhashes: item.ImageBlurHashes
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -308,7 +308,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
|||
return apiClient.getItems(apiClient.getCurrentUserId(), modifyQueryWithFilters(instance, {
|
||||
StartIndex: startIndex,
|
||||
Limit: limit,
|
||||
Fields: 'PrimaryImageAspectRatio,SortName',
|
||||
Fields: 'PrimaryImageAspectRatio,SortName,Path',
|
||||
ImageTypeLimit: 1,
|
||||
ParentId: item.Id,
|
||||
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';
|
||||
|
||||
function loadPage(page, config) {
|
||||
|
|
|
@ -157,7 +157,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
});
|
||||
|
||||
if (!displayName) {
|
||||
displayItem.Type;
|
||||
displayName = displayItem.Type;
|
||||
}
|
||||
|
||||
titleElement.innerHTML = displayName;
|
||||
|
|
|
@ -23,13 +23,6 @@
|
|||
</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 class="verticalSection verticalSection-extrabottompadding">
|
||||
|
@ -62,7 +55,7 @@
|
|||
<input is="emby-input" type="text" id="txtLoginDisclaimer" label="${LabelLoginDisclaimer}" />
|
||||
<div class="fieldDescription">${LabelLoginDisclaimerHelp}</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<div class="inputContainer customCssContainer">
|
||||
<textarea is="emby-textarea" id="txtCustomCss" label="${LabelCustomCss}" class="textarea-mono"></textarea>
|
||||
<div class="fieldDescription">${LabelCustomCssHelp}</div>
|
||||
</div>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<a is="emby-linkbutton" href="dlnaprofile.html" class="fab submit" style="margin:0 0 0 1em">
|
||||
<span class="material-icons add"></span>
|
||||
</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>
|
||||
|
||||
<p>${CustomDlnaProfilesHelp}</p>
|
||||
|
|
|
@ -148,7 +148,7 @@ define(['browser', 'dom', 'layoutManager', 'keyboardnavigation', 'css!./emby-sli
|
|||
this.classList.add('mdl-slider');
|
||||
this.classList.add('mdl-js-slider');
|
||||
|
||||
if (browser.edge || browser.msie) {
|
||||
if (browser.edge) {
|
||||
this.classList.add('slider-browser-edge');
|
||||
}
|
||||
if (!layoutManager.mobile) {
|
||||
|
|
|
@ -55,6 +55,7 @@ define(['layoutManager', 'browser', 'css!./emby-textarea', 'registerElement', 'e
|
|||
newHeight = textarea.scrollHeight/* - offset*/;
|
||||
hasGrown = true;
|
||||
}
|
||||
$('.customCssContainer').css('height', newHeight + 'px');
|
||||
textarea.style.height = newHeight + 'px';
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,9 @@
|
|||
<p class="itemGenres"></p>
|
||||
<h3 class="tagline"></h3>
|
||||
<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="itemBirthLocation"></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 applicationNightly = '6F511C87';
|
||||
|
||||
var applicationID = applicationStable;
|
||||
if (userSettings.chromecastVersion === 'nightly') {
|
||||
applicationID = applicationNightly;
|
||||
}
|
||||
|
||||
var messageNamespace = 'urn:x-cast:com.connectsdk';
|
||||
|
||||
var CastPlayer = function () {
|
||||
|
@ -105,6 +100,11 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
|||
return;
|
||||
}
|
||||
|
||||
var applicationID = applicationStable;
|
||||
if (userSettings.chromecastVersion() === 'nightly') {
|
||||
applicationID = applicationNightly;
|
||||
}
|
||||
|
||||
// request session
|
||||
var sessionRequest = new chrome.cast.SessionRequest(applicationID);
|
||||
var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
|
|
@ -281,14 +281,6 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
|||
}
|
||||
|
||||
self.play = function (options) {
|
||||
|
||||
if (browser.msie) {
|
||||
if (options.playMethod === 'Transcode' && !window.MediaSource) {
|
||||
alert('Playback of this content is not supported in Internet Explorer. For a better experience, try a modern browser such as Microsoft Edge, Google Chrome, Firefox or Opera.');
|
||||
return Promise.reject();
|
||||
}
|
||||
}
|
||||
|
||||
self._started = false;
|
||||
self._timeUpdated = false;
|
||||
|
||||
|
@ -1425,13 +1417,6 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
|||
var video = document.createElement('video');
|
||||
if (video.webkitSupportsPresentationMode && typeof video.webkitSetPresentationMode === 'function' || document.pictureInPictureEnabled) {
|
||||
list.push('PictureInPicture');
|
||||
} else if (browser.ipad) {
|
||||
// Unfortunately this creates a false positive on devices where its' not actually supported
|
||||
if (navigator.userAgent.toLowerCase().indexOf('os 9') === -1) {
|
||||
if (video.webkitSupportsPresentationMode && video.webkitSupportsPresentationMode && typeof video.webkitSetPresentationMode === 'function') {
|
||||
list.push('PictureInPicture');
|
||||
}
|
||||
}
|
||||
} else if (window.Windows) {
|
||||
if (Windows.UI.ViewManagement.ApplicationView.getForCurrentView().isViewModeSupported(Windows.UI.ViewManagement.ApplicationViewMode.compactOverlay)) {
|
||||
list.push('PictureInPicture');
|
|
@ -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) {
|
||||
'use strict';
|
||||
import connectionManager from 'connectionManager';
|
||||
|
||||
function PhotoPlayer() {
|
||||
|
||||
var self = this;
|
||||
|
||||
self.name = 'Photo Player';
|
||||
self.type = 'mediaplayer';
|
||||
self.id = 'photoplayer';
|
||||
|
||||
// Let any players created by plugins take priority
|
||||
self.priority = 1;
|
||||
export default class PhotoPlayer {
|
||||
constructor() {
|
||||
this.name = 'Photo Player';
|
||||
this.type = 'mediaplayer';
|
||||
this.id = 'photoplayer';
|
||||
this.priority = 1;
|
||||
}
|
||||
|
||||
PhotoPlayer.prototype.play = function (options) {
|
||||
play(options) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['slideshow'], function (slideshow) {
|
||||
import('slideshow').then(({default: slideshow}) => {
|
||||
|
||||
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 PhotoPlayer;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -14,10 +14,6 @@ define([], function () {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (userAgent.indexOf('nintendo') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (userAgent.indexOf('viera') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
@ -93,7 +89,7 @@ define([], function () {
|
|||
var _supportsCssAnimation;
|
||||
var _supportsCssAnimationWithPrefix;
|
||||
function supportsCssAnimation(allowPrefix) {
|
||||
|
||||
// TODO: Assess if this is still needed, as all of our targets should natively support CSS animations.
|
||||
if (allowPrefix) {
|
||||
if (_supportsCssAnimationWithPrefix === true || _supportsCssAnimationWithPrefix === false) {
|
||||
return _supportsCssAnimationWithPrefix;
|
||||
|
@ -145,7 +141,6 @@ define([], function () {
|
|||
/(chrome)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(safari)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(firefox)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(msie) ([\w.]+)/.exec(ua) ||
|
||||
ua.indexOf('compatible') < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
|
||||
[];
|
||||
|
||||
|
@ -161,14 +156,6 @@ define([], function () {
|
|||
|
||||
if (browser === 'edge') {
|
||||
platform_match = [''];
|
||||
} else {
|
||||
if (ua.indexOf('windows phone') !== -1 || ua.indexOf('iemobile') !== -1) {
|
||||
|
||||
// http://www.neowin.net/news/ie11-fakes-user-agent-to-fool-gmail-in-windows-phone-81-gdr1-update
|
||||
browser = 'msie';
|
||||
} else if (ua.indexOf('like gecko') !== -1 && ua.indexOf('webkit') === -1 && ua.indexOf('opera') === -1 && ua.indexOf('chrome') === -1 && ua.indexOf('safari') === -1) {
|
||||
browser = 'msie';
|
||||
}
|
||||
}
|
||||
|
||||
if (browser === 'opr') {
|
||||
|
@ -211,7 +198,7 @@ define([], function () {
|
|||
browser[matched.platform] = true;
|
||||
}
|
||||
|
||||
if (!browser.chrome && !browser.msie && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf('webkit') !== -1) {
|
||||
if (!browser.chrome && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf('webkit') !== -1) {
|
||||
browser.safari = true;
|
||||
}
|
||||
|
||||
|
@ -224,7 +211,10 @@ define([], function () {
|
|||
browser.mobile = true;
|
||||
}
|
||||
|
||||
browser.xboxOne = userAgent.toLowerCase().indexOf('xbox') !== -1;
|
||||
if (userAgent.toLowerCase().indexOf('xbox') !== -1) {
|
||||
browser.xboxOne = true;
|
||||
browser.tv = true;
|
||||
}
|
||||
browser.animate = typeof document !== 'undefined' && document.documentElement.animate != null;
|
||||
browser.tizen = userAgent.toLowerCase().indexOf('tizen') !== -1 || self.tizen != null;
|
||||
browser.web0s = userAgent.toLowerCase().indexOf('Web0S'.toLowerCase()) !== -1;
|
||||
|
|
|
@ -188,20 +188,6 @@ define(['browser'], function (browser) {
|
|||
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) {
|
||||
var supported = false;
|
||||
var profileContainer = container;
|
||||
|
@ -230,9 +216,6 @@ define(['browser'], function (browser) {
|
|||
break;
|
||||
case 'flv':
|
||||
supported = browser.tizen || browser.orsay;
|
||||
//if (!supported && window.MediaSource != null && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"')) {
|
||||
// return getFlvMseDirectPlayProfile();
|
||||
//}
|
||||
break;
|
||||
case '3gp':
|
||||
case 'mts':
|
||||
|
|
|
@ -209,7 +209,7 @@ define(['datetime', 'jQuery', 'globalize', 'material-icons'], function (datetime
|
|||
function onNodeOpen(event, data) {
|
||||
var page = $(this).parents('.page')[0];
|
||||
var node = data.node;
|
||||
if (node.children && node.children) {
|
||||
if (node.children) {
|
||||
loadNodesToLoad(page, node);
|
||||
}
|
||||
if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) {
|
||||
|
@ -221,7 +221,7 @@ define(['datetime', 'jQuery', 'globalize', 'material-icons'], function (datetime
|
|||
function onNodeLoad(event, data) {
|
||||
var page = $(this).parents('.page')[0];
|
||||
var node = data.node;
|
||||
if (node.children && node.children) {
|
||||
if (node.children) {
|
||||
loadNodesToLoad(page, node);
|
||||
}
|
||||
if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) {
|
||||
|
|
|
@ -602,27 +602,25 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
|||
if (libraryMenuOptions) {
|
||||
getUserViews(apiClient, userId).then(function (result) {
|
||||
var items = result;
|
||||
var html = '';
|
||||
html += '<h3 class="sidebarHeader">';
|
||||
html += globalize.translate('HeaderMedia');
|
||||
html += '</h3>';
|
||||
var html = `<h3 class="sidebarHeader">${globalize.translate('HeaderMedia')}</h3>`;
|
||||
html += items.map(function (i) {
|
||||
var icon = i.icon || imageHelper.getLibraryIcon(i.CollectionType);
|
||||
var itemId = i.Id;
|
||||
|
||||
if (i.onclick) {
|
||||
i.onclick;
|
||||
}
|
||||
const linkHtml = `<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 '<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('');
|
||||
libraryMenuOptions.innerHTML = html;
|
||||
var elem = libraryMenuOptions;
|
||||
var sidebarLinks = elem.querySelectorAll('.navMenuOption');
|
||||
|
||||
for (var i = 0, length = sidebarLinks.length; i < length; i++) {
|
||||
sidebarLinks[i].removeEventListener('click', onSidebarLinkClick);
|
||||
sidebarLinks[i].addEventListener('click', onSidebarLinkClick);
|
||||
for (const sidebarLink of sidebarLinks) {
|
||||
sidebarLink.removeEventListener('click', onSidebarLinkClick);
|
||||
sidebarLink.addEventListener('click', onSidebarLinkClick);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -936,6 +934,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
|||
|
||||
updateMenuForPageType(isDashboardPage, isLibraryPage);
|
||||
|
||||
// TODO: Seems to do nothing? Check if needed (also in other views).
|
||||
if (!e.detail.isRestored) {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
|
|
@ -69,10 +69,11 @@ define(['loading', 'listView', 'cardBuilder', 'libraryMenu', 'libraryBrowser', '
|
|||
showLoadingMessage();
|
||||
var query = getQuery(view);
|
||||
var promise1 = ApiClient.getItems(Dashboard.getCurrentUserId(), query);
|
||||
// TODO: promise2 is unused, check if necessary.
|
||||
var promise2 = Dashboard.getCurrentUser();
|
||||
Promise.all([promise1, promise2]).then(function (responses) {
|
||||
var result = responses[0];
|
||||
responses[1];
|
||||
// TODO: Is the scroll necessary?
|
||||
window.scrollTo(0, 0);
|
||||
var html = '';
|
||||
var viewStyle = getPageData(view).view;
|
||||
|
|
|
@ -180,6 +180,20 @@ export class UserSettings {
|
|||
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.
|
||||
* @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 enableThemeVideos = currentSettings.enableThemeVideos.bind(currentSettings);
|
||||
export const enableFastFadein = currentSettings.enableFastFadein.bind(currentSettings);
|
||||
export const enableBlurhash = currentSettings.enableBlurhash.bind(currentSettings);
|
||||
export const enableBackdrops = currentSettings.enableBackdrops.bind(currentSettings);
|
||||
export const detailsBanner = currentSettings.detailsBanner.bind(currentSettings);
|
||||
export const language = currentSettings.language.bind(currentSettings);
|
||||
|
|
|
@ -375,8 +375,7 @@ var AppInfo = {};
|
|||
}
|
||||
}
|
||||
|
||||
function initRequireWithBrowser(browser) {
|
||||
var bowerPath = getBowerPath();
|
||||
function initRequireWithBrowser() {
|
||||
var componentsPath = getComponentsPath();
|
||||
var scriptsPath = getScriptsPath();
|
||||
|
||||
|
@ -385,13 +384,7 @@ var AppInfo = {};
|
|||
define('lazyLoader', [componentsPath + '/lazyLoader/lazyLoaderIntersectionObserver'], returnFirstDependency);
|
||||
define('shell', [scriptsPath + '/shell'], returnFirstDependency);
|
||||
|
||||
if ('registerElement' in document) {
|
||||
define('registerElement', []);
|
||||
} else if (browser.msie) {
|
||||
define('registerElement', ['webcomponents'], returnFirstDependency);
|
||||
} else {
|
||||
define('registerElement', ['document-register-element'], returnFirstDependency);
|
||||
}
|
||||
|
||||
define('alert', [componentsPath + '/alert'], returnFirstDependency);
|
||||
|
||||
|
@ -486,21 +479,22 @@ var AppInfo = {};
|
|||
function loadPlugins(appHost, browser, shell) {
|
||||
console.debug('loading installed plugins');
|
||||
var list = [
|
||||
'components/playback/playaccessvalidation',
|
||||
'components/playback/experimentalwarnings',
|
||||
'components/htmlAudioPlayer/plugin',
|
||||
'components/htmlVideoPlayer/plugin',
|
||||
'components/photoPlayer/plugin',
|
||||
'components/youtubeplayer/plugin',
|
||||
'components/backdropScreensaver/plugin',
|
||||
'components/logoScreensaver/plugin'
|
||||
'plugins/playAccessValidation/plugin',
|
||||
'plugins/experimentalWarnings/plugin',
|
||||
'plugins/htmlAudioPlayer/plugin',
|
||||
'plugins/htmlVideoPlayer/plugin',
|
||||
'plugins/photoPlayer/plugin',
|
||||
'plugins/bookPlayer/plugin',
|
||||
'plugins/youtubePlayer/plugin',
|
||||
'plugins/backdropScreensaver/plugin',
|
||||
'plugins/logoScreensaver/plugin'
|
||||
];
|
||||
|
||||
if (appHost.supports('remotecontrol')) {
|
||||
list.push('components/sessionPlayer');
|
||||
list.push('plugins/sessionPlayer/plugin');
|
||||
|
||||
if (browser.chrome || browser.opera) {
|
||||
list.push('components/chromecast/chromecastplayer');
|
||||
list.push('plugins/chromecastPlayer/plugin');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -561,6 +555,7 @@ var AppInfo = {};
|
|||
require(['components/playback/volumeosd']);
|
||||
}
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (navigator.mediaSession || window.NativeShell) {
|
||||
require(['mediaSession']);
|
||||
}
|
||||
|
@ -616,8 +611,8 @@ var AppInfo = {};
|
|||
/* eslint-enable compat/compat */
|
||||
}
|
||||
|
||||
function onWebComponentsReady(browser) {
|
||||
initRequireWithBrowser(browser);
|
||||
function onWebComponentsReady() {
|
||||
initRequireWithBrowser();
|
||||
|
||||
if (self.appMode === 'cordova' || self.appMode === 'android' || self.appMode === 'standalone') {
|
||||
AppInfo.isNativeApp = true;
|
||||
|
@ -659,7 +654,8 @@ var AppInfo = {};
|
|||
nowPlayingHelper: componentsPath + '/playback/nowplayinghelper',
|
||||
pluginManager: componentsPath + '/pluginManager',
|
||||
packageManager: componentsPath + '/packagemanager',
|
||||
screensaverManager: componentsPath + '/screensavermanager'
|
||||
screensaverManager: componentsPath + '/screensavermanager',
|
||||
chromecastHelper: 'plugins/chromecastPlayer/chromecastHelpers'
|
||||
};
|
||||
|
||||
requirejs.onError = onRequireJsError;
|
||||
|
@ -677,6 +673,7 @@ var AppInfo = {};
|
|||
'fetch',
|
||||
'flvjs',
|
||||
'jstree',
|
||||
'epubjs',
|
||||
'jQuery',
|
||||
'hlsjs',
|
||||
'howler',
|
||||
|
@ -778,7 +775,6 @@ var AppInfo = {};
|
|||
define('appSettings', [scriptsPath + '/settings/appSettings'], returnFirstDependency);
|
||||
define('userSettings', [scriptsPath + '/settings/userSettings'], returnFirstDependency);
|
||||
|
||||
define('chromecastHelper', [componentsPath + '/chromecast/chromecasthelpers'], returnFirstDependency);
|
||||
define('mediaSession', [componentsPath + '/playback/mediasession'], returnFirstDependency);
|
||||
define('actionsheet', [componentsPath + '/actionSheet/actionSheet'], returnFirstDependency);
|
||||
define('tunerPicker', [componentsPath + '/tunerPicker'], returnFirstDependency);
|
||||
|
@ -1137,7 +1133,7 @@ var AppInfo = {};
|
|||
});
|
||||
})();
|
||||
|
||||
return require(['browser'], onWebComponentsReady);
|
||||
return onWebComponentsReady();
|
||||
}();
|
||||
|
||||
pageClassOn('viewshow', 'standalonePage', function () {
|
||||
|
|
|
@ -1540,8 +1540,6 @@
|
|||
"CopyStreamURLError": "Při kopírování URL došlo k chybě.",
|
||||
"LabelVideoResolution": "Rozlišení videa:",
|
||||
"LabelStreamType": "Typ streamu:",
|
||||
"EnableFastImageFadeInHelp": "Zobrazí plakáty a další obrázky s rychlejší animací přechodu po dokončení načítání.",
|
||||
"EnableFastImageFadeIn": "Rychlé animace přechodů obrazu",
|
||||
"LabelPlayerDimensions": "Zobrazené rozlišení:",
|
||||
"LabelDroppedFrames": "Vynechané snímky:",
|
||||
"LabelCorruptedFrames": "Poškozené snímky:",
|
||||
|
@ -1603,7 +1601,7 @@
|
|||
"HeaderDVR": "Nahrávání",
|
||||
"SaveChanges": "Uložit změny",
|
||||
"LabelSyncPlayPlaybackDiff": "Rozdíl v době přehrávání:",
|
||||
"SyncPlayAccessHelp": "Určuje úroveň přístupu k synchronizaci přehrávání, kterou tento uživatel bude mít. Tato funkce umožňuje synchronizovat přehrávání s dalšími uživateli.",
|
||||
"SyncPlayAccessHelp": "Určuje úroveň přístupu k synchronizaci přehrávání, kterou tento uživatel bude mít. Tato funkce umožňuje synchronizovat přehrávání s dalšími zařízeními.",
|
||||
"MessageSyncPlayErrorMedia": "Zapnutí synchronizace přehrávání se nezdařilo. Chyba média.",
|
||||
"MessageSyncPlayErrorMissingSession": "Zapnutí synchronizace přehrávání se nezdařilo. Nebyla nalezena relace.",
|
||||
"MessageSyncPlayErrorNoActivePlayer": "Nebyl nalezen žádný aktivní přehrávač. Synchronizace přehrávání byla vypnuta.",
|
||||
|
@ -1633,5 +1631,7 @@
|
|||
"HeaderSyncPlayEnabled": "Synchronizace přehrávání povolena",
|
||||
"HeaderSyncPlaySelectGroup": "Připojit ke skupině",
|
||||
"EnableDetailsBannerHelp": "Zobrazí obrázek ve vrchní části detailu položky.",
|
||||
"EnableDetailsBanner": "Obrázek detailu"
|
||||
"EnableDetailsBanner": "Obrázek detailu",
|
||||
"ShowMore": "Zobrazit více",
|
||||
"ShowLess": "Zobrazit méně"
|
||||
}
|
||||
|
|
|
@ -1569,8 +1569,6 @@
|
|||
"LabelStreamType": "Stream type:",
|
||||
"LabelSonyAggregationFlags": "Sony aggregering flag:",
|
||||
"LabelSize": "Størrelse:",
|
||||
"EnableFastImageFadeInHelp": "Aktivér hurtigere fade-in-animation til indlæste billeder",
|
||||
"EnableFastImageFadeIn": "Hurtigt billede indtoning",
|
||||
"LabelPleaseRestart": "Ændringer vil træde i kraft efter web klienten er blevet genindlæst manuelt.",
|
||||
"LabelPlayMethod": "Afspilnings metode:",
|
||||
"LabelPlayerDimensions": "Afspillerdimensioner:",
|
||||
|
|
|
@ -1478,8 +1478,6 @@
|
|||
"MessageConfirmAppExit": "Wirklich verlassen?",
|
||||
"LabelVideoResolution": "Videoauflösung:",
|
||||
"LabelStreamType": "Streamtyp:",
|
||||
"EnableFastImageFadeInHelp": "Aktiviere schnellere Einblendeanimation für geladene Bilder",
|
||||
"EnableFastImageFadeIn": "Schnelle Bildeinblendung",
|
||||
"LabelPlayerDimensions": "Playerabmessungen:",
|
||||
"LabelDroppedFrames": "Verlorene Frames:",
|
||||
"LabelCorruptedFrames": "Fehlerhafte Frames:",
|
||||
|
@ -1540,7 +1538,7 @@
|
|||
"HeaderServerAddressSettings": "Server-Adresseinstellungen",
|
||||
"HeaderRemoteAccessSettings": "Fernzugriffs-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.",
|
||||
"MessageSyncPlayErrorMissingSession": "SyncPlay konnte nicht aktiviert werden! Fehlende Sitzung.",
|
||||
"MessageSyncPlayErrorNoActivePlayer": "Keine aktive Wiedergabe gefunden. SyncPlay wurde deaktiviert.",
|
||||
|
@ -1569,5 +1567,9 @@
|
|||
"MillisecondsUnit": "ms",
|
||||
"LabelSyncPlayTimeOffset": "Zeitversatz mit dem Server:",
|
||||
"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:",
|
||||
"LabelSeasonNumber": "Season number:",
|
||||
"LabelScreensaver": "Screensaver:",
|
||||
"EnableFastImageFadeIn": "Fast image fade-in",
|
||||
"EnableFastImageFadeInHelp": "Enable faster fade-in animation for loaded images",
|
||||
"EnableFasterAnimations": "Faster animations",
|
||||
"EnableFasterAnimationsHelp": "Use faster animations and transitions",
|
||||
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
|
||||
"LabelSaveLocalMetadataHelp": "Saving artwork into media folders will put them in a place where they can be easily edited.",
|
||||
"LabelRuntimeMinutes": "Run time (minutes):",
|
||||
|
|
|
@ -826,8 +826,8 @@
|
|||
"LabelSaveLocalMetadataHelp": "Saving artwork into media folders will put them in a place where they can be easily edited.",
|
||||
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
|
||||
"LabelScreensaver": "Screensaver:",
|
||||
"EnableFastImageFadeIn": "Fast Image Fade Animations",
|
||||
"EnableFastImageFadeInHelp": "Show posters and other images with a quicker fade animation when they finish loading.",
|
||||
"EnableFasterAnimations": "Faster animations",
|
||||
"EnableFasterAnimationsHelp": "Use faster animations and transitions",
|
||||
"LabelSeasonNumber": "Season number:",
|
||||
"LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:",
|
||||
"LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.",
|
||||
|
@ -1373,6 +1373,8 @@
|
|||
"Share": "Share",
|
||||
"ShowAdvancedSettings": "Show advanced settings",
|
||||
"ShowIndicatorsFor": "Show indicators for:",
|
||||
"ShowLess": "Show less",
|
||||
"ShowMore": "Show more",
|
||||
"ShowTitle": "Show title",
|
||||
"ShowYear": "Show year",
|
||||
"Shows": "Shows",
|
||||
|
@ -1403,7 +1405,7 @@
|
|||
"Suggestions": "Suggestions",
|
||||
"Sunday": "Sunday",
|
||||
"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.",
|
||||
"TV": "TV",
|
||||
"TabAccess": "Access",
|
||||
|
@ -1546,5 +1548,7 @@
|
|||
"EveryHour": "Every hour",
|
||||
"EveryXHours": "Every {0} hours",
|
||||
"OnApplicationStartup": "On application startup",
|
||||
"UnsupportedPlayback": "Jellyfin cannot decrypt content protected by DRM but all content will be attempted regardless, including protected titles. Some files may appear completely black due to encryption or other unsupported features, such as interactive titles."
|
||||
"UnsupportedPlayback": "Jellyfin cannot decrypt content protected by DRM but all content will be attempted regardless, including protected titles. Some files may appear completely black due to encryption or other unsupported features, such as interactive titles.",
|
||||
"EnableBlurhash": "Enable blurred placeholders for images",
|
||||
"EnableBlurhashHelp": "Images that are still being loaded will be displayed with a blurred placeholder"
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"AddToCollection": "Aldoni al kolekto",
|
||||
"Actor": "Aktoro",
|
||||
"Absolute": "Absoluto"
|
||||
"Absolute": "Absoluta"
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
"AnamorphicVideoNotSupported": "Video anamorfico no soportado",
|
||||
"AnyLanguage": "Cualquier idioma",
|
||||
"Anytime": "En cualquier momento",
|
||||
"AroundTime": "Alrededor de {0}",
|
||||
"AroundTime": "Alrededor de",
|
||||
"Art": "Arte",
|
||||
"Artists": "Artistas",
|
||||
"AsManyAsPossible": "Tantos como sea posible",
|
||||
|
@ -103,7 +103,7 @@
|
|||
"ButtonRemove": "Remover",
|
||||
"ButtonRename": "Renombrar",
|
||||
"ButtonRepeat": "Repetir",
|
||||
"ButtonResetEasyPassword": "Reiniciar el código pin sencillo",
|
||||
"ButtonResetEasyPassword": "Restablecer código PIN sencillo",
|
||||
"ButtonResetPassword": "Restablecer contraseña",
|
||||
"ButtonRestart": "Reiniciar",
|
||||
"ButtonResume": "Continuar",
|
||||
|
@ -203,7 +203,7 @@
|
|||
"EnableBackdrops": "Imágenes de fondo",
|
||||
"EnableBackdropsHelp": "Muestra imágenes de fondo en el fondo de algunas páginas mientras se navega por la biblioteca.",
|
||||
"EnableCinemaMode": "Modo cine",
|
||||
"EnableColorCodedBackgrounds": "Fondos de color codificados",
|
||||
"EnableColorCodedBackgrounds": "Fondos de colores codificados",
|
||||
"EnableDisplayMirroring": "Duplicado de pantalla",
|
||||
"EnableExternalVideoPlayers": "Reproductores de video externos",
|
||||
"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",
|
||||
"HeaderRecordingPostProcessing": "Post procesado de las grabaciones",
|
||||
"HeaderRemoteControl": "Control remoto",
|
||||
"HeaderRemoveMediaFolder": "Eliminar carpeta de medios",
|
||||
"HeaderRemoveMediaLocation": "Eliminar ubicación de medios",
|
||||
"HeaderRemoveMediaFolder": "Remover carpeta de medios",
|
||||
"HeaderRemoveMediaLocation": "Remover ubicación de medios",
|
||||
"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.",
|
||||
"HeaderRestart": "Reiniciar",
|
||||
|
@ -697,7 +697,7 @@
|
|||
"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.",
|
||||
"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:",
|
||||
"LabelOriginalTitle": "Título original:",
|
||||
"LabelOverview": "Resumen:",
|
||||
|
@ -878,7 +878,7 @@
|
|||
"MessageConfirmDeleteTunerDevice": "¿Estás seguro de querer eliminar este dispositivo?",
|
||||
"MessageConfirmProfileDeletion": "¿Estás seguro de querer eliminar este perfil?",
|
||||
"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?",
|
||||
"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?",
|
||||
|
@ -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.",
|
||||
"MessageReenableUser": "Ver abajo para volver a habilitar",
|
||||
"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.",
|
||||
"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.",
|
||||
|
@ -1453,7 +1453,6 @@
|
|||
"LabelTranscodingFramerate": "Velocidad de cuadros de la transcodificación:",
|
||||
"LabelSize": "Tamaño:",
|
||||
"SelectAdminUsername": "Por favor, selecciona un nombre de usuario para la cuenta de administrador.",
|
||||
"EnableFastImageFadeInHelp": "Habilita una animación más rápida de desvanecimiento para las imágenes cargadas",
|
||||
"LabelDroppedFrames": "Cuadros saltados:",
|
||||
"CopyStreamURLError": "Hubo un error al copiar la URL.",
|
||||
"ButtonSplit": "Dividir",
|
||||
|
@ -1484,7 +1483,6 @@
|
|||
"MessageConfirmAppExit": "¿Deseas salir?",
|
||||
"LabelVideoResolution": "Resolución de video:",
|
||||
"LabelStreamType": "Tipo de transmisión:",
|
||||
"EnableFastImageFadeIn": "Desvanecimiento rápido de las imágenes",
|
||||
"LabelPlayerDimensions": "Dimensiones del reproductor:",
|
||||
"LabelCorruptedFrames": "Cuadros corruptos:",
|
||||
"HeaderNavigation": "Navegación",
|
||||
|
@ -1524,5 +1522,37 @@
|
|||
"HeaderRemoteAccessSettings": "Opciones de acceso remoto",
|
||||
"HeaderHttpsSettings": "Opciones HTTPS",
|
||||
"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",
|
||||
"AddItemToCollectionHelp": "Agregue elementos a las colecciones buscándolos y haciendo clic con el botón derecho o tocando los menús para agregarlos a una colección.",
|
||||
"AddToCollection": "Añadir a la colección",
|
||||
|
@ -1458,8 +1458,8 @@
|
|||
"ButtonSplit": "Dividir",
|
||||
"HeaderNavigation": "Navegación",
|
||||
"MessageConfirmAppExit": "¿Quieres salir?",
|
||||
"EnableFastImageFadeInHelp": "Mostrar carteles y otras imágenes con difuminado rápido cuando termine la carga.",
|
||||
"EnableFastImageFadeIn": "Difuminado rápido de imágenes",
|
||||
"EnableFasterAnimationsHelp": "Las animaciones y transiciones durarán menos tiempo",
|
||||
"EnableFasterAnimations": "Animaciones más rápidas",
|
||||
"CopyStreamURLError": "Ha habido un error copiando la dirección.",
|
||||
"AllowFfmpegThrottlingHelp": "Cuando una transcodificación o un remux se adelanta lo suficiente desde la posición de reproducción actual, pause el proceso para que consuma menos recursos. Esto es más útil cuando se reproduce de forma linear, sin saltar de posición de reproducción a menudo. Desactívelo si experimenta problemas de reproducción.",
|
||||
"PlaybackErrorNoCompatibleStream": "Este contenido no es compatible con este dispositivo y no se puede reproducir: No se puede obtener del servidor en un formato compatible.",
|
||||
|
@ -1524,8 +1524,10 @@
|
|||
"LabelEnableHttps": "Activar HTTPS",
|
||||
"TabDVR": "DVR",
|
||||
"SaveChanges": "Guardar cambios",
|
||||
"EnableBlurhash": "Mostrar una representación de las imágenes mientras cargan",
|
||||
"EnableBlurhashHelp": "Aparecerá una representación de los colores de las imágenes antes de que terminen de cargar",
|
||||
"HeaderDVR": "DVR",
|
||||
"SyncPlayAccessHelp": "Selecciona 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.",
|
||||
"MessageSyncPlayErrorMissingSession": "¡No se pudo activar SyncPlay! Sesión desconectada.",
|
||||
"MessageSyncPlayErrorNoActivePlayer": "No hay reproductor activo. SyncPlay ha sido desactivado.",
|
||||
|
@ -1556,5 +1558,7 @@
|
|||
"HeaderSyncPlayEnabled": "Syncplay activo",
|
||||
"HeaderSyncPlaySelectGroup": "Unirse a un grupo",
|
||||
"EnableDetailsBannerHelp": "Mostrar imagen de banner en el tope de la página de detalles del elemento.",
|
||||
"EnableDetailsBanner": "Barra de Detalles"
|
||||
"EnableDetailsBanner": "Barra de Detalles",
|
||||
"ShowMore": "Mostrar más",
|
||||
"ShowLess": "Mostrar menos"
|
||||
}
|
||||
|
|
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": "حذف این مورد، آن را هم از فایل سیستمی و هم از کتابخانه رسانه شما حذف می کند. آیا اطمینان دارید که میخواهید ادامه دهید؟",
|
||||
"AlwaysPlaySubtitlesHelp": "زیرنویسهای متناسب با توجه به اولویت زبان بدون در نظر گرفتن زبان صوتی ویدیو پخش می شوند.",
|
||||
"AllowedRemoteAddressesHelp": "لیستی از آدرس های IP یا ورودیهای IP/netmask برای شبکه هایی که به آنها امکان ارتباط از راه دور داده میشود ، با کاما از هم جدا شدند. در صورت خالی ماندن ، تمام آدرسهای راه دور مجاز خواهند بود.",
|
||||
"AllowOnTheFlySubtitleExtractionHelp": "زیرنویس های جاسازی شده را میتوان از فیلمها استخراج کرد و به منظور جلوگیری از کدگذاری فیلم ، به صورت متن ساده به بازدید کننده ارسال کرد. در بعضی از سیستمها این میتواند مدت زیادی طول بکشد و باعث شود پخش فیلم در طول فرآیند استخراج متوقف شود. این گزینه را غیرفعال کنید تا زیرنویسهای جاسازی شده با استفاده از رمزگذاری ویدیو در حالی که به طور محلی توسط دستگاه بازدیدکننده پشتیبانی نمیشوند ارسال شود.",
|
||||
"AllowOnTheFlySubtitleExtractionHelp": "زیرنویس های جاسازی شده را میتوان از ویدئو ها استخراج کرد و به منظور جلوگیری از کدگذاری فیلم ، به صورت متن ساده به بازدید کننده ارسال کرد. در بعضی از سیستمها این میتواند مدت زیادی طول بکشد و باعث شود پخش فیلم در طول فرآیند استخراج متوقف شود. این گزینه را غیرفعال کنید تا زیرنویسهای جاسازی شده با استفاده از رمزگذاری ویدیو در حالی که به طور محلی توسط دستگاه بازدیدکننده پشتیبانی نمیشوند ارسال شود.",
|
||||
"AdditionalNotificationServices": "برای نصب سرویسهای اعلان اضافی، در فروشگاه افزونهها جستجو کنید.",
|
||||
"OptionThumbCard": "کارت بندانگشتی",
|
||||
"OptionThumb": "بندانگشتی",
|
||||
|
@ -702,5 +702,102 @@
|
|||
"MessageUnauthorizedUser": "در حال حاضر مجاز به دسترسی به سرور نیستید. لطفا برای اطلاعات بیشتر با مدیر سرور خود تماس بگیرید.",
|
||||
"MessageInvalidUser": "نام کاربری یا گذرواژه نامعتبر است. لطفا دوباره تلاش کنید.",
|
||||
"MessageInvalidForgotPasswordPin": "کد پین نامعتبر یا منقضی شده وارد شد. لطفا دوباره تلاش کنید.",
|
||||
"MessageInstallPluginFromApp": "این افزونه باید از داخل برنامهای که قصد استفاده از آن را دارید نصب شود."
|
||||
"MessageInstallPluginFromApp": "این افزونه باید از داخل برنامهای که قصد استفاده از آن را دارید نصب شود.",
|
||||
"PasswordResetHeader": "بازنشانی گذرواژه",
|
||||
"PasswordResetConfirmation": "آیا واقعا تمایل به بازنشانی گذرواژه دارید؟",
|
||||
"PasswordResetComplete": "گذرواژه بازنشانی شد.",
|
||||
"PasswordMatchError": "گذرواژه و تکرار گذرواژه باید یکسان باشند.",
|
||||
"PackageInstallFailed": "{0} (نسخه {1}) نصب به مشکل برخورد.",
|
||||
"PackageInstallCompleted": "{0} (نسخه {1})نصب به پایان رسید.",
|
||||
"PackageInstallCancelled": "{0} ( نسخه {1})نصب لغو شد.",
|
||||
"Overview": "بررسی اجمالی",
|
||||
"OtherArtist": "هنرمند دیگر",
|
||||
"OriginalAirDateValue": "زمان پخش اصلی : {0}",
|
||||
"OptionWeekly": "هفتگی",
|
||||
"OptionWeekends": "آخر هفته ها",
|
||||
"OptionWeekdays": "روز های هفته",
|
||||
"OptionWednesday": "چهارشنبه",
|
||||
"OptionWakeFromSleep": "از خواب بیدار شدن",
|
||||
"OptionUnairedEpisode": "قسمت های پخش نشده",
|
||||
"OptionTvdbRating": "نمره TVDB",
|
||||
"OptionTuesday": "سه شنبه",
|
||||
"OptionTrackName": "نام ترک",
|
||||
"OptionRequirePerfectSubtitleMatchHelp": "نتیجه کامل زیرنویس ها را به صورتی فیلتر می کند که فقط مواردی را که دقیقا با فایل تصویری شما آزمایش و تأیید شده اند ،شامل شود. حذف این گزینه احتمال بارگیری زیرنویس ها را افزایش می دهد ، اما شانس متن زیرنویس ناهماهنگ یا غلط نیز افزایش می یابد.",
|
||||
"ServerNameIsShuttingDown": "سرور جلی فین - {0} در حال خاموش شدن می باشد.",
|
||||
"ServerNameIsRestarting": "سرور جلی فین - {0} در حال راه اندازی مجدد می باشد.",
|
||||
"SeriesYearToPresent": "{0}- در حال حاضر",
|
||||
"SeriesSettings": "تنظیمات سریال",
|
||||
"SeriesRecordingScheduled": "ضبط کردن سریال زمانبندی شد.",
|
||||
"SeriesDisplayOrderHelp": "قسمت ها را بر اساس تاریخ پخش شدن، ترتیب دی وی دی یا فقط شماره مرتب کنید.",
|
||||
"SeriesCancelled": "سریال متوقف شده است.",
|
||||
"Series": "سریال ها",
|
||||
"SelectAdminUsername": "لطفا یک نام کاربری برای حساب مدیر انتخاب کنید.",
|
||||
"Season": "فصل",
|
||||
"SearchResults": "نتایج جستجو",
|
||||
"SearchForSubtitles": "زیرنویس ها را جستجو کنید",
|
||||
"SearchForMissingMetadata": "فراداده های گم شده را جستجو کنید",
|
||||
"SearchForCollectionInternetMetadata": "در اینترنت برای پیدا کردن فراداده و عکس جستجو کنید",
|
||||
"Search": "جستجو کردن",
|
||||
"Screenshots": "نماگرفت ها",
|
||||
"Screenshot": "نماگرفت",
|
||||
"Schedule": "برنامه زمانی",
|
||||
"ScanLibrary": "کتابخانه را اسکن کنید",
|
||||
"ScanForNewAndUpdatedFiles": "فایل های جدید و به روز رسانی شده را اسکن کنید",
|
||||
"ChannelAccessHelp": "کانال هایی که قصد اشتراک گذاری با این کاربر را دارید انتخاب کنید. مدیران توانایی ویرایش همه ی کانال ها را با استفاده از مدیریت فراداده دارند.",
|
||||
"ChangingMetadataImageSettingsNewContent": "تغییر تنظیمات دانلود فراداده ها و عکس ها فقط بر روی محتواهای جدیدی که به کتابخانه اضافه می شوند، اعمال می شوند. برای اعمال تغییرات بر روی محتوای موجود، شما باید فراداده را به صورت دستی به روزرسانی کنید.",
|
||||
"Refresh": "بهروزرسانی",
|
||||
"Recordings": "ضبط شده ها",
|
||||
"RecordingScheduled": "ضبط برنامه ریزی شد.",
|
||||
"RecordingPathChangeMessage": "با تغییر محل ذخیره فایل های ضبط شده، فایل های موجود به صورت خودکار منتقل نمی شوند. در صورت نیاز، شما باید خودتان این کار را انجام دهید.",
|
||||
"RecordingCancelled": "ضبط شدن لغو شد.",
|
||||
"RecordSeries": "ضبط کردن سریال ها",
|
||||
"Record": "ضبط کردن",
|
||||
"RecommendationStarring": "با هنرمندی {0}",
|
||||
"RecommendationDirectedBy": "کارگردانی شده توسط {0}",
|
||||
"RecommendationBecauseYouWatched": "برای اینکه تو {0} مشاهده کردی",
|
||||
"RecommendationBecauseYouLike": "برای اینکه تو {0} را نیز دوست داری",
|
||||
"RecentlyWatched": "اخیرا مشاهده شده",
|
||||
"Rate": "ارزیابی کن",
|
||||
"Raised": "مطرح شده",
|
||||
"QueueAllFromHere": "همه را از اینجا در صف قرار بده",
|
||||
"Quality": "کیفیت",
|
||||
"Programs": "برنامه ها",
|
||||
"ProductionLocations": "محل تولید",
|
||||
"Producer": "تولید کننده",
|
||||
"Primary": "اصلی",
|
||||
"Previous": "قبلی",
|
||||
"Premieres": "برتر ها",
|
||||
"Premiere": "برتر",
|
||||
"PreferEmbeddedEpisodeInfosOverFileNames": "اطلاعات تعبیه شده در فراداده را به اسم فایل ترجیح بده",
|
||||
"PreferEmbeddedEpisodeInfosOverFileNamesHelp": "این از اطلاعات قسمت در فراداده های تعبیه شده در صورت موجود استفاده می کند.",
|
||||
"PreferEmbeddedTitlesOverFileNamesHelp": "این عنوان نمایش را به صورت پیش فرض تعیین می کند، زمانی که فراداده اینترنتی یا محلی موجود نباشند.",
|
||||
"PreferEmbeddedTitlesOverFileNames": "عنوان های تعبیه شده را به نام فایل ترجیح بده",
|
||||
"PluginInstalledMessage": "افزونه با موفقیت نصب شد. برای اعمال تغییرات سرور جلیفین نیاز به بارگذاری مجدد دارد.",
|
||||
"PleaseSelectTwoItems": "لطفا حداقل دو مورد را انتخاب کنید.",
|
||||
"PleaseRestartServerName": "لطفا سرور جلیفین را دوباره بارگذاری کنید - {0}.",
|
||||
"PleaseEnterNameOrId": "لطفا یک نام یا شناسه خارجی را وارد کنید.",
|
||||
"PleaseConfirmPluginInstallation": "لطفا با کلیک بر روی OK تایید کنید که شما متن بالا را خوانده اید و می خواهید که افزونه را نصب کنید.",
|
||||
"PleaseAddAtLeastOneFolder": "لطفا حداقل یک پوشه به این کتابخانه با کلیک بر روی \"افزودن\" اضافه کنید.",
|
||||
"Played": "اجرا شده",
|
||||
"PlaybackErrorNoCompatibleStream": "سرویس گیرنده با مدیا سازگاری ندارد و سرور یک فرمت سازگار را ارسال نمی کند.",
|
||||
"PlayNextEpisodeAutomatically": "قسمت بعدی را به صورت خودکار اجرا کن",
|
||||
"PlayNext": "بعدی را اجرا کن",
|
||||
"PlayFromBeginning": "از ابتدا اجرا کن",
|
||||
"PlaybackData": "اجرای مجدد داده",
|
||||
"PlayAllFromHere": "همه را از اینجا اجرا کن",
|
||||
"Play": "اجرا کردن",
|
||||
"PinCodeResetConfirmation": "آیا مطمئن هستید که می خواهید کد پین را باز نشانی کنید؟",
|
||||
"PinCodeResetComplete": "کد پین بازنشانی شد.",
|
||||
"PictureInPicture": "تصویر در تصویر",
|
||||
"Person": "فرد",
|
||||
"PerfectMatch": "همتای کامل",
|
||||
"People": "افراد",
|
||||
"MillisecondsUnit": "میلیثانیه",
|
||||
"LabelSyncPlayTimeOffset": "اختلاف زمانی با سرور:",
|
||||
"LabelSeriesRecordingPath": "مسیر ضبط سریالها (اختیاری):",
|
||||
"LabelSelectFolderGroups": "به طور خودکار محتواهای پوشههای زیر را به فیلم ، موسیقی و تلویزیون گروه بندی شود:",
|
||||
"LabelSeasonNumber": "شماره فصل:",
|
||||
"ConfigureDateAdded": "تنظیم کنید که چگونه تاریخ اضافه شده در داشبورد سرور Jellyfin تحت تنظیمات کتابخانه تعیین میشود",
|
||||
"CinemaModeConfigurationHelp": "حالت سینما تجربه تئاتر گونه را مستقیم به اتاق نشیمن شما میآورد با قابلیت پخش تریلرها و پیش نمایشها قبل از سایر ویژگیهای اصلی.",
|
||||
"LaunchWebAppOnStartup": "نمای وب هنگامی که سرور آغاز به کار میکند باز بشود"
|
||||
}
|
||||
|
|
|
@ -1458,8 +1458,6 @@
|
|||
"MessageConfirmAppExit": "Voulez-vous quitter ?",
|
||||
"LabelVideoResolution": "Résolution vidéo :",
|
||||
"LabelStreamType": "Type de flux :",
|
||||
"EnableFastImageFadeInHelp": "Activer un fondu plus rapide pour l'animation des images chargées.",
|
||||
"EnableFastImageFadeIn": "Fondu d'image rapide",
|
||||
"LabelPlayerDimensions": "Dimension du lecteur :",
|
||||
"LabelDroppedFrames": "Images perdues :",
|
||||
"LabelCorruptedFrames": "Images corrompues :",
|
||||
|
|
|
@ -1393,8 +1393,6 @@
|
|||
"ButtonSplit": "Szétvág",
|
||||
"Absolute": "Abszolút",
|
||||
"LabelSkipIfAudioTrackPresentHelp": "Vedd ki a pipát, ha minden videóhoz szeretnél feliratot az audio nyelvétől függetlenül.",
|
||||
"EnableFastImageFadeInHelp": "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",
|
||||
"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.",
|
||||
|
@ -1539,5 +1537,22 @@
|
|||
"LabelSyncPlaySyncMethod": "Szinkronizálási mód:",
|
||||
"MillisecondsUnit": "ms",
|
||||
"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?",
|
||||
"HeaderNavigation": "Navigazione",
|
||||
"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.",
|
||||
"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}",
|
||||
|
@ -1520,5 +1518,37 @@
|
|||
"TabDVR": "DVR",
|
||||
"SaveChanges": "Salva modifiche",
|
||||
"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?",
|
||||
"LabelVideoResolution": "Beıne ajyratymdylyǵy:",
|
||||
"LabelStreamType": "Aǵyn túri:",
|
||||
"EnableFastImageFadeInHelp": "Júktelgen sýretter úshin shapshan kórsetilýin qosý",
|
||||
"EnableFastImageFadeIn": "Sýrettiń shapshan kórsetilýi",
|
||||
"LabelPlayerDimensions": "Oınatqysh ólshemderi:",
|
||||
"LabelDroppedFrames": "Ótkizilgen kadrlar:",
|
||||
"LabelCorruptedFrames": "Búlingen kadrlar:",
|
||||
|
|
|
@ -1343,8 +1343,6 @@
|
|||
"LabelSkipIfAudioTrackPresentHelp": "오디오 언어와 상관없이 모든 비디오가 자막을 갖추도록 하려면 이 항목을 체크하지 마십시오.",
|
||||
"LabelSelectFolderGroupsHelp": "체크되지 않은 폴더는 폴더 고유의 보기 방식으로 표시됩니다.",
|
||||
"LabelSelectFolderGroups": "자동으로 이하의 폴더의 항목을 영화, 음악, TV 와 같은 보기 방식으로 그룹화:",
|
||||
"EnableFastImageFadeInHelp": "로드된 이미지에 더 빠른 페이드 인 효과를 적용",
|
||||
"EnableFastImageFadeIn": "빠른 이미지 페이드 인 효과",
|
||||
"LabelScheduledTaskLastRan": "최근 실행: {0}, 소모시간: {1}.",
|
||||
"LabelRemoteClientBitrateLimitHelp": "(선택) 모든 외부 네트워크로 접속된 장치들에 적용되는 각 스트리밍별 비트레이트 제한입니다. 이는 서버의 인터넷이 처리할 수 있는 한계보다 더 높은 비트레이트를 요청하는 것을 방지할 수 있습니다. 비디오를 더 낮은 비트레이트로 트랜스코딩하기 위해 서버에 높은 CPU 부하를 줄 수 있습니다.",
|
||||
"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.",
|
||||
"MessageInstallPluginFromApp": "Šis paplašinājums ir jāuzstāda no lietotnes, kurā jūs to vēlaties izmantot.",
|
||||
"LabelEmbedAlbumArtDidl": "Ievietot albumu vākus iekš Didl",
|
||||
"EnableFastImageFadeIn": "Ātra attēlu ieplūšana",
|
||||
"EnableFastImageFadeInHelp": "Iespējot ātrāku ieplūšanas animāciju priekš ielādētiem attēliem",
|
||||
"LabelSelectFolderGroups": "Automātiski grupēt saturu no sekojošām datnēm skatos kā Filmas, Mūzika un TV:"
|
||||
}
|
||||
|
|
|
@ -1454,8 +1454,6 @@
|
|||
"SelectAdminUsername": "Vennligst velg et brukernavn for administrator kontoen. ",
|
||||
"HeaderNavigation": "Navigering",
|
||||
"MessageConfirmAppExit": "Vil du avslutte?",
|
||||
"EnableFastImageFadeInHelp": "Bruk rask inntoning av animasjon for lastede bilder",
|
||||
"EnableFastImageFadeIn": "Rask bilde inntoning",
|
||||
"CopyStreamURLError": "Det var en feil under kopiering av URL'en.",
|
||||
"LabelVideoResolution": "Oppløsning på video:",
|
||||
"LabelPlayerDimensions": "Dimensjoner på avspiller:",
|
||||
|
|
|
@ -1471,8 +1471,6 @@
|
|||
"Artist": "Artiest",
|
||||
"AllowFfmpegThrottlingHelp": "Wanneer een transcode of remux ver genoeg voorloopt op de huidige afspeelpositie, pauzeer het proces, zodat het minder middelen verbruikt. Dit is vooral handig wanneer u kijkt zonder vaak te zoeken. Schakel dit uit als u afspeelproblemen ondervindt.",
|
||||
"AllowFfmpegThrottling": "Throttle Transcodes",
|
||||
"EnableFastImageFadeInHelp": "Toon posters en andere afbeeldingen met een snellere fade-animatie wanneer ze klaar zijn met laden.",
|
||||
"EnableFastImageFadeIn": "Fast Image Fade Animaties",
|
||||
"LabelPlayerDimensions": "Afspeellengte:",
|
||||
"LabelLibraryPageSizeHelp": "Kies het aantal artikelen dat wordt weergegeven op een bibliotheekpagina. Kies 0 om dit te verbergen.",
|
||||
"LabelLibraryPageSize": "Bibliotheekpagina grootte:",
|
||||
|
|
|
@ -1466,8 +1466,6 @@
|
|||
"NoCreatedLibraries": "Wygląda na to, że nie utworzyłeś jeszcze żadnych bibliotek. {0}Czy chcesz utworzyć jedną teraz?{1}",
|
||||
"LabelVideoResolution": "Rozdzielczość wideo:",
|
||||
"LabelStreamType": "Typ transmisji:",
|
||||
"EnableFastImageFadeInHelp": "Włącz szybszą animację pojawiania się dla załadowanych obrazów",
|
||||
"EnableFastImageFadeIn": "Szybkie pojawianie się obrazów",
|
||||
"Artist": "Artysta",
|
||||
"AlbumArtist": "Album artysty",
|
||||
"Album": "Album",
|
||||
|
|
|
@ -1456,7 +1456,6 @@
|
|||
"MessageConfirmAppExit": "Você quer sair?",
|
||||
"LabelVideoResolution": "Resolução de vídeo:",
|
||||
"LabelStreamType": "Tipo de stream:",
|
||||
"EnableFastImageFadeIn": "Fade-in rápido da imagem",
|
||||
"LabelPlayerDimensions": "Dimensões do player:",
|
||||
"LabelCorruptedFrames": "Quadros corrompidos:",
|
||||
"HeaderNavigation": "Navegação",
|
||||
|
@ -1465,7 +1464,6 @@
|
|||
"AskAdminToCreateLibrary": "Peça a um administrador para criar uma biblioteca.",
|
||||
"AllowFfmpegThrottling": "Transcodes do Acelerador",
|
||||
"PlaybackErrorNoCompatibleStream": "Este cliente não é compatível com a media e o servidor não está enviando um formato de mídia compatível.",
|
||||
"EnableFastImageFadeInHelp": "Mostrar pôsteres e outras imagens com uma animação mais rápida ao terminar de carregar.",
|
||||
"LabelDroppedFrames": "Quadros caídos:",
|
||||
"AllowFfmpegThrottlingHelp": "Quando uma transcodificação ou remux estiver suficientemente avançada da posição atual de reprodução, pause o processo para que consuma menos recursos. Isso é mais proveitoso para quando não há avanço ou retrocesso do vídeo com frequência. Desative se tiver problemas de reprodução.",
|
||||
"PreferEmbeddedEpisodeInfosOverFileNames": "Preferir informações dos episódios incorporadas nos arquivos ao invés dos nomes",
|
||||
|
|
|
@ -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.",
|
||||
"AllowRemoteAccessHelp": "Se desmarcada, todas as conexões remotas serão bloqueadas.",
|
||||
"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",
|
||||
"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",
|
||||
"AllLanguages": "Todos os idiomas",
|
||||
"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",
|
||||
"All": "Todos",
|
||||
"Alerts": "Alertas",
|
||||
|
@ -1314,8 +1314,6 @@
|
|||
"LabelSortOrder": "Ordem de classificação:",
|
||||
"LabelSortBy": "Ordenar por:",
|
||||
"LabelSkin": "Pele:",
|
||||
"EnableFastImageFadeInHelp": "Habilite uma animação mais rápida para imagens carregadas",
|
||||
"EnableFastImageFadeIn": "Efeito de imagem fade-in rápido",
|
||||
"LabelRemoteClientBitrateLimitHelp": "Um limite opcional de taxa de bits por fluxo para todos os dispositivos fora da rede. Isso é útil para impedir que os dispositivos solicitem uma taxa de bits mais alta do que a sua conexão à Internet pode suportar. Isso pode resultar no aumento da carga da CPU no servidor para transcodificar vídeos em tempo real para uma taxa de bits mais baixa.",
|
||||
"LabelPlayerDimensions": "Dimensões do reprodutor:",
|
||||
"LabelParentNumber": "Número pai:",
|
||||
|
|
|
@ -250,7 +250,7 @@
|
|||
"ButtonSubmit": "Trimite",
|
||||
"Collections": "Colecții",
|
||||
"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ă",
|
||||
"AnyLanguage": "Orice Limbă",
|
||||
"Anytime": "Oricând",
|
||||
|
@ -1238,7 +1238,7 @@
|
|||
"Repeat": "Repetă",
|
||||
"RemoveFromPlaylist": "Scoateți din lista de redare",
|
||||
"RemoveFromCollection": "Scoateți din colecție",
|
||||
"RememberMe": "Ține-mă minte",
|
||||
"RememberMe": "Ține-mă Minte",
|
||||
"ReleaseDate": "Data lansării",
|
||||
"RefreshQueued": "Actualizare adăugată în coadă.",
|
||||
"RefreshMetadata": "Actualizați metadatele",
|
||||
|
@ -1454,8 +1454,6 @@
|
|||
"HeaderNavigation": "Navigare",
|
||||
"MessageConfirmAppExit": "Vrei să ieși?",
|
||||
"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:",
|
||||
"LabelStreamType": "Tipul streamului:",
|
||||
"LabelPlayerDimensions": "Dimensiunile soft redare:",
|
||||
|
@ -1519,5 +1517,37 @@
|
|||
"HeaderHttpsSettings": "Setări https",
|
||||
"TabDVR": "DVR",
|
||||
"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": "Навигация",
|
||||
"LabelVideoResolution": "Разрешение видео:",
|
||||
"LabelStreamType": "Тип потока:",
|
||||
"EnableFastImageFadeInHelp": "Включить быстрое появление анимации для загруженных изображений",
|
||||
"EnableFastImageFadeIn": "Быстрое появление изображения",
|
||||
"LabelPlayerDimensions": "Размеры проигрывателя:",
|
||||
"LabelDroppedFrames": "Пропущенные кадры:",
|
||||
"LabelCorruptedFrames": "Испорченные кадры:",
|
||||
|
@ -1520,5 +1518,39 @@
|
|||
"HeaderServerAddressSettings": "Параметры адреса сервера",
|
||||
"HeaderRemoteAccessSettings": "Параметры удалённого доступа",
|
||||
"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ť",
|
||||
"RefreshMetadata": "Obnoviť metadáta",
|
||||
"ReleaseDate": "Dátum vydania",
|
||||
"RememberMe": "Zapamätať si ma",
|
||||
"RememberMe": "Zapamätaj si ma",
|
||||
"RemoveFromCollection": "Odobrať z kolekcie",
|
||||
"Repeat": "Opakovať",
|
||||
"RepeatAll": "Opakovať všetko",
|
||||
|
@ -1457,8 +1457,6 @@
|
|||
"MessageConfirmAppExit": "Chceli by ste odísiť?",
|
||||
"LabelVideoResolution": "Rozlíšenie videa:",
|
||||
"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:",
|
||||
"LabelDroppedFrames": "Vynechané snímky:",
|
||||
"LabelCorruptedFrames": "Poškodené snímky:",
|
||||
|
@ -1550,5 +1548,8 @@
|
|||
"MillisecondsUnit": "ms",
|
||||
"LabelSyncPlayTimeOffset": "Časový rozdiel so serverom:",
|
||||
"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:",
|
||||
"LabelServerName": "Servernamn:",
|
||||
"LabelSecureConnectionsMode": "Säker uppkopplings läge:",
|
||||
"EnableFastImageFadeInHelp": "Aktivera snabbare fade-in animationer för laddade bilder",
|
||||
"EnableFastImageFadeIn": "Snabb bild fade-in",
|
||||
"LabelPostProcessorArgumentsHelp": "Använd {path} som sökväg till inspelade filen.",
|
||||
"LabelPostProcessorArguments": "Post-processor kommandoradsargument:",
|
||||
"LabelDroppedFrames": "Tappade ramar:",
|
||||
|
|
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