Merge branch 'es6' into es6-migration-6

This commit is contained in:
dkanada 2020-07-10 18:27:42 +09:00 committed by GitHub
commit 2253759b8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
107 changed files with 3430 additions and 2194 deletions

View File

@ -193,4 +193,4 @@ module.exports = {
}
}
]
}
};

View File

@ -5,13 +5,13 @@
"repository": "https://github.com/jellyfin/jellyfin-web",
"license": "GPL-2.0-or-later",
"devDependencies": {
"@babel/core": "^7.10.2",
"@babel/core": "^7.10.3",
"@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.10.2",
"autoprefixer": "^9.8.0",
"@babel/preset-env": "^7.10.3",
"autoprefixer": "^9.8.2",
"babel-eslint": "^11.0.0-beta.2",
"babel-loader": "^8.0.6",
"browser-sync": "^2.26.7",
@ -44,7 +44,7 @@
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"style-loader": "^1.1.3",
"stylelint": "^13.6.0",
"stylelint": "^13.6.1",
"stylelint-config-rational-order": "^0.1.2",
"stylelint-no-browser-hacks": "^1.2.1",
"stylelint-order": "^4.1.0",
@ -60,7 +60,7 @@
"date-fns": "^2.14.0",
"document-register-element": "^1.14.3",
"epubjs": "^0.3.85",
"fast-text-encoding": "^1.0.1",
"fast-text-encoding": "^1.0.3",
"flv.js": "^1.5.0",
"headroom.js": "^0.11.0",
"hls.js": "^0.13.1",
@ -69,7 +69,7 @@
"jellyfin-apiclient": "^1.2.2",
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
"jquery": "^3.5.1",
"jstree": "^3.3.7",
"jstree": "^3.3.10",
"libass-wasm": "https://github.com/jellyfin/JavascriptSubtitlesOctopus#4.0.0-jf-smarttv",
"material-design-icons-iconfont": "^5.0.1",
"native-promise-only": "^0.8.0-a",
@ -77,9 +77,9 @@
"query-string": "^6.13.1",
"resize-observer-polyfill": "^1.5.1",
"screenfull": "^5.0.2",
"shaka-player": "^2.5.13",
"shaka-player": "^3.0.1",
"sortablejs": "^1.10.2",
"swiper": "^5.4.3",
"swiper": "^5.4.5",
"webcomponents.js": "^0.7.24",
"whatwg-fetch": "^3.0.0"
},
@ -92,15 +92,26 @@
"test": [
"src/components/accessSchedule/accessSchedule.js",
"src/components/actionSheet/actionSheet.js",
"src/components/alphaPicker/alphaPicker.js",
"src/components/autoFocuser.js",
"src/components/cardbuilder/cardBuilder.js",
"src/components/cardbuilder/chaptercardbuilder.js",
"src/components/cardbuilder/peoplecardbuilder.js",
"src/components/displaySettings/displaySettings.js",
"src/components/homeScreenSettings/homeScreenSettings.js",
"src/components/collectionEditor/collectionEditor.js",
"src/components/dialog/dialog.js",
"src/components/dialogHelper/dialogHelper.js",
"src/components/channelMapper/channelMapper.js",
"src/components/images/imageLoader.js",
"src/components/imageUploader/imageUploader.js",
"src/components/indicators/indicators.js",
"src/components/itemidentifier/itemidentifier.js",
"src/components/itemMediaInfo/itemMediaInfo.js",
"src/components/lazyLoader/lazyLoaderIntersectionObserver.js",
"src/components/mediaLibraryCreator/mediaLibraryCreator.js",
"src/components/mediaLibraryEditor/mediaLibraryEditor.js",
"src/components/listview/listview.js",
"src/components/playback/brightnessosd.js",
"src/components/playback/mediasession.js",
"src/components/playback/nowplayinghelper.js",
@ -111,14 +122,23 @@
"src/components/playback/remotecontrolautoplay.js",
"src/components/playback/volumeosd.js",
"src/components/playbackSettings/playbackSettings.js",
"src/components/playlisteditor/playlisteditor.js",
"src/components/groupedcards.js",
"src/components/htmlMediaHelper.js",
"src/components/playmenu.js",
"src/components/sanatizefilename.js",
"src/components/scrollManager.js",
"src/components/settingshelper.js",
"src/components/subtitlesettings/subtitlesettings.js",
"src/components/subtitlesettings/subtitleappearancehelper.js",
"src/components/shortcuts.js",
"src/components/syncPlay/groupSelectionMenu.js",
"src/components/syncPlay/playbackPermissionManager.js",
"src/components/syncPlay/syncPlayManager.js",
"src/components/syncPlay/timeSyncManager.js",
"src/controllers/dashboard/logs.js",
"src/controllers/user/subtitles.js",
"src/controllers/dashboard/plugins/repositories.js",
"src/plugins/bookPlayer/plugin.js",
"src/plugins/bookPlayer/tableOfContents.js",
"src/plugins/photoPlayer/plugin.js",
@ -135,6 +155,7 @@
"src/scripts/keyboardNavigation.js",
"src/scripts/settings/appSettings.js",
"src/scripts/settings/userSettings.js",
"src/scripts/themeLoader.js",
"src/scripts/settings/webSettings.js"
],
"plugins": [

View File

@ -121,6 +121,11 @@ div[data-role=page] {
transform: translateY(-100%);
}
.drawerContent {
/* make sure the bottom of the drawer is visible when music is playing */
padding-bottom: 4em;
}
.force-scroll {
overflow-y: scroll;
}

View File

@ -31,7 +31,7 @@ define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize)
options.buttons = items;
return dialog(options).then(function (result) {
return dialog.show(options).then(function (result) {
if (result === 'ok') {
return Promise.resolve();
}

View File

@ -1,11 +1,22 @@
define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-button-light', 'material-icons'], function (focusManager, layoutManager, dom) {
'use strict';
/* eslint-disable indent */
var selectedButtonClass = 'alphaPickerButton-selected';
/**
* Module alphaPicker.
* @module components/alphaPicker/alphaPicker
*/
import focusManager from 'focusManager';
import layoutManager from 'layoutManager';
import dom from 'dom';
import 'css!./style.css';
import 'paper-icon-button-light';
import 'material-icons';
const selectedButtonClass = 'alphaPickerButton-selected';
function focus() {
var scope = this;
var selected = scope.querySelector('.' + selectedButtonClass);
const scope = this;
const selected = scope.querySelector(`.${selectedButtonClass}`);
if (selected) {
focusManager.focus(selected);
@ -16,7 +27,7 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
function getAlphaPickerButtonClassName(vertical) {
var alphaPickerButtonClassName = 'alphaPickerButton';
let alphaPickerButtonClassName = 'alphaPickerButton';
if (layoutManager.tv) {
alphaPickerButtonClassName += ' alphaPickerButton-tv';
@ -30,12 +41,12 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
}
function getLetterButton(l, vertical) {
return '<button data-value="' + l + '" class="' + getAlphaPickerButtonClassName(vertical) + '">' + l + '</button>';
return `<button data-value="${l}" class="${getAlphaPickerButtonClassName(vertical)}">${l}</button>`;
}
function mapLetters(letters, vertical) {
return letters.map(function (l) {
return letters.map(l => {
return getLetterButton(l, vertical);
});
}
@ -48,26 +59,26 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
element.classList.add('alphaPicker-tv');
}
var vertical = element.classList.contains('alphaPicker-vertical');
const vertical = element.classList.contains('alphaPicker-vertical');
if (!vertical) {
element.classList.add('focuscontainer-x');
}
var html = '';
var letters;
let html = '';
let letters;
var alphaPickerButtonClassName = getAlphaPickerButtonClassName(vertical);
const alphaPickerButtonClassName = getAlphaPickerButtonClassName(vertical);
var rowClassName = 'alphaPickerRow';
let rowClassName = 'alphaPickerRow';
if (vertical) {
rowClassName += ' alphaPickerRow-vertical';
}
html += '<div class="' + rowClassName + '">';
html += `<div class="${rowClassName}">`;
if (options.mode === 'keyboard') {
html += '<button data-value=" " is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><span class="material-icons alphaPickerButtonIcon space_bar"></span></button>';
html += `<button data-value=" " is="paper-icon-button-light" class="${alphaPickerButtonClassName}"><span class="material-icons alphaPickerButtonIcon space_bar"></span></button>`;
} else {
letters = ['#'];
html += mapLetters(letters, vertical).join('');
@ -77,11 +88,11 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
html += mapLetters(letters, vertical).join('');
if (options.mode === 'keyboard') {
html += '<button data-value="backspace" is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><span class="material-icons alphaPickerButtonIcon backspace"></span></button>';
html += `<button data-value="backspace" is="paper-icon-button-light" class="${alphaPickerButtonClassName}"><span class="material-icons alphaPickerButtonIcon backspace"></span></button>`;
html += '</div>';
letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
html += '<div class="' + rowClassName + '">';
html += `<div class="${rowClassName}">`;
html += '<br/>';
html += mapLetters(letters, vertical).join('');
html += '</div>';
@ -95,227 +106,228 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
element.focus = focus;
}
function AlphaPicker(options) {
export class AlphaPicker {
constructor(options) {
var self = this;
this.options = options;
this.options = options;
var element = options.element;
var itemsContainer = options.itemsContainer;
var itemClass = options.itemClass;
const element = options.element;
const itemsContainer = options.itemsContainer;
const itemClass = options.itemClass;
var itemFocusValue;
var itemFocusTimeout;
let itemFocusValue;
let itemFocusTimeout;
function onItemFocusTimeout() {
itemFocusTimeout = null;
self.value(itemFocusValue);
}
var alphaFocusedElement;
var alphaFocusTimeout;
function onAlphaFocusTimeout() {
alphaFocusTimeout = null;
if (document.activeElement === alphaFocusedElement) {
var value = alphaFocusedElement.getAttribute('data-value');
self.value(value, true);
function onItemFocusTimeout() {
itemFocusTimeout = null;
this.value(itemFocusValue);
}
}
function onAlphaPickerInKeyboardModeClick(e) {
let alphaFocusedElement;
let alphaFocusTimeout;
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
function onAlphaFocusTimeout() {
if (alphaPickerButton) {
var value = alphaPickerButton.getAttribute('data-value');
element.dispatchEvent(new CustomEvent('alphavalueclicked', {
cancelable: false,
detail: {
value: value
}
}));
}
}
function onAlphaPickerClick(e) {
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) {
var value = alphaPickerButton.getAttribute('data-value');
if ((this._currentValue || '').toUpperCase() === value.toUpperCase()) {
self.value(null, true);
} else {
self.value(value, true);
}
}
}
function onAlphaPickerFocusIn(e) {
if (alphaFocusTimeout) {
clearTimeout(alphaFocusTimeout);
alphaFocusTimeout = null;
if (document.activeElement === alphaFocusedElement) {
const value = alphaFocusedElement.getAttribute('data-value');
this.value(value, true);
}
}
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
function onAlphaPickerInKeyboardModeClick(e) {
if (alphaPickerButton) {
alphaFocusedElement = alphaPickerButton;
alphaFocusTimeout = setTimeout(onAlphaFocusTimeout, 600);
const alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) {
const value = alphaPickerButton.getAttribute('data-value');
element.dispatchEvent(new CustomEvent('alphavalueclicked', {
cancelable: false,
detail: {
value
}
}));
}
}
}
function onItemsFocusIn(e) {
function onAlphaPickerClick(e) {
var item = dom.parentWithClass(e.target, itemClass);
const alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (item) {
var prefix = item.getAttribute('data-prefix');
if (prefix && prefix.length) {
itemFocusValue = prefix[0];
if (itemFocusTimeout) {
clearTimeout(itemFocusTimeout);
if (alphaPickerButton) {
const value = alphaPickerButton.getAttribute('data-value');
if ((this._currentValue || '').toUpperCase() === value.toUpperCase()) {
this.value(null, true);
} else {
this.value(value, true);
}
itemFocusTimeout = setTimeout(onItemFocusTimeout, 100);
}
}
}
self.enabled = function (enabled) {
function onAlphaPickerFocusIn(e) {
if (enabled) {
if (itemsContainer) {
itemsContainer.addEventListener('focus', onItemsFocusIn, true);
if (alphaFocusTimeout) {
clearTimeout(alphaFocusTimeout);
alphaFocusTimeout = null;
}
if (options.mode === 'keyboard') {
element.addEventListener('click', onAlphaPickerInKeyboardModeClick);
}
const alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) {
alphaFocusedElement = alphaPickerButton;
alphaFocusTimeout = setTimeout(onAlphaFocusTimeout, 600);
}
}
function onItemsFocusIn(e) {
const item = dom.parentWithClass(e.target, itemClass);
if (item) {
const prefix = item.getAttribute('data-prefix');
if (prefix && prefix.length) {
itemFocusValue = prefix[0];
if (itemFocusTimeout) {
clearTimeout(itemFocusTimeout);
}
itemFocusTimeout = setTimeout(onItemFocusTimeout, 100);
}
}
}
this.enabled = function (enabled) {
if (enabled) {
if (itemsContainer) {
itemsContainer.addEventListener('focus', onItemsFocusIn, true);
}
if (options.mode === 'keyboard') {
element.addEventListener('click', onAlphaPickerInKeyboardModeClick);
}
if (options.valueChangeEvent !== 'click') {
element.addEventListener('focus', onAlphaPickerFocusIn, true);
} else {
element.addEventListener('click', onAlphaPickerClick.bind(this));
}
if (options.valueChangeEvent !== 'click') {
element.addEventListener('focus', onAlphaPickerFocusIn, true);
} else {
element.addEventListener('click', onAlphaPickerClick.bind(this));
}
} else {
if (itemsContainer) {
itemsContainer.removeEventListener('focus', onItemsFocusIn, true);
}
element.removeEventListener('click', onAlphaPickerInKeyboardModeClick);
element.removeEventListener('focus', onAlphaPickerFocusIn, true);
element.removeEventListener('click', onAlphaPickerClick.bind(this));
}
};
render(element, options);
this.enabled(true);
this.visible(true);
}
AlphaPicker.prototype.value = function (value, applyValue) {
var element = this.options.element;
var btn;
var selected;
if (value !== undefined) {
if (value != null) {
value = value.toUpperCase();
this._currentValue = value;
if (this.options.mode !== 'keyboard') {
selected = element.querySelector('.' + selectedButtonClass);
try {
btn = element.querySelector('.alphaPickerButton[data-value=\'' + value + '\']');
} catch (err) {
console.error('error in querySelector: ' + err);
if (itemsContainer) {
itemsContainer.removeEventListener('focus', onItemsFocusIn, true);
}
if (btn && btn !== selected) {
btn.classList.add(selectedButtonClass);
element.removeEventListener('click', onAlphaPickerInKeyboardModeClick);
element.removeEventListener('focus', onAlphaPickerFocusIn, true);
element.removeEventListener('click', onAlphaPickerClick.bind(this));
}
};
render(element, options);
this.enabled(true);
this.visible(true);
}
value(value, applyValue) {
const element = this.options.element;
let btn;
let selected;
if (value !== undefined) {
if (value != null) {
value = value.toUpperCase();
this._currentValue = value;
if (this.options.mode !== 'keyboard') {
selected = element.querySelector(`.${selectedButtonClass}`);
try {
btn = element.querySelector(`.alphaPickerButton[data-value='${value}']`);
} catch (err) {
console.error('error in querySelector:', err);
}
if (btn && btn !== selected) {
btn.classList.add(selectedButtonClass);
}
if (selected && selected !== btn) {
selected.classList.remove(selectedButtonClass);
}
}
if (selected && selected !== btn) {
} else {
this._currentValue = value;
selected = element.querySelector(`.${selectedButtonClass}`);
if (selected) {
selected.classList.remove(selectedButtonClass);
}
}
} else {
this._currentValue = value;
selected = element.querySelector('.' + selectedButtonClass);
if (selected) {
selected.classList.remove(selectedButtonClass);
}
}
if (applyValue) {
element.dispatchEvent(new CustomEvent('alphavaluechanged', {
cancelable: false,
detail: {
value
}
}));
}
return this._currentValue;
}
if (applyValue) {
element.dispatchEvent(new CustomEvent('alphavaluechanged', {
cancelable: false,
detail: {
value: value
}
}));
on(name, fn) {
const element = this.options.element;
element.addEventListener(name, fn);
}
return this._currentValue;
};
AlphaPicker.prototype.on = function (name, fn) {
var element = this.options.element;
element.addEventListener(name, fn);
};
AlphaPicker.prototype.off = function (name, fn) {
var element = this.options.element;
element.removeEventListener(name, fn);
};
AlphaPicker.prototype.visible = function (visible) {
var element = this.options.element;
element.style.visibility = visible ? 'visible' : 'hidden';
};
AlphaPicker.prototype.values = function () {
var element = this.options.element;
var elems = element.querySelectorAll('.alphaPickerButton');
var values = [];
for (var i = 0, length = elems.length; i < length; i++) {
values.push(elems[i].getAttribute('data-value'));
off(name, fn) {
const element = this.options.element;
element.removeEventListener(name, fn);
}
return values;
};
visible(visible) {
AlphaPicker.prototype.focus = function () {
const element = this.options.element;
element.style.visibility = visible ? 'visible' : 'hidden';
}
var element = this.options.element;
focusManager.autoFocus(element, true);
};
values() {
AlphaPicker.prototype.destroy = function () {
const element = this.options.element;
const elems = element.querySelectorAll('.alphaPickerButton');
const values = [];
for (let i = 0, length = elems.length; i < length; i++) {
var element = this.options.element;
this.enabled(false);
element.classList.remove('focuscontainer-x');
this.options = null;
};
values.push(elems[i].getAttribute('data-value'));
return AlphaPicker;
});
}
return values;
}
focus() {
const element = this.options.element;
focusManager.autoFocus(element, true);
}
destroy() {
const element = this.options.element;
this.enabled(false);
element.classList.remove('focuscontainer-x');
this.options = null;
}
}
/* eslint-enable indent */
export default AlphaPicker;

View File

@ -192,9 +192,14 @@ button::-moz-focus-inner {
/* Needed in case this is a button */
display: block;
/* Needed in case this is a button */
margin: 0 !important;
border: 0 !important;
padding: 0 !important;
cursor: pointer;
color: inherit;
width: 100%;
font-family: inherit;
font-size: inherit;
/* Needed in safari */
height: 100%;
@ -203,19 +208,12 @@ button::-moz-focus-inner {
contain: strict;
}
.cardContent-button {
border: 0 !important;
padding: 0 !important;
cursor: pointer;
color: inherit;
width: 100%;
vertical-align: middle;
font-family: inherit;
font-size: inherit;
.cardContent:not(.defaultCardBackground) {
background-color: transparent;
}
.cardContent-button:not(.defaultCardBackground) {
background-color: transparent;
.cardBox:not(.visualCardBox) .cardPadder {
background-color: #242424;
}
.visualCardBox .cardContent {
@ -223,7 +221,8 @@ button::-moz-focus-inner {
border-bottom-right-radius: 0;
}
.cardContent-shadow {
.cardContent-shadow,
.cardBox:not(.visualCardBox) .cardPadder {
box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37);
}

View File

@ -368,9 +368,7 @@ import 'programStyles';
let apiClient;
let lastServerId;
for (let i = 0; i < items.length; i++) {
let item = items[i];
for (const [i, item] of items.entries()) {
let serverId = item.ServerId || options.serverId;
if (serverId !== lastServerId) {
@ -541,7 +539,7 @@ import 'programStyles';
imgType = 'Backdrop';
imgTag = item.ParentBackdropImageTags[0];
itemId = item.ParentBackdropItemId;
} else if (item.ImageTags && item.ImageTags.Primary) {
} else if (item.ImageTags && item.ImageTags.Primary && (item.Type !== 'Episode' || item.ChildCount !== 0)) {
imgType = 'Primary';
imgTag = item.ImageTags.Primary;
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
@ -556,7 +554,10 @@ import 'programStyles';
coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2;
}
}
} else if (item.SeriesPrimaryImageTag) {
imgType = 'Primary';
imgTag = item.SeriesPrimaryImageTag;
itemId = item.SeriesId;
} else if (item.PrimaryImageTag) {
imgType = 'Primary';
imgTag = item.PrimaryImageTag;
@ -577,10 +578,6 @@ import 'programStyles';
imgType = 'Primary';
imgTag = item.ParentPrimaryImageTag;
itemId = item.ParentPrimaryImageItemId;
} else if (item.SeriesPrimaryImageTag) {
imgType = 'Primary';
imgTag = item.SeriesPrimaryImageTag;
itemId = item.SeriesId;
} else if (item.AlbumId && item.AlbumPrimaryImageTag) {
imgType = 'Primary';
imgTag = item.AlbumPrimaryImageTag;
@ -1370,9 +1367,6 @@ import 'programStyles';
let cardScalableClose = '';
let cardContentClass = 'cardContent';
if (!options.cardLayout) {
cardContentClass += ' cardContent-shadow';
}
let blurhashAttrib = '';
if (blurhash && blurhash.length > 0) {
@ -1380,21 +1374,20 @@ import 'programStyles';
}
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 + '" ' + 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 + '" ' + blurhashAttrib + '>') : ('<button data-action="' + action + '" class="cardContent-button ' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction">');
cardImageContainerOpen = imgUrl ? ('<button data-action="' + action + '" class="' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction lazy" data-src="' + imgUrl + '" ' + blurhashAttrib + '>') : ('<button data-action="' + action + '" class="' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction">');
cardImageContainerClose = '</button>';
}
let cardScalableClass = 'cardScalable';
cardImageContainerOpen = '<div class="' + cardBoxClass + '"><div class="' + cardScalableClass + '"><div class="cardPadder-' + shape + '"></div>' + cardImageContainerOpen;
cardImageContainerOpen = '<div class="' + cardBoxClass + '"><div class="' + cardScalableClass + '"><div class="cardPadder cardPadder-' + shape + '"></div>' + cardImageContainerOpen;
cardBoxClose = '</div>';
cardScalableClose = '</div>';

View File

@ -1,10 +1,21 @@
define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'actionsheet', 'emby-input', 'paper-icon-button-light', 'emby-button', 'listViewStyle', 'material-icons', 'formDialogStyle'], function (dom, dialogHelper, loading, connectionManager, globalize, actionsheet) {
'use strict';
import dom from 'dom';
import dialogHelper from 'dialogHelper';
import loading from 'loading';
import connectionManager from 'connectionManager';
import globalize from 'globalize';
import actionsheet from 'actionsheet';
import 'emby-input';
import 'paper-icon-button-light';
import 'emby-button';
import 'listViewStyle';
import 'material-icons';
import 'formDialogStyle';
return function (options) {
export default class channelMapper {
constructor(options) {
function mapChannel(button, channelId, providerChannelId) {
loading.show();
var providerId = options.providerId;
const providerId = options.providerId;
connectionManager.getApiClient(options.serverId).ajax({
type: 'POST',
url: ApiClient.getUrl('LiveTv/ChannelMappings'),
@ -14,8 +25,8 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
providerChannelId: providerChannelId
},
dataType: 'json'
}).then(function (mapping) {
var listItem = dom.parentWithClass(button, 'listItem');
}).then(mapping => {
const listItem = dom.parentWithClass(button, 'listItem');
button.setAttribute('data-providerid', mapping.ProviderChannelId);
listItem.querySelector('.secondary').innerHTML = getMappingSecondaryName(mapping, currentMappingOptions.ProviderName);
loading.hide();
@ -23,42 +34,42 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
}
function onChannelsElementClick(e) {
var btnMap = dom.parentWithClass(e.target, 'btnMap');
const btnMap = dom.parentWithClass(e.target, 'btnMap');
if (btnMap) {
var channelId = btnMap.getAttribute('data-id');
var providerChannelId = btnMap.getAttribute('data-providerid');
var menuItems = currentMappingOptions.ProviderChannels.map(function (m) {
const channelId = btnMap.getAttribute('data-id');
const providerChannelId = btnMap.getAttribute('data-providerid');
const menuItems = currentMappingOptions.ProviderChannels.map(m => {
return {
name: m.Name,
id: m.Id,
selected: m.Id.toLowerCase() === providerChannelId.toLowerCase()
};
}).sort(function (a, b) {
}).sort((a, b) => {
return a.name.localeCompare(b.name);
});
actionsheet.show({
positionTo: btnMap,
items: menuItems
}).then(function (newChannelId) {
}).then(newChannelId => {
mapChannel(btnMap, channelId, newChannelId);
});
}
}
function getChannelMappingOptions(serverId, providerId) {
var apiClient = connectionManager.getApiClient(serverId);
const apiClient = connectionManager.getApiClient(serverId);
return apiClient.getJSON(apiClient.getUrl('LiveTv/ChannelMappingOptions', {
providerId: providerId
}));
}
function getMappingSecondaryName(mapping, providerName) {
return (mapping.ProviderChannelName || '') + ' - ' + providerName;
return `${mapping.ProviderChannelName || ''} - ${providerName}`;
}
function getTunerChannelHtml(channel, providerName) {
var html = '';
let html = '';
html += '<div class="listItem">';
html += '<span class="material-icons listItemIcon dvr"></span>';
html += '<div class="listItemBody two-line">';
@ -73,16 +84,16 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
html += '</div>';
html += '</div>';
html += '<button class="btnMap autoSize" is="paper-icon-button-light" type="button" data-id="' + channel.Id + '" data-providerid="' + channel.ProviderChannelId + '"><span class="material-icons mode_edit"></span></button>';
html += `<button class="btnMap autoSize" is="paper-icon-button-light" type="button" data-id="${channel.Id}" data-providerid="${channel.ProviderChannelId}"><span class="material-icons mode_edit"></span></button>`;
return html += '</div>';
}
function getEditorHtml() {
var html = '';
let html = '';
html += '<div class="formDialogContent smoothScrollY">';
html += '<div class="dialogContentInner dialog-content-centered">';
html += '<form style="margin:auto;">';
html += '<h1>' + globalize.translate('HeaderChannels') + '</h1>';
html += `<h1>${globalize.translate('HeaderChannels')}</h1>`;
html += '<div class="channels paperList">';
html += '</div>';
html += '</form>';
@ -91,30 +102,29 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
}
function initEditor(dlg, options) {
getChannelMappingOptions(options.serverId, options.providerId).then(function (result) {
getChannelMappingOptions(options.serverId, options.providerId).then(result => {
currentMappingOptions = result;
var channelsElement = dlg.querySelector('.channels');
channelsElement.innerHTML = result.TunerChannels.map(function (channel) {
const channelsElement = dlg.querySelector('.channels');
channelsElement.innerHTML = result.TunerChannels.map(channel => {
return getTunerChannelHtml(channel, result.ProviderName);
}).join('');
channelsElement.addEventListener('click', onChannelsElementClick);
});
}
var currentMappingOptions;
var self = this;
let currentMappingOptions;
self.show = function () {
var dialogOptions = {
this.show = () => {
const dialogOptions = {
removeOnClose: true
};
dialogOptions.size = 'small';
var dlg = dialogHelper.createDialog(dialogOptions);
const dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog');
dlg.classList.add('ui-body-a');
dlg.classList.add('background-theme-a');
var html = '';
var title = globalize.translate('MapChannels');
let html = '';
const title = globalize.translate('MapChannels');
html += '<div class="formDialogHeader">';
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
html += '<h3 class="formDialogHeaderTitle">';
@ -124,13 +134,13 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
html += getEditorHtml();
dlg.innerHTML = html;
initEditor(dlg, options);
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dlg.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dlg);
});
return new Promise(function (resolve, reject) {
return new Promise(resolve => {
dlg.addEventListener('close', resolve);
dialogHelper.open(dlg);
});
};
};
});
}
}

View File

@ -1,16 +1,32 @@
define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (dom, dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize) {
'use strict';
import dom from 'dom';
import dialogHelper from 'dialogHelper';
import loading from 'loading';
import appHost from 'apphost';
import layoutManager from 'layoutManager';
import connectionManager from 'connectionManager';
import appRouter from 'appRouter';
import globalize from 'globalize';
import 'emby-checkbox';
import 'emby-input';
import 'paper-icon-button-light';
import 'emby-select';
import 'material-icons';
import 'css!./../formdialog';
import 'emby-button';
import 'flexStyles';
var currentServerId;
/* eslint-disable indent */
let currentServerId;
function onSubmit(e) {
loading.show();
var panel = dom.parentWithClass(this, 'dialog');
const panel = dom.parentWithClass(this, 'dialog');
var collectionId = panel.querySelector('#selectCollectionToAddTo').value;
const collectionId = panel.querySelector('#selectCollectionToAddTo').value;
var apiClient = connectionManager.getApiClient(currentServerId);
const apiClient = connectionManager.getApiClient(currentServerId);
if (collectionId) {
addToCollection(apiClient, panel, collectionId);
@ -24,7 +40,7 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
function createCollection(apiClient, dlg) {
var url = apiClient.getUrl('Collections', {
const url = apiClient.getUrl('Collections', {
Name: dlg.querySelector('#txtNewCollectionName').value,
IsLocked: !dlg.querySelector('#chkEnableInternetMetadata').checked,
@ -36,11 +52,11 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
url: url,
dataType: 'json'
}).then(function (result) {
}).then(result => {
loading.hide();
var id = result.Id;
const id = result.Id;
dlg.submitted = true;
dialogHelper.close(dlg);
@ -56,7 +72,7 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
function addToCollection(apiClient, dlg, id) {
var url = apiClient.getUrl('Collections/' + id + '/Items', {
const url = apiClient.getUrl(`Collections/${id}/Items`, {
Ids: dlg.querySelector('.fldSelectedItemIds').value || ''
});
@ -65,14 +81,14 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
type: 'POST',
url: url
}).then(function () {
}).then(() => {
loading.hide();
dlg.submitted = true;
dialogHelper.close(dlg);
require(['toast'], function (toast) {
import('toast').then(({default: toast}) => {
toast(globalize.translate('MessageItemsAdded'));
});
});
@ -86,11 +102,11 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
loading.show();
var select = panel.querySelector('#selectCollectionToAddTo');
const select = panel.querySelector('#selectCollectionToAddTo');
panel.querySelector('.newCollectionInfo').classList.add('hide');
var options = {
const options = {
Recursive: true,
IncludeItemTypes: 'BoxSet',
@ -98,16 +114,16 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
EnableTotalRecordCount: false
};
var apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getItems(apiClient.getCurrentUserId(), options).then(function (result) {
const apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getItems(apiClient.getCurrentUserId(), options).then(result => {
var html = '';
let html = '';
html += '<option value="">' + globalize.translate('OptionNew') + '</option>';
html += `<option value="">${globalize.translate('OptionNew')}</option>`;
html += result.Items.map(function (i) {
html += result.Items.map(i => {
return '<option value="' + i.Id + '">' + i.Name + '</option>';
return `<option value="${i.Id}">${i.Name}</option>`;
});
select.innerHTML = html;
@ -120,7 +136,7 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
function getEditorHtml() {
var html = '';
let html = '';
html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">';
html += '<div class="dialogContentInner dialog-content-centered">';
@ -134,27 +150,27 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
html += '<br/>';
html += '<br/>';
html += '<div class="selectContainer">';
html += '<select is="emby-select" label="' + globalize.translate('LabelCollection') + '" id="selectCollectionToAddTo" autofocus></select>';
html += `<select is="emby-select" label="${globalize.translate('LabelCollection')}" id="selectCollectionToAddTo" autofocus></select>`;
html += '</div>';
html += '</div>';
html += '<div class="newCollectionInfo">';
html += '<div class="inputContainer">';
html += '<input is="emby-input" type="text" id="txtNewCollectionName" required="required" label="' + globalize.translate('LabelName') + '" />';
html += '<div class="fieldDescription">' + globalize.translate('NewCollectionNameExample') + '</div>';
html += `<input is="emby-input" type="text" id="txtNewCollectionName" required="required" label="${globalize.translate('LabelName')}" />`;
html += `<div class="fieldDescription">${globalize.translate('NewCollectionNameExample')}</div>`;
html += '</div>';
html += '<label class="checkboxContainer">';
html += '<input is="emby-checkbox" type="checkbox" id="chkEnableInternetMetadata" />';
html += '<span>' + globalize.translate('SearchForCollectionInternetMetadata') + '</span>';
html += `<span>${globalize.translate('SearchForCollectionInternetMetadata')}</span>`;
html += '</label>';
// newCollectionInfo
html += '</div>';
html += '<div class="formDialogFooter">';
html += '<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">' + globalize.translate('ButtonOk') + '</button>';
html += `<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">${globalize.translate('ButtonOk')}</button>`;
html += '</div>';
html += '<input type="hidden" class="fldSelectedItemIds" />';
@ -188,7 +204,7 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
} else {
content.querySelector('.fldSelectCollection').classList.add('hide');
var selectCollectionToAddTo = content.querySelector('#selectCollectionToAddTo');
const selectCollectionToAddTo = content.querySelector('#selectCollectionToAddTo');
selectCollectionToAddTo.innerHTML = '';
selectCollectionToAddTo.value = '';
triggerChange(selectCollectionToAddTo);
@ -196,79 +212,77 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
}
function centerFocus(elem, horiz, on) {
require(['scrollHelper'], function (scrollHelper) {
var fn = on ? 'on' : 'off';
import('scrollHelper').then(scrollHelper => {
const fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz);
});
}
function CollectionEditor() {
export class showEditor {
constructor(options) {
}
const items = options.items || {};
currentServerId = options.serverId;
CollectionEditor.prototype.show = function (options) {
var items = options.items || {};
currentServerId = options.serverId;
var dialogOptions = {
removeOnClose: true,
scrollY: false
};
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
} else {
dialogOptions.size = 'small';
}
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog');
var html = '';
var title = items.length ? globalize.translate('HeaderAddToCollection') : globalize.translate('NewCollection');
html += '<div class="formDialogHeader">';
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
html += '<h3 class="formDialogHeaderTitle">';
html += title;
html += '</h3>';
if (appHost.supports('externallinks')) {
html += '<a is="emby-linkbutton" class="button-link btnHelp flex align-items-center" href="https://web.archive.org/web/20181216120305/https://github.com/MediaBrowser/Wiki/wiki/Collections" target="_blank" style="margin-left:auto;margin-right:.5em;padding:.25em;" title="' + globalize.translate('Help') + '"><span class="material-icons info"></span><span style="margin-left:.25em;">' + globalize.translate('Help') + '</span></a>';
}
html += '</div>';
html += getEditorHtml();
dlg.innerHTML = html;
initEditor(dlg, items);
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg);
});
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
}
return dialogHelper.open(dlg).then(function () {
const dialogOptions = {
removeOnClose: true,
scrollY: false
};
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
dialogOptions.size = 'fullscreen';
} else {
dialogOptions.size = 'small';
}
if (dlg.submitted) {
return Promise.resolve();
const dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog');
let html = '';
const title = items.length ? globalize.translate('HeaderAddToCollection') : globalize.translate('NewCollection');
html += '<div class="formDialogHeader">';
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
html += '<h3 class="formDialogHeaderTitle">';
html += title;
html += '</h3>';
if (appHost.supports('externallinks')) {
html += `<a is="emby-linkbutton" class="button-link btnHelp flex align-items-center" href="https://web.archive.org/web/20181216120305/https://github.com/MediaBrowser/Wiki/wiki/Collections" target="_blank" style="margin-left:auto;margin-right:.5em;padding:.25em;" title="${globalize.translate('Help')}"><span class="material-icons info"></span><span style="margin-left:.25em;">${globalize.translate('Help')}</span></a>`;
}
return Promise.reject();
});
};
html += '</div>';
return CollectionEditor;
});
html += getEditorHtml();
dlg.innerHTML = html;
initEditor(dlg, items);
dlg.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dlg);
});
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
}
return dialogHelper.open(dlg).then(() => {
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
}
if (dlg.submitted) {
return Promise.resolve();
}
return Promise.reject();
});
}
}
/* eslint-enable indent */
export default showEditor;

View File

@ -53,7 +53,7 @@ define(['browser', 'dialog', 'globalize'], function(browser, dialog, globalize)
options.buttons = items;
return dialog(options).then(function (result) {
return dialog.show(options).then(function (result) {
if (result === 'ok') {
return Promise.resolve();
}

View File

@ -1,20 +1,31 @@
define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'material-icons', 'emby-button', 'paper-icon-button-light', 'emby-input', 'formDialogStyle', 'flexStyles'], function (dialogHelper, dom, layoutManager, scrollHelper, globalize, require) {
'use strict';
import dialogHelper from 'dialogHelper';
import dom from 'dom';
import layoutManager from 'layoutManager';
import scrollHelper from 'scrollHelper';
import globalize from 'globalize';
import 'material-icons';
import 'emby-button';
import 'paper-icon-button-light';
import 'emby-input';
import 'formDialogStyle';
import 'flexStyles';
/* eslint-disable indent */
function showDialog(options, template) {
var dialogOptions = {
const dialogOptions = {
removeOnClose: true,
scrollY: false
};
var enableTvLayout = layoutManager.tv;
const enableTvLayout = layoutManager.tv;
if (enableTvLayout) {
dialogOptions.size = 'fullscreen';
}
var dlg = dialogHelper.createDialog(dialogOptions);
const dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog');
@ -22,7 +33,7 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
dlg.classList.add('align-items-center');
dlg.classList.add('justify-content-center');
var formDialogContent = dlg.querySelector('.formDialogContent');
const formDialogContent = dlg.querySelector('.formDialogContent');
formDialogContent.classList.add('no-grow');
if (enableTvLayout) {
@ -30,7 +41,7 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
formDialogContent.style['max-height'] = '60%';
scrollHelper.centerFocus.on(formDialogContent, false);
} else {
formDialogContent.style.maxWidth = (Math.min((options.buttons.length * 150) + 200, dom.getWindowSize().innerWidth - 50)) + 'px';
formDialogContent.style.maxWidth = `${Math.min((options.buttons.length * 150) + 200, dom.getWindowSize().innerWidth - 50)}px`;
dlg.classList.add('dialog-fullscreen-lowres');
}
@ -44,27 +55,27 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
dlg.querySelector('.formDialogHeaderTitle').classList.add('hide');
}
var displayText = options.html || options.text || '';
const displayText = options.html || options.text || '';
dlg.querySelector('.text').innerHTML = displayText;
if (!displayText) {
dlg.querySelector('.dialogContentInner').classList.add('hide');
}
var i;
var length;
var html = '';
var hasDescriptions = false;
let i;
let length;
let html = '';
let hasDescriptions = false;
for (i = 0, length = options.buttons.length; i < length; i++) {
var item = options.buttons[i];
var autoFocus = i === 0 ? ' autofocus' : '';
const item = options.buttons[i];
const autoFocus = i === 0 ? ' autofocus' : '';
var buttonClass = 'btnOption raised formDialogFooterItem formDialogFooterItem-autosize';
let buttonClass = 'btnOption raised formDialogFooterItem formDialogFooterItem-autosize';
if (item.type) {
buttonClass += ' button-' + item.type;
buttonClass += ` button-${item.type}`;
}
if (item.description) {
@ -75,10 +86,10 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
buttonClass += ' formDialogFooterItem-vertical formDialogFooterItem-nomarginbottom';
}
html += '<button is="emby-button" type="button" class="' + buttonClass + '" data-id="' + item.id + '"' + autoFocus + '>' + item.name + '</button>';
html += `<button is="emby-button" type="button" class="${buttonClass}" data-id="${item.id}"${autoFocus}>${item.name}</button>`;
if (item.description) {
html += '<div class="formDialogFooterItem formDialogFooterItem-autosize fieldDescription" style="margin-top:.25em!important;margin-bottom:1.25em!important;">' + item.description + '</div>';
html += `<div class="formDialogFooterItem formDialogFooterItem-autosize fieldDescription" style="margin-top:.25em!important;margin-bottom:1.25em!important;">${item.description}</div>`;
}
}
@ -88,18 +99,18 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
dlg.querySelector('.formDialogFooter').classList.add('formDialogFooter-vertical');
}
var dialogResult;
let dialogResult;
function onButtonClick() {
dialogResult = this.getAttribute('data-id');
dialogHelper.close(dlg);
}
var buttons = dlg.querySelectorAll('.btnOption');
const buttons = dlg.querySelectorAll('.btnOption');
for (i = 0, length = buttons.length; i < length; i++) {
buttons[i].addEventListener('click', onButtonClick);
}
return dialogHelper.open(dlg).then(function () {
return dialogHelper.open(dlg).then(() => {
if (enableTvLayout) {
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
@ -113,9 +124,9 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
});
}
return function (text, title) {
export async function show(text, title) {
var options;
let options;
if (typeof text === 'string') {
options = {
title: title,
@ -125,10 +136,13 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
options = text;
}
return new Promise(function (resolve, reject) {
require(['text!./dialog.template.html'], function (template) {
showDialog(options, template).then(resolve, reject);
});
const { default: template } = await import('text!./dialog.template.html');
return new Promise((resolve, reject) => {
showDialog(options, template).then(resolve, reject);
});
};
});
}
/* eslint-enable indent */
export default {
show: show
};

View File

@ -4,12 +4,8 @@
<div class="formDialogContent smoothScrollY">
<div class="dialogContentInner dialog-content-centered" style="padding-top:1em;padding-bottom: 1em; text-align: center;">
<div class="text">
</div>
<div class="text"></div>
</div>
</div>
<div class="formDialogFooter formDialogFooter-clear formDialogFooter-flex" style="padding-bottom: 1.5em;">
</div>
<div class="formDialogFooter formDialogFooter-clear formDialogFooter-flex" style="margin:1em"></div>

View File

@ -1,7 +1,15 @@
define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager', 'dom', 'css!./dialoghelper.css', 'scrollStyles'], function (appRouter, focusManager, browser, layoutManager, inputManager, dom) {
'use strict';
import appRouter from 'appRouter';
import focusManager from 'focusManager';
import browser from 'browser';
import layoutManager from 'layoutManager';
import inputManager from 'inputManager';
import dom from 'dom';
import 'css!./dialoghelper.css';
import 'scrollStyles';
var globalOnOpenCallback;
/* eslint-disable indent */
let globalOnOpenCallback;
function enableAnimation() {
@ -25,7 +33,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
}
function tryRemoveElement(elem) {
var parentNode = elem.parentNode;
const parentNode = elem.parentNode;
if (parentNode) {
// Seeing crashes in edge webview
@ -39,14 +47,14 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
function DialogHashHandler(dlg, hash, resolve) {
var self = this;
const self = this;
self.originalUrl = window.location.href;
var activeElement = document.activeElement;
var removeScrollLockOnClose = false;
const activeElement = document.activeElement;
let removeScrollLockOnClose = false;
function onHashChange(e) {
var isBack = self.originalUrl === window.location.href;
const isBack = self.originalUrl === window.location.href;
if (isBack || !isOpened(dlg)) {
window.removeEventListener('popstate', onHashChange);
@ -84,7 +92,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
}
if (!self.closedByBack && isHistoryEnabled(dlg)) {
var state = history.state || {};
const state = history.state || {};
if (state.dialogId === hash) {
history.back();
}
@ -97,7 +105,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
if (dlg.getAttribute('data-removeonclose') !== 'false') {
removeCenterFocus(dlg);
var dialogContainer = dlg.dialogContainer;
const dialogContainer = dlg.dialogContainer;
if (dialogContainer) {
tryRemoveElement(dialogContainer);
dlg.dialogContainer = null;
@ -108,7 +116,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
//resolve();
// if we just called history.back(), then use a timeout to allow the history events to fire first
setTimeout(function () {
setTimeout(() => {
resolve({
element: dlg,
closedByBack: self.closedByBack
@ -118,7 +126,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
dlg.addEventListener('close', onDialogClosed);
var center = !dlg.classList.contains('dialog-fixedSize');
const center = !dlg.classList.contains('dialog-fixedSize');
if (center) {
dlg.classList.add('centeredDialog');
}
@ -141,7 +149,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
animateDialogOpen(dlg);
if (isHistoryEnabled(dlg)) {
appRouter.pushState({ dialogId: hash }, 'Dialog', '#' + hash);
appRouter.pushState({ dialogId: hash }, 'Dialog', `#${hash}`);
window.addEventListener('popstate', onHashChange);
} else {
@ -151,10 +159,10 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
function addBackdropOverlay(dlg) {
var backdrop = document.createElement('div');
const backdrop = document.createElement('div');
backdrop.classList.add('dialogBackdrop');
var backdropParent = dlg.dialogContainer || dlg;
const backdropParent = dlg.dialogContainer || dlg;
backdropParent.parentNode.insertBefore(backdrop, backdropParent);
dlg.backdrop = backdrop;
@ -162,7 +170,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
void backdrop.offsetWidth;
backdrop.classList.add('dialogBackdropOpened');
dom.addEventListener((dlg.dialogContainer || backdrop), 'click', function (e) {
dom.addEventListener((dlg.dialogContainer || backdrop), 'click', e => {
if (e.target === dlg.dialogContainer) {
close(dlg);
}
@ -170,7 +178,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
passive: true
});
dom.addEventListener((dlg.dialogContainer || backdrop), 'contextmenu', function (e) {
dom.addEventListener((dlg.dialogContainer || backdrop), 'contextmenu', e => {
if (e.target === dlg.dialogContainer) {
// Close the application dialog menu
close(dlg);
@ -184,26 +192,26 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
return dlg.getAttribute('data-history') === 'true';
}
function open(dlg) {
export function open(dlg) {
if (globalOnOpenCallback) {
globalOnOpenCallback(dlg);
}
var parent = dlg.parentNode;
const parent = dlg.parentNode;
if (parent) {
parent.removeChild(dlg);
}
var dialogContainer = document.createElement('div');
const dialogContainer = document.createElement('div');
dialogContainer.classList.add('dialogContainer');
dialogContainer.appendChild(dlg);
dlg.dialogContainer = dialogContainer;
document.body.appendChild(dialogContainer);
return new Promise(function (resolve, reject) {
return new Promise((resolve, reject) => {
new DialogHashHandler(dlg, 'dlg' + new Date().getTime(), resolve);
new DialogHashHandler(dlg, `dlg${new Date().getTime()}`, resolve);
});
}
@ -213,7 +221,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
return !dlg.classList.contains('hide');
}
function close(dlg) {
export function close(dlg) {
if (isOpened(dlg)) {
if (isHistoryEnabled(dlg)) {
@ -233,7 +241,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
cancelable: false
}));
var onAnimationFinish = function () {
const onAnimationFinish = () => {
focusManager.popScope(dlg);
dlg.classList.add('hide');
@ -249,7 +257,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
function animateDialogOpen(dlg) {
var onAnimationFinish = function () {
const onAnimationFinish = () => {
focusManager.pushScope(dlg);
if (dlg.getAttribute('data-autofocus') === 'true') {
@ -264,7 +272,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
if (enableAnimation()) {
var onFinish = function () {
const onFinish = () => {
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: true
});
@ -283,24 +291,24 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
if (enableAnimation()) {
var animated = true;
let animated = true;
switch (dlg.animationConfig.exit.name) {
case 'fadeout':
dlg.style.animation = 'fadeout ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both';
dlg.style.animation = `fadeout ${dlg.animationConfig.exit.timing.duration}ms ease-out normal both`;
break;
case 'scaledown':
dlg.style.animation = 'scaledown ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both';
dlg.style.animation = `scaledown ${dlg.animationConfig.exit.timing.duration}ms ease-out normal both`;
break;
case 'slidedown':
dlg.style.animation = 'slidedown ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both';
dlg.style.animation = `slidedown ${dlg.animationConfig.exit.timing.duration}ms ease-out normal both`;
break;
default:
animated = false;
break;
}
var onFinish = function () {
const onFinish = () => {
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: true
});
@ -318,7 +326,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
onAnimationFinish();
}
var supportsOverscrollBehavior = 'overscroll-behavior-y' in document.body.style;
const supportsOverscrollBehavior = 'overscroll-behavior-y' in document.body.style;
function shouldLockDocumentScroll(options) {
@ -343,7 +351,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
function removeBackdrop(dlg) {
var backdrop = dlg.backdrop;
const backdrop = dlg.backdrop;
if (!backdrop) {
return;
@ -351,7 +359,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
dlg.backdrop = null;
var onAnimationFinish = function () {
const onAnimationFinish = () => {
tryRemoveElement(backdrop);
};
@ -368,20 +376,20 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
}
function centerFocus(elem, horiz, on) {
require(['scrollHelper'], function (scrollHelper) {
var fn = on ? 'on' : 'off';
import('scrollHelper').then(scrollHelper => {
const fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz);
});
}
function createDialog(options) {
export function createDialog(options) {
options = options || {};
// If there's no native dialog support, use a plain div
// Also not working well in samsung tizen browser, content inside not clickable
// Just go ahead and always use a plain div because we're seeing issues overlaying absoltutely positioned content over a modal dialog
var dlg = document.createElement('div');
const dlg = document.createElement('div');
dlg.classList.add('focuscontainer');
dlg.classList.add('hide');
@ -406,17 +414,17 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
dlg.setAttribute('data-autofocus', 'true');
}
var defaultEntryAnimation;
var defaultExitAnimation;
let defaultEntryAnimation;
let defaultExitAnimation;
defaultEntryAnimation = 'scaleup';
defaultExitAnimation = 'scaledown';
var entryAnimation = options.entryAnimation || defaultEntryAnimation;
var exitAnimation = options.exitAnimation || defaultExitAnimation;
const entryAnimation = options.entryAnimation || defaultEntryAnimation;
const exitAnimation = options.exitAnimation || defaultExitAnimation;
// If it's not fullscreen then lower the default animation speed to make it open really fast
var entryAnimationDuration = options.entryAnimationDuration || (options.size !== 'fullscreen' ? 180 : 280);
var exitAnimationDuration = options.exitAnimationDuration || (options.size !== 'fullscreen' ? 120 : 220);
const entryAnimationDuration = options.entryAnimationDuration || (options.size !== 'fullscreen' ? 180 : 280);
const exitAnimationDuration = options.exitAnimationDuration || (options.size !== 'fullscreen' ? 120 : 220);
dlg.animationConfig = {
// scale up
@ -461,7 +469,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
if (options.size) {
dlg.classList.add('dialog-fixedSize');
dlg.classList.add('dialog-' + options.size);
dlg.classList.add(`dialog-${options.size}`);
}
if (enableAnimation()) {
@ -469,16 +477,16 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
switch (dlg.animationConfig.entry.name) {
case 'fadein':
dlg.style.animation = 'fadein ' + entryAnimationDuration + 'ms ease-out normal';
dlg.style.animation = `fadein ${entryAnimationDuration}ms ease-out normal`;
break;
case 'scaleup':
dlg.style.animation = 'scaleup ' + entryAnimationDuration + 'ms ease-out normal both';
dlg.style.animation = `scaleup ${entryAnimationDuration}ms ease-out normal both`;
break;
case 'slideup':
dlg.style.animation = 'slideup ' + entryAnimationDuration + 'ms ease-out normal';
dlg.style.animation = `slideup ${entryAnimationDuration}ms ease-out normal`;
break;
case 'slidedown':
dlg.style.animation = 'slidedown ' + entryAnimationDuration + 'ms ease-out normal';
dlg.style.animation = `slidedown ${entryAnimationDuration}ms ease-out normal`;
break;
default:
break;
@ -488,12 +496,15 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
return dlg;
}
return {
open: open,
close: close,
createDialog: createDialog,
setOnOpen: function (val) {
globalOnOpenCallback = val;
}
};
});
export function setOnOpen(val) {
globalOnOpenCallback = val;
}
/* eslint-enable indent */
export default {
open: open,
close: close,
createDialog: createDialog,
setOnOpen: setOnOpen
};

View File

@ -55,7 +55,7 @@
/* Without this emby-checkbox is able to appear on top */
z-index: 1;
align-items: flex-end;
justify-content: flex-end;
justify-content: center;
flex-wrap: wrap;
}

View File

@ -1,5 +1,8 @@
define(['dom', 'appRouter', 'connectionManager'], function (dom, appRouter, connectionManager) {
'use strict';
/* eslint-disable indent */
import dom from 'dom';
import appRouter from 'appRouter';
import connectionManager from 'connectionManager';
function onGroupedCardClick(e, card) {
var itemId = card.getAttribute('data-id');
@ -31,7 +34,7 @@ define(['dom', 'appRouter', 'connectionManager'], function (dom, appRouter, conn
}
}
function onItemsContainerClick(e) {
export function onItemsContainerClick(e) {
var groupedCard = dom.parentWithClass(e.target, 'groupedCard');
if (groupedCard) {
@ -39,7 +42,4 @@ define(['dom', 'appRouter', 'connectionManager'], function (dom, appRouter, conn
}
}
return {
onItemsContainerClick: onItemsContainerClick
};
});
/* eslint-enable indent */

View File

@ -168,7 +168,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
}
function getPortraitShape() {
return enableScrollX() ? 'autooverflow' : 'auto';
return enableScrollX() ? 'overflowPortrait' : 'portrait';
}
function getLibraryButtonsHtml(items) {
@ -254,7 +254,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
return cardBuilder.getCardsHtml({
items: items,
shape: shape,
preferThumb: viewType !== 'movies' && itemType !== 'Channel' && viewType !== 'music' ? 'auto' : null,
preferThumb: viewType !== 'movies' && viewType !== 'tvshows' && itemType !== 'Channel' && viewType !== 'music' ? 'auto' : null,
showUnplayedIndicator: false,
showChildCountIndicator: true,
context: 'home',

View File

@ -1,17 +1,20 @@
define(['appSettings', 'browser', 'events'], function (appSettings, browser, events) {
'use strict';
/* eslint-disable indent */
function getSavedVolume() {
import appSettings from 'appSettings' ;
import browser from 'browser';
import events from 'events';
export function getSavedVolume() {
return appSettings.get('volume') || 1;
}
function saveVolume(value) {
export function saveVolume(value) {
if (value) {
appSettings.set('volume', value);
}
}
function getCrossOriginValue(mediaSource) {
export function getCrossOriginValue(mediaSource) {
if (mediaSource.IsRemote) {
return null;
}
@ -30,7 +33,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
return false;
}
function enableHlsShakaPlayer(item, mediaSource, mediaType) {
export function enableHlsShakaPlayer(item, mediaSource, mediaType) {
/* eslint-disable-next-line compat/compat */
if (!!window.MediaSource && !!MediaSource.isTypeSupported) {
@ -56,7 +59,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
return false;
}
function enableHlsJsPlayer(runTimeTicks, mediaType) {
export function enableHlsJsPlayer(runTimeTicks, mediaType) {
if (window.MediaSource == null) {
return false;
@ -98,7 +101,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
var recoverDecodingErrorDate;
var recoverSwapAudioCodecDate;
function handleHlsJsMediaError(instance, reject) {
export function handleHlsJsMediaError(instance, reject) {
var hlsPlayer = instance._hlsPlayer;
@ -134,7 +137,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
}
}
function onErrorInternal(instance, type) {
export function onErrorInternal(instance, type) {
// Needed for video
if (instance.destroyCustomTrack) {
@ -148,7 +151,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
]);
}
function isValidDuration(duration) {
export function isValidDuration(duration) {
if (duration && !isNaN(duration) && duration !== Number.POSITIVE_INFINITY && duration !== Number.NEGATIVE_INFINITY) {
return true;
}
@ -162,7 +165,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
}
}
function seekOnPlaybackStart(instance, element, ticks, onMediaReady) {
export function seekOnPlaybackStart(instance, element, ticks, onMediaReady) {
var seconds = (ticks || 0) / 10000000;
@ -200,7 +203,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
}
}
function applySrc(elem, src, options) {
export function applySrc(elem, src, options) {
if (window.Windows && options.mediaSource && options.mediaSource.IsLocal) {
@ -228,7 +231,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
elem.addEventListener('error', onErrorFn);
}
function playWithPromise(elem, onErrorFn) {
export function playWithPromise(elem, onErrorFn) {
try {
var promise = elem.play();
@ -256,7 +259,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
}
}
function destroyCastPlayer(instance) {
export function destroyCastPlayer(instance) {
var player = instance._castPlayer;
if (player) {
@ -270,7 +273,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
}
}
function destroyShakaPlayer(instance) {
export function destroyShakaPlayer(instance) {
var player = instance._shakaPlayer;
if (player) {
try {
@ -283,7 +286,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
}
}
function destroyHlsPlayer(instance) {
export function destroyHlsPlayer(instance) {
var player = instance._hlsPlayer;
if (player) {
try {
@ -296,7 +299,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
}
}
function destroyFlvPlayer(instance) {
export function destroyFlvPlayer(instance) {
var player = instance._flvPlayer;
if (player) {
try {
@ -311,7 +314,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
}
}
function bindEventsToHlsPlayer(instance, hls, elem, onErrorFn, resolve, reject) {
export function bindEventsToHlsPlayer(instance, hls, elem, onErrorFn, resolve, reject) {
hls.on(Hls.Events.MANIFEST_PARSED, function () {
playWithPromise(elem, onErrorFn).then(resolve, function () {
@ -403,7 +406,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
});
}
function onEndedInternal(instance, elem, onErrorFn) {
export function onEndedInternal(instance, elem, onErrorFn) {
elem.removeEventListener('error', onErrorFn);
@ -427,7 +430,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
instance._currentPlayOptions = null;
}
function getBufferedRanges(instance, elem) {
export function getBufferedRanges(instance, elem) {
var ranges = [];
var seekable = elem.buffered || [];
@ -462,23 +465,4 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
return ranges;
}
return {
getSavedVolume: getSavedVolume,
saveVolume: saveVolume,
enableHlsJsPlayer: enableHlsJsPlayer,
enableHlsShakaPlayer: enableHlsShakaPlayer,
handleHlsJsMediaError: handleHlsJsMediaError,
isValidDuration: isValidDuration,
onErrorInternal: onErrorInternal,
seekOnPlaybackStart: seekOnPlaybackStart,
applySrc: applySrc,
playWithPromise: playWithPromise,
destroyHlsPlayer: destroyHlsPlayer,
destroyFlvPlayer: destroyFlvPlayer,
destroyCastPlayer: destroyCastPlayer,
bindEventsToHlsPlayer: bindEventsToHlsPlayer,
onEndedInternal: onEndedInternal,
getCrossOriginValue: getCrossOriginValue,
getBufferedRanges: getBufferedRanges
};
});
/* eslint-enable indent */

View File

@ -1,10 +1,26 @@
define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', 'layoutManager', 'globalize', 'require', 'emby-button', 'emby-select', 'formDialogStyle', 'css!./style'], function (dialogHelper, connectionManager, dom, loading, scrollHelper, layoutManager, globalize, require) {
'use strict';
/* eslint-disable indent */
var currentItemId;
var currentServerId;
var currentFile;
var hasChanges = false;
/**
* Module for imageUploader.
* @module components/imageUploader/imageUploader
*/
import dialogHelper from 'dialogHelper';
import connectionManager from 'connectionManager';
import dom from 'dom';
import loading from 'loading';
import scrollHelper from 'scrollHelper';
import layoutManager from 'layoutManager';
import globalize from 'globalize';
import 'emby-button';
import 'emby-select';
import 'formDialogStyle';
import 'css!./style';
let currentItemId;
let currentServerId;
let currentFile;
let hasChanges = false;
function onFileReaderError(evt) {
@ -12,14 +28,14 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
switch (evt.target.error.code) {
case evt.target.error.NOT_FOUND_ERR:
require(['toast'], function (toast) {
import('toast').then(({default: toast}) => {
toast(globalize.translate('MessageFileReadError'));
});
break;
case evt.target.error.ABORT_ERR:
break; // noop
default:
require(['toast'], function (toast) {
import('toast').then(({default: toast}) => {
toast(globalize.translate('MessageFileReadError'));
});
break;
@ -28,7 +44,7 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
function setFiles(page, files) {
var file = files[0];
const file = files[0];
if (!file || !file.type.match('image.*')) {
page.querySelector('#imageOutput').innerHTML = '';
@ -39,23 +55,23 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
currentFile = file;
var reader = new FileReader();
const reader = new FileReader();
reader.onerror = onFileReaderError;
reader.onloadstart = function () {
reader.onloadstart = () => {
page.querySelector('#fldUpload').classList.add('hide');
};
reader.onabort = function () {
reader.onabort = () => {
loading.hide();
console.debug('File read cancelled');
};
// Closure to capture the file information.
reader.onload = (function (theFile) {
return function (e) {
reader.onload = (theFile => {
return e => {
// Render thumbnail.
var html = ['<img style="max-width:100%;max-height:100%;" src="', e.target.result, '" title="', escape(theFile.name), '"/>'].join('');
const html = ['<img style="max-width:100%;max-height:100%;" src="', e.target.result, '" title="', escape(theFile.name), '"/>'].join('');
page.querySelector('#imageOutput').innerHTML = html;
page.querySelector('#dropImageText').classList.add('hide');
@ -69,14 +85,14 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
function onSubmit(e) {
var file = currentFile;
const file = currentFile;
if (!file) {
return false;
}
if (!file.type.startsWith('image/')) {
require(['toast'], function (toast) {
import('toast').then(({default: toast}) => {
toast(globalize.translate('MessageImageFileTypeAllowed'));
});
e.preventDefault();
@ -85,18 +101,18 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
loading.show();
var dlg = dom.parentWithClass(this, 'dialog');
const dlg = dom.parentWithClass(this, 'dialog');
var imageType = dlg.querySelector('#selectImageType').value;
const imageType = dlg.querySelector('#selectImageType').value;
if (imageType === 'None') {
require(['toast'], function(toast) {
import('toast').then(({default: toast}) => {
toast(globalize.translate('MessageImageTypeNotSelected'));
});
e.preventDefault();
return false;
}
connectionManager.getApiClient(currentServerId).uploadItemImage(currentItemId, imageType, file).then(function () {
connectionManager.getApiClient(currentServerId).uploadItemImage(currentItemId, imageType, file).then(() => {
dlg.querySelector('#uploadImage').value = '';
@ -117,21 +133,21 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
setFiles(page, this.files);
});
page.querySelector('.btnBrowse').addEventListener('click', function () {
page.querySelector('.btnBrowse').addEventListener('click', () => {
page.querySelector('#uploadImage').click();
});
}
function showEditor(options, resolve, reject) {
function showEditor(options, resolve) {
options = options || {};
require(['text!./imageUploader.template.html'], function (template) {
return import('text!./imageUploader.template.html').then(({default: template}) => {
currentItemId = options.itemId;
currentServerId = options.serverId;
var dialogOptions = {
const dialogOptions = {
removeOnClose: true
};
@ -141,7 +157,7 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
dialogOptions.size = 'small';
}
var dlg = dialogHelper.createDialog(dialogOptions);
const dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog');
@ -152,7 +168,7 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
}
// Has to be assigned a z-index after the call to .open()
dlg.addEventListener('close', function () {
dlg.addEventListener('close', () => {
if (layoutManager.tv) {
scrollHelper.centerFocus.off(dlg, false);
@ -168,22 +184,24 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
dlg.querySelector('#selectImageType').value = options.imageType || 'Primary';
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dlg.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dlg);
});
});
}
return {
show: function (options) {
export function show(options) {
return new Promise(function (resolve, reject) {
return new Promise(resolve => {
hasChanges = false;
hasChanges = false;
showEditor(options, resolve, reject);
});
}
};
});
showEditor(options, resolve);
});
}
/* eslint-enable indent */
export default {
show: show
};

View File

@ -1,11 +1,11 @@
.lazy-image-fadein {
opacity: 1;
transition: opacity 0.7s;
transition: opacity 0.5s;
}
.lazy-image-fadein-fast {
opacity: 1;
transition: opacity 0.2s;
transition: opacity 0.1s;
}
.lazy-hidden {

View File

@ -319,7 +319,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
switch (id) {
case 'addtocollection':
require(['collectionEditor'], function (collectionEditor) {
new collectionEditor().show({
new collectionEditor.showEditor({
items: [itemId],
serverId: serverId
}).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
@ -327,7 +327,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
break;
case 'addtoplaylist':
require(['playlistEditor'], function (playlistEditor) {
new playlistEditor().show({
new playlistEditor.showEditor({
items: [itemId],
serverId: serverId
}).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));

View File

@ -1,44 +1,61 @@
define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', 'connectionManager', 'loading', 'focusManager', 'dom', 'apphost', 'emby-select', 'listViewStyle', 'paper-icon-button-light', 'css!./../formdialog', 'material-icons', 'emby-button', 'flexStyles'], function (dialogHelper, require, layoutManager, globalize, userSettings, connectionManager, loading, focusManager, dom, appHost) {
'use strict';
/* eslint-disable indent */
/**
* Module for display media info.
* @module components/itemMediaInfo/itemMediaInfo
*/
import dialogHelper from 'dialogHelper';
import layoutManager from 'layoutManager';
import globalize from 'globalize';
import connectionManager from 'connectionManager';
import loading from 'loading';
import 'emby-select';
import 'listViewStyle';
import 'paper-icon-button-light';
import 'css!./../formdialog';
import 'material-icons';
import 'emby-button';
import 'flexStyles';
function setMediaInfo(user, page, item) {
var html = item.MediaSources.map(function (version) {
let html = item.MediaSources.map(version => {
return getMediaSourceHtml(user, item, version);
}).join('<div style="border-top:1px solid #444;margin: 1em 0;"></div>');
if (item.MediaSources.length > 1) {
html = '<br/>' + html;
html = `<br/>${html}`;
}
var mediaInfoContent = page.querySelector('#mediaInfoContent');
const mediaInfoContent = page.querySelector('#mediaInfoContent');
mediaInfoContent.innerHTML = html;
}
function getMediaSourceHtml(user, item, version) {
var html = '';
let html = '';
if (version.Name) {
html += '<div><h2 class="mediaInfoStreamType">' + version.Name + '</h2></div>';
html += `<div><h2 class="mediaInfoStreamType">${version.Name}</h2></div>`;
}
if (version.Container) {
html += createAttribute(globalize.translate('MediaInfoContainer'), version.Container) + '<br/>';
html += `${createAttribute(globalize.translate('MediaInfoContainer'), version.Container)}<br/>`;
}
if (version.Formats && version.Formats.length) {
html += createAttribute(globalize.translate('MediaInfoFormat'), version.Formats.join(',')) + '<br/>';
html += `${createAttribute(globalize.translate('MediaInfoFormat'), version.Formats.join(','))}<br/>`;
}
if (version.Path && user && user.Policy.IsAdministrator) {
html += createAttribute(globalize.translate('MediaInfoPath'), version.Path) + '<br/>';
html += `${createAttribute(globalize.translate('MediaInfoPath'), version.Path)}<br/>`;
}
if (version.Size) {
var size = (version.Size / (1024 * 1024)).toFixed(0) + ' MB';
html += createAttribute(globalize.translate('MediaInfoSize'), size) + '<br/>';
const size = `${(version.Size / (1024 * 1024)).toFixed(0)} MB`;
html += `${createAttribute(globalize.translate('MediaInfoSize'), size)}<br/>`;
}
for (var i = 0, length = version.MediaStreams.length; i < length; i++) {
var stream = version.MediaStreams[i];
for (let i = 0, length = version.MediaStreams.length; i < length; i++) {
const stream = version.MediaStreams[i];
if (stream.Type === 'Data') {
continue;
}
html += '<div class="mediaInfoStream">';
var displayType = globalize.translate('MediaInfoStreamType' + stream.Type);
html += '<h2 class="mediaInfoStreamType">' + displayType + '</h2>';
var attributes = [];
const displayType = globalize.translate(`MediaInfoStreamType${stream.Type}`);
html += `<h2 class="mediaInfoStreamType">${displayType}</h2>`;
const attributes = [];
if (stream.DisplayTitle) {
attributes.push(createAttribute('Title', stream.DisplayTitle));
}
@ -61,7 +78,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings',
attributes.push(createAttribute(globalize.translate('MediaInfoLevel'), stream.Level));
}
if (stream.Width || stream.Height) {
attributes.push(createAttribute(globalize.translate('MediaInfoResolution'), stream.Width + 'x' + stream.Height));
attributes.push(createAttribute(globalize.translate('MediaInfoResolution'), `${stream.Width}x${stream.Height}`));
}
if (stream.AspectRatio && stream.Codec !== 'mjpeg') {
attributes.push(createAttribute(globalize.translate('MediaInfoAspectRatio'), stream.AspectRatio));
@ -79,16 +96,16 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings',
attributes.push(createAttribute(globalize.translate('MediaInfoLayout'), stream.ChannelLayout));
}
if (stream.Channels) {
attributes.push(createAttribute(globalize.translate('MediaInfoChannels'), stream.Channels + ' ch'));
attributes.push(createAttribute(globalize.translate('MediaInfoChannels'), `${stream.Channels} ch`));
}
if (stream.BitRate && stream.Codec !== 'mjpeg') {
attributes.push(createAttribute(globalize.translate('MediaInfoBitrate'), (parseInt(stream.BitRate / 1000)) + ' kbps'));
attributes.push(createAttribute(globalize.translate('MediaInfoBitrate'), `${parseInt(stream.BitRate / 1000)} kbps`));
}
if (stream.SampleRate) {
attributes.push(createAttribute(globalize.translate('MediaInfoSampleRate'), stream.SampleRate + ' Hz'));
attributes.push(createAttribute(globalize.translate('MediaInfoSampleRate'), `${stream.SampleRate} Hz`));
}
if (stream.BitDepth) {
attributes.push(createAttribute(globalize.translate('MediaInfoBitDepth'), stream.BitDepth + ' bit'));
attributes.push(createAttribute(globalize.translate('MediaInfoBitDepth'), `${stream.BitDepth} bit`));
}
if (stream.PixelFormat) {
attributes.push(createAttribute(globalize.translate('MediaInfoPixelFormat'), stream.PixelFormat));
@ -116,13 +133,13 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings',
}
function createAttribute(label, value) {
return '<span class="mediaInfoLabel">' + label + '</span><span class="mediaInfoAttribute">' + value + '</span>';
return `<span class="mediaInfoLabel">${label}</span><span class="mediaInfoAttribute">${value}</span>`;
}
function showMediaInfoMore(itemId, serverId, template) {
var apiClient = connectionManager.getApiClient(serverId);
return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
var dialogOptions = {
function loadMediaInfo(itemId, serverId, template) {
const apiClient = connectionManager.getApiClient(serverId);
return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(item => {
const dialogOptions = {
size: 'small',
removeOnClose: true,
scrollY: false
@ -130,35 +147,35 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings',
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
}
var dlg = dialogHelper.createDialog(dialogOptions);
const dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog');
var html = '';
let html = '';
html += globalize.translateDocument(template, 'core');
dlg.innerHTML = html;
if (layoutManager.tv) {
dlg.querySelector('.formDialogContent');
}
dialogHelper.open(dlg);
dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
dlg.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dlg);
});
apiClient.getCurrentUser().then(function (user) {
apiClient.getCurrentUser().then(user => {
setMediaInfo(user, dlg, item);
});
loading.hide();
});
}
function showMediaInfo(itemId, serverId) {
export function show(itemId, serverId) {
loading.show();
return new Promise(function (resolve, reject) {
require(['text!./itemMediaInfo.template.html'], function (template) {
showMediaInfoMore(itemId, serverId, template).then(resolve, reject);
return import('text!./itemMediaInfo.template.html').then(({default: template}) => {
return new Promise((resolve, reject) => {
loadMediaInfo(itemId, serverId, template).then(resolve, reject);
});
});
}
return {
show: showMediaInfo
};
});
/* eslint-enable indent */
export default {
show: show
};

View File

@ -1,15 +1,34 @@
define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize', 'scrollHelper', 'layoutManager', 'focusManager', 'browser', 'emby-input', 'emby-checkbox', 'paper-icon-button-light', 'css!./../formdialog', 'material-icons', 'cardStyle'], function (dialogHelper, loading, connectionManager, require, globalize, scrollHelper, layoutManager, focusManager, browser) {
'use strict';
/* eslint-disable indent */
var enableFocusTransform = !browser.slow && !browser.edge;
/**
* Module for itemidentifier media item.
* @module components/itemidentifier/itemidentifier
*/
var currentItem;
var currentItemType;
var currentServerId;
var currentResolve;
var currentReject;
var hasChanges = false;
var currentSearchResult;
import dialogHelper from 'dialogHelper';
import loading from 'loading';
import connectionManager from 'connectionManager';
import globalize from 'globalize';
import scrollHelper from 'scrollHelper';
import layoutManager from 'layoutManager';
import focusManager from 'focusManager';
import browser from 'browser';
import 'emby-input';
import 'emby-checkbox';
import 'paper-icon-button-light';
import 'css!./../formdialog';
import 'material-icons';
import 'cardStyle';
const enableFocusTransform = !browser.slow && !browser.edge;
let currentItem;
let currentItemType;
let currentServerId;
let currentResolve;
let currentReject;
let hasChanges = false;
let currentSearchResult;
function getApiClient() {
return connectionManager.getApiClient(currentServerId);
@ -17,14 +36,14 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
function searchForIdentificationResults(page) {
var lookupInfo = {
let lookupInfo = {
ProviderIds: {}
};
var i;
var length;
var identifyField = page.querySelectorAll('.identifyField');
var value;
let i;
let length;
const identifyField = page.querySelectorAll('.identifyField');
let value;
for (i = 0, length = identifyField.length; i < length; i++) {
value = identifyField[i].value;
@ -39,9 +58,9 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
}
}
var hasId = false;
let hasId = false;
var txtLookupId = page.querySelectorAll('.txtLookupId');
const txtLookupId = page.querySelectorAll('.txtLookupId');
for (i = 0, length = txtLookupId.length; i < length; i++) {
value = txtLookupId[i].value;
@ -53,7 +72,7 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
}
if (!hasId && !lookupInfo.Name) {
require(['toast'], function (toast) {
import('toast').then(({default: toast}) => {
toast(globalize.translate('PleaseEnterNameOrId'));
});
return;
@ -71,16 +90,16 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
loading.show();
var apiClient = getApiClient();
const apiClient = getApiClient();
apiClient.ajax({
type: 'POST',
url: apiClient.getUrl('Items/RemoteSearch/' + currentItemType),
url: apiClient.getUrl(`Items/RemoteSearch/${currentItemType}`),
data: JSON.stringify(lookupInfo),
contentType: 'application/json',
dataType: 'json'
}).then(function (results) {
}).then(results => {
loading.hide();
showIdentificationSearchResults(page, results);
@ -89,29 +108,29 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
function showIdentificationSearchResults(page, results) {
var identificationSearchResults = page.querySelector('.identificationSearchResults');
const identificationSearchResults = page.querySelector('.identificationSearchResults');
page.querySelector('.popupIdentifyForm').classList.add('hide');
identificationSearchResults.classList.remove('hide');
page.querySelector('.identifyOptionsForm').classList.add('hide');
page.querySelector('.dialogContentInner').classList.remove('dialog-content-centered');
var html = '';
var i;
var length;
let html = '';
let i;
let length;
for (i = 0, length = results.length; i < length; i++) {
var result = results[i];
const result = results[i];
html += getSearchResultHtml(result, i);
}
var elem = page.querySelector('.identificationSearchResultList');
const elem = page.querySelector('.identificationSearchResultList');
elem.innerHTML = html;
function onSearchImageClick() {
var index = parseInt(this.getAttribute('data-index'));
const index = parseInt(this.getAttribute('data-index'));
var currentResult = results[index];
const currentResult = results[index];
if (currentItem != null) {
@ -122,7 +141,7 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
}
}
var searchImages = elem.querySelectorAll('.card');
const searchImages = elem.querySelectorAll('.card');
for (i = 0, length = searchImages.length; i < length; i++) {
searchImages[i].addEventListener('click', onSearchImageClick);
@ -143,7 +162,7 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
function showIdentifyOptions(page, identifyResult) {
var identifyOptionsForm = page.querySelector('.identifyOptionsForm');
const identifyOptionsForm = page.querySelector('.identifyOptionsForm');
page.querySelector('.popupIdentifyForm').classList.add('hide');
page.querySelector('.identificationSearchResults').classList.add('hide');
@ -153,19 +172,19 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
currentSearchResult = identifyResult;
var lines = [];
const lines = [];
lines.push(identifyResult.Name);
if (identifyResult.ProductionYear) {
lines.push(identifyResult.ProductionYear);
}
var resultHtml = lines.join('<br/>');
let resultHtml = lines.join('<br/>');
if (identifyResult.ImageUrl) {
var displayUrl = getSearchImageDisplayUrl(identifyResult.ImageUrl, identifyResult.SearchProviderName);
const displayUrl = getSearchImageDisplayUrl(identifyResult.ImageUrl, identifyResult.SearchProviderName);
resultHtml = '<div style="display:flex;align-items:center;"><img src="' + displayUrl + '" style="max-height:240px;" /><div style="margin-left:1em;">' + resultHtml + '</div>';
resultHtml = `<div style="display:flex;align-items:center;"><img src="${displayUrl}" style="max-height:240px;" /><div style="margin-left:1em;">${resultHtml}</div>`;
}
page.querySelector('.selectedSearchResult').innerHTML = resultHtml;
@ -177,10 +196,10 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
// TODO move card creation code to Card component
var html = '';
var cssClass = 'card scalableCard';
var cardBoxCssClass = 'cardBox';
var padderClass;
let html = '';
let cssClass = 'card scalableCard';
let cardBoxCssClass = 'cardBox';
let padderClass;
if (currentItemType === 'Episode') {
cssClass += ' backdropCard backdropCard-scalable';
@ -203,30 +222,30 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
cardBoxCssClass += ' cardBox-bottompadded';
html += '<button type="button" class="' + cssClass + '" data-index="' + index + '">';
html += '<div class="' + cardBoxCssClass + '">';
html += `<button type="button" class="${cssClass}" data-index="${index}">`;
html += `<div class="${cardBoxCssClass}">`;
html += '<div class="cardScalable">';
html += '<div class="' + padderClass + '"></div>';
html += `<div class="${padderClass}"></div>`;
html += '<div class="cardContent searchImage">';
if (result.ImageUrl) {
var displayUrl = getSearchImageDisplayUrl(result.ImageUrl, result.SearchProviderName);
const displayUrl = getSearchImageDisplayUrl(result.ImageUrl, result.SearchProviderName);
html += '<div class="cardImageContainer coveredImage" style="background-image:url(\'' + displayUrl + '\');"></div>';
html += `<div class="cardImageContainer coveredImage" style="background-image:url('${displayUrl}');"></div>`;
} else {
html += '<div class="cardImageContainer coveredImage defaultCardBackground defaultCardBackground1"><div class="cardText cardCenteredText">' + result.Name + '</div></div>';
html += `<div class="cardImageContainer coveredImage defaultCardBackground defaultCardBackground1"><div class="cardText cardCenteredText">${result.Name}</div></div>`;
}
html += '</div>';
html += '</div>';
var numLines = 2;
let numLines = 2;
if (currentItemType === 'MusicAlbum') {
numLines++;
}
var lines = [result.Name];
const lines = [result.Name];
if (result.AlbumArtist) {
lines.push(result.AlbumArtist.Name);
@ -235,7 +254,7 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
lines.push(result.ProductionYear);
}
for (var i = 0; i < numLines; i++) {
for (let i = 0; i < numLines; i++) {
if (i === 0) {
html += '<div class="cardText cardText-first cardTextCentered">';
@ -252,7 +271,7 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
}
function getSearchImageDisplayUrl(url, provider) {
var apiClient = getApiClient();
const apiClient = getApiClient();
return apiClient.getUrl('Items/RemoteSearch/Image', { imageUrl: url, ProviderName: provider });
}
@ -261,26 +280,26 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
loading.show();
var options = {
const options = {
ReplaceAllImages: page.querySelector('#chkIdentifyReplaceImages').checked
};
var apiClient = getApiClient();
const apiClient = getApiClient();
apiClient.ajax({
type: 'POST',
url: apiClient.getUrl('Items/RemoteSearch/Apply/' + currentItem.Id, options),
url: apiClient.getUrl(`Items/RemoteSearch/Apply/${currentItem.Id}`, options),
data: JSON.stringify(currentSearchResult),
contentType: 'application/json'
}).then(function () {
}).then(() => {
hasChanges = true;
loading.hide();
dialogHelper.close(page);
}, function () {
}, () => {
loading.hide();
@ -290,28 +309,28 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
function showIdentificationForm(page, item) {
var apiClient = getApiClient();
const apiClient = getApiClient();
apiClient.getJSON(apiClient.getUrl('Items/' + item.Id + '/ExternalIdInfos')).then(function (idList) {
apiClient.getJSON(apiClient.getUrl(`Items/${item.Id}/ExternalIdInfos`)).then(idList => {
var html = '';
let html = '';
for (var i = 0, length = idList.length; i < length; i++) {
for (let i = 0, length = idList.length; i < length; i++) {
var idInfo = idList[i];
const idInfo = idList[i];
var id = 'txtLookup' + idInfo.Key;
const id = `txtLookup${idInfo.Key}`;
html += '<div class="inputContainer">';
var fullName = idInfo.Name;
let fullName = idInfo.Name;
if (idInfo.Type) {
fullName = idInfo.Name + ' ' + globalize.translate(idInfo.Type);
fullName = `${idInfo.Name} ${globalize.translate(idInfo.Type)}`;
}
var idLabel = globalize.translate('LabelDynamicExternalId', fullName);
const idLabel = globalize.translate('LabelDynamicExternalId', fullName);
html += '<input is="emby-input" class="txtLookupId" data-providerkey="' + idInfo.Key + '" id="' + id + '" label="' + idLabel + '"/>';
html += `<input is="emby-input" class="txtLookupId" data-providerkey="${idInfo.Key}" id="${id}" label="${idLabel}"/>`;
html += '</div>';
}
@ -338,16 +357,16 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
loading.show();
require(['text!./itemidentifier.template.html'], function (template) {
return import('text!./itemidentifier.template.html').then(({default: template}) => {
var apiClient = getApiClient();
const apiClient = getApiClient();
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(item => {
currentItem = item;
currentItemType = currentItem.Type;
var dialogOptions = {
const dialogOptions = {
size: 'small',
removeOnClose: true,
scrollY: false
@ -357,12 +376,12 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
dialogOptions.size = 'fullscreen';
}
var dlg = dialogHelper.createDialog(dialogOptions);
const dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog');
dlg.classList.add('recordingDialog');
var html = '';
let html = '';
html += globalize.translateDocument(template, 'core');
dlg.innerHTML = html;
@ -384,21 +403,21 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
dialogHelper.open(dlg);
dlg.querySelector('.popupIdentifyForm').addEventListener('submit', function (e) {
dlg.querySelector('.popupIdentifyForm').addEventListener('submit', e => {
e.preventDefault();
searchForIdentificationResults(dlg);
return false;
});
dlg.querySelector('.identifyOptionsForm').addEventListener('submit', function (e) {
dlg.querySelector('.identifyOptionsForm').addEventListener('submit', e => {
e.preventDefault();
submitIdentficationResult(dlg);
return false;
});
dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
dlg.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dlg);
});
@ -421,14 +440,15 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
}
}
// TODO investigate where this was used
function showEditorFindNew(itemName, itemYear, itemType, resolveFunc) {
currentItem = null;
currentItemType = itemType;
require(['text!./itemidentifier.template.html'], function (template) {
return import('text!./itemidentifier.template.html').then(({default: template}) => {
var dialogOptions = {
const dialogOptions = {
size: 'small',
removeOnClose: true,
scrollY: false
@ -438,12 +458,12 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
dialogOptions.size = 'fullscreen';
}
var dlg = dialogHelper.createDialog(dialogOptions);
const dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog');
dlg.classList.add('recordingDialog');
var html = '';
let html = '';
html += globalize.translateDocument(template, 'core');
dlg.innerHTML = html;
@ -454,22 +474,22 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
dialogHelper.open(dlg);
dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
dlg.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dlg);
});
dlg.querySelector('.popupIdentifyForm').addEventListener('submit', function (e) {
dlg.querySelector('.popupIdentifyForm').addEventListener('submit', e => {
e.preventDefault();
searchForIdentificationResults(dlg);
return false;
});
dlg.addEventListener('close', function () {
dlg.addEventListener('close', () => {
loading.hide();
var foundItem = hasChanges ? currentSearchResult : null;
const foundItem = hasChanges ? currentSearchResult : null;
resolveFunc(foundItem);
});
@ -498,29 +518,32 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
dlg.querySelector('.formDialogHeaderTitle').innerHTML = globalize.translate('Search');
}
return {
show: function (itemId, serverId) {
export function show(itemId, serverId) {
return new Promise(function (resolve, reject) {
return new Promise((resolve, reject) => {
currentResolve = resolve;
currentReject = reject;
currentServerId = serverId;
hasChanges = false;
currentResolve = resolve;
currentReject = reject;
currentServerId = serverId;
hasChanges = false;
showEditor(itemId);
});
},
showEditor(itemId);
});
}
showFindNew: function (itemName, itemYear, itemType, serverId) {
export function showFindNew(itemName, itemYear, itemType, serverId) {
return new Promise(function (resolve, reject) {
return new Promise((resolve) => {
currentServerId = serverId;
currentServerId = serverId;
hasChanges = false;
showEditorFindNew(itemName, itemYear, itemType, resolve);
});
}
};
});
hasChanges = false;
showEditorFindNew(itemName, itemYear, itemType, resolve);
});
}
/* eslint-enable indent */
export default {
show: show,
showFindNew: showFindNew
};

View File

@ -11,9 +11,9 @@
(entries) => {
entries.forEach(entry => {
callback(entry);
},
{rootMargin: '50%'});
});
});
},
{rootMargin: '25%'});
this.observer = observer;
}

View File

@ -1,5 +1,20 @@
define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutManager', 'globalize', 'datetime', 'apphost', 'css!./listview', 'emby-ratingbutton', 'emby-playstatebutton'], function (itemHelper, mediaInfo, indicators, connectionManager, layoutManager, globalize, datetime, appHost) {
'use strict';
/* eslint-disable indent */
/**
* Module for display list view.
* @module components/listview/listview
*/
import itemHelper from 'itemHelper';
import mediaInfo from 'mediaInfo';
import indicators from 'indicators';
import connectionManager from 'connectionManager';
import layoutManager from 'layoutManager';
import globalize from 'globalize';
import datetime from 'datetime';
import 'css!./listview';
import 'emby-ratingbutton';
import 'emby-playstatebutton';
function getIndex(item, options) {
@ -8,9 +23,9 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
return item.ParentIndexNumber == null ? '' : globalize.translate('ValueDiscNumber', item.ParentIndexNumber);
}
var sortBy = (options.sortBy || '').toLowerCase();
var code;
var name;
const sortBy = (options.sortBy || '').toLowerCase();
let code;
let name;
if (sortBy.indexOf('sortname') === 0) {
@ -69,10 +84,10 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
function getImageUrl(item, width) {
var apiClient = connectionManager.getApiClient(item.ServerId);
const apiClient = connectionManager.getApiClient(item.ServerId);
let itemId;
var options = {
const options = {
maxWidth: width * 2,
type: 'Primary'
};
@ -102,8 +117,8 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
function getChannelImageUrl(item, width) {
var apiClient = connectionManager.getApiClient(item.ServerId);
var options = {
const apiClient = connectionManager.getApiClient(item.ServerId);
const options = {
maxWidth: width * 2,
type: 'Primary'
};
@ -121,13 +136,13 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
function getTextLinesHtml(textlines, isLargeStyle) {
var html = '';
let html = '';
var largeTitleTagName = layoutManager.tv ? 'h2' : 'div';
const largeTitleTagName = layoutManager.tv ? 'h2' : 'div';
for (var i = 0, length = textlines.length; i < length; i++) {
for (let i = 0, length = textlines.length; i < length; i++) {
var text = textlines[i];
const text = textlines[i];
if (!text) {
continue;
@ -135,7 +150,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
if (i === 0) {
if (isLargeStyle) {
html += '<' + largeTitleTagName + ' class="listItemBodyText">';
html += `<${largeTitleTagName} class="listItemBodyText">`;
} else {
html += '<div class="listItemBodyText">';
}
@ -144,7 +159,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
}
html += (textlines[i] || '&nbsp;');
if (i === 0 && isLargeStyle) {
html += '</' + largeTitleTagName + '>';
html += `</${largeTitleTagName}>`;
} else {
html += '</div>';
}
@ -155,13 +170,13 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
function getRightButtonsHtml(options) {
var html = '';
let html = '';
for (var i = 0, length = options.rightButtons.length; i < length; i++) {
for (let i = 0, length = options.rightButtons.length; i < length; i++) {
var button = options.rightButtons[i];
const button = options.rightButtons[i];
html += '<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="custom" data-customaction="' + button.id + '" title="' + button.title + '"><span class="material-icons ' + button.icon + '"></span></button>';
html += `<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="custom" data-customaction="${button.id}" title="${button.title}"><span class="material-icons ${button.icon}"></span></button>`;
}
return html;
@ -171,34 +186,34 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
return item.Id;
}
function getListViewHtml(options) {
export function getListViewHtml(options) {
var items = options.items;
const items = options.items;
var groupTitle = '';
var action = options.action || 'link';
let groupTitle = '';
const action = options.action || 'link';
var isLargeStyle = options.imageSize === 'large';
var enableOverview = options.enableOverview;
const isLargeStyle = options.imageSize === 'large';
const enableOverview = options.enableOverview;
var clickEntireItem = layoutManager.tv ? true : false;
var outerTagName = clickEntireItem ? 'button' : 'div';
var enableSideMediaInfo = options.enableSideMediaInfo != null ? options.enableSideMediaInfo : true;
const clickEntireItem = layoutManager.tv ? true : false;
const outerTagName = clickEntireItem ? 'button' : 'div';
const enableSideMediaInfo = options.enableSideMediaInfo != null ? options.enableSideMediaInfo : true;
var outerHtml = '';
let outerHtml = '';
var enableContentWrapper = options.enableOverview && !layoutManager.tv;
var containerAlbumArtistIds = (options.containerAlbumArtists || []).map(getId);
const enableContentWrapper = options.enableOverview && !layoutManager.tv;
const containerAlbumArtistIds = (options.containerAlbumArtists || []).map(getId);
for (var i = 0, length = items.length; i < length; i++) {
for (let i = 0, length = items.length; i < length; i++) {
var item = items[i];
const item = items[i];
var html = '';
let html = '';
if (options.showIndex) {
var itemGroupTitle = getIndex(item, options);
const itemGroupTitle = getIndex(item, options);
if (itemGroupTitle !== groupTitle) {
@ -220,7 +235,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
}
}
var cssClass = 'listItem';
let cssClass = 'listItem';
if (options.border || (options.highlight !== false && !layoutManager.tv)) {
cssClass += ' listItem-border';
@ -234,28 +249,28 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
cssClass += ' listItem-focusscale';
}
var downloadWidth = 80;
let downloadWidth = 80;
if (isLargeStyle) {
cssClass += ' listItem-largeImage';
downloadWidth = 500;
}
var playlistItemId = item.PlaylistItemId ? (' data-playlistitemid="' + item.PlaylistItemId + '"') : '';
const playlistItemId = item.PlaylistItemId ? (` data-playlistitemid="${item.PlaylistItemId}"`) : '';
var positionTicksData = item.UserData && item.UserData.PlaybackPositionTicks ? (' data-positionticks="' + item.UserData.PlaybackPositionTicks + '"') : '';
var collectionIdData = options.collectionId ? (' data-collectionid="' + options.collectionId + '"') : '';
var playlistIdData = options.playlistId ? (' data-playlistid="' + options.playlistId + '"') : '';
var mediaTypeData = item.MediaType ? (' data-mediatype="' + item.MediaType + '"') : '';
var collectionTypeData = item.CollectionType ? (' data-collectiontype="' + item.CollectionType + '"') : '';
var channelIdData = item.ChannelId ? (' data-channelid="' + item.ChannelId + '"') : '';
const positionTicksData = item.UserData && item.UserData.PlaybackPositionTicks ? (` data-positionticks="${item.UserData.PlaybackPositionTicks}"`) : '';
const collectionIdData = options.collectionId ? (` data-collectionid="${options.collectionId}"`) : '';
const playlistIdData = options.playlistId ? (` data-playlistid="${options.playlistId}"`) : '';
const mediaTypeData = item.MediaType ? (` data-mediatype="${item.MediaType}"`) : '';
const collectionTypeData = item.CollectionType ? (` data-collectiontype="${item.CollectionType}"`) : '';
const channelIdData = item.ChannelId ? (` data-channelid="${item.ChannelId}"`) : '';
if (enableContentWrapper) {
cssClass += ' listItem-withContentWrapper';
}
html += '<' + outerTagName + ' class="' + cssClass + '"' + playlistItemId + ' data-action="' + action + '" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + positionTicksData + collectionIdData + playlistIdData + '>';
html += `<${outerTagName} class="${cssClass}"${playlistItemId} data-action="${action}" data-isfolder="${item.IsFolder}" data-id="${item.Id}" data-serverid="${item.ServerId}" data-type="${item.Type}"${mediaTypeData}${collectionTypeData}${channelIdData}${positionTicksData}${collectionIdData}${playlistIdData}>`;
if (enableContentWrapper) {
@ -278,37 +293,37 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
imageClass += ' listItemImage-large-tv';
}
var playOnImageClick = options.imagePlayButton && !layoutManager.tv;
const playOnImageClick = options.imagePlayButton && !layoutManager.tv;
if (!clickEntireItem) {
imageClass += ' itemAction';
}
var imageAction = playOnImageClick ? 'resume' : action;
const imageAction = playOnImageClick ? 'resume' : action;
let blurhashAttrib = '';
if (blurhash && blurhash.length > 0) {
blurhashAttrib = 'data-blurhash="' + blurhash + '"';
blurhashAttrib = `data-blurhash="${blurhash}"`;
}
if (imgUrl) {
html += '<div data-action="' + imageAction + '" class="' + imageClass + ' lazy" data-src="' + imgUrl + '" ' + blurhashAttrib + ' item-icon>';
html += `<div data-action="${imageAction}" class="${imageClass} lazy" data-src="${imgUrl}" ${blurhashAttrib} item-icon>`;
} else {
html += '<div class="' + imageClass + '">';
html += `<div class="${imageClass}">`;
}
var indicatorsHtml = '';
let indicatorsHtml = '';
indicatorsHtml += indicators.getPlayedIndicatorHtml(item);
if (indicatorsHtml) {
html += '<div class="indicators listItemIndicators">' + indicatorsHtml + '</div>';
html += `<div class="indicators listItemIndicators">${indicatorsHtml}</div>`;
}
if (playOnImageClick) {
html += '<button is="paper-icon-button-light" class="listItemImageButton itemAction" data-action="resume"><span class="material-icons listItemImageButton-icon play_arrow"></span></button>';
}
var progressHtml = indicators.getProgressBarHtml(item, {
const progressHtml = indicators.getProgressBarHtml(item, {
containerClass: 'listItemProgressBar'
});
@ -325,7 +340,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
html += '</div>';
}
var textlines = [];
const textlines = [];
if (options.showProgramDateTime) {
textlines.push(datetime.toLocaleString(datetime.parseISO8601Date(item.StartDate), {
@ -348,7 +363,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
}
}
var parentTitle = null;
let parentTitle = null;
if (options.showParentTitle) {
if (item.Type === 'Episode') {
@ -358,12 +373,12 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
}
}
var displayName = itemHelper.getDisplayName(item, {
let displayName = itemHelper.getDisplayName(item, {
includeParentInfo: options.includeParentInfoInTitle
});
if (options.showIndexNumber && item.IndexNumber != null) {
displayName = item.IndexNumber + '. ' + displayName;
displayName = `${item.IndexNumber}. ${displayName}`;
}
if (options.showParentTitle && options.parentTitleWithTitle) {
@ -394,14 +409,14 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
}
} else {
var showArtist = options.artist === true;
var artistItems = item.ArtistItems;
let showArtist = options.artist === true;
const artistItems = item.ArtistItems;
if (!showArtist && options.artist !== false) {
if (!artistItems || !artistItems.length) {
showArtist = true;
} else if (artistItems.length > 1 || containerAlbumArtistIds.indexOf(artistItems[0].Id) === -1) {
} else if (artistItems.length > 1 || !containerAlbumArtistIds.includes(artistItems[0].Id)) {
showArtist = true;
}
}
@ -409,7 +424,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
if (showArtist) {
if (artistItems && item.Type !== 'MusicAlbum') {
textlines.push(artistItems.map(function (a) {
textlines.push(artistItems.map(a => {
return a.Name;
}).join(', '));
}
@ -432,7 +447,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
cssClass += ' listItemBody-noleftpadding';
}
html += '<div class="' + cssClass + '">';
html += `<div class="${cssClass}">`;
const moreIcon = 'more_vert';
@ -441,14 +456,16 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
if (options.mediaInfo !== false) {
if (!enableSideMediaInfo) {
var mediaInfoClass = 'secondary listItemMediaInfo listItemBodyText';
const mediaInfoClass = 'secondary listItemMediaInfo listItemBodyText';
html += '<div class="' + mediaInfoClass + '">' + mediaInfo.getPrimaryMediaInfoHtml(item, {
html += `<div class="${mediaInfoClass}">`;
html += mediaInfo.getPrimaryMediaInfoHtml(item, {
episodeTitle: false,
originalAirDate: false,
subtitles: false
}) + '</div>';
});
html += '</div>';
}
}
@ -462,7 +479,8 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
if (options.mediaInfo !== false) {
if (enableSideMediaInfo) {
html += '<div class="secondary listItemMediaInfo">' + mediaInfo.getPrimaryMediaInfoHtml(item, {
html += '<div class="secondary listItemMediaInfo">';
html += mediaInfo.getPrimaryMediaInfoHtml(item, {
year: false,
container: false,
@ -470,7 +488,8 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
criticRating: false,
endsAt: false
}) + '</div>';
});
html += '</div>';
}
}
@ -487,7 +506,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
}
if (options.moreButton !== false) {
html += '<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="menu"><span class="material-icons ' + moreIcon + '"></span></button>';
html += `<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="menu"><span class="material-icons ${moreIcon}"></span></button>`;
}
if (options.infoButton) {
@ -500,15 +519,15 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
if (options.enableUserDataButtons !== false) {
var userData = item.UserData || {};
var likes = userData.Likes == null ? '' : userData.Likes;
const userData = item.UserData || {};
const likes = userData.Likes == null ? '' : userData.Likes;
if (itemHelper.canMarkPlayed(item)) {
html += '<button is="emby-playstatebutton" type="button" class="listItemButton paper-icon-button-light" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-played="' + (userData.Played) + '"><span class="material-icons check"></span></button>';
html += `<button is="emby-playstatebutton" type="button" class="listItemButton paper-icon-button-light" data-id="${item.Id}" data-serverid="${item.ServerId}" data-itemtype="${item.Type}" data-played="${userData.Played}"><span class="material-icons check"></span></button>`;
}
if (itemHelper.canRate(item)) {
html += '<button is="emby-ratingbutton" type="button" class="listItemButton paper-icon-button-light" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-likes="' + likes + '" data-isfavorite="' + (userData.IsFavorite) + '"><span class="material-icons favorite"></span></button>';
html += `<button is="emby-ratingbutton" type="button" class="listItemButton paper-icon-button-light" data-id="${item.Id}" data-serverid="${item.ServerId}" data-itemtype="${item.Type}" data-likes="${likes}" data-isfavorite="${userData.IsFavorite}"><span class="material-icons favorite"></span></button>`;
}
}
}
@ -524,7 +543,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
}
}
html += '</' + outerTagName + '>';
html += `</${outerTagName}>`;
outerHtml += html;
}
@ -532,7 +551,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
return outerHtml;
}
return {
getListViewHtml: getListViewHtml
};
});
/* eslint-enable indent */
export default {
getListViewHtml: getListViewHtml
};

View File

@ -1,92 +0,0 @@
define(['loading', 'events', 'dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'material-icons', 'emby-button', 'paper-icon-button-light', 'emby-input', 'formDialogStyle', 'flexStyles'], function (loading, events, dialogHelper, dom, layoutManager, scrollHelper, globalize, require) {
'use strict';
function showDialog(instance, options, template) {
var dialogOptions = {
removeOnClose: true,
scrollY: false
};
var enableTvLayout = layoutManager.tv;
if (enableTvLayout) {
dialogOptions.size = 'fullscreen';
}
var dlg = dialogHelper.createDialog(dialogOptions);
var configuredButtons = [];
dlg.classList.add('formDialog');
dlg.innerHTML = globalize.translateHtml(template, 'core');
dlg.classList.add('align-items-center');
dlg.classList.add('justify-items-center');
var formDialogContent = dlg.querySelector('.formDialogContent');
formDialogContent.style['flex-grow'] = 'initial';
formDialogContent.style['max-width'] = '50%';
formDialogContent.style['max-height'] = '60%';
if (enableTvLayout) {
scrollHelper.centerFocus.on(formDialogContent, false);
dlg.querySelector('.formDialogHeader').style.marginTop = '15%';
} else {
dlg.classList.add('dialog-fullscreen-lowres');
}
//dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
// dialogHelper.close(dlg);
//});
dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.title;
dlg.querySelector('.text').innerHTML = options.text;
instance.dlg = dlg;
return dialogHelper.open(dlg).then(function () {
if (enableTvLayout) {
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
}
loading.hide();
});
}
function LoadingDialog(options) {
this.options = options;
}
LoadingDialog.prototype.show = function () {
var instance = this;
loading.show();
return new Promise(function (resolve, reject) {
require(['text!./../dialog/dialog.template.html'], function (template) {
showDialog(instance, instance.options, template);
resolve();
});
});
};
LoadingDialog.prototype.setTitle = function (title) {
};
LoadingDialog.prototype.setText = function (text) {
};
LoadingDialog.prototype.hide = function () {
if (this.dlg) {
dialogHelper.close(this.dlg);
this.dlg = null;
}
};
LoadingDialog.prototype.destroy = function () {
this.dlg = null;
this.options = null;
};
return LoadingDialog;
});

View File

@ -1,5 +1,24 @@
define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionseditor/libraryoptionseditor', 'globalize', 'emby-toggle', 'emby-input', 'emby-select', 'paper-icon-button-light', 'listViewStyle', 'formDialogStyle', 'emby-button', 'flexStyles'], function (loading, dialogHelper, dom, $, libraryoptionseditor, globalize) {
'use strict';
/* eslint-disable indent */
/**
* Module for media library creator.
* @module components/mediaLibraryCreator/mediaLibraryCreator
*/
import loading from 'loading';
import dialogHelper from 'dialogHelper';
import dom from 'dom';
import $ from 'jQuery';
import libraryoptionseditor from 'components/libraryoptionseditor/libraryoptionseditor';
import globalize from 'globalize';
import 'emby-toggle';
import 'emby-input';
import 'emby-select';
import 'paper-icon-button-light';
import 'listViewStyle';
import 'formDialogStyle';
import 'emby-button';
import 'flexStyles';
function onAddLibrary() {
if (isCreating) {
@ -7,7 +26,7 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
}
if (pathInfos.length == 0) {
require(['alert'], function (alert) {
import('alert').then(({default: alert}) => {
alert({
text: globalize.translate('PleaseAddAtLeastOneFolder'),
type: 'error'
@ -19,23 +38,23 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
isCreating = true;
loading.show();
var dlg = dom.parentWithClass(this, 'dlg-librarycreator');
var name = $('#txtValue', dlg).val();
var type = $('#selectCollectionType', dlg).val();
const dlg = dom.parentWithClass(this, 'dlg-librarycreator');
const name = $('#txtValue', dlg).val();
let type = $('#selectCollectionType', dlg).val();
if (type == 'mixed') {
type = null;
}
var libraryOptions = libraryoptionseditor.getLibraryOptions(dlg.querySelector('.libraryOptions'));
const libraryOptions = libraryoptionseditor.getLibraryOptions(dlg.querySelector('.libraryOptions'));
libraryOptions.PathInfos = pathInfos;
ApiClient.addVirtualFolder(name, type, currentOptions.refresh, libraryOptions).then(function () {
ApiClient.addVirtualFolder(name, type, currentOptions.refresh, libraryOptions).then(() => {
hasChanges = true;
isCreating = false;
loading.hide();
dialogHelper.close(dlg);
}, function () {
require(['toast'], function (toast) {
}, () => {
import('toast').then(({default: toast}) => {
toast(globalize.translate('ErrorAddingMediaPathToVirtualFolder'));
});
@ -46,15 +65,15 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
}
function getCollectionTypeOptionsHtml(collectionTypeOptions) {
return collectionTypeOptions.map(function (i) {
return '<option value="' + i.value + '">' + i.name + '</option>';
return collectionTypeOptions.map(i => {
return `<option value="${i.value}">${i.name}</option>`;
}).join('');
}
function initEditor(page, collectionTypeOptions) {
$('#selectCollectionType', page).html(getCollectionTypeOptionsHtml(collectionTypeOptions)).val('').on('change', function () {
var value = this.value;
var dlg = $(this).parents('.dialog')[0];
const value = this.value;
const dlg = $(this).parents('.dialog')[0];
libraryoptionseditor.setContentType(dlg.querySelector('.libraryOptions'), value == 'mixed' ? '' : value);
if (value) {
@ -64,12 +83,12 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
}
if (value != 'mixed') {
var index = this.selectedIndex;
const index = this.selectedIndex;
if (index != -1) {
var name = this.options[index].innerHTML.replace('*', '').replace('&amp;', '&');
const name = this.options[index].innerHTML.replace('*', '').replace('&amp;', '&');
$('#txtValue', dlg).val(name);
var folderOption = collectionTypeOptions.filter(function (i) {
const folderOption = collectionTypeOptions.filter(i => {
return i.value == value;
})[0];
$('.collectionTypeFieldDescription', dlg).html(folderOption.message || '');
@ -83,15 +102,15 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
}
function onToggleAdvancedChange() {
var dlg = dom.parentWithClass(this, 'dlg-librarycreator');
const dlg = dom.parentWithClass(this, 'dlg-librarycreator');
libraryoptionseditor.setAdvancedVisible(dlg.querySelector('.libraryOptions'), this.checked);
}
function onAddButtonClick() {
var page = dom.parentWithClass(this, 'dlg-librarycreator');
const page = dom.parentWithClass(this, 'dlg-librarycreator');
require(['directorybrowser'], function (directoryBrowser) {
var picker = new directoryBrowser();
import('directorybrowser').then(({default: directoryBrowser}) => {
const picker = new directoryBrowser();
picker.show({
enableNetworkSharePath: true,
callback: function (path, networkSharePath) {
@ -106,24 +125,24 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
}
function getFolderHtml(pathInfo, index) {
var html = '';
let html = '';
html += '<div class="listItem listItem-border lnkPath" style="padding-left:.5em;">';
html += '<div class="' + (pathInfo.NetworkPath ? 'listItemBody two-line' : 'listItemBody') + '">';
html += '<div class="listItemBodyText">' + pathInfo.Path + '</div>';
html += `<div class="${pathInfo.NetworkPath ? 'listItemBody two-line' : 'listItemBody'}">`;
html += `<div class="listItemBodyText">${pathInfo.Path}</div>`;
if (pathInfo.NetworkPath) {
html += '<div class="listItemBodyText secondary">' + pathInfo.NetworkPath + '</div>';
html += `<div class="listItemBodyText secondary">${pathInfo.NetworkPath}</div>`;
}
html += '</div>';
html += '<button type="button" is="paper-icon-button-light"" class="listItemButton btnRemovePath" data-index="' + index + '"><span class="material-icons remove_circle"></span></button>';
html += `<button type="button" is="paper-icon-button-light"" class="listItemButton btnRemovePath" data-index="${index}"><span class="material-icons remove_circle"></span></button>`;
html += '</div>';
return html;
}
function renderPaths(page) {
var foldersHtml = pathInfos.map(getFolderHtml).join('');
var folderList = page.querySelector('.folderList');
const foldersHtml = pathInfos.map(getFolderHtml).join('');
const folderList = page.querySelector('.folderList');
folderList.innerHTML = foldersHtml;
if (foldersHtml) {
@ -134,13 +153,13 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
}
function addMediaLocation(page, path, networkSharePath) {
var pathLower = path.toLowerCase();
var pathFilter = pathInfos.filter(function (p) {
const pathLower = path.toLowerCase();
const pathFilter = pathInfos.filter(p => {
return p.Path.toLowerCase() == pathLower;
});
if (!pathFilter.length) {
var pathInfo = {
const pathInfo = {
Path: path
};
@ -154,11 +173,11 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
}
function onRemoveClick(e) {
var button = dom.parentWithClass(e.target, 'btnRemovePath');
var index = parseInt(button.getAttribute('data-index'));
var location = pathInfos[index].Path;
var locationLower = location.toLowerCase();
pathInfos = pathInfos.filter(function (p) {
const button = dom.parentWithClass(e.target, 'btnRemovePath');
const index = parseInt(button.getAttribute('data-index'));
const location = pathInfos[index].Path;
const locationLower = location.toLowerCase();
pathInfos = pathInfos.filter(p => {
return p.Path.toLowerCase() != locationLower;
});
renderPaths(dom.parentWithClass(button, 'dlg-librarycreator'));
@ -169,54 +188,49 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
}
function initLibraryOptions(dlg) {
libraryoptionseditor.embed(dlg.querySelector('.libraryOptions')).then(function () {
libraryoptionseditor.embed(dlg.querySelector('.libraryOptions')).then(() => {
$('#selectCollectionType', dlg).trigger('change');
onToggleAdvancedChange.call(dlg.querySelector('.chkAdvanced'));
});
}
function editor() {
this.show = function (options) {
return new Promise(function (resolve, reject) {
currentOptions = options;
currentResolve = resolve;
hasChanges = false;
var xhr = new XMLHttpRequest();
xhr.open('GET', 'components/mediaLibraryCreator/mediaLibraryCreator.template.html', true);
xhr.onload = function (e) {
var template = this.response;
var dlg = dialogHelper.createDialog({
size: 'small',
modal: false,
removeOnClose: true,
scrollY: false
});
dlg.classList.add('ui-body-a');
dlg.classList.add('background-theme-a');
dlg.classList.add('dlg-librarycreator');
dlg.classList.add('formDialog');
dlg.innerHTML = globalize.translateDocument(template);
initEditor(dlg, options.collectionTypeOptions);
dlg.addEventListener('close', onDialogClosed);
dialogHelper.open(dlg);
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg);
});
pathInfos = [];
renderPaths(dlg);
initLibraryOptions(dlg);
};
xhr.send();
export class showEditor {
constructor(options) {
return new Promise((resolve) => {
currentOptions = options;
currentResolve = resolve;
hasChanges = false;
import('text!./components/mediaLibraryCreator/mediaLibraryCreator.template.html').then(({default: template}) => {
const dlg = dialogHelper.createDialog({
size: 'small',
modal: false,
removeOnClose: true,
scrollY: false
});
dlg.classList.add('ui-body-a');
dlg.classList.add('background-theme-a');
dlg.classList.add('dlg-librarycreator');
dlg.classList.add('formDialog');
dlg.innerHTML = globalize.translateDocument(template);
initEditor(dlg, options.collectionTypeOptions);
dlg.addEventListener('close', onDialogClosed);
dialogHelper.open(dlg);
dlg.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dlg);
});
pathInfos = [];
renderPaths(dlg);
initLibraryOptions(dlg);
});
};
});
}
}
var pathInfos = [];
var currentResolve;
var currentOptions;
var hasChanges = false;
var isCreating = false;
return editor;
});
let pathInfos = [];
let currentResolve;
let currentOptions;
let hasChanges = false;
let isCreating = false;
/* eslint-enable indent */
export default showEditor;

View File

@ -1,5 +1,22 @@
define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionseditor/libraryoptionseditor', 'globalize', 'emby-button', 'listViewStyle', 'paper-icon-button-light', 'formDialogStyle', 'emby-toggle', 'flexStyles'], function (jQuery, loading, dialogHelper, dom, libraryoptionseditor, globalize) {
'use strict';
/* eslint-disable indent */
/**
* Module for media library editor.
* @module components/mediaLibraryEditor/mediaLibraryEditor
*/
import jQuery from 'jQuery';
import loading from 'loading';
import dialogHelper from 'dialogHelper';
import dom from 'dom';
import libraryoptionseditor from 'components/libraryoptionseditor/libraryoptionseditor';
import globalize from 'globalize';
import 'emby-button';
import 'listViewStyle';
import 'paper-icon-button-light';
import 'formDialogStyle';
import 'emby-toggle';
import 'flexStyles';
function onEditLibrary() {
if (isCreating) {
@ -8,15 +25,15 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
isCreating = true;
loading.show();
var dlg = dom.parentWithClass(this, 'dlg-libraryeditor');
var libraryOptions = libraryoptionseditor.getLibraryOptions(dlg.querySelector('.libraryOptions'));
const dlg = dom.parentWithClass(this, 'dlg-libraryeditor');
let libraryOptions = libraryoptionseditor.getLibraryOptions(dlg.querySelector('.libraryOptions'));
libraryOptions = Object.assign(currentOptions.library.LibraryOptions || {}, libraryOptions);
ApiClient.updateVirtualFolderOptions(currentOptions.library.ItemId, libraryOptions).then(function () {
ApiClient.updateVirtualFolderOptions(currentOptions.library.ItemId, libraryOptions).then(() => {
hasChanges = true;
isCreating = false;
loading.hide();
dialogHelper.close(dlg);
}, function () {
}, () => {
isCreating = false;
loading.hide();
});
@ -24,50 +41,50 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
}
function addMediaLocation(page, path, networkSharePath) {
var virtualFolder = currentOptions.library;
var refreshAfterChange = currentOptions.refresh;
ApiClient.addMediaPath(virtualFolder.Name, path, networkSharePath, refreshAfterChange).then(function () {
const virtualFolder = currentOptions.library;
const refreshAfterChange = currentOptions.refresh;
ApiClient.addMediaPath(virtualFolder.Name, path, networkSharePath, refreshAfterChange).then(() => {
hasChanges = true;
refreshLibraryFromServer(page);
}, function () {
require(['toast'], function (toast) {
}, () => {
import('toast').then(({default: toast}) => {
toast(globalize.translate('ErrorAddingMediaPathToVirtualFolder'));
});
});
}
function updateMediaLocation(page, path, networkSharePath) {
var virtualFolder = currentOptions.library;
const virtualFolder = currentOptions.library;
ApiClient.updateMediaPath(virtualFolder.Name, {
Path: path,
NetworkPath: networkSharePath
}).then(function () {
}).then(() => {
hasChanges = true;
refreshLibraryFromServer(page);
}, function () {
require(['toast'], function (toast) {
}, () => {
import('toast').then(({default: toast}) => {
toast(globalize.translate('ErrorAddingMediaPathToVirtualFolder'));
});
});
}
function onRemoveClick(btnRemovePath, location) {
var button = btnRemovePath;
var virtualFolder = currentOptions.library;
const button = btnRemovePath;
const virtualFolder = currentOptions.library;
require(['confirm'], function (confirm) {
import('confirm').then(({default: confirm}) => {
confirm({
title: globalize.translate('HeaderRemoveMediaLocation'),
text: globalize.translate('MessageConfirmRemoveMediaLocation'),
confirmText: globalize.translate('ButtonDelete'),
primary: 'delete'
}).then(function () {
var refreshAfterChange = currentOptions.refresh;
ApiClient.removeMediaPath(virtualFolder.Name, location, refreshAfterChange).then(function () {
}).then(() => {
const refreshAfterChange = currentOptions.refresh;
ApiClient.removeMediaPath(virtualFolder.Name, location, refreshAfterChange).then(() => {
hasChanges = true;
refreshLibraryFromServer(dom.parentWithClass(button, 'dlg-libraryeditor'));
}, function () {
require(['toast'], function (toast) {
}, () => {
import('toast').then(({default: toast}) => {
toast(globalize.translate('DefaultErrorMessage'));
});
});
@ -76,14 +93,14 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
}
function onListItemClick(e) {
var listItem = dom.parentWithClass(e.target, 'listItem');
const listItem = dom.parentWithClass(e.target, 'listItem');
if (listItem) {
var index = parseInt(listItem.getAttribute('data-index'));
var pathInfos = (currentOptions.library.LibraryOptions || {}).PathInfos || [];
var pathInfo = null == index ? {} : pathInfos[index] || {};
var originalPath = pathInfo.Path || (null == index ? null : currentOptions.library.Locations[index]);
var btnRemovePath = dom.parentWithClass(e.target, 'btnRemovePath');
const index = parseInt(listItem.getAttribute('data-index'));
const pathInfos = (currentOptions.library.LibraryOptions || {}).PathInfos || [];
const pathInfo = null == index ? {} : pathInfos[index] || {};
const originalPath = pathInfo.Path || (null == index ? null : currentOptions.library.Locations[index]);
const btnRemovePath = dom.parentWithClass(e.target, 'btnRemovePath');
if (btnRemovePath) {
onRemoveClick(btnRemovePath, originalPath);
@ -95,26 +112,26 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
}
function getFolderHtml(pathInfo, index) {
var html = '';
html += '<div class="listItem listItem-border lnkPath" data-index="' + index + '" style="padding-left:.5em;">';
html += '<div class="' + (pathInfo.NetworkPath ? 'listItemBody two-line' : 'listItemBody') + '">';
let html = '';
html += `<div class="listItem listItem-border lnkPath" data-index="${index}" style="padding-left:.5em;">`;
html += `<div class="${pathInfo.NetworkPath ? 'listItemBody two-line' : 'listItemBody'}">`;
html += '<h3 class="listItemBodyText">';
html += pathInfo.Path;
html += '</h3>';
if (pathInfo.NetworkPath) {
html += '<div class="listItemBodyText secondary">' + pathInfo.NetworkPath + '</div>';
html += `<div class="listItemBodyText secondary">${pathInfo.NetworkPath}</div>`;
}
html += '</div>';
html += '<button type="button" is="paper-icon-button-light" class="listItemButton btnRemovePath" data-index="' + index + '"><span class="material-icons remove_circle"></span></button>';
html += `<button type="button" is="paper-icon-button-light" class="listItemButton btnRemovePath" data-index="${index}"><span class="material-icons remove_circle"></span></button>`;
html += '</div>';
return html;
}
function refreshLibraryFromServer(page) {
ApiClient.getVirtualFolders().then(function (result) {
var library = result.filter(function (f) {
ApiClient.getVirtualFolders().then(result => {
const library = result.filter(f => {
return f.Name === currentOptions.library.Name;
})[0];
@ -126,10 +143,10 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
}
function renderLibrary(page, options) {
var pathInfos = (options.library.LibraryOptions || {}).PathInfos || [];
let pathInfos = (options.library.LibraryOptions || {}).PathInfos || [];
if (!pathInfos.length) {
pathInfos = options.library.Locations.map(function (p) {
pathInfos = options.library.Locations.map(p => {
return {
Path: p
};
@ -150,8 +167,8 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
}
function showDirectoryBrowser(context, originalPath, networkPath) {
require(['directorybrowser'], function (directoryBrowser) {
var picker = new directoryBrowser();
import('directorybrowser').then(({default: directoryBrowser}) => {
const picker = new directoryBrowser();
picker.show({
enableNetworkSharePath: true,
pathReadOnly: null != originalPath,
@ -173,7 +190,7 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
}
function onToggleAdvancedChange() {
var dlg = dom.parentWithClass(this, 'dlg-libraryeditor');
const dlg = dom.parentWithClass(this, 'dlg-libraryeditor');
libraryoptionseditor.setAdvancedVisible(dlg.querySelector('.libraryOptions'), this.checked);
}
@ -183,7 +200,7 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
dlg.querySelector('.folderList').addEventListener('click', onListItemClick);
dlg.querySelector('.chkAdvanced').addEventListener('change', onToggleAdvancedChange);
dlg.querySelector('.btnSubmit').addEventListener('click', onEditLibrary);
libraryoptionseditor.embed(dlg.querySelector('.libraryOptions'), options.library.CollectionType, options.library.LibraryOptions).then(function () {
libraryoptionseditor.embed(dlg.querySelector('.libraryOptions'), options.library.CollectionType, options.library.LibraryOptions).then(() => {
onToggleAdvancedChange.call(dlg.querySelector('.chkAdvanced'));
});
}
@ -192,46 +209,41 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
currentDeferred.resolveWith(null, [hasChanges]);
}
function editor() {
this.show = function (options) {
var deferred = jQuery.Deferred();
currentOptions = options;
currentDeferred = deferred;
hasChanges = false;
var xhr = new XMLHttpRequest();
xhr.open('GET', 'components/mediaLibraryEditor/mediaLibraryEditor.template.html', true);
xhr.onload = function (e) {
var template = this.response;
var dlg = dialogHelper.createDialog({
size: 'small',
modal: false,
removeOnClose: true,
scrollY: false
});
dlg.classList.add('dlg-libraryeditor');
dlg.classList.add('ui-body-a');
dlg.classList.add('background-theme-a');
dlg.classList.add('formDialog');
dlg.innerHTML = globalize.translateDocument(template);
dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.library.Name;
initEditor(dlg, options);
dlg.addEventListener('close', onDialogClosed);
dialogHelper.open(dlg);
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg);
});
refreshLibraryFromServer(dlg);
};
xhr.send();
return deferred.promise();
};
export class showEditor {
constructor(options) {
const deferred = jQuery.Deferred();
currentOptions = options;
currentDeferred = deferred;
hasChanges = false;
import('text!./components/mediaLibraryEditor/mediaLibraryEditor.template.html').then(({default: template}) => {
const dlg = dialogHelper.createDialog({
size: 'small',
modal: false,
removeOnClose: true,
scrollY: false
});
dlg.classList.add('dlg-libraryeditor');
dlg.classList.add('ui-body-a');
dlg.classList.add('background-theme-a');
dlg.classList.add('formDialog');
dlg.innerHTML = globalize.translateDocument(template);
dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.library.Name;
initEditor(dlg, options);
dlg.addEventListener('close', onDialogClosed);
dialogHelper.open(dlg);
dlg.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dlg);
});
refreshLibraryFromServer(dlg);
});
return deferred.promise();
}
}
var currentDeferred;
var currentOptions;
var hasChanges = false;
var isCreating = false;
return editor;
});
let currentDeferred;
let currentOptions;
let hasChanges = false;
let isCreating = false;
/* eslint-enable indent */
export default showEditor;

View File

@ -7,7 +7,6 @@
<div class="formDialogContent smoothScrollY" style="padding-top:2em;">
<form class="popupEditPersonForm dialogContentInner dialog-content-centered">
<div class="inputContainer">
<input type="text" is="emby-input" class="txtPersonName" required="required" label="${LabelName}" />
</div>
@ -23,6 +22,7 @@
<option value="Writer">${Writer}</option>
</select>
</div>
<div class="inputContainer fldRole hide">
<input is="emby-input" type="text" class="txtPersonRole" label="${LabelPersonRole}" />
<div class="fieldDescription">${LabelPersonRoleHelp}</div>
@ -33,6 +33,5 @@
<span>${Save}</span>
</button>
</div>
</form>
</div>

View File

@ -255,7 +255,7 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
switch (id) {
case 'addtocollection':
require(['collectionEditor'], function (collectionEditor) {
new collectionEditor().show({
new collectionEditor.showEditor({
items: items,
serverId: serverId
});
@ -265,7 +265,7 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
break;
case 'playlist':
require(['playlistEditor'], function (playlistEditor) {
new playlistEditor().show({
new playlistEditor.showEditor({
items: items,
serverId: serverId
});

View File

@ -241,6 +241,15 @@ import connectionManager from 'connectionManager';
navigator.mediaSession.setActionHandler('seekforward', function () {
execute('fastForward');
});
/* eslint-disable-next-line compat/compat */
navigator.mediaSession.setActionHandler('seekto', function (object) {
let item = playbackManager.getPlayerState(currentPlayer).NowPlayingItem;
// Convert to ms
let duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0);
let wantedTime = object.seekTime * 1000;
playbackManager.seekPercent(wantedTime / duration * 100, currentPlayer);
});
}
events.on(playbackManager, 'playerchange', function () {

View File

@ -1,13 +1,28 @@
define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', 'connectionManager', 'userSettings', 'appRouter', 'globalize', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button'], function (dom, shell, dialogHelper, loading, layoutManager, playbackManager, connectionManager, userSettings, appRouter, globalize) {
'use strict';
import dom from 'dom';
import dialogHelper from 'dialogHelper';
import loading from 'loading';
import layoutManager from 'layoutManager';
import playbackManager from 'playbackManager';
import connectionManager from 'connectionManager';
import * as userSettings from 'userSettings';
import appRouter from 'appRouter';
import globalize from 'globalize';
import 'emby-input';
import 'paper-icon-button-light';
import 'emby-select';
import 'material-icons';
import 'css!./../formdialog';
import 'emby-button';
var currentServerId;
/* eslint-disable indent */
let currentServerId;
function onSubmit(e) {
var panel = dom.parentWithClass(this, 'dialog');
const panel = dom.parentWithClass(this, 'dialog');
var playlistId = panel.querySelector('#selectPlaylistToAddTo').value;
var apiClient = connectionManager.getApiClient(currentServerId);
const playlistId = panel.querySelector('#selectPlaylistToAddTo').value;
const apiClient = connectionManager.getApiClient(currentServerId);
if (playlistId) {
userSettings.set('playlisteditor-lastplaylistid', playlistId);
@ -23,7 +38,7 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
function createPlaylist(apiClient, dlg) {
loading.show();
var url = apiClient.getUrl('Playlists', {
const url = apiClient.getUrl('Playlists', {
Name: dlg.querySelector('#txtNewPlaylistName').value,
Ids: dlg.querySelector('.fldSelectedItemIds').value || '',
userId: apiClient.getCurrentUserId()
@ -34,10 +49,10 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
type: 'POST',
url: url,
dataType: 'json'
}).then(function (result) {
}).then(result => {
loading.hide();
var id = result.Id;
const id = result.Id;
dlg.submitted = true;
dialogHelper.close(dlg);
redirectToPlaylist(apiClient, id);
@ -49,7 +64,7 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
}
function addToPlaylist(apiClient, dlg, id) {
var itemIds = dlg.querySelector('.fldSelectedItemIds').value || '';
const itemIds = dlg.querySelector('.fldSelectedItemIds').value || '';
if (id === 'queue') {
playbackManager.queue({
@ -63,7 +78,7 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
loading.show();
var url = apiClient.getUrl('Playlists/' + id + '/Items', {
const url = apiClient.getUrl(`Playlists/${id}/Items`, {
Ids: itemIds,
userId: apiClient.getCurrentUserId()
});
@ -72,7 +87,7 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
type: 'POST',
url: url
}).then(function () {
}).then(() => {
loading.hide();
dlg.submitted = true;
@ -85,36 +100,36 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
}
function populatePlaylists(editorOptions, panel) {
var select = panel.querySelector('#selectPlaylistToAddTo');
const select = panel.querySelector('#selectPlaylistToAddTo');
loading.hide();
panel.querySelector('.newPlaylistInfo').classList.add('hide');
var options = {
const options = {
Recursive: true,
IncludeItemTypes: 'Playlist',
SortBy: 'SortName',
EnableTotalRecordCount: false
};
var apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getItems(apiClient.getCurrentUserId(), options).then(function (result) {
var html = '';
const apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getItems(apiClient.getCurrentUserId(), options).then(result => {
let html = '';
if (editorOptions.enableAddToPlayQueue !== false && playbackManager.isPlaying()) {
html += '<option value="queue">' + globalize.translate('AddToPlayQueue') + '</option>';
html += `<option value="queue">${globalize.translate('AddToPlayQueue')}</option>`;
}
html += '<option value="">' + globalize.translate('OptionNew') + '</option>';
html += `<option value="">${globalize.translate('OptionNew')}</option>`;
html += result.Items.map(function (i) {
return '<option value="' + i.Id + '">' + i.Name + '</option>';
html += result.Items.map(i => {
return `<option value="${i.Id}">${i.Name}</option>`;
});
select.innerHTML = html;
var defaultValue = editorOptions.defaultValue;
let defaultValue = editorOptions.defaultValue;
if (!defaultValue) {
defaultValue = userSettings.get('playlisteditor-lastplaylistid') || '';
}
@ -132,29 +147,29 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
}
function getEditorHtml(items) {
var html = '';
let html = '';
html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">';
html += '<div class="dialogContentInner dialog-content-centered">';
html += '<form style="margin:auto;">';
html += '<div class="fldSelectPlaylist selectContainer">';
var autoFocus = items.length ? ' autofocus' : '';
html += '<select is="emby-select" id="selectPlaylistToAddTo" label="' + globalize.translate('LabelPlaylist') + '"' + autoFocus + '></select>';
let autoFocus = items.length ? ' autofocus' : '';
html += `<select is="emby-select" id="selectPlaylistToAddTo" label="${globalize.translate('LabelPlaylist')}"${autoFocus}></select>`;
html += '</div>';
html += '<div class="newPlaylistInfo">';
html += '<div class="inputContainer">';
autoFocus = items.length ? '' : ' autofocus';
html += '<input is="emby-input" type="text" id="txtNewPlaylistName" required="required" label="' + globalize.translate('LabelName') + '"' + autoFocus + ' />';
html += `<input is="emby-input" type="text" id="txtNewPlaylistName" required="required" label="${globalize.translate('LabelName')}"${autoFocus} />`;
html += '</div>';
// newPlaylistInfo
html += '</div>';
html += '<div class="formDialogFooter">';
html += '<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">' + globalize.translate('Add') + '</button>';
html += `<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">${globalize.translate('Add')}</button>`;
html += '</div>';
html += '<input type="hidden" class="fldSelectedItemIds" />';
@ -187,7 +202,7 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
} else {
content.querySelector('.fldSelectPlaylist').classList.add('hide');
var selectPlaylistToAddTo = content.querySelector('#selectPlaylistToAddTo');
const selectPlaylistToAddTo = content.querySelector('#selectPlaylistToAddTo');
selectPlaylistToAddTo.innerHTML = '';
selectPlaylistToAddTo.value = '';
triggerChange(selectPlaylistToAddTo);
@ -195,72 +210,70 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
}
function centerFocus(elem, horiz, on) {
require(['scrollHelper'], function (scrollHelper) {
var fn = on ? 'on' : 'off';
import('scrollHelper').then(scrollHelper => {
const fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz);
});
}
function PlaylistEditor() {
export class showEditor {
constructor(options) {
const items = options.items || {};
currentServerId = options.serverId;
const dialogOptions = {
removeOnClose: true,
scrollY: false
};
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
} else {
dialogOptions.size = 'small';
}
const dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog');
let html = '';
const title = globalize.translate('HeaderAddToPlaylist');
html += '<div class="formDialogHeader">';
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
html += '<h3 class="formDialogHeaderTitle">';
html += title;
html += '</h3>';
html += '</div>';
html += getEditorHtml(items);
dlg.innerHTML = html;
initEditor(dlg, options, items);
dlg.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dlg);
});
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
}
return dialogHelper.open(dlg).then(() => {
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
}
if (dlg.submitted) {
return Promise.resolve();
}
return Promise.reject();
});
}
}
PlaylistEditor.prototype.show = function (options) {
var items = options.items || {};
currentServerId = options.serverId;
var dialogOptions = {
removeOnClose: true,
scrollY: false
};
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
} else {
dialogOptions.size = 'small';
}
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog');
var html = '';
var title = globalize.translate('HeaderAddToPlaylist');
html += '<div class="formDialogHeader">';
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
html += '<h3 class="formDialogHeaderTitle">';
html += title;
html += '</h3>';
html += '</div>';
html += getEditorHtml(items);
dlg.innerHTML = html;
initEditor(dlg, options, items);
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg);
});
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
}
return dialogHelper.open(dlg).then(function () {
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
}
if (dlg.submitted) {
return Promise.resolve();
}
return Promise.reject();
});
};
return PlaylistEditor;
});
/* eslint-enable indent */
export default showEditor;

View File

@ -2,12 +2,12 @@
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1">
<span class="material-icons arrow_back"></span>
</button>
<h3 class="formDialogHeaderTitle"></h3>
</div>
<div class="formDialogContent smoothScrollY">
<div class="dialogContentInner dialog-content-centered" style="padding-top:2em;">
<form>
<div class="inputContainer">
<input is="emby-input" type="text" id="txtInput" label="" />
@ -19,7 +19,6 @@
<span class="submitText"></span>
</button>
</div>
</form>
</div>
</div>

View File

@ -196,7 +196,7 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
context.querySelector('.nowPlayingPageImage').classList.remove('nowPlayingPageImageAudio');
}
} else {
imgContainer.innerHTML = '<div class="nowPlayingPageImageContainerNoAlbum"><button data-action="link" class="cardContent-button cardImageContainer coveredImage ' + cardBuilder.getDefaultBackgroundClass(item.Name) + ' cardContent cardContent-shadow itemAction"><span class="cardImageIcon material-icons album"></span></button></div>';
imgContainer.innerHTML = '<div class="nowPlayingPageImageContainerNoAlbum"><button data-action="link" class="cardImageContainer coveredImage ' + cardBuilder.getDefaultBackgroundClass(item.Name) + ' cardContent cardContent-shadow itemAction"><span class="cardImageIcon material-icons album"></span></button></div>';
}
}
@ -589,7 +589,7 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
require(['playlistEditor'], function (playlistEditor) {
getSaveablePlaylistItems().then(function (items) {
var serverId = items.length ? items[0].ServerId : ApiClient.serverId();
new playlistEditor().show({
new playlistEditor.showEditor({
items: items.map(function (i) {
return i.Id;
}),

View File

@ -43,7 +43,7 @@ define(['layoutManager', 'globalize', 'require', 'events', 'browser', 'alphaPick
function initAlphaPicker(alphaPickerElement, instance) {
instance.alphaPicker = new AlphaPicker({
instance.alphaPicker = new AlphaPicker.default({
element: alphaPickerElement,
mode: 'keyboard'
});

View File

@ -1,158 +0,0 @@
define(['loading', 'events', 'dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'material-icons', 'emby-button', 'paper-icon-button-light', 'emby-input', 'formDialogStyle', 'flexStyles'], function (loading, events, dialogHelper, dom, layoutManager, scrollHelper, globalize, require) {
'use strict';
var currentApiClient;
var currentDlg;
var currentInstance;
function reloadPageWhenServerAvailable(retryCount) {
var apiClient = currentApiClient;
if (!apiClient) {
return;
}
// Don't use apiclient method because we don't want it reporting authentication under the old version
apiClient.getJSON(apiClient.getUrl('System/Info')).then(function (info) {
// If this is back to false, the restart completed
if (!info.IsShuttingDown) {
currentInstance.restarted = true;
dialogHelper.close(currentDlg);
} else {
retryReload(retryCount);
}
}, function () {
retryReload(retryCount);
});
}
function retryReload(retryCount) {
setTimeout(function () {
retryCount = retryCount || 0;
retryCount++;
if (retryCount < 150) {
reloadPageWhenServerAvailable(retryCount);
}
}, 500);
}
function startRestart(instance, apiClient, dlg) {
currentApiClient = apiClient;
currentDlg = dlg;
currentInstance = instance;
apiClient.restartServer().then(function () {
setTimeout(reloadPageWhenServerAvailable, 250);
});
}
function showDialog(instance, options, template) {
var dialogOptions = {
removeOnClose: true,
scrollY: false
};
var enableTvLayout = layoutManager.tv;
if (enableTvLayout) {
dialogOptions.size = 'fullscreen';
}
var dlg = dialogHelper.createDialog(dialogOptions);
var configuredButtons = [];
dlg.classList.add('formDialog');
dlg.innerHTML = globalize.translateHtml(template, 'core');
dlg.classList.add('align-items-center');
dlg.classList.add('justify-items-center');
var formDialogContent = dlg.querySelector('.formDialogContent');
formDialogContent.style['flex-grow'] = 'initial';
if (enableTvLayout) {
formDialogContent.style['max-width'] = '50%';
formDialogContent.style['max-height'] = '60%';
scrollHelper.centerFocus.on(formDialogContent, false);
} else {
formDialogContent.style.maxWidth = (Math.min((configuredButtons.length * 150) + 200, dom.getWindowSize().innerWidth - 50)) + 'px';
dlg.classList.add('dialog-fullscreen-lowres');
}
dlg.querySelector('.formDialogHeaderTitle').innerHTML = globalize.translate('HeaderRestartingServer');
dlg.querySelector('.text').innerHTML = globalize.translate('RestartPleaseWaitMessage');
var i;
var length;
var html = '';
for (i = 0, length = configuredButtons.length; i < length; i++) {
var item = configuredButtons[i];
var autoFocus = i === 0 ? ' autofocus' : '';
var buttonClass = 'btnOption raised formDialogFooterItem formDialogFooterItem-autosize';
if (item.type) {
buttonClass += ' button-' + item.type;
}
html += '<button is="emby-button" type="button" class="' + buttonClass + '" data-id="' + item.id + '"' + autoFocus + '>' + item.name + '</button>';
}
dlg.querySelector('.formDialogFooter').innerHTML = html;
function onButtonClick() {
dialogHelper.close(dlg);
}
var buttons = dlg.querySelectorAll('.btnOption');
for (i = 0, length = buttons.length; i < length; i++) {
buttons[i].addEventListener('click', onButtonClick);
}
var dlgPromise = dialogHelper.open(dlg);
startRestart(instance, options.apiClient, dlg);
return dlgPromise.then(function () {
if (enableTvLayout) {
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
}
instance.destroy();
loading.hide();
if (instance.restarted) {
events.trigger(instance, 'restarted');
}
});
}
function ServerRestartDialog(options) {
this.options = options;
}
ServerRestartDialog.prototype.show = function () {
var instance = this;
loading.show();
return new Promise(function (resolve, reject) {
require(['text!./../dialog/dialog.template.html'], function (template) {
showDialog(instance, instance.options, template).then(resolve, reject);
});
});
};
ServerRestartDialog.prototype.destroy = function () {
currentApiClient = null;
currentDlg = null;
currentInstance = null;
this.options = null;
};
return ServerRestartDialog;
});

View File

@ -0,0 +1,22 @@
import globalize from 'globalize';
/**
* Helper for handling settings.
* @module components/settingsHelper
*/
export function populateLanguages(select, languages) {
let html = '';
html += "<option value=''>" + globalize.translate('AnyLanguage') + '</option>';
for (let i = 0, length = languages.length; i < length; i++) {
const culture = languages[i];
html += "<option value='" + culture.ThreeLetterISOLanguageName + "'>" + culture.DisplayName + '</option>';
}
select.innerHTML = html;
}
export default {
populateLanguages: populateLanguages
};

View File

@ -1,18 +1,30 @@
define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'globalize', 'loading', 'dom', 'recordingHelper'], function (playbackManager, inputManager, connectionManager, appRouter, globalize, loading, dom, recordingHelper) {
'use strict';
/* eslint-disable indent */
/**
* Module shortcuts.
* @module components/shortcuts
*/
import playbackManager from 'playbackManager';
import inputManager from 'inputManager';
import connectionManager from 'connectionManager';
import appRouter from 'appRouter';
import globalize from 'globalize';
import dom from 'dom';
import recordingHelper from 'recordingHelper';
function playAllFromHere(card, serverId, queue) {
var parent = card.parentNode;
var className = card.classList.length ? ('.' + card.classList[0]) : '';
var cards = parent.querySelectorAll(className + '[data-id]');
const parent = card.parentNode;
const className = card.classList.length ? (`.${card.classList[0]}`) : '';
const cards = parent.querySelectorAll(`${className}[data-id]`);
var ids = [];
const ids = [];
var foundCard = false;
var startIndex;
let foundCard = false;
let startIndex;
for (var i = 0, length = cards.length; i < length; i++) {
for (let i = 0, length = cards.length; i < length; i++) {
if (cards[i] === card) {
foundCard = true;
startIndex = i;
@ -22,12 +34,12 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
}
}
var itemsContainer = dom.parentWithClass(card, 'itemsContainer');
const itemsContainer = dom.parentWithClass(card, 'itemsContainer');
if (itemsContainer && itemsContainer.fetchData) {
var queryOptions = queue ? { StartIndex: startIndex } : {};
const queryOptions = queue ? { StartIndex: startIndex } : {};
return itemsContainer.fetchData(queryOptions).then(function (result) {
return itemsContainer.fetchData(queryOptions).then(result => {
if (queue) {
return playbackManager.queue({
@ -64,7 +76,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
function showProgramDialog(item) {
require(['recordingCreator'], function (recordingCreator) {
import('recordingCreator').then(({default:recordingCreator}) => {
recordingCreator.show(item.Id, item.ServerId);
});
@ -73,11 +85,11 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
function getItem(button) {
button = dom.parentWithAttribute(button, 'data-id');
var serverId = button.getAttribute('data-serverid');
var id = button.getAttribute('data-id');
var type = button.getAttribute('data-type');
const serverId = button.getAttribute('data-serverid');
const id = button.getAttribute('data-id');
const type = button.getAttribute('data-type');
var apiClient = connectionManager.getApiClient(serverId);
const apiClient = connectionManager.getApiClient(serverId);
if (type === 'Timer') {
return apiClient.getLiveTvTimer(id);
@ -99,19 +111,19 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
function showContextMenu(card, options) {
getItem(card).then(function (item) {
getItem(card).then(item => {
var playlistId = card.getAttribute('data-playlistid');
var collectionId = card.getAttribute('data-collectionid');
const playlistId = card.getAttribute('data-playlistid');
const collectionId = card.getAttribute('data-collectionid');
if (playlistId) {
var elem = dom.parentWithAttribute(card, 'data-playlistitemid');
const elem = dom.parentWithAttribute(card, 'data-playlistitemid');
item.PlaylistItemId = elem ? elem.getAttribute('data-playlistitemid') : null;
}
require(['itemContextMenu'], function (itemContextMenu) {
import('itemContextMenu').then(({default: itemContextMenu}) => {
connectionManager.getApiClient(item.ServerId).getCurrentUser().then(function (user) {
connectionManager.getApiClient(item.ServerId).getCurrentUser().then(user => {
itemContextMenu.show(Object.assign({
item: item,
play: true,
@ -122,9 +134,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
collectionId: collectionId,
user: user
}, options || {})).then(function (result) {
var itemsContainer;
}, options || {})).then(result => {
if (result.command === 'playallfromhere' || result.command === 'queueallfromhere') {
executeAction(card, options.positionTo, result.command);
@ -157,9 +167,9 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
function showPlayMenu(card, target) {
var item = getItemInfoFromCard(card);
const item = getItemInfoFromCard(card);
require(['playMenu'], function (playMenu) {
import('playMenu').then(({default: playMenu}) => {
playMenu.show({
@ -170,7 +180,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
}
function sendToast(text) {
require(['toast'], function (toast) {
import('toast').then(({default: toast}) => {
toast(text);
});
}
@ -179,19 +189,19 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
target = target || card;
var id = card.getAttribute('data-id');
let id = card.getAttribute('data-id');
if (!id) {
card = dom.parentWithAttribute(card, 'data-id');
id = card.getAttribute('data-id');
}
var item = getItemInfoFromCard(card);
const item = getItemInfoFromCard(card);
var serverId = item.ServerId;
var type = item.Type;
const serverId = item.ServerId;
const type = item.Type;
var playableItemId = type === 'Program' ? item.ChannelId : item.Id;
const playableItemId = type === 'Program' ? item.ChannelId : item.Id;
if (item.MediaType === 'Photo' && action === 'link') {
action = 'play';
@ -213,7 +223,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
});
} else if (action === 'play' || action === 'resume') {
var startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0');
const startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0');
playbackManager.play({
ids: [playableItemId],
@ -244,7 +254,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
onRecordCommand(serverId, id, type, card.getAttribute('data-timerid'), card.getAttribute('data-seriestimerid'));
} else if (action === 'menu') {
var options = target.getAttribute('data-playoptions') === 'false' ?
const options = target.getAttribute('data-playoptions') === 'false' ?
{
shuffle: false,
instantMix: false,
@ -261,7 +271,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
} else if (action === 'playmenu') {
showPlayMenu(card, target);
} else if (action === 'edit') {
getItem(target).then(function (item) {
getItem(target).then(item => {
editItem(item, serverId);
});
} else if (action === 'playtrailer') {
@ -270,9 +280,9 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
getItem(target).then(addToPlaylist);
} else if (action === 'custom') {
var customAction = target.getAttribute('data-customaction');
const customAction = target.getAttribute('data-customaction');
card.dispatchEvent(new CustomEvent('action-' + customAction, {
card.dispatchEvent(new CustomEvent(`action-${customAction}`, {
detail: {
playlistItemId: card.getAttribute('data-playlistitemid')
},
@ -283,7 +293,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
}
function addToPlaylist(item) {
require(['playlistEditor'], function (playlistEditor) {
import('playlistEditor').then(({default: playlistEditor}) => {
new playlistEditor().show({
items: [item.Id],
@ -295,35 +305,35 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
function playTrailer(item) {
var apiClient = connectionManager.getApiClient(item.ServerId);
const apiClient = connectionManager.getApiClient(item.ServerId);
apiClient.getLocalTrailers(apiClient.getCurrentUserId(), item.Id).then(function (trailers) {
apiClient.getLocalTrailers(apiClient.getCurrentUserId(), item.Id).then(trailers => {
playbackManager.play({ items: trailers });
});
}
function editItem(item, serverId) {
var apiClient = connectionManager.getApiClient(serverId);
const apiClient = connectionManager.getApiClient(serverId);
return new Promise(function (resolve, reject) {
return new Promise((resolve, reject) => {
var serverId = apiClient.serverInfo().Id;
const serverId = apiClient.serverInfo().Id;
if (item.Type === 'Timer') {
if (item.ProgramId) {
require(['recordingCreator'], function (recordingCreator) {
import('recordingCreator').then(({default: recordingCreator}) => {
recordingCreator.show(item.ProgramId, serverId).then(resolve, reject);
});
} else {
require(['recordingEditor'], function (recordingEditor) {
import('recordingEditor').then(({default: recordingEditor}) => {
recordingEditor.show(item.Id, serverId).then(resolve, reject);
});
}
} else {
require(['metadataEditor'], function (metadataEditor) {
import('metadataEditor').then(({default: metadataEditor}) => {
metadataEditor.show(item.Id, serverId).then(resolve, reject);
});
@ -335,19 +345,19 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
if (type === 'Program' || timerId || seriesTimerId) {
var programId = type === 'Program' ? id : null;
const programId = type === 'Program' ? id : null;
recordingHelper.toggleRecording(serverId, programId, timerId, seriesTimerId);
}
}
function onClick(e) {
export function onClick(e) {
var card = dom.parentWithClass(e.target, 'itemAction');
const card = dom.parentWithClass(e.target, 'itemAction');
if (card) {
var actionElement = card;
var action = actionElement.getAttribute('data-action');
let actionElement = card;
let action = actionElement.getAttribute('data-action');
if (!action) {
actionElement = dom.parentWithAttribute(actionElement, 'data-action');
@ -368,12 +378,12 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
function onCommand(e) {
var cmd = e.detail.command;
const cmd = e.detail.command;
if (cmd === 'play' || cmd === 'resume' || cmd === 'record' || cmd === 'menu' || cmd === 'info') {
var target = e.target;
var card = dom.parentWithClass(target, 'itemAction') || dom.parentWithAttribute(target, 'data-id');
const target = e.target;
const card = dom.parentWithClass(target, 'itemAction') || dom.parentWithAttribute(target, 'data-id');
if (card) {
e.preventDefault();
@ -383,7 +393,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
}
}
function on(context, options) {
export function on(context, options) {
options = options || {};
@ -396,7 +406,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
}
}
function off(context, options) {
export function off(context, options) {
options = options || {};
context.removeEventListener('click', onClick);
@ -406,23 +416,24 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
}
}
function getShortcutAttributesHtml(item, serverId) {
export function getShortcutAttributesHtml(item, serverId) {
var html = 'data-id="' + item.Id + '" data-serverid="' + (serverId || item.ServerId) + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-channelid="' + item.ChannelId + '" data-isfolder="' + item.IsFolder + '"';
let html = `data-id="${item.Id}" data-serverid="${serverId || item.ServerId}" data-type="${item.Type}" data-mediatype="${item.MediaType}" data-channelid="${item.ChannelId}" data-isfolder="${item.IsFolder}"`;
var collectionType = item.CollectionType;
const collectionType = item.CollectionType;
if (collectionType) {
html += ' data-collectiontype="' + collectionType + '"';
html += ` data-collectiontype="${collectionType}"`;
}
return html;
}
return {
on: on,
off: off,
onClick: onClick,
getShortcutAttributesHtml: getShortcutAttributesHtml
};
/* eslint-enable indent */
export default {
on: on,
off: off,
onClick: onClick,
getShortcutAttributesHtml: getShortcutAttributesHtml
};
});

View File

@ -1,159 +1,154 @@
define([], function () {
'use strict';
/**
* Subtitle settings visual helper.
* @module components/subtitleSettings/subtitleAppearanceHelper
*/
function getTextStyles(settings, isCue) {
function getTextStyles(settings, isCue) {
var list = [];
let list = [];
if (isCue) {
switch (settings.textSize || '') {
if (isCue) {
switch (settings.textSize || '') {
case 'smaller':
list.push({ name: 'font-size', value: '.5em' });
break;
case 'small':
list.push({ name: 'font-size', value: '.7em' });
break;
case 'large':
list.push({ name: 'font-size', value: '1.3em' });
break;
case 'larger':
list.push({ name: 'font-size', value: '1.72em' });
break;
case 'extralarge':
list.push({ name: 'font-size', value: '2em' });
break;
default:
case 'medium':
break;
}
} else {
switch (settings.textSize || '') {
case 'smaller':
list.push({ name: 'font-size', value: '.8em' });
break;
case 'small':
list.push({ name: 'font-size', value: 'inherit' });
break;
case 'larger':
list.push({ name: 'font-size', value: '2em' });
break;
case 'extralarge':
list.push({ name: 'font-size', value: '2.2em' });
break;
case 'large':
list.push({ name: 'font-size', value: '1.72em' });
break;
default:
case 'medium':
list.push({ name: 'font-size', value: '1.36em' });
break;
}
}
switch (settings.dropShadow || '') {
case 'raised':
list.push({ name: 'text-shadow', value: '-1px -1px white, 0px -1px white, -1px 0px white, 1px 1px black, 0px 1px black, 1px 0px black' });
case 'smaller':
list.push({ name: 'font-size', value: '.5em' });
break;
case 'depressed':
list.push({ name: 'text-shadow', value: '1px 1px white, 0px 1px white, 1px 0px white, -1px -1px black, 0px -1px black, -1px 0px black' });
case 'small':
list.push({ name: 'font-size', value: '.7em' });
break;
case 'uniform':
list.push({ name: 'text-shadow', value: '-1px 0px #000000, 0px 1px #000000, 1px 0px #000000, 0px -1px #000000' });
case 'large':
list.push({ name: 'font-size', value: '1.3em' });
break;
case 'none':
list.push({ name: 'text-shadow', value: 'none' });
case 'larger':
list.push({ name: 'font-size', value: '1.72em' });
break;
case 'extralarge':
list.push({ name: 'font-size', value: '2em' });
break;
default:
case 'dropshadow':
list.push({ name: 'text-shadow', value: '#000000 0px 0px 7px' });
case 'medium':
break;
}
} else {
switch (settings.textSize || '') {
var background = settings.textBackground || 'transparent';
if (background) {
list.push({ name: 'background-color', value: background });
}
var textColor = settings.textColor || '#ffffff';
if (textColor) {
list.push({ name: 'color', value: textColor });
}
switch (settings.font || '') {
case 'typewriter':
list.push({ name: 'font-family', value: '"Courier New",monospace' });
list.push({ name: 'font-variant', value: 'none' });
case 'smaller':
list.push({ name: 'font-size', value: '.8em' });
break;
case 'print':
list.push({ name: 'font-family', value: 'Georgia,Times New Roman,Arial,Helvetica,serif' });
list.push({ name: 'font-variant', value: 'none' });
case 'small':
list.push({ name: 'font-size', value: 'inherit' });
break;
case 'console':
list.push({ name: 'font-family', value: 'Consolas,Lucida Console,Menlo,Monaco,monospace' });
list.push({ name: 'font-variant', value: 'none' });
case 'larger':
list.push({ name: 'font-size', value: '2em' });
break;
case 'cursive':
list.push({ name: 'font-family', value: 'Lucida Handwriting,Brush Script MT,Segoe Script,cursive,Quintessential,system-ui,-apple-system,BlinkMacSystemFont,sans-serif' });
list.push({ name: 'font-variant', value: 'none' });
case 'extralarge':
list.push({ name: 'font-size', value: '2.2em' });
break;
case 'casual':
list.push({ name: 'font-family', value: 'Gabriola,Segoe Print,Comic Sans MS,Chalkboard,Short Stack,system-ui,-apple-system,BlinkMacSystemFont,sans-serif' });
list.push({ name: 'font-variant', value: 'none' });
break;
case 'smallcaps':
list.push({ name: 'font-family', value: 'Copperplate Gothic,Copperplate Gothic Bold,Copperplate,system-ui,-apple-system,BlinkMacSystemFont,sans-serif' });
list.push({ name: 'font-variant', value: 'small-caps' });
case 'large':
list.push({ name: 'font-size', value: '1.72em' });
break;
default:
list.push({ name: 'font-family', value: 'inherit' });
list.push({ name: 'font-variant', value: 'none' });
case 'medium':
list.push({ name: 'font-size', value: '1.36em' });
break;
}
return list;
}
function getWindowStyles(settings) {
switch (settings.dropShadow || '') {
return [];
case 'raised':
list.push({ name: 'text-shadow', value: '-1px -1px white, 0px -1px white, -1px 0px white, 1px 1px black, 0px 1px black, 1px 0px black' });
break;
case 'depressed':
list.push({ name: 'text-shadow', value: '1px 1px white, 0px 1px white, 1px 0px white, -1px -1px black, 0px -1px black, -1px 0px black' });
break;
case 'uniform':
list.push({ name: 'text-shadow', value: '-1px 0px #000000, 0px 1px #000000, 1px 0px #000000, 0px -1px #000000' });
break;
case 'none':
list.push({ name: 'text-shadow', value: 'none' });
break;
default:
case 'dropshadow':
list.push({ name: 'text-shadow', value: '#000000 0px 0px 7px' });
break;
}
function getStyles(settings, isCue) {
return {
text: getTextStyles(settings, isCue),
window: getWindowStyles(settings)
};
const background = settings.textBackground || 'transparent';
if (background) {
list.push({ name: 'background-color', value: background });
}
function applyStyleList(styles, elem) {
for (var i = 0, length = styles.length; i < length; i++) {
var style = styles[i];
elem.style[style.name] = style.value;
}
const textColor = settings.textColor || '#ffffff';
if (textColor) {
list.push({ name: 'color', value: textColor });
}
function applyStyles(elements, appearanceSettings) {
switch (settings.font || '') {
var styles = getStyles(appearanceSettings);
if (elements.text) {
applyStyleList(styles.text, elements.text);
}
if (elements.window) {
applyStyleList(styles.window, elements.window);
}
case 'typewriter':
list.push({ name: 'font-family', value: '"Courier New",monospace' });
list.push({ name: 'font-variant', value: 'none' });
break;
case 'print':
list.push({ name: 'font-family', value: 'Georgia,Times New Roman,Arial,Helvetica,serif' });
list.push({ name: 'font-variant', value: 'none' });
break;
case 'console':
list.push({ name: 'font-family', value: 'Consolas,Lucida Console,Menlo,Monaco,monospace' });
list.push({ name: 'font-variant', value: 'none' });
break;
case 'cursive':
list.push({ name: 'font-family', value: 'Lucida Handwriting,Brush Script MT,Segoe Script,cursive,Quintessential,system-ui,-apple-system,BlinkMacSystemFont,sans-serif' });
list.push({ name: 'font-variant', value: 'none' });
break;
case 'casual':
list.push({ name: 'font-family', value: 'Gabriola,Segoe Print,Comic Sans MS,Chalkboard,Short Stack,system-ui,-apple-system,BlinkMacSystemFont,sans-serif' });
list.push({ name: 'font-variant', value: 'none' });
break;
case 'smallcaps':
list.push({ name: 'font-family', value: 'Copperplate Gothic,Copperplate Gothic Bold,Copperplate,system-ui,-apple-system,BlinkMacSystemFont,sans-serif' });
list.push({ name: 'font-variant', value: 'small-caps' });
break;
default:
list.push({ name: 'font-family', value: 'inherit' });
list.push({ name: 'font-variant', value: 'none' });
break;
}
return list;
}
export function getStyles(settings, isCue) {
return {
getStyles: getStyles,
applyStyles: applyStyles
text: getTextStyles(settings, isCue),
window: []
};
});
}
function applyStyleList(styles, elem) {
for (let i = 0, length = styles.length; i < length; i++) {
let style = styles[i];
elem.style[style.name] = style.value;
}
}
export function applyStyles(elements, appearanceSettings) {
let styles = getStyles(appearanceSettings);
if (elements.text) {
applyStyleList(styles.text, elements.text);
}
if (elements.window) {
applyStyleList(styles.window, elements.window);
}
}
export default {
getStyles: getStyles,
applyStyles: applyStyles
};

View File

@ -1,109 +1,212 @@
define(['require', 'globalize', 'appSettings', 'apphost', 'focusManager', 'loading', 'connectionManager', 'subtitleAppearanceHelper', 'dom', 'events', 'listViewStyle', 'emby-select', 'emby-input', 'emby-checkbox', 'flexStyles'], function (require, globalize, appSettings, appHost, focusManager, loading, connectionManager, subtitleAppearanceHelper, dom, events) {
'use strict';
import require from 'require';
import globalize from 'globalize';
import appHost from 'apphost';
import appSettings from 'appSettings';
import focusManager from 'focusManager';
import loading from 'loading';
import connectionManager from 'connectionManager';
import subtitleAppearanceHelper from 'subtitleAppearanceHelper';
import settingsHelper from 'settingsHelper';
import dom from 'dom';
import events from 'events';
import 'listViewStyle';
import 'emby-select';
import 'emby-input';
import 'emby-checkbox';
import 'flexStyles';
function populateLanguages(select, languages) {
var html = '';
/**
* Subtitle settings.
* @module components/subtitleSettings/subtitleSettings
*/
html += "<option value=''>" + globalize.translate('AnyLanguage') + '</option>';
for (var i = 0, length = languages.length; i < length; i++) {
var culture = languages[i];
html += "<option value='" + culture.ThreeLetterISOLanguageName + "'>" + culture.DisplayName + '</option>';
function getSubtitleAppearanceObject(context) {
let appearanceSettings = {};
appearanceSettings.textSize = context.querySelector('#selectTextSize').value;
appearanceSettings.dropShadow = context.querySelector('#selectDropShadow').value;
appearanceSettings.font = context.querySelector('#selectFont').value;
appearanceSettings.textBackground = context.querySelector('#inputTextBackground').value;
appearanceSettings.textColor = context.querySelector('#inputTextColor').value;
return appearanceSettings;
}
function loadForm(context, user, userSettings, appearanceSettings, apiClient) {
apiClient.getCultures().then(function (allCultures) {
if (appHost.supports('subtitleburnsettings') && user.Policy.EnableVideoPlaybackTranscoding) {
context.querySelector('.fldBurnIn').classList.remove('hide');
}
select.innerHTML = html;
}
let selectSubtitleLanguage = context.querySelector('#selectSubtitleLanguage');
function getSubtitleAppearanceObject(context) {
var appearanceSettings = {};
settingsHelper.populateLanguages(selectSubtitleLanguage, allCultures);
appearanceSettings.textSize = context.querySelector('#selectTextSize').value;
appearanceSettings.dropShadow = context.querySelector('#selectDropShadow').value;
appearanceSettings.font = context.querySelector('#selectFont').value;
appearanceSettings.textBackground = context.querySelector('#inputTextBackground').value;
appearanceSettings.textColor = context.querySelector('#inputTextColor').value;
selectSubtitleLanguage.value = user.Configuration.SubtitleLanguagePreference || '';
context.querySelector('#selectSubtitlePlaybackMode').value = user.Configuration.SubtitleMode || '';
return appearanceSettings;
}
context.querySelector('#selectSubtitlePlaybackMode').dispatchEvent(new CustomEvent('change', {}));
function loadForm(context, user, userSettings, appearanceSettings, apiClient) {
context.querySelector('#selectTextSize').value = appearanceSettings.textSize || '';
context.querySelector('#selectDropShadow').value = appearanceSettings.dropShadow || '';
context.querySelector('#inputTextBackground').value = appearanceSettings.textBackground || 'transparent';
context.querySelector('#inputTextColor').value = appearanceSettings.textColor || '#ffffff';
context.querySelector('#selectFont').value = appearanceSettings.font || '';
apiClient.getCultures().then(function (allCultures) {
context.querySelector('#selectSubtitleBurnIn').value = appSettings.get('subtitleburnin') || '';
if (appHost.supports('subtitleburnsettings') && user.Policy.EnableVideoPlaybackTranscoding) {
context.querySelector('.fldBurnIn').classList.remove('hide');
}
onAppearanceFieldChange({
target: context.querySelector('#selectTextSize')
});
var selectSubtitleLanguage = context.querySelector('#selectSubtitleLanguage');
loading.hide();
});
}
populateLanguages(selectSubtitleLanguage, allCultures);
function saveUser(context, user, userSettingsInstance, appearanceKey, apiClient) {
selectSubtitleLanguage.value = user.Configuration.SubtitleLanguagePreference || '';
context.querySelector('#selectSubtitlePlaybackMode').value = user.Configuration.SubtitleMode || '';
let appearanceSettings = userSettingsInstance.getSubtitleAppearanceSettings(appearanceKey);
appearanceSettings = Object.assign(appearanceSettings, getSubtitleAppearanceObject(context));
context.querySelector('#selectSubtitlePlaybackMode').dispatchEvent(new CustomEvent('change', {}));
userSettingsInstance.setSubtitleAppearanceSettings(appearanceSettings, appearanceKey);
context.querySelector('#selectTextSize').value = appearanceSettings.textSize || '';
context.querySelector('#selectDropShadow').value = appearanceSettings.dropShadow || '';
context.querySelector('#inputTextBackground').value = appearanceSettings.textBackground || 'transparent';
context.querySelector('#inputTextColor').value = appearanceSettings.textColor || '#ffffff';
context.querySelector('#selectFont').value = appearanceSettings.font || '';
user.Configuration.SubtitleLanguagePreference = context.querySelector('#selectSubtitleLanguage').value;
user.Configuration.SubtitleMode = context.querySelector('#selectSubtitlePlaybackMode').value;
context.querySelector('#selectSubtitleBurnIn').value = appSettings.get('subtitleburnin') || '';
return apiClient.updateUserConfiguration(user.Id, user.Configuration);
}
onAppearanceFieldChange({
target: context.querySelector('#selectTextSize')
});
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
loading.show();
appSettings.set('subtitleburnin', context.querySelector('#selectSubtitleBurnIn').value);
apiClient.getUser(userId).then(function (user) {
saveUser(context, user, userSettings, instance.appearanceKey, apiClient).then(function () {
loading.hide();
if (enableSaveConfirmation) {
require(['toast'], function (toast) {
toast(globalize.translate('SettingsSaved'));
});
}
events.trigger(instance, 'saved');
}, function () {
loading.hide();
});
});
}
function onSubtitleModeChange(e) {
let view = dom.parentWithClass(e.target, 'subtitlesettings');
let subtitlesHelp = view.querySelectorAll('.subtitlesHelp');
for (let i = 0, length = subtitlesHelp.length; i < length; i++) {
subtitlesHelp[i].classList.add('hide');
}
view.querySelector('.subtitles' + this.value + 'Help').classList.remove('hide');
}
function onAppearanceFieldChange(e) {
let view = dom.parentWithClass(e.target, 'subtitlesettings');
let appearanceSettings = getSubtitleAppearanceObject(view);
let elements = {
window: view.querySelector('.subtitleappearance-preview-window'),
text: view.querySelector('.subtitleappearance-preview-text')
};
subtitleAppearanceHelper.applyStyles(elements, appearanceSettings);
}
function embed(options, self) {
require(['text!./subtitlesettings.template.html'], function (template) {
options.element.classList.add('subtitlesettings');
options.element.innerHTML = globalize.translateDocument(template, 'core');
options.element.querySelector('form').addEventListener('submit', self.onSubmit.bind(self));
options.element.querySelector('#selectSubtitlePlaybackMode').addEventListener('change', onSubtitleModeChange);
options.element.querySelector('#selectTextSize').addEventListener('change', onAppearanceFieldChange);
options.element.querySelector('#selectDropShadow').addEventListener('change', onAppearanceFieldChange);
options.element.querySelector('#selectFont').addEventListener('change', onAppearanceFieldChange);
options.element.querySelector('#inputTextColor').addEventListener('change', onAppearanceFieldChange);
options.element.querySelector('#inputTextBackground').addEventListener('change', onAppearanceFieldChange);
if (options.enableSaveButton) {
options.element.querySelector('.btnSave').classList.remove('hide');
}
if (appHost.supports('subtitleappearancesettings')) {
options.element.querySelector('.subtitleAppearanceSection').classList.remove('hide');
}
self.loadData();
if (options.autoFocus) {
focusManager.autoFocus(options.element);
}
});
}
export class SubtitleSettings {
constructor(options) {
this.options = options;
embed(options, this);
}
function saveUser(context, user, userSettingsInstance, appearanceKey, apiClient) {
var appearanceSettings = userSettingsInstance.getSubtitleAppearanceSettings(appearanceKey);
appearanceSettings = Object.assign(appearanceSettings, getSubtitleAppearanceObject(context));
userSettingsInstance.setSubtitleAppearanceSettings(appearanceSettings, appearanceKey);
user.Configuration.SubtitleLanguagePreference = context.querySelector('#selectSubtitleLanguage').value;
user.Configuration.SubtitleMode = context.querySelector('#selectSubtitlePlaybackMode').value;
return apiClient.updateUserConfiguration(user.Id, user.Configuration);
}
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
loadData() {
let self = this;
let context = self.options.element;
loading.show();
appSettings.set('subtitleburnin', context.querySelector('#selectSubtitleBurnIn').value);
let userId = self.options.userId;
let apiClient = connectionManager.getApiClient(self.options.serverId);
let userSettings = self.options.userSettings;
apiClient.getUser(userId).then(function (user) {
userSettings.setUserInfo(userId, apiClient).then(function () {
self.dataLoaded = true;
saveUser(context, user, userSettings, instance.appearanceKey, apiClient).then(function () {
let appearanceSettings = userSettings.getSubtitleAppearanceSettings(self.options.appearanceKey);
loading.hide();
if (enableSaveConfirmation) {
require(['toast'], function (toast) {
toast(globalize.translate('SettingsSaved'));
});
}
events.trigger(instance, 'saved');
}, function () {
loading.hide();
loadForm(context, user, userSettings, appearanceSettings, apiClient);
});
});
}
function onSubmit(e) {
var self = this;
var apiClient = connectionManager.getApiClient(self.options.serverId);
var userId = self.options.userId;
var userSettings = self.options.userSettings;
submit() {
this.onSubmit(null);
}
destroy() {
this.options = null;
}
onSubmit(e) {
const self = this;
let apiClient = connectionManager.getApiClient(self.options.serverId);
let userId = self.options.userId;
let userSettings = self.options.userSettings;
userSettings.setUserInfo(userId, apiClient).then(function () {
var enableSaveConfirmation = self.options.enableSaveConfirmation;
let enableSaveConfirmation = self.options.enableSaveConfirmation;
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
});
@ -111,103 +214,8 @@ define(['require', 'globalize', 'appSettings', 'apphost', 'focusManager', 'loadi
if (e) {
e.preventDefault();
}
return false;
}
}
function onSubtitleModeChange(e) {
var view = dom.parentWithClass(e.target, 'subtitlesettings');
var subtitlesHelp = view.querySelectorAll('.subtitlesHelp');
for (var i = 0, length = subtitlesHelp.length; i < length; i++) {
subtitlesHelp[i].classList.add('hide');
}
view.querySelector('.subtitles' + this.value + 'Help').classList.remove('hide');
}
function onAppearanceFieldChange(e) {
var view = dom.parentWithClass(e.target, 'subtitlesettings');
var appearanceSettings = getSubtitleAppearanceObject(view);
var elements = {
window: view.querySelector('.subtitleappearance-preview-window'),
text: view.querySelector('.subtitleappearance-preview-text')
};
subtitleAppearanceHelper.applyStyles(elements, appearanceSettings);
}
function embed(options, self) {
require(['text!./subtitlesettings.template.html'], function (template) {
options.element.classList.add('subtitlesettings');
options.element.innerHTML = globalize.translateDocument(template, 'core');
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
options.element.querySelector('#selectSubtitlePlaybackMode').addEventListener('change', onSubtitleModeChange);
options.element.querySelector('#selectTextSize').addEventListener('change', onAppearanceFieldChange);
options.element.querySelector('#selectDropShadow').addEventListener('change', onAppearanceFieldChange);
options.element.querySelector('#selectFont').addEventListener('change', onAppearanceFieldChange);
options.element.querySelector('#inputTextColor').addEventListener('change', onAppearanceFieldChange);
options.element.querySelector('#inputTextBackground').addEventListener('change', onAppearanceFieldChange);
if (options.enableSaveButton) {
options.element.querySelector('.btnSave').classList.remove('hide');
}
if (appHost.supports('subtitleappearancesettings')) {
options.element.querySelector('.subtitleAppearanceSection').classList.remove('hide');
}
self.loadData();
if (options.autoFocus) {
focusManager.autoFocus(options.element);
}
});
}
function SubtitleSettings(options) {
this.options = options;
embed(options, this);
}
SubtitleSettings.prototype.loadData = function () {
var self = this;
var context = self.options.element;
loading.show();
var userId = self.options.userId;
var apiClient = connectionManager.getApiClient(self.options.serverId);
var userSettings = self.options.userSettings;
apiClient.getUser(userId).then(function (user) {
userSettings.setUserInfo(userId, apiClient).then(function () {
self.dataLoaded = true;
var appearanceSettings = userSettings.getSubtitleAppearanceSettings(self.options.appearanceKey);
loadForm(context, user, userSettings, appearanceSettings, apiClient);
});
});
};
SubtitleSettings.prototype.submit = function () {
onSubmit.call(this);
};
SubtitleSettings.prototype.destroy = function () {
this.options = null;
};
return SubtitleSettings;
});
export default SubtitleSettings;

View File

@ -65,8 +65,6 @@ class TimeSyncManager {
this.pings = 0; // number of pings
this.measurement = null; // current time sync
this.measurements = [];
this.startPing();
}
/**

View File

@ -51,7 +51,7 @@ define(['playbackManager', 'userSettings', 'alphaPicker', 'alphaNumericShortcuts
instance.itemsContainer = view.querySelector('.itemsContainer');
instance.alphaPicker = new AlphaPicker({
instance.alphaPicker = new AlphaPicker.default({
element: instance.alphaPickerElement,
itemsContainer: instance.itemsContainer,
itemClass: 'card'

View File

@ -3,7 +3,7 @@ define(['jQuery', 'apphost', 'scripts/taskbutton', 'loading', 'libraryMenu', 'gl
function addVirtualFolder(page) {
require(['medialibrarycreator'], function (medialibrarycreator) {
new medialibrarycreator().show({
new medialibrarycreator.showEditor({
collectionTypeOptions: getCollectionTypeOptions().filter(function (f) {
return !f.hidden;
}),
@ -18,7 +18,7 @@ define(['jQuery', 'apphost', 'scripts/taskbutton', 'loading', 'libraryMenu', 'gl
function editVirtualFolder(page, virtualFolder) {
require(['medialibraryeditor'], function (medialibraryeditor) {
new medialibraryeditor().show({
new medialibraryeditor.showEditor({
refresh: shouldRefreshLibraryAfterChanges(page),
library: virtualFolder
}).then(function (hasChanges) {

View File

@ -123,6 +123,9 @@ define(['loading', 'libraryMenu', 'globalize', 'cardStyle', 'emby-button', 'emby
}, {
href: 'availableplugins.html',
name: globalize.translate('TabCatalog')
}, {
href: 'repositories.html',
name: globalize.translate('TabRepositories')
}];
}

View File

@ -37,18 +37,22 @@ define(['loading', 'libraryMenu', 'dom', 'globalize', 'cardStyle', 'emby-button'
})[0];
var configPageUrl = configPage ? Dashboard.getConfigurationPageUrl(configPage.Name) : null;
var html = '';
html += "<div data-id='" + plugin.Id + "' data-name='" + plugin.Name + "' class='card backdropCard'>";
html += "<div data-id='" + plugin.Id + "' data-name='" + plugin.Name + "' data-removable='" + plugin.CanUninstall + "' class='card backdropCard'>";
html += '<div class="cardBox visualCardBox">';
html += '<div class="cardScalable">';
html += '<div class="cardPadder cardPadder-backdrop"></div>';
html += configPageUrl ? '<a class="cardContent cardImageContainer" is="emby-linkbutton" href="' + configPageUrl + '">' : '<div class="cardContent noConfigPluginCard noHoverEffect cardImageContainer">';
html += configPageUrl ? '<a class="cardContent cardImageContainer" is="emby-linkbutton" href="' + configPageUrl + '">' : '<div class="cardContent noConfigPluginCard noHoverEffect cardImageContainer emby-button">';
html += '<span class="cardImageIcon material-icons folder"></span>';
html += configPageUrl ? '</a>' : '</div>';
html += '</div>';
html += '<div class="cardFooter">';
html += '<div style="text-align:right; float:right;padding-top:5px;">';
html += '<button type="button" is="paper-icon-button-light" class="btnCardMenu autoSize"><span class="material-icons more_vert"></span></button>';
html += '</div>';
if (configPage || plugin.CanUninstall) {
html += '<div style="text-align:right; float:right;padding-top:5px;">';
html += '<button type="button" is="paper-icon-button-light" class="btnCardMenu autoSize"><span class="material-icons more_vert"></span></button>';
html += '</div>';
}
html += "<div class='cardText'>";
html += configPage && configPage.DisplayName ? configPage.DisplayName : plugin.Name;
html += '</div>';
@ -104,6 +108,7 @@ define(['loading', 'libraryMenu', 'dom', 'globalize', 'cardStyle', 'emby-button'
var card = dom.parentWithClass(elem, 'card');
var id = card.getAttribute('data-id');
var name = card.getAttribute('data-name');
var removable = card.getAttribute('data-removable');
var configHref = card.querySelector('.cardContent').getAttribute('href');
var menuItems = [];
@ -115,11 +120,13 @@ define(['loading', 'libraryMenu', 'dom', 'globalize', 'cardStyle', 'emby-button'
});
}
menuItems.push({
name: globalize.translate('ButtonUninstall'),
id: 'delete',
icon: 'delete'
});
if (removable === 'true') {
menuItems.push({
name: globalize.translate('ButtonUninstall'),
id: 'delete',
icon: 'delete'
});
}
require(['actionsheet'], function (actionsheet) {
actionsheet.show({
@ -153,6 +160,9 @@ define(['loading', 'libraryMenu', 'dom', 'globalize', 'cardStyle', 'emby-button'
}, {
href: 'availableplugins.html',
name: globalize.translate('TabCatalog')
}, {
href: 'repositories.html',
name: globalize.translate('TabRepositories')
}];
}

View File

@ -0,0 +1,153 @@
import loading from 'loading';
import libraryMenu from 'libraryMenu';
import globalize from 'globalize';
import dialogHelper from 'dialogHelper';
import 'emby-button';
import 'emby-checkbox';
import 'emby-select';
import 'formDialogStyle';
import 'listViewStyle';
let repositories = [];
function reloadList(page) {
loading.show();
ApiClient.getJSON(ApiClient.getUrl('Repositories')).then(list => {
repositories = list;
populateList({
listElement: page.querySelector('#repositories'),
noneElement: page.querySelector('#none'),
repositories: repositories
});
}).catch(error => {
console.error('error loading repositories');
page.querySelector('#none').classList.remove('hide');
loading.hide();
});
}
function saveList(page) {
loading.show();
ApiClient.ajax({
type: 'POST',
url: ApiClient.getUrl('Repositories'),
data: JSON.stringify(repositories),
contentType: 'application/json'
}).then(response => {
reloadList(page);
}).catch(error => {
console.error('error saving repositories');
loading.hide();
});
}
function populateList(options) {
var html = '';
html += '<div class="paperList">';
for (var i = 0; i < options.repositories.length; i++) {
html += getRepositoryHtml(options.repositories[i]);
}
html += '</div>';
if (!options.repositories.length) {
options.noneElement.classList.remove('hide');
}
options.listElement.innerHTML = html;
loading.hide();
}
function getRepositoryHtml(repository) {
var html = '';
html += '<div class="listItem listItem-border">';
html += `<a is="emby-linkbutton" style="margin:0;padding:0" class="clearLink listItemIconContainer" href="${repository.Url}">`;
html += '<span class="material-icons listItemIcon open_in_new"></span>';
html += '</a>';
html += '<div class="listItemBody two-line">';
html += `<h3 class="listItemBodyText">${repository.Name}</h3>`;
html += `<div class="listItemBodyText secondary">${repository.Url}</div>`;
html += '</div>';
html += `<button type="button" is="paper-icon-button-light" id="${repository.Url}" class="btnDelete" title="${globalize.translate('ButtonDelete')}"><span class="material-icons delete"></span></button>`;
html += '</div>';
return html;
}
function getTabs() {
return [{
href: 'installedplugins.html',
name: globalize.translate('TabMyPlugins')
}, {
href: 'availableplugins.html',
name: globalize.translate('TabCatalog')
}, {
href: 'repositories.html',
name: globalize.translate('TabRepositories')
}];
}
export default function(view, params) {
view.addEventListener('viewshow', function () {
libraryMenu.setTabs('plugins', 2, getTabs);
reloadList(this);
var save = this;
$('#repositories', view).on('click', '.btnDelete', function() {
var button = this;
repositories = repositories.filter(function (r) {
return r.Url !== button.id;
});
saveList(save);
});
});
view.querySelector('.btnNewRepository').addEventListener('click', () => {
let dialog = dialogHelper.createDialog({
scrollY: false,
size: 'large',
modal: false,
removeOnClose: true
});
let html = '';
html += '<div class="formDialogHeader">';
html += '<button type="button" is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
html += `<h3 class="formDialogHeaderTitle">${globalize.translate('HeaderNewRepository')}</h3>`;
html += '</div>';
html += '<form class="newPluginForm" style="margin:4em">';
html += '<div class="inputContainer">';
html += `<input is="emby-input" id="txtRepositoryName" label="${globalize.translate('LabelRepositoryName')}" type="text" required />`;
html += `<div class="fieldDescription">${globalize.translate('LabelRepositoryNameHelp')}</div>`;
html += '</div>';
html += '<div class="inputContainer">';
html += `<input is="emby-input" id="txtRepositoryUrl" label="${globalize.translate('LabelRepositoryUrl')}" type="url" required />`;
html += `<div class="fieldDescription">${globalize.translate('LabelRepositoryUrlHelp')}</div>`;
html += '</div>';
html += `<button is="emby-button" type="submit" class="raised button-submit block"><span>${globalize.translate('ButtonSave')}</span></button>`;
html += '</div>';
html += '</form>';
dialog.innerHTML = html;
dialog.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dialog);
});
dialog.querySelector('.newPluginForm').addEventListener('submit', () => {
repositories.push({
Name: dialog.querySelector('#txtRepositoryName').value,
Url: dialog.querySelector('#txtRepositoryUrl').value,
Enabled: true
});
saveList(view);
dialogHelper.close(dialog);
return false;
});
dialogHelper.open(dialog);
});
}

View File

@ -400,6 +400,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
} else if (item.Album) {
parentNameHtml.push(item.Album);
}
// FIXME: This whole section needs some refactoring, so it becames easier to scale across all form factors. See GH #1022
var html = '';
var tvShowHtml = parentNameHtml[0];
@ -415,9 +416,9 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
}
} else {
if (layoutManager.mobile) {
html = '<h1 class="parentName" style="margin: .1em 0 .25em;">' + parentNameHtml.join('</br>') + '</h1>';
html = '<h1 class="parentName" style="margin: 0.2em 0 0">' + parentNameHtml.join('</br>') + '</h1>';
} else {
html = '<h1 class="parentName" style="margin: .1em 0 .25em;">' + tvShowHtml + '</h1>';
html = '<h1 class="parentName" style="margin: 0.2em 0 0">' + tvShowHtml + '</h1>';
}
}
}
@ -425,20 +426,19 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
var name = itemHelper.getDisplayName(item, {
includeParentInfo: false
});
var offset = parentNameLast ? '.25em' : '.5em';
if (html && !parentNameLast) {
if (!layoutManager.mobile && tvSeasonHtml) {
html += '<h3 class="itemName infoText" style="margin: .25em 0 .5em;">' + tvSeasonHtml + ' - ' + name + '</h3>';
html += '<h3 class="itemName infoText" style="margin: 0.2em 0 0">' + tvSeasonHtml + ' - ' + name + '</h3>';
} else {
html += '<h3 class="itemName infoText" style="margin: .25em 0 .5em;">' + name + '</h3>';
html += '<h3 class="itemName infoText" style="margin: 0.2em 0 0">' + name + '</h3>';
}
} else {
html = '<h1 class="itemName infoText" style="margin: .1em 0 ' + offset + ';">' + name + '</h1>' + html;
html = '<h1 class="itemName infoText" style="margin: 0.4em 0 0">' + name + '</h1>' + html;
}
if (item.OriginalTitle && item.OriginalTitle != item.Name) {
html += '<h4 class="itemName infoText" style="margin: -' + offset + ' 0 0;">' + item.OriginalTitle + '</h4>';
html += '<h4 class="itemName infoText" style="margin: 0 0 0;">' + item.OriginalTitle + '</h4>';
}
container.innerHTML = html;
@ -1106,10 +1106,10 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
var externalLinksElem = page.querySelector('.itemExternalLinks');
renderOverview([overview], item);
var i;
var itemMiscInfo;
itemMiscInfo = page.querySelectorAll('.itemMiscInfo-primary');
for (i = 0; i < itemMiscInfo.length; i++) {
mediaInfo.fillPrimaryMediaInfo(itemMiscInfo[i], item, {
interactive: true,
@ -1125,7 +1125,6 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
}
itemMiscInfo = page.querySelectorAll('.itemMiscInfo-secondary');
for (i = 0; i < itemMiscInfo.length; i++) {
mediaInfo.fillSecondaryMediaInfo(itemMiscInfo[i], item, {
interactive: true

View File

@ -1,4 +1,4 @@
define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager', 'cardBuilder', 'loading', 'connectionManager', 'alphaNumericShortcuts', 'scroller', 'playbackManager', 'alphaPicker', 'emby-itemscontainer', 'emby-scroller'], function (globalize, listView, layoutManager, userSettings, focusManager, cardBuilder, loading, connectionManager, AlphaNumericShortcuts, scroller, playbackManager, alphaPicker) {
define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager', 'cardBuilder', 'loading', 'connectionManager', 'alphaNumericShortcuts', 'scroller', 'playbackManager', 'alphaPicker', 'emby-itemscontainer', 'emby-scroller'], function (globalize, listView, layoutManager, userSettings, focusManager, cardBuilder, loading, connectionManager, AlphaNumericShortcuts, scroller, playbackManager, AlphaPicker) {
'use strict';
function getInitialLiveTvQuery(instance, params) {
@ -386,7 +386,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
var instance = this;
require(['playlistEditor'], function (playlistEditor) {
new playlistEditor().show({
new playlistEditor.showEditor({
items: [],
serverId: instance.params.serverId
});
@ -544,7 +544,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
alphaPickerElement.classList.add('focuscontainer-right');
self.itemsContainer.parentNode.classList.add('padded-right-withalphapicker');
self.alphaPicker = new alphaPicker({
self.alphaPicker = new AlphaPicker.default({
element: alphaPickerElement,
itemsContainer: layoutManager.tv ? self.itemsContainer : null,
itemClass: 'card',

View File

@ -155,8 +155,8 @@ define(['jQuery', 'globalize', 'scripts/taskbutton', 'dom', 'libraryMenu', 'layo
}
function mapChannels(page, providerId) {
require(['components/channelMapper/channelMapper'], function (channelmapper) {
new channelmapper({
require(['components/channelMapper/channelMapper'], function (channelMapper) {
new channelMapper.default({
serverId: ApiClient.serverInfo().Id,
providerId: providerId
}).show();

View File

@ -242,7 +242,7 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB
tabContent.querySelector('.btnNewCollection').addEventListener('click', function () {
require(['collectionEditor'], function (collectionEditor) {
var serverId = ApiClient.serverInfo().Id;
new collectionEditor().show({
new collectionEditor.showEditor({
items: [],
serverId: serverId
});

View File

@ -1,4 +1,4 @@
define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser', 'alphaPicker', 'listView', 'cardBuilder', 'globalize', 'emby-itemscontainer'], function (loading, layoutManager, userSettings, events, libraryBrowser, alphaPicker, listView, cardBuilder, globalize) {
define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser', 'alphaPicker', 'listView', 'cardBuilder', 'globalize', 'emby-itemscontainer'], function (loading, layoutManager, userSettings, events, libraryBrowser, AlphaPicker, listView, cardBuilder, globalize) {
'use strict';
return function (view, params, tabContent, options) {
@ -168,7 +168,7 @@ define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser',
query.StartIndex = 0;
itemsContainer.refreshItems();
});
self.alphaPicker = new alphaPicker({
self.alphaPicker = new AlphaPicker.default({
element: alphaPickerElement,
valueChangeEvent: 'click'
});

View File

@ -1,4 +1,4 @@
define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', 'alphaPicker', 'listView', 'cardBuilder', 'userSettings', 'globalize', 'emby-itemscontainer'], function (layoutManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, userSettings, globalize) {
define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', 'alphaPicker', 'listView', 'cardBuilder', 'userSettings', 'globalize', 'emby-itemscontainer'], function (layoutManager, loading, events, libraryBrowser, imageLoader, AlphaPicker, listView, cardBuilder, userSettings, globalize) {
'use strict';
return function (view, params, tabContent) {
@ -213,7 +213,7 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
query.StartIndex = 0;
reloadItems();
});
self.alphaPicker = new alphaPicker({
self.alphaPicker = new AlphaPicker.default({
element: alphaPickerElement,
valueChangeEvent: 'click'
});

View File

@ -1,4 +1,4 @@
define(['layoutManager', 'playbackManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', 'alphaPicker', 'listView', 'cardBuilder', 'userSettings', 'globalize', 'emby-itemscontainer'], function (layoutManager, playbackManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, userSettings, globalize) {
define(['layoutManager', 'playbackManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', 'alphaPicker', 'listView', 'cardBuilder', 'userSettings', 'globalize', 'emby-itemscontainer'], function (layoutManager, playbackManager, loading, events, libraryBrowser, imageLoader, AlphaPicker, listView, cardBuilder, userSettings, globalize) {
'use strict';
return function (view, params, tabContent) {
@ -215,7 +215,7 @@ define(['layoutManager', 'playbackManager', 'loading', 'events', 'libraryBrowser
query.StartIndex = 0;
reloadItems(tabContent);
});
self.alphaPicker = new alphaPicker({
self.alphaPicker = new AlphaPicker.default({
element: alphaPickerElement,
valueChangeEvent: 'click'
});

View File

@ -1,4 +1,4 @@
define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', 'alphaPicker', 'listView', 'cardBuilder', 'apphost', 'userSettings', 'emby-itemscontainer'], function (layoutManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, appHost, userSettings) {
define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', 'alphaPicker', 'listView', 'cardBuilder', 'apphost', 'userSettings', 'emby-itemscontainer'], function (layoutManager, loading, events, libraryBrowser, imageLoader, AlphaPicker, listView, cardBuilder, appHost, userSettings) {
'use strict';
return function (view, params, tabContent) {
@ -199,7 +199,7 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
query.StartIndex = 0;
reloadItems(tabContent);
});
self.alphaPicker = new alphaPicker({
self.alphaPicker = new AlphaPicker.default({
element: alphaPickerElement,
valueChangeEvent: 'click'
});

View File

@ -1,4 +1,4 @@
define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardBuilder', 'alphaPicker', 'userSettings', 'globalize', 'emby-itemscontainer'], function (layoutManager, loading, events, libraryBrowser, imageLoader, listView, cardBuilder, alphaPicker, userSettings, globalize) {
define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardBuilder', 'alphaPicker', 'userSettings', 'globalize', 'emby-itemscontainer'], function (layoutManager, loading, events, libraryBrowser, imageLoader, listView, cardBuilder, AlphaPicker, userSettings, globalize) {
'use strict';
return function (view, params, tabContent) {
@ -226,7 +226,7 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
query.StartIndex = 0;
reloadItems(tabContent);
});
self.alphaPicker = new alphaPicker({
self.alphaPicker = new AlphaPicker.default({
element: alphaPickerElement,
valueChangeEvent: 'click'
});

View File

@ -1,52 +1,63 @@
define(['subtitleSettings', 'userSettings', 'autoFocuser'], function (SubtitleSettings, userSettings, autoFocuser) {
'use strict';
import subtitleSettings from 'subtitleSettings';
import {UserSettings, currentSettings as userSettings} from 'userSettings';
import autoFocuser from 'autoFocuser';
// Shortcuts
const UserSettings = userSettings.UserSettings;
export class SubtitleController {
constructor(view, params) {
this.userId = params.userId || ApiClient.getCurrentUserId();
this.currentSettings = this.userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
this.hasChanges = false;
this.subtitleSettingsInstance = null;
this.view = view;
return function (view, params) {
function onBeforeUnload(e) {
if (hasChanges) {
e.returnValue = 'You currently have unsaved changes. Are you sure you wish to leave?';
}
view.addEventListener('viewshow', this.viewShow.bind(this));
view.addEventListener('change', this.change.bind(this));
view.addEventListener('viewbeforehide', this.viewBeforeHide.bind(this));
view.addEventListener('viewdestroy', this.viewDestroy.bind(this));
}
viewShow() {
window.addEventListener('beforeunload', this.beforeUnload.bind(this));
if (this.subtitleSettingsInstance) {
this.subtitleSettingsInstance.loadData();
} else {
this.subtitleSettingsInstance = new subtitleSettings({
serverId: ApiClient.serverId(),
userId: this.userId,
element: this.view.querySelector('.settingsContainer'),
userSettings: this.currentSettings,
enableSaveButton: false,
enableSaveConfirmation: false,
autoFocus: autoFocuser.isEnabled()
});
}
}
var subtitleSettingsInstance;
var hasChanges;
var userId = params.userId || ApiClient.getCurrentUserId();
var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
view.addEventListener('viewshow', function () {
window.addEventListener('beforeunload', onBeforeUnload);
viewDestroy() {
if (this.subtitleSettingsInstance) {
this.subtitleSettingsInstance.destroy();
this.subtitleSettingsInstance = null;
}
}
if (subtitleSettingsInstance) {
subtitleSettingsInstance.loadData();
} else {
subtitleSettingsInstance = new SubtitleSettings({
serverId: ApiClient.serverId(),
userId: userId,
element: view.querySelector('.settingsContainer'),
userSettings: currentSettings,
enableSaveButton: false,
enableSaveConfirmation: false,
autoFocus: autoFocuser.isEnabled()
});
}
});
view.addEventListener('change', function () {
hasChanges = true;
});
view.addEventListener('viewbeforehide', function () {
hasChanges = false;
viewBeforeHide() {
this.hasChanges = false;
if (subtitleSettingsInstance) {
subtitleSettingsInstance.submit();
}
});
view.addEventListener('viewdestroy', function () {
if (subtitleSettingsInstance) {
subtitleSettingsInstance.destroy();
subtitleSettingsInstance = null;
}
});
};
});
if (this.subtitleSettingsInstance) {
this.subtitleSettingsInstance.submit();
}
}
change() {
this.hasChanges = true;
}
beforeUnload(e) {
if (this.hasChanges) {
e.returnValue = 'You currently have unsaved changes. Are you sure you wish to leave?';
}
}
}
export default SubtitleController;

View File

@ -109,9 +109,7 @@ define(['layoutManager', 'browser', 'dom', 'css!./emby-input', 'registerElement'
}
EmbyInputPrototype.attachedCallback = function () {
this.labelElement.htmlFor = this.id;
onChange.call(this);
};

View File

@ -10,8 +10,8 @@
<div class="detailPagePrimaryContainer padded-left padded-right">
<div class="infoWrapper infoText">
<div class="nameContainer"></div>
<div class="itemMiscInfo itemMiscInfo-primary"></div>
<div class="itemMiscInfo itemMiscInfo-secondary"></div>
<div class="itemMiscInfo itemMiscInfo-primary" style="margin-bottom: 0.6em"></div>
<div class="itemMiscInfo itemMiscInfo-secondary" style="margin-bottom: 0.6em"></div>
</div>
<div class="mainDetailButtons">

19
src/repositories.html Normal file
View File

@ -0,0 +1,19 @@
<div id="repositories" data-role="page" class="page type-interior withTabs fullWidthContent">
<div>
<div class="content-primary">
<div class="sectionTitleContainer flex align-items-center">
<h2 class="sectionTitle">${TabRepositories}</h2>
<button is="emby-button" type="button" class="fab btnNewRepository submit" style="margin-left:1em;" title="${ButtonAdd}">
<span class="material-icons add" aria-hidden="true"></span>
</button>
</div>
<div id="repositories"></div>
<div id="none" class="noItemsMessage centerMessage hide">
<h1>${MessageNoRepositories}</h1>
<p>${MessageAddRepository}</p>
</div>
</div>
</div>
</div>

View File

@ -834,6 +834,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
var headerAudioPlayerButton;
var headerSyncButton;
var enableLibraryNavDrawer = layoutManager.desktop;
var enableLibraryNavDrawerHome = !layoutManager.tv;
var skinHeader = document.querySelector('.skinHeader');
var requiresUserRefresh = true;
var lastOpenTime = new Date().getTime();
@ -920,7 +921,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
refreshDashboardInfoInDrawer(apiClient);
} else {
if (mainDrawerButton) {
if (enableLibraryNavDrawer || isHomePage) {
if (enableLibraryNavDrawer || (isHomePage && enableLibraryNavDrawerHome)) {
mainDrawerButton.classList.remove('hide');
} else {
mainDrawerButton.classList.add('hide');

View File

@ -184,7 +184,7 @@ define(['loading', 'listView', 'cardBuilder', 'libraryMenu', 'libraryBrowser', '
view.querySelector('.btnNewPlaylist').addEventListener('click', function () {
require(['playlistEditor'], function (playlistEditor) {
var serverId = ApiClient.serverInfo().Id;
new playlistEditor().show({
new playlistEditor.showEditor({
items: [],
serverId: serverId
});

View File

@ -215,6 +215,12 @@ define([
roles: 'admin',
controller: 'dashboard/plugins/available'
});
defineRoute({
path: '/repositories.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/plugins/repositories'
});
defineRoute({
path: '/home.html',

View File

@ -193,25 +193,6 @@ var Dashboard = {
}).then(options.callback || function () {});
});
},
restartServer: function () {
var apiClient = window.ApiClient;
if (apiClient) {
require(['serverRestartDialog', 'events'], function (ServerRestartDialog, events) {
var dialog = new ServerRestartDialog({
apiClient: apiClient
});
events.on(dialog, 'restarted', function () {
if (AppInfo.isNativeApp) {
apiClient.ensureWebSocket();
} else {
window.location.reload(true);
}
});
dialog.show();
});
}
},
capabilities: function (appHost) {
var capabilities = {
PlayableMediaTypes: ['Audio', 'Video'],
@ -814,7 +795,6 @@ var AppInfo = {};
define('tabbedView', [componentsPath + '/tabbedview/tabbedview'], returnFirstDependency);
define('itemsTab', [componentsPath + '/tabbedview/itemstab'], returnFirstDependency);
define('collectionEditor', [componentsPath + '/collectionEditor/collectionEditor'], returnFirstDependency);
define('serverRestartDialog', [componentsPath + '/serverRestartDialog'], returnFirstDependency);
define('playlistEditor', [componentsPath + '/playlisteditor/playlisteditor'], returnFirstDependency);
define('recordingCreator', [componentsPath + '/recordingcreator/recordingcreator'], returnFirstDependency);
define('recordingEditor', [componentsPath + '/recordingcreator/recordingeditor'], returnFirstDependency);
@ -837,6 +817,7 @@ var AppInfo = {};
define('upNextDialog', [componentsPath + '/upnextdialog/upnextdialog'], returnFirstDependency);
define('subtitleAppearanceHelper', [componentsPath + '/subtitlesettings/subtitleappearancehelper'], returnFirstDependency);
define('subtitleSettings', [componentsPath + '/subtitlesettings/subtitlesettings'], returnFirstDependency);
define('settingsHelper', [componentsPath + '/settingshelper'], returnFirstDependency);
define('displaySettings', [componentsPath + '/displaySettings/displaySettings'], returnFirstDependency);
define('playbackSettings', [componentsPath + '/playbackSettings/playbackSettings'], returnFirstDependency);
define('homescreenSettings', [componentsPath + '/homeScreenSettings/homeScreenSettings'], returnFirstDependency);
@ -857,7 +838,6 @@ var AppInfo = {};
define('deleteHelper', [scriptsPath + '/deleteHelper'], returnFirstDependency);
define('tvguide', [componentsPath + '/guide/guide'], returnFirstDependency);
define('guide-settings-dialog', [componentsPath + '/guide/guide-settings'], returnFirstDependency);
define('loadingDialog', [componentsPath + '/loadingDialog/loadingDialog'], returnFirstDependency);
define('viewManager', [componentsPath + '/viewManager/viewManager'], function (viewManager) {
window.ViewManager = viewManager;
viewManager.dispatchPageEvents(true);

View File

@ -1,27 +1,29 @@
define(['userSettings', 'skinManager', 'connectionManager', 'events'], function (userSettings, skinManager, connectionManager, events) {
'use strict';
import * as userSettings from 'userSettings';
import skinManager from 'skinManager';
import connectionManager from 'connectionManager';
import events from 'events';
var currentViewType;
pageClassOn('viewbeforeshow', 'page', function () {
var classList = this.classList;
var viewType = classList.contains('type-interior') || classList.contains('wizardPage') ? 'a' : 'b';
var currentViewType;
pageClassOn('viewbeforeshow', 'page', function () {
var classList = this.classList;
var viewType = classList.contains('type-interior') || classList.contains('wizardPage') ? 'a' : 'b';
if (viewType !== currentViewType) {
currentViewType = viewType;
var theme;
var context;
if (viewType !== currentViewType) {
currentViewType = viewType;
var theme;
var context;
if ('a' === viewType) {
theme = userSettings.dashboardTheme();
context = 'serverdashboard';
} else {
theme = userSettings.theme();
}
skinManager.setTheme(theme, context);
if ('a' === viewType) {
theme = userSettings.dashboardTheme();
context = 'serverdashboard';
} else {
theme = userSettings.theme();
}
});
events.on(connectionManager, 'localusersignedin', function (e, user) {
currentViewType = null;
});
skinManager.setTheme(theme, context);
}
});
events.on(connectionManager, 'localusersignedin', function (e, user) {
currentViewType = null;
});

View File

@ -1018,7 +1018,6 @@
"HeaderSeriesStatus": "حالة المسلسل",
"HeaderSeriesOptions": "اعدادات المسلسل",
"HeaderSecondsValue": "{0} ثوانى",
"HeaderRestartingServer": "اعادة تشغيل الخادم",
"HeaderRecordingOptions": "اعدادات التسجيل",
"HeaderPlaybackError": "خطأ فى التشغيل",
"HeaderPlayOn": "شغل على",

View File

@ -812,7 +812,7 @@
"MessageNoAvailablePlugins": "Nejsou dostupné žádné zásuvné moduly.",
"MessageNoMovieSuggestionsAvailable": "Žádné návrhy nejsou v současnosti k dispozici. Začněte sledovat a hodnotit filmy, a pak se vám doporučení zobrazí.",
"MessageNoPluginsInstalled": "Nemáte instalovány žádné zásuvné moduly.",
"MessageNoTrailersFound": "Nebyly nalezeny žádné upoutávky k filmu. Chcete-li si zlepšit zážitek ze sledování, nainstalujte si kanál s upoutávkami.",
"MessageNoTrailersFound": "Chcete-li si zlepšit zážitek ze sledování, nainstalujte si kanál s upoutávkami.",
"MessageNothingHere": "Tady nic není.",
"MessagePasswordResetForUsers": "Obnovení hesla bylo provedeno následujícími uživateli. Nyní se mohou přihlásit pomocí kódů PIN, které byly použity k provedení resetu.",
"MessagePlayAccessRestricted": "Přehrávání tohoto obsahu je aktuálně omezeno. Další informace získáte od správce serveru.",
@ -1059,7 +1059,6 @@
"RepeatOne": "Opakovat jeden",
"ReplaceAllMetadata": "Přepsat všechna metadata",
"ReplaceExistingImages": "Nahradit existující obrázky",
"RestartPleaseWaitMessage": "Počkejte prosím, než se server Jellyfin vypne a restartuje. Může to trvat několik minut.",
"ResumeAt": "Obnovit přehrávání od {0}",
"Rewind": "Přetočit zpět",
"RunAtStartup": "Spustit po startu",
@ -1395,7 +1394,6 @@
"HeaderFavoriteAlbums": "Oblíbená alba",
"HeaderFavoriteArtists": "Oblíbení interpreti",
"HeaderFavoriteSongs": "Oblíbená hudba",
"HeaderRestartingServer": "Restartování serveru",
"LabelAuthProvider": "Poskytovatel ověření:",
"LabelServerNameHelp": "Tento název bude použit k identifikaci serveru a bude výchozí pro název počítače serveru.",
"LabelPasswordResetProvider": "Poskytovatel obnovy hesla:",
@ -1635,5 +1633,20 @@
"ShowMore": "Zobrazit více",
"ShowLess": "Zobrazit méně",
"EnableBlurhashHelp": "Nenačtené obrázky budou zobrazeny pomocí neurčitých zástupných obrázků",
"EnableBlurhash": "Povolit zástupné obrázky"
"EnableBlurhash": "Povolit zástupné obrázky",
"ButtonCast": "Přehrát v zařízení",
"ButtonSyncPlay": "Synchronizace přehrávání",
"MessageNoGenresAvailable": "Povolit některým poskytovatelům metadat stahovat informace o žánrech z Internetu.",
"EnableFasterAnimationsHelp": "Použít rychlejší animace a přechody",
"EnableFasterAnimations": "Rychlejší animace",
"EnableDecodingColorDepth10Vp9": "Povolit 10bitové hardwarové dekódování formátu VP9",
"EnableDecodingColorDepth10Hevc": "Povolit 10bitové hardwarové dekódování formátu HEVC",
"TabRepositories": "Repozitáře",
"MessageAddRepository": "Pokud chcete přidat repozitář, klikněte na tlačítko vedle záhlaví a vyplňte požadované informace.",
"LabelRepositoryNameHelp": "Vlastní pojmenování, které slouží k odlišení tohoto repozitáře od ostatních repozitářů přidaných na vašem serveru.",
"LabelRepositoryName": "Název repozitáře",
"LabelRepositoryUrlHelp": "Umístění manifestu repozitáře, který chcete zahrnout.",
"LabelRepositoryUrl": "URL adresa repozitáře",
"HeaderNewRepository": "Nový repozitář",
"MessageNoRepositories": "Neexistují žádné repozitáře."
}

View File

@ -1414,7 +1414,6 @@
"RepeatAll": "Gentag alle",
"RepeatMode": "Gentagelses tilstand",
"RepeatOne": "Gentag én",
"RestartPleaseWaitMessage": "Vent venligst mens Jellyfin Server lukker og genstarter. Dette kan tage et minut eller to.",
"RunAtStartup": "Kør ved opstart",
"ScanForNewAndUpdatedFiles": "Skan for nye og opdaterede filer",
"Schedule": "Tidsplan",
@ -1500,7 +1499,6 @@
"HeaderHome": "Hjem",
"LabelServerName": "Server navn:",
"LabelUserLoginAttemptsBeforeLockout": "Fejlede loginforsøg før bruger lukkes ude:",
"HeaderRestartingServer": "Genstarter Server",
"ButtonAddImage": "Tilføj billede",
"AllowFfmpegThrottlingHelp": "Når en omkodning eller remux kommer langt nok foran den nuværende afspildings position, pauses processen så der bruges færre resurser. Dette er mest brugbart når man ikke springer i filmen. Slå dette fra hvis du har problemer med playback.",
"AllowFfmpegThrottling": "Begræns Omkodning",

View File

@ -862,7 +862,7 @@
"MessageNoAvailablePlugins": "Keine verfügbaren Erweiterungen.",
"MessageNoMovieSuggestionsAvailable": "Momentan sind keine Filmvorschläge verfügbar. Schaue und bewerte zuerst deine Filme. Komme danach zurück, um deine Filmvorschläge anzuschauen.",
"MessageNoPluginsInstalled": "Du hast keine Plugins installiert.",
"MessageNoTrailersFound": "Keine Trailer gefunden. Installieren Sie den Trailer-Channel um Ihre Film-Bibliothek mit Trailer aus dem Internet zu erweitern.",
"MessageNoTrailersFound": "Installiere den Filmvorschau-Kanal um die Film-Bibliothek mit Filmvorschauen aus dem Internet zu erweitern.",
"MessageNothingHere": "Nichts hier.",
"MessagePasswordResetForUsers": "Die Passwörter der folgenden Benutzer wurden zurückgesetzt. Diese können sich nun mit den PIN-Codes anmelden, mit denen der Reset durchgeführt wurde.",
"MessagePlayAccessRestricted": "Das Abspielen dieses Inhaltes ist derzeit eingeschränkt. Bitte kontaktiere deinen Server-Administrator für weitere Informationen.",
@ -1105,7 +1105,6 @@
"ReplaceAllMetadata": "Ersetze alle Metadaten",
"ReplaceExistingImages": "Ersetze vorhandene Bilder",
"RequiredForAllRemoteConnections": "Benötigt für alle Remote Verbindungen",
"RestartPleaseWaitMessage": "Warte bitte bis der Jellyfin Server heruntergefahren und neu gestartet wurde. Dieser Vorgang dauert 1 bis 2 Minuten.",
"ResumeAt": "Fortsetzen bei {0}",
"Rewind": "Zurückspulen",
"RunAtStartup": "Nach Hochfahren automatisch starten",
@ -1407,7 +1406,6 @@
"HeaderFavoriteArtists": "Lieblings-Interpreten",
"HeaderFavoriteSongs": "Lieblingslieder",
"HeaderFavoriteVideos": "Lieblingsvideos",
"HeaderRestartingServer": "Server startet neu",
"LabelAuthProvider": "Authentifizierungsanbieter:",
"LabelServerName": "Servername:",
"LabelTranscodePath": "Transkodierungspfad:",
@ -1573,5 +1571,20 @@
"ShowMore": "Mehr anzeigen",
"ShowLess": "Weniger anzeigen",
"EnableBlurhashHelp": "Bilder, die noch nicht fertig geladen wurden, werden mit einem verschwommenen Platzhalter dargestellt",
"EnableBlurhash": "Verschwommene Platzhalter für Bilder erlauben"
"EnableBlurhash": "Verschwommene Platzhalter für Bilder erlauben",
"EnableFasterAnimations": "Schnellere Animationen",
"EnableDecodingColorDepth10Vp9": "Aktiviere 10-Bit-Hardware-Dekodierung für VP9",
"EnableDecodingColorDepth10Hevc": "Aktiviere 10-Bit-Hardware-Dekodierung für HEVC",
"MessageNoGenresAvailable": "Aktiviere einige Metadaten-Anbieter um Genres aus dem Internet zu holen.",
"EnableFasterAnimationsHelp": "Benutze schnellere Animationen und Übergänge",
"ButtonCast": "Besetzung",
"ButtonSyncPlay": "SyncPlay",
"TabRepositories": "Repositories",
"MessageAddRepository": "Wenn Sie ein Repository hinzufügen möchten, klicken Sie auf die Schaltfläche neben der Kopfzeile und füllen Sie die angeforderten Informationen aus.",
"LabelRepositoryUrlHelp": "Der Speicherort des Repository-Manifests, das Sie aufnehmen möchten.",
"LabelRepositoryNameHelp": "Ein benutzerdefinierter Name zur Unterscheidung dieses Repositorys von den anderen, die zu Ihrem Server hinzugefügt wurden.",
"LabelRepositoryName": "Name des Repository",
"LabelRepositoryUrl": "URL des Repository",
"HeaderNewRepository": "Neues Repository",
"MessageNoRepositories": "Keine Repositories."
}

View File

@ -985,7 +985,6 @@
"RepeatOne": "Επαναλάβετε ένα",
"ReplaceAllMetadata": "Αντικατάσταση όλων των μεταδεδομένων",
"ReplaceExistingImages": "Αντικατάσταση υπαρχουσών εικόνων",
"RestartPleaseWaitMessage": "Περιμένετε μέχρι ο τερματικός σταθμός Jellyfin να τερματιστεί και να επανεκκινήσει. Αυτό μπορεί να διαρκέσει ένα λεπτό ή δύο.",
"ResumeAt": "Συνέχιση από {0}",
"Rewind": "Αναπαραγωγή προς τα πίσω",
"RunAtStartup": "Εκτέλεση κατά την εκκίνηση",
@ -1165,7 +1164,6 @@
"HeaderSelectMetadataPathHelp": "Περιηγηθείτε ή επιλέξτε την διαδρομή αποθήκευσης των μεταδεδομένων. Ο φάκελος πρέπει να είναι εγγράψιμος.",
"HeaderSelectMetadataPath": "Επιλέξτε Διαδρομή Μεταδεδομένων",
"HeaderSelectCertificatePath": "Επιλέξτε Διαδρομή Πιστοποιητικού",
"HeaderRestartingServer": "Επανεκκίνηση Διακομιστή",
"HeaderRemoveMediaFolder": "Αφαίρεση Φακέλου Μέσων",
"HeaderPeople": "Πρόσωπα",
"HeaderIdentification": "Ταυτοποίηση",

View File

@ -63,7 +63,7 @@
"Alerts": "Alerts",
"All": "All",
"AllChannels": "All channels",
"AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)",
"AllComplexFormats": "All Complex Formats (ASS, SSA, VOBSUB, PGS, SUB, IDX, …)",
"AllEpisodes": "All episodes",
"AllLanguages": "All languages",
"AllLibraries": "All libraries",
@ -71,7 +71,7 @@
"AllowMediaConversion": "Allow media conversion",
"AllowMediaConversionHelp": "Grant or deny access to the convert media feature.",
"AllowOnTheFlySubtitleExtraction": "Allow subtitle extraction on the fly",
"AllowOnTheFlySubtitleExtractionHelp": "Embedded subtitles can be extracted from videos and delivered to clients in plain text in order to help prevent video transcoding. On some systems this can take a long time and cause video playback to stall during the extraction process. Disable this to have embedded subtitles burned in with video transcoding when they are not natively supported by the client device.",
"AllowOnTheFlySubtitleExtractionHelp": "Embedded subtitles can be extracted from videos and delivered to clients in plain text, in order to help prevent video transcoding. On some systems this can take a long time and cause video playback to stall during the extraction process. Disable this to have embedded subtitles burned in with video transcoding when they are not natively supported by the client device.",
"AllowRemoteAccess": "Allow remote connections to this Jellyfin Server.",
"AllowRemoteAccessHelp": "If unchecked, all remote connections will be blocked.",
"AllowedRemoteAddressesHelp": "Comma separated list of IP addresses or IP/netmask entries for networks that will be allowed to connect remotely. If left blank, all remote addresses will be allowed.",
@ -79,7 +79,7 @@
"AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.",
"AnyLanguage": "Any Language",
"Anytime": "Anytime",
"AroundTime": "Around {0}",
"AroundTime": "Around",
"Art": "Art",
"AsManyAsPossible": "As many as possible",
"Ascending": "Ascending",
@ -100,7 +100,7 @@
"Box": "Box",
"BoxRear": "Box (rear)",
"Browse": "Browse",
"BurnSubtitlesHelp": "Determines if the server should burn in subtitles when transcoding videos. Avoiding this will greatly improve performance. Select Auto to burn image based formats (VOBSUB, PGS, SUB, IDX) and certain ASS or SSA subtitles.",
"BurnSubtitlesHelp": "Determines if the server should burn in subtitles when transcoding videos. Avoiding this will greatly improve performance. Select Auto to burn image based formats (VOBSUB, PGS, SUB, IDX, …) and certain ASS or SSA subtitles.",
"ButtonAdd": "Add",
"ButtonAddMediaLibrary": "Add Media Library",
"ButtonAddScheduledTaskTrigger": "Add Trigger",
@ -561,7 +561,6 @@
"RunAtStartup": "Run at startup",
"Rewind": "Rewind",
"ResumeAt": "Resume from {0}",
"RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.",
"RequiredForAllRemoteConnections": "Required for all remote connections",
"ReplaceExistingImages": "Replace existing images",
"ReplaceAllMetadata": "Replace all metadata",
@ -720,7 +719,7 @@
"MessagePlayAccessRestricted": "Playback of this content is currently restricted. Please contact your server administrator for more information.",
"MessagePasswordResetForUsers": "The following users have had their passwords reset. They can now sign in with the pin codes that were used to perform the reset.",
"MessageNothingHere": "Nothing here.",
"MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
"MessageNoTrailersFound": "Install the trailers channel to enhance your movie experience by adding a library of internet trailers.",
"MessageNoServersAvailable": "No servers have been found using the automatic server discovery.",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
"MessageNoAvailablePlugins": "No available plugins.",
@ -1246,7 +1245,7 @@
"LabelPasswordResetProvider": "Password Reset Provider:",
"LabelPasswordConfirm": "Password (confirm):",
"LabelOriginalTitle": "Original title:",
"LabelOptionalNetworkPathHelp": "If this folder is shared on your network, supplying the network share path can allow Jellyfin apps on other devices to access media files directly.",
"LabelOptionalNetworkPathHelp": "If this folder is shared on your network, supplying the network share path can allow Jellyfin apps on other devices to access media files directly. For example, {0} or {1}.",
"LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
"LabelNumberOfGuideDays": "Number of days of guide data to download:",
"LabelNumber": "Number:",
@ -1435,7 +1434,6 @@
"HeaderScenes": "Scenes",
"HeaderRunningTasks": "Running Tasks",
"HeaderRevisionHistory": "Revision History",
"HeaderRestartingServer": "Restarting Server",
"HeaderRestart": "Restart",
"HeaderResponseProfile": "Response Profile",
"HeaderRemoveMediaLocation": "Remove Media Location",
@ -1515,5 +1513,66 @@
"ButtonTogglePlaylist": "Playlist",
"ButtonToggleContextMenu": "More",
"HeaderDVR": "DVR",
"ApiKeysCaption": "List of the currently enabled API keys"
"ApiKeysCaption": "List of the currently enabled API keys",
"ButtonCast": "Cast",
"ButtonSyncPlay": "SyncPlay",
"EnableBlurhashHelp": "Images that are still being loaded will be displayed with a blurred placeholder",
"EnableBlurhash": "Enable blurred placeholders for images",
"TabDVR": "DVR",
"TabRepositories": "Repositories",
"SyncPlayAccessHelp": "Select the level of access this user has to the SyncPlay feature. SyncPlay enables to sync playback with other devices.",
"ShowMore": "Show more",
"ShowLess": "Show less",
"SaveChanges": "Save changes",
"MessageSyncPlayErrorMedia": "Failed to enable SyncPlay! Media error.",
"MessageSyncPlayErrorMissingSession": "Failed to enable SyncPlay! Missing session.",
"MessageSyncPlayErrorNoActivePlayer": "No active player found. SyncPlay has been disabled.",
"MessageSyncPlayErrorAccessingGroups": "An error occurred while accessing groups list.",
"MessageSyncPlayLibraryAccessDenied": "Access to this content is restricted.",
"MessageSyncPlayJoinGroupDenied": "Permission required to use SyncPlay.",
"MessageSyncPlayCreateGroupDenied": "Permission required to create a group.",
"MessageSyncPlayGroupDoesNotExist": "Failed to join group because it does not exist.",
"MessageSyncPlayPlaybackPermissionRequired": "Playback permission required.",
"MessageSyncPlayNoGroupsAvailable": "No groups available. Start playing something first.",
"MessageSyncPlayGroupWait": "<b>{0}</b> is buffering...",
"MessageSyncPlayUserLeft": "<b>{0}</b> has left the group.",
"MessageSyncPlayUserJoined": "<b>{0}</b> has joined the group.",
"MessageSyncPlayDisabled": "SyncPlay disabled.",
"MessageSyncPlayEnabled": "SyncPlay enabled.",
"MessageNoGenresAvailable": "Enable some metadata providers to pull genres from the internet.",
"MessageAddRepository": "If you wish to add a repository, click the button next to the header and fill out the requested information.",
"LabelRepositoryNameHelp": "A custom name to distinguish this repository from any others added to your server.",
"LabelRepositoryName": "Repository Name",
"LabelRepositoryUrlHelp": "The location of the repository manifest you want to include.",
"LabelRepositoryUrl": "Repository URL",
"HeaderNewRepository": "New Repository",
"MessageNoRepositories": "No repositories.",
"LabelSyncPlayAccess": "SyncPlay access",
"LabelSyncPlayAccessNone": "Disabled for this user",
"LabelSyncPlayAccessJoinGroups": "Allow user to join groups",
"LabelSyncPlayAccessCreateAndJoinGroups": "Allow user to create and join groups",
"LabelSyncPlayLeaveGroupDescription": "Disable SyncPlay",
"LabelSyncPlayLeaveGroup": "Leave group",
"LabelSyncPlayNewGroupDescription": "Create a new group",
"LabelSyncPlayNewGroup": "New group",
"LabelSyncPlaySyncMethod": "Sync method:",
"LabelSyncPlayPlaybackDiff": "Playback time difference:",
"MillisecondsUnit": "ms",
"LabelSyncPlayTimeOffset": "Time offset with the server:",
"LabelRequireHttpsHelp": "If checked, the server will automatically redirect all requests over HTTP to HTTPS. This has no effect if the server is not listening on HTTPS.",
"LabelRequireHttps": "Require HTTPS",
"LabelNightly": "Nightly",
"LabelStable": "Stable",
"LabelChromecastVersion": "Chromecast Version",
"LabelEnableHttpsHelp": "Enables the server to listen on the configured HTTPS port. A valid certificate must also be configured in order for this to take effect.",
"LabelEnableHttps": "Enable HTTPS",
"HeaderSyncPlayEnabled": "SyncPlay enabled",
"HeaderSyncPlaySelectGroup": "Join a group",
"HeaderServerAddressSettings": "Server Address Settings",
"HeaderRemoteAccessSettings": "Remote Access Settings",
"HeaderHttpsSettings": "HTTPS Settings",
"EnableDetailsBannerHelp": "Display a banner image at the top of the item details page.",
"EnableDetailsBanner": "Details Banner",
"EnableDecodingColorDepth10Vp9": "Enable 10-Bit hardware decoding for VP9",
"EnableDecodingColorDepth10Hevc": "Enable 10-Bit hardware decoding for HEVC"
}

View File

@ -226,7 +226,7 @@
"EnableCinemaMode": "Cinema mode",
"EnableColorCodedBackgrounds": "Color coded backgrounds",
"EnableDecodingColorDepth10Hevc": "Enable 10-Bit hardware decoding for HEVC",
"EnableDecodingColorDepth10Vp9": "Enable 10-Bit hardware decoding for Vp9",
"EnableDecodingColorDepth10Vp9": "Enable 10-Bit hardware decoding for VP9",
"EnableDisplayMirroring": "Display mirroring",
"EnableExternalVideoPlayers": "External video players",
"EnableExternalVideoPlayersHelp": "An external player menu will be shown when starting video playback.",
@ -462,7 +462,6 @@
"HeaderResponseProfile": "Response Profile",
"HeaderResponseProfileHelp": "Response profiles provide a way to customize information sent to the device when playing certain kinds of media.",
"HeaderRestart": "Restart",
"HeaderRestartingServer": "Restarting Server",
"HeaderRevisionHistory": "Revision History",
"HeaderRunningTasks": "Running Tasks",
"HeaderScenes": "Scenes",
@ -1025,6 +1024,13 @@
"MessageItemsAdded": "Items added.",
"MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item or the global default value.",
"MessageNoAvailablePlugins": "No available plugins.",
"MessageNoRepositories": "No repositories.",
"HeaderNewRepository": "New Repository",
"LabelRepositoryUrl": "Repository URL",
"LabelRepositoryUrlHelp": "The location of the repository manifest you want to include.",
"LabelRepositoryName": "Repository Name",
"LabelRepositoryNameHelp": "A custom name to distinguish this repository from any others added to your server.",
"MessageAddRepository": "If you wish to add a repository, click the button next to the header and fill out the requested information.",
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, and Albums. Click the + button to start creating collections.",
"MessageNoGenresAvailable": "Enable some metadata providers to pull genres from the internet.",
"MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
@ -1337,7 +1343,6 @@
"RepeatOne": "Repeat one",
"ReplaceAllMetadata": "Replace all metadata",
"ReplaceExistingImages": "Replace existing images",
"RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.",
"ResumeAt": "Resume from {0}",
"Rewind": "Rewind",
"RunAtStartup": "Run at startup",
@ -1417,6 +1422,7 @@
"TabAlbums": "Albums",
"TabArtists": "Artists",
"TabCatalog": "Catalog",
"TabRepositories": "Repositories",
"TabChannels": "Channels",
"TabCodecs": "Codecs",
"TabCollections": "Collections",

File diff suppressed because it is too large Load Diff

View File

@ -1159,7 +1159,6 @@
"ReplaceAllMetadata": "Reemplazar todos los metadatos",
"ReplaceExistingImages": "Reemplazar imágenes existentes",
"RequiredForAllRemoteConnections": "Requerido para todas las conexiones remotas",
"RestartPleaseWaitMessage": "Por favor, espera mientras el servidor Jellyfin se apaga y reinicia. Esto puede tomar un minuto o dos.",
"ResumeAt": "Reanudar desde {0}",
"Rewind": "Rebobinar",
"RunAtStartup": "Ejecutar al iniciar",
@ -1361,7 +1360,6 @@
"HeaderFavoriteSongs": "Canciones favoritas",
"HeaderFavoriteVideos": "Videos favoritos",
"HeaderHome": "Inicio",
"HeaderRestartingServer": "Reiniciando servidor",
"HeaderVideos": "Videos",
"Horizontal": "Horizontal",
"LabelAudio": "Audio",

View File

@ -1,9 +1,9 @@
{
"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",
"AddToPlaylist": "Añadir a la lista de reproducción",
"AddItemToCollectionHelp": "Puedes añadir elementos a las colecciones buscándolos en tu biblioteca. Una vez hecho esto, abre el menú y selecciona 'Añadir a una colección'.",
"AddToCollection": "Añadir a una colección",
"AddToPlaylist": "Añadir a una lista de reproducción",
"AddedOnValue": "Añadido {0}",
"AdditionalNotificationServices": "Visite el catálogo de extensiones para instalar servicios de notificación adicionales.",
"Albums": "Álbumes",
@ -14,11 +14,11 @@
"AllEpisodes": "Todos los episodios",
"AllLanguages": "Todos los idiomas",
"AllLibraries": "Todas las bibliotecas",
"AllowHWTranscodingHelp": "Permite al sintonizador transcodificar secuencias en vivo. Esto puede ayudar a reducir la transcodificación requerida por el servidor.",
"AllowHWTranscodingHelp": "Permite al sintonizador convertir el contenido directamente. Esto puede ayudar a reducir la potencia requerida por el servidor.",
"AllowMediaConversion": "Permitir convertir los medios",
"AllowMediaConversionHelp": "Concede o deniega el acceso a la función de conversión de medios.",
"AllowOnTheFlySubtitleExtraction": "Permitir la extracción de subtítulos sobre la marcha",
"AllowOnTheFlySubtitleExtractionHelp": "Los subtítulos incrustados pueden extraerse de los vídeos y enviarse en texto sin formato para ayudar a evitar la transcodificación del vídeo. En algunos sistemas, esto puede llevar mucho tiempo y hacer que la reproducción de vídeo se bloquee durante el proceso de extracción. Deshabilite esta opción para tener subtítulos incrustados grabados con transcodificación de video cuando no sean compatibles de forma nativa con el cliente.",
"AllowOnTheFlySubtitleExtractionHelp": "Cuando el cliente sea compatible, los subtítulos pueden extraerse durante la reproducción para evitar convertir el vídeo. Sin embargo, y en algunos servidores, esto puede llevar mucho tiempo y hacer que la reproducción tenga cortes durante el proceso. Deshabilita esta opción para grabar los subtítulos directamente en el vídeo cuando no sean compatibles de forma nativa con el cliente.",
"AllowRemoteAccess": "Permitir conexiones remotas a este servidor Jellyfin.",
"AllowRemoteAccessHelp": "Si no está activado, todas las conexiones remotas serán bloqueadas.",
"AllowedRemoteAddressesHelp": "Lista separada por comas de direcciones IP o entradas de IP / máscara de red para redes a las que se les permitirá conectarse de forma remota. Si se deja en blanco, se permitirán todas las direcciones remotas.",
@ -376,7 +376,7 @@
"HeaderSelectServerCachePath": "Seleccione la ruta para el caché del servidor",
"HeaderSelectServerCachePathHelp": "Navega o introduce la ruta para alojar los archivos caché del servidor. Tienes que tener permisos de escritura en esa carpeta.",
"HeaderSelectTranscodingPath": "Seleccione la ruta temporal del transcodificador",
"HeaderSelectTranscodingPathHelp": "Busque o escriba la ruta de acceso que se utilizará para la transcodificación de archivos temporales. La carpeta debe tener permiso de escritura.",
"HeaderSelectTranscodingPathHelp": "Busca o escribe la ruta que se utilizará para guardar los archivos temporales que se generarán mientras se convierten los archivos. Jellyfin debe tener permisos de escritura en la carpeta.",
"HeaderSendMessage": "Enviar mensaje",
"HeaderSeries": "Series",
"HeaderSeriesOptions": "Opciones de series",
@ -399,8 +399,8 @@
"HeaderTags": "Etiquetas",
"HeaderTaskTriggers": "Tareas de activación",
"HeaderThisUserIsCurrentlyDisabled": "Este usuario está desactivado",
"HeaderTranscodingProfile": "Perfil de transcodificación",
"HeaderTranscodingProfileHelp": "Añadir perfiles de transcodificación para indicar qué formatos se deben utilizar cuando se requiera transcodificación.",
"HeaderTranscodingProfile": "Parámetros de conversión",
"HeaderTranscodingProfileHelp": "Añade los diferentes parámetros de conversión para este dispositivo, de manera que el servidor convierta automáticamente el contenido en un formato compatible para él.",
"HeaderTunerDevices": "Sintonizadores",
"HeaderTuners": "Sintonizadores",
"HeaderTypeImageFetchers": "{0} capturadores de imágenes",
@ -449,7 +449,7 @@
"LabelAlbumArtPN": "Carátula del album PN:",
"LabelAlbumArtists": "Artistas de los álbumes:",
"LabelAll": "Todo",
"LabelAllowHWTranscoding": "Permitir transcodificación por hardware",
"LabelAllowHWTranscoding": "Activar la conversión acelerada por hardware",
"LabelAllowServerAutoRestart": "Permitir al servidor reiniciarse automáticamente para aplicar las actualizaciones",
"LabelAllowServerAutoRestartHelp": "El servidor solo se reiniciará durante periodos de reposo, cuando no haya usuarios activos.",
"LabelAllowedRemoteAddresses": "Filtro de dirección IP remota:",
@ -620,7 +620,7 @@
"LabelMoviePrefix": "Prefijo de película:",
"LabelMoviePrefixHelp": "Si se aplica un prefijo a títulos de películas, escríbalo para que el servidor pueda manejarlo correctamente.",
"LabelMovieRecordingPath": "Ruta de grabaciones de películas (opcional):",
"LabelMusicStreamingTranscodingBitrate": "Tasa de bits de transcodificación de música:",
"LabelMusicStreamingTranscodingBitrate": "Tasa de bits para la reproducción de música:",
"LabelMusicStreamingTranscodingBitrateHelp": "Especifique una tasa de bits máxima cuando transmita música.",
"LabelName": "Nombre:",
"LabelNewName": "Nuevo nombre:",
@ -667,7 +667,7 @@
"LabelPublicHttpsPort": "Puerto público HTTPS:",
"LabelPublicHttpsPortHelp": "Puerto público que debe ser enlazado al puerto local HTTPS.",
"LabelReadHowYouCanContribute": "Aprenda cómo contribuir.",
"LabelReasonForTranscoding": "Motivo de la transcodificación:",
"LabelReasonForTranscoding": "Motivo por el que se realiza la conversión:",
"LabelRecord": "Grabar:",
"LabelRecordingPath": "Ruta de grabaciones por defecto:",
"LabelRecordingPathHelp": "Especifica la ubicación por defecto para guardar las grabaciones. Si lo dejas vacío se usará la carpeta de datos del servidor.",
@ -694,7 +694,7 @@
"LabelSkipIfAudioTrackPresent": "Omitir si la pista de audio por defecto coincide con el idioma de descarga",
"LabelSkipIfAudioTrackPresentHelp": "Desactive esta opción para asegurar que todos los vídeos tienen subtítulos, sin importar el idioma de audio.",
"LabelSkipIfGraphicalSubsPresent": "Saltar si el vídeo tiene subtítulos integrados",
"LabelSkipIfGraphicalSubsPresentHelp": "Mantener versiones de texto de subtítulos dará lugar a una entrega más eficiente y a disminuir la probabilidad de transcodificación de vídeo.",
"LabelSkipIfGraphicalSubsPresentHelp": "Mantener versiones de los subtítulos en texto plano puede hacer que la reproducción sea más eficiente en un número mayor de dispositivos, evitando la conversión del vídeo.",
"LabelSonyAggregationFlags": "Agregación de banderas Sony:",
"LabelSonyAggregationFlagsHelp": "Determina el contenido del elemento aggregationFlags en el espacio de nombre urn:schemas-sonycom:av.",
"LabelSortTitle": "Clasificar por título:",
@ -721,9 +721,9 @@
"LabelTrackNumber": "Número de pista:",
"LabelTranscodingAudioCodec": "Códec de audio:",
"LabelTranscodingContainer": "Contenedor:",
"LabelTranscodingTempPathHelp": "Establece la ruta personaliza para la transcodificación de archivos servidos a los clientes. Dejar en blanco para usar la ruta por defecto del servidor.",
"LabelTranscodingThreadCount": "Cantidad de instancias de transcodificación:",
"LabelTranscodingThreadCountHelp": "Selecciona el número máximo de instancias de transcodificación. Reducirlas disminuirá el uso del procesador pero puede no convertirá lo suficientemente rápido para una reproducción fluida.",
"LabelTranscodingTempPathHelp": "Establece la carpeta que se usará para almacenar los archivos temporales de las conversiones. Déjalo en blanco para usar la ruta por defecto.",
"LabelTranscodingThreadCount": "Núcleos a utilizar durante la conversión:",
"LabelTranscodingThreadCountHelp": "Selecciona el número de núcleos a utilizar para la conversión. A menos núcleos, menor será el uso del procesador, pero puede que la conversión no vaya lo suficientemente rápido para una reproducción fluida.",
"LabelTranscodingVideoCodec": "Códec de video:",
"LabelTriggerType": "Tipo de evento:",
"LabelTunerIpAddress": "IP del sintonizador:",
@ -821,7 +821,7 @@
"MessageNoAvailablePlugins": "No hay extensiones disponibles.",
"MessageNoMovieSuggestionsAvailable": "No hay sugerencias de películas disponibles. Comience ver y calificar sus películas y vuelva para ver las recomendaciones.",
"MessageNoPluginsInstalled": "No hay extensiones instaladas.",
"MessageNoTrailersFound": "No se han encontrado tráilers. Instala el canal de tráilers para mejorar su experiencia añadiendo una biblioteca de tráilers por internet.",
"MessageNoTrailersFound": "Instale el canal de tráilers para mejorar su experiencia cinematográfica agregando una biblioteca de tráilers de Internet.",
"MessageNothingHere": "Nada aquí.",
"MessagePasswordResetForUsers": "Se ha restablecido las contraseñas a los siguientes usuarios. Ahora pueden iniciar sesión con los códigos PIN que usaron para el restablecimiento.",
"MessagePleaseEnsureInternetMetadata": "Asegúrate de que la descarga de etiquetas desde internet está activada.",
@ -874,21 +874,21 @@
"OptionAlbum": "Álbum",
"OptionAlbumArtist": "Artista de álbum",
"OptionAllUsers": "Todos los usuarios",
"OptionAllowAudioPlaybackTranscoding": "Permitir reproducción de audio que requiere transcodificación",
"OptionAllowAudioPlaybackTranscoding": "Activar la conversión del audio",
"OptionAllowBrowsingLiveTv": "Permitir acceso a la televisión en directo",
"OptionAllowContentDownloading": "Permitir la descarga de medios",
"OptionAllowLinkSharing": "Permitir compartir los medios en redes sociales",
"OptionAllowLinkSharingHelp": "Sólo se comparten las páginas web con información de medios. Los archivos nunca se comparten públicamente. Lo compartido expirará después de {0} días.",
"OptionAllowManageLiveTv": "Habilitar la administración de grabación de la televisión en directo",
"OptionAllowMediaPlayback": "Permitir la reproducción de medios",
"OptionAllowMediaPlaybackTranscodingHelp": "Restringir el acceso a la transcodificación puede causar fallos de reproducción en aplicaciones Jellyfin debido a formatos de medios no compatibles.",
"OptionAllowMediaPlaybackTranscodingHelp": "Con la conversión, el servidor se asegura que cualquier cliente es capaz de reproducir el contenido, sin importar su formato. Al desactivar la conversión de alguno de estos elementos, es posible que los vídeos no tengan audio o que, directamente, no se pueda reproducir el archivo por no ser compatible con el dispositivo. Para evitar problemas con la reproducción es mejor dejarlas todas por defecto.",
"OptionAllowRemoteControlOthers": "Habilitar el control remoto de otros usuarios",
"OptionAllowRemoteSharedDevices": "Habilitar el control remoto de otros equipos compartidos",
"OptionAllowRemoteSharedDevicesHelp": "Los equipos DLNA son considerados compartidos hasta que un usuario empiece a controlarlos.",
"OptionAllowSyncTranscoding": "Permitir la descarga que requiera transcodificación",
"OptionAllowSyncTranscoding": "Permitir la conversión del contenido cuando se descargue o se sincronice",
"OptionAllowUserToManageServer": "Permite a este usuario administrar el servidor",
"OptionAllowVideoPlaybackRemuxing": "Permitir la reproducción de vídeo que requiere conversión sin necesidad de volver a codificar",
"OptionAllowVideoPlaybackTranscoding": "Permitir reproducción de vídeo que requiere transcodificación",
"OptionAllowVideoPlaybackRemuxing": "Activar el cambio de contenedor para el contenido cuyo audio y vídeo es compatible, pero no lo es su contenedor",
"OptionAllowVideoPlaybackTranscoding": "Activar la conversión del vídeo",
"OptionArtist": "Artista",
"OptionAscending": "Ascendente",
"OptionAutomaticallyGroupSeries": "Combinar automáticamente series que se distribuyen en varias carpetas",
@ -949,7 +949,7 @@
"OptionHideUserFromLoginHelp": "Útil para privado o cuentas de administradores escondidos. El usuario tendrá que acceder entrando su nombre de usuario y contraseña manualmente.",
"OptionHlsSegmentedSubtitles": "Subtítulos segmentados HLS",
"OptionHomeVideos": "Fotos",
"OptionIgnoreTranscodeByteRangeRequests": "Ignorar las solicitudes de intervalo de bytes de transcodificación",
"OptionIgnoreTranscodeByteRangeRequests": "En las conversiones, ignorar las solicitudes de un intervalo específico de bytes",
"OptionIgnoreTranscodeByteRangeRequestsHelp": "Si está activado, estas solicitudes serán atendidas pero ignorarán el encabezado de intervalo de bytes.",
"OptionImdbRating": "Valoración IMDb",
"OptionLikes": "Me gusta",
@ -1160,7 +1160,7 @@
"TabSongs": "Canciones",
"TabStreaming": "Transmisión",
"TabSuggestions": "Sugerencias",
"TabTranscoding": "Transcodificación",
"TabTranscoding": "Conversión",
"TabUpcoming": "Próximos",
"TabUsers": "Usuarios",
"Tags": "Etiquetas",
@ -1173,7 +1173,7 @@
"TitleHostingSettings": "Configuración del alojamiento",
"TitlePlayback": "Reproducción",
"TrackCount": "{0} pistas",
"Transcoding": "Transcodificación",
"Transcoding": "Conversión",
"Tuesday": "Martes",
"TvLibraryHelp": "Revisar la {0}guía de nombres de los programas de TV{1}.",
"UninstallPluginConfirmation": "¿Esta seguro que desea desinstalar {0}?",
@ -1351,11 +1351,10 @@
"HeaderFavoriteSongs": "Canciones favoritas",
"HeaderFavoriteVideos": "Vídeos favoritos",
"HeaderHome": "Inicio",
"HeaderRestartingServer": "Reiniciando servidor",
"LabelAuthProvider": "Proveedor de autenticación:",
"LabelPasswordResetProvider": "Proveedor de restablecimiento de contraseña:",
"LabelServerName": "Nombre del servidor:",
"LabelTranscodePath": "Ruta de transcodificación:",
"LabelTranscodePath": "Ruta para los archivos temporales de las conversiones:",
"LabelTranscodes": "Transcodificaciones:",
"LabelUserLoginAttemptsBeforeLockout": "Intentos fallidos de inicio de sesión antes de que el usuario sea bloqueado:",
"DashboardVersionNumber": "Versión: {0}",
@ -1397,7 +1396,6 @@
"Premiere": "Estreno",
"Raised": "Elevación",
"RefreshDialogHelp": "Las etiquetas se actualizan basándose en las configuraciones y los servicios de internet activados desde el panel de control de Jellyfin.",
"RestartPleaseWaitMessage": "Por favor, espera mientras el servidor Jellyfin se reinicia. Esto puede tardar un minuto o dos.",
"RunAtStartup": "Ejecutar al iniciar",
"Series": "Series",
"SeriesDisplayOrderHelp": "Ordena los episodios por fecha de emisión, orden de DVD o número absoluto.",
@ -1432,8 +1430,8 @@
"MoreMediaInfo": "Información del archivo",
"LabelVideoCodec": "Codec de video:",
"LabelVideoBitrate": "Bitrade de video:",
"LabelTranscodingProgress": "Progreso de la transcodificación:",
"LabelTranscodingFramerate": "Velocidad de fotogramas de la transcodificación:",
"LabelTranscodingProgress": "Progreso de la conversión:",
"LabelTranscodingFramerate": "Velocidad de la conversión:",
"LabelSize": "Tamaño:",
"LabelPleaseRestart": "Los cambios surtirán efecto tras recargar manualmente el cliente web.",
"LabelPlayMethod": "Método de reproducción:",
@ -1461,9 +1459,9 @@
"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.",
"AllowFfmpegThrottlingHelp": "Las conversiones se pausarán cuando se adelanten lo suficiente desde la posición en la que se encuentre el reproductor. Puede reducir la carga en el servidor y es útil cuando se reproduce de forma continua, sin saltar entre intervalos de tiempo, pero puede que tengas que desactivarlo si experimentas problemas en la reproducción o cambias de posición frecuentemente mientras reproduces contenido.",
"PlaybackErrorNoCompatibleStream": "Este contenido no es compatible con este dispositivo y no se puede reproducir: No se puede obtener del servidor en un formato compatible.",
"OptionForceRemoteSourceTranscoding": "Forzar la transcodificación para fuentes remotas de medios (como LiveTV)",
"OptionForceRemoteSourceTranscoding": "Forzar la conversión para fuentes externas (como la televisión en directo)",
"NoCreatedLibraries": "Parece que aún no se han creado librearías. {0}¿Quiere crear una ahora?{1}",
"LabelVideoResolution": "Resolución de video:",
"LabelStreamType": "Tipo de stream:",
@ -1471,7 +1469,7 @@
"LabelDroppedFrames": "Frames perdidos:",
"LabelCorruptedFrames": "Frames corruptos:",
"AskAdminToCreateLibrary": "Solo un administrador puede crear librerías.",
"AllowFfmpegThrottling": "Acelerar transcodificación",
"AllowFfmpegThrottling": "Pausar las conversiones",
"ClientSettings": "Ajustes de cliente",
"PreferEmbeddedEpisodeInfosOverFileNames": "Priorizar la información embebida sobre los nombres de archivos",
"PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Usar la información de episodio de los metadatos embebidos si está disponible.",
@ -1562,5 +1560,8 @@
"ShowMore": "Ver más",
"ShowLess": "Ver menos",
"ButtonSyncPlay": "SyncPlay",
"ButtonCast": "Enviar"
"ButtonCast": "Enviar",
"MessageNoGenresAvailable": "Permitir a algunos proveedores de metadatos extraer géneros de Internet.",
"EnableDecodingColorDepth10Vp9": "Habilite la decodificación por hardware de 10 bits para Vp9",
"EnableDecodingColorDepth10Hevc": "Habilite la decodificación por hardware de 10 bits para HEVC"
}

View File

@ -51,8 +51,8 @@
"LabelNightly": "Nocturno",
"HeaderVideos": "Videos",
"Director": "Director",
"Depressed": "Presionado",
"BoxSet": "Box Set",
"Depressed": "No presionado",
"BoxSet": "Caja",
"UnsupportedPlayback": "Jellyfin no puede desencriptar contenido protegido por DRM de todas formas todo el contenido será intentado, incluyendo los títulos protegidos. Algunos archivos pueden aparecer completamente en negro debido al encriptado o características no soportadas, como títulos interactivos.",
"OnApplicationStartup": "Cuando se inicia la aplicación",
"EveryXHours": "Cada {0} horas",
@ -564,7 +564,6 @@
"RunAtStartup": "Ejecutar al iniciar",
"Rewind": "Rebobinar",
"ResumeAt": "Reanudar desde {0}",
"RestartPleaseWaitMessage": "Por favor, espera mientras el servidor Jellyfin se apaga y reinicia. Esto puede tomar un minuto o dos.",
"ReplaceExistingImages": "Reemplazar imágenes existentes",
"ReplaceAllMetadata": "Reemplazar todos los metadatos",
"RepeatOne": "Repetir uno",
@ -1074,7 +1073,6 @@
"HeaderScenes": "Escenas",
"HeaderRunningTasks": "Tareas en ejecución",
"HeaderRevisionHistory": "Historial de versiones",
"HeaderRestartingServer": "Reiniciando servidor",
"HeaderRestart": "Reiniciar",
"HeaderResponseProfileHelp": "Los perfiles de respuesta proporcionan un medio para personalizar la información enviada al dispositivo cuando se reproducen ciertos tipos de medios.",
"HeaderResponseProfile": "Perfil de respuesta",

View File

@ -776,7 +776,6 @@
"SaveSubtitlesIntoMediaFolders": "Tallenna tekstitykset mediakansioihin",
"Saturday": "Lauantai",
"ResumeAt": "Jatka kohdasta {0}",
"RestartPleaseWaitMessage": "Odota kunnes Jellyfin palvelin sammuu ja käynnistyy uudelleen. Tämä voi kestää hetken aikaa.",
"RequiredForAllRemoteConnections": "Vaadittu kaikille etäyhteyksille",
"ReplaceExistingImages": "Korvaa olemassaolevat kuvat",
"ReplaceAllMetadata": "Korvaa kaikki metadata",
@ -902,7 +901,6 @@
"HeaderSecondsValue": "{0} Sekuntia",
"HeaderRunningTasks": "Käynnissä olevat tehtävät",
"HeaderRevisionHistory": "Versiohistoria",
"HeaderRestartingServer": "Uudelleenkäynnistetään palvelinta",
"HeaderRemoveMediaFolder": "Poista mediakansio",
"HeaderRemoteControl": "Etäohjaus",
"HeaderPleaseSignIn": "Ole hyvä ja kirjaudu sisään",

View File

@ -896,7 +896,7 @@
"MessageNoAvailablePlugins": "Aucune extension disponible.",
"MessageNoMovieSuggestionsAvailable": "Aucune suggestion de film n'est actuellement disponible. Commencez à regarder et à noter vos films pour avoir des suggestions.",
"MessageNoPluginsInstalled": "Vous n'avez aucune extension installée.",
"MessageNoTrailersFound": "Aucune bande-annonce trouvée. Installez la chaîne Trailers pour améliorer votre expérience, par l'ajout d'une médiathèque de bandes-annonces disponibles sur Internet.",
"MessageNoTrailersFound": "Installez la chaîne Trailers pour améliorer votre expérience cinéma, par l'ajout d'une médiathèque de bandes-annonces disponibles sur Internet.",
"MessageNothingHere": "Il n'y a rien ici.",
"MessagePasswordResetForUsers": "Les mot de passes de ces utilisateurs ont été réinitialisés. Ils peuvent maintenant se connecter avec le code PIN utilisé pour la réinitialisation.",
"MessagePlayAccessRestricted": "La lecture de ce contenu est actuellement restreinte. Contactez l'administrateur de votre serveur pour plus d'informations.",
@ -1149,7 +1149,6 @@
"ReplaceAllMetadata": "Remplacer toutes les métadonnées",
"ReplaceExistingImages": "Remplacer les images existantes",
"RequiredForAllRemoteConnections": "Obligatoire pour toutes les connexions externes",
"RestartPleaseWaitMessage": "Veuillez patienter pendant que le serveur Jellyfin s'arrête et redémarre. Cela peut prendre une minute ou deux.",
"ResumeAt": "Reprendre à {0}",
"Rewind": "Rembobiner",
"RunAtStartup": "Exécuter au démarrage",
@ -1386,7 +1385,6 @@
"HeaderFavoriteArtists": "Artistes préférés",
"HeaderFavoriteSongs": "Chansons préférées",
"HeaderFavoriteVideos": "Vidéos préférées",
"HeaderRestartingServer": "Redémarrage du serveur",
"LabelServerName": "Nom du serveur :",
"DashboardVersionNumber": "Version : {0}",
"DashboardServerName": "Serveur : {0}",
@ -1554,6 +1552,21 @@
"MessageSyncPlayErrorAccessingGroups": "Une erreur s'est produite pendant l'accès à la liste de groupes.",
"ShowMore": "Voir plus",
"ShowLess": "Voir moins",
"EnableBlurhashHelp": "Les images qui sont encore en cours de chargement seront affichées avec un caractère de remplissage flou",
"EnableBlurhash": "Permettre des espaces flous pour les images"
"EnableBlurhashHelp": "Les images qui sont encore en cours de chargement seront remplacées par une image générique floue",
"EnableBlurhash": "Utilise des images génériques floues à la place des images",
"ButtonCast": "Diffuser",
"ButtonSyncPlay": "Lecture synchronisée",
"TabRepositories": "Dépôts",
"MessageNoGenresAvailable": "Utiliser des fournisseurs de métadonnées pour récupérer les genres depuis internet.",
"MessageAddRepository": "Si vous souhaitez ajouter un dépôt, cliquez sur le bouton près de l'entête et renseignez les informations demandées.",
"LabelRepositoryNameHelp": "Un nom personnalisé pour distinguer ce dépôt des autres ajoutés sur votre serveur.",
"LabelRepositoryName": "Nom du dépôt",
"LabelRepositoryUrlHelp": "La localisation du manifeste du dépôt que vous voulez inclure.",
"LabelRepositoryUrl": "URL du dépôt",
"HeaderNewRepository": "Nouveau dépôt",
"MessageNoRepositories": "Pas de dépôts.",
"EnableFasterAnimationsHelp": "Utiliser des animations et des transitions plus rapides",
"EnableFasterAnimations": "Animations plus rapides",
"EnableDecodingColorDepth10Vp9": "Activer le décodage hardware 10-Bit pour VP9",
"EnableDecodingColorDepth10Hevc": "Activer le décodage hardware 10-Bit pour HEVC"
}

View File

@ -607,7 +607,6 @@
"HeaderSelectServer": "בחר שרת",
"HeaderSecondsValue": "{0} שניות",
"HeaderSeasons": "עונות",
"HeaderRestartingServer": "מאתחל שרת",
"HeaderRestart": "הפעלה מחדש",
"HeaderProfileInformation": "מידע פרופיל",
"HeaderProfile": "פרופיל",

View File

@ -7,14 +7,14 @@
"AdditionalNotificationServices": "Pretražite katalog dodataka kako bi instalirali dodatne servise za obavijesti.",
"AllChannels": "Svi kanali",
"AllEpisodes": "Sve epizode",
"AllowHWTranscodingHelp": "Ako je omogućeno, omogućite TV/radio uređaju da konvertira strujanja u letu. Ovo može pomoći smanjiti konvertiranje koje zahtijeva Jellyfin Server.",
"AllowHWTranscodingHelp": "Omogućite TV/radio uređaju da konvertira strujanja u letu. Ovo može pomoći smanjiti konvertiranje koje zahtijeva Jellyfin Server.",
"Anytime": "Bilo kada",
"AroundTime": "Oko {0}",
"AroundTime": "Oko",
"AsManyAsPossible": "Što više je moguće",
"AttributeNew": "Novo",
"Backdrops": "Pozadine",
"BirthDateValue": "Rođen: {0}",
"BirthLocation": "Lokacije rođenja",
"BirthLocation": "Lokacija rođenja",
"BirthPlaceValue": "Mjesto rođenja: {0}",
"BrowsePluginCatalogMessage": "Pregledajte dostupne dodatke u našem katalogu.",
"ButtonAdd": "Dodaj",
@ -120,35 +120,35 @@
"DoNotRecord": "Ne snimi",
"Download": "Preuzimanje",
"DrmChannelsNotImported": "Kanali s DRM se neće uvesti.",
"EasyPasswordHelp": "Vaš laki PIN kod se koristi za izvan-mrežni pristup s podržanim Jellyfin aplikacijama, a također se može koristiti za jednostavnu mrežnu prijavu.",
"EasyPasswordHelp": "Vaš laki PIN kod se koristi za izvan-mrežni pristup na podržanim klijentima i također se može koristiti za jednostavnu mrežnu prijavu.",
"Edit": "Izmjeni",
"EditImages": "Uređivanje slika",
"EditSubtitles": "Uredi titlove",
"EnableColorCodedBackgrounds": "Omogući kodirane boje pozadine",
"EnablePhotos": "Omogući slike",
"EnablePhotosHelp": "Slike će biti otkrite i prikazivane zajedno s drugim medijskim datotekama.",
"EnableColorCodedBackgrounds": "Kodirane boje pozadine",
"EnablePhotos": "Prikaži slike",
"EnablePhotosHelp": "Slike će biti otkrivene i prikazivane zajedno s drugim medijskim datotekama.",
"Ended": "Završeno",
"EndsAtValue": "Završava u {0}",
"ErrorAddingListingsToSchedulesDirect": "Došlo je do pogreške prilikom dodavanja postava vašim zakazanim direktnim računima. Raspored dopušta samo ograničen broj postava po računu. Možda ćete morati se prijavite u zakazanim \"Direct\" web stranicama i ukloniti unose drugih s računa prije nastavka.",
"ErrorAddingMediaPathToVirtualFolder": "Došlo je do pogreške prilikom dodavanja putanje medija. Provjerite dali je putanja valjana i da proces Jellyfin Server-a ima pristup tom mjestu.",
"ErrorAddingTunerDevice": "Došlo je do pogreške prilikom dodavanja uređaja TV/radio pretraživača. Provjerite da je dostupan i pokušajte ponovno.",
"ErrorGettingTvLineups": "Došlo je do pogreške prilikom preuzimanja tv postave. Provjerite dali su vaše informacije točne i pokušajte ponovno.",
"ErrorGettingTvLineups": "Došlo je do pogreške prilikom preuzimanja TV postave. Provjerite dali su vaše informacije točne i pokušajte ponovno.",
"ErrorMessageStartHourGreaterThanEnd": "Vrijeme završetka mora biti veće od početka.",
"ErrorPleaseSelectLineup": "Odaberite postavu i pokušajte ponovno. Ako niti jedna postava nije dostupna provjerite dali su korisničko ime, lozinka i poštanski broj točni.",
"ErrorSavingTvProvider": "Došlo je do pogreške prilikom snimanja TV pružatelja. Provjerite da je dostupan i pokušajte ponovno.",
"ExtractChapterImagesHelp": "Izdvajanje slika poglavlja omogućiti će Jellyfin aplikaciji za prikaz grafičkih izbornika za odabir scena. Proces može biti spor, CPU intenzivno korišten i može zahtijevati nekoliko gigabajta prostora. Ono se pokreće kad je otkriven video, a također i kao noćni zadatak. Raspored je podesiv u području rasporeda zadataka. Ne preporučuje se za pokretanje ovog zadatka tijekom sati čestog korištenja.",
"ExtractChapterImagesHelp": "Izdvajanje slika poglavlja omogućiti će klijentima prikaz grafičkih izbornika za odabir scena. Proces može biti spor, resursi intenzivno korišteni i može zahtijevati nekoliko gigabajta prostora. Ono se pokreće kad je otkriven video, a također i kao noćni zadatak. Raspored je podesiv u području rasporeda zadataka. Ne preporučuje se za pokretanje ovog zadatka tijekom sati čestog korištenja.",
"FFmpegSavePathNotFound": "Nismo mogli locirati FFmpeg korištenjem putanje koju ste unijeli. FFprobe je također potreban i mora postojati u istoj mapi. Te komponente su obično u paketu zajedno u istom preuzimanju. Provjerite putanju i pokušajte ponovno.",
"Favorite": "Omiljeni",
"File": "Datoteka",
"FileNotFound": "Datoteka nije pronađena.",
"FileReadCancelled": "Učitavanje datoteke je prekinuto.",
"FileReadError": "Prilikom učitavanja datoteke desila se greška",
"FileReadError": "Prilikom učitavanja datoteke dogodila se greška.",
"FolderTypeBooks": "Knjige",
"FolderTypeMovies": "Filmovi",
"FolderTypeMusic": "Glazba",
"FolderTypeMusicVideos": "Glazbeni videi",
"FolderTypeMusicVideos": "Glazbeni spotovi",
"FolderTypeTvShows": "TV",
"FolderTypeUnset": "Isključi (miješani sadržaj)",
"FolderTypeUnset": "Miješani sadržaj",
"Friday": "Petak",
"Genres": "Žanrovi",
"GroupVersions": "Verzija grupe",
@ -158,7 +158,7 @@
"H264CrfHelp": "Konstante brzine faktora (CRF) je postavka zadane kvalitete za x264 enkodera. Možete postaviti vrijednosti između 0 i 51, gdje će niže vrijednosti rezultirati boljom kvalitetom (na račun veće veličine datoteka). Razumne vrijednosti su između 18 i 28. Zadana za x264 je 23, tako da to možete koristiti kao početnu točku.",
"EncoderPresetHelp": "Odaberite bržu vrijednost za poboljšanje performansi ili sporiju za poboljšanje kvalitete.",
"HDPrograms": "HD programi",
"HardwareAccelerationWarning": "Omogućavanje hardverskog ubrzanja može uzrokovati nestabilnostima u nekim sredinama. Pobrinite se da Vaš operativni sustav i video drajveri su u potpunosti ažurni. Ako imate poteškoća s reprodukcijom videa nakon omogućavanja ovoga, morat ćete promijeniti postavku natrag na Automatski.",
"HardwareAccelerationWarning": "Omogućavanje hardverskog ubrzanja može uzrokovati nestabilnostima u nekim sredinama. Pobrinite se da Vaš operativni sustav i video drajveri su u potpunosti ažurni. Ako imate poteškoća s reprodukcijom videa nakon omogućavanja ovoga, morat ćete promijeniti postavku natrag na Ništa.",
"HeaderAccessSchedule": "Raspored pristupa",
"HeaderAccessScheduleHelp": "Napravite raspored pristupa da bi ograničili pristup određenim satima.",
"HeaderActiveDevices": "Aktivni uređaji",
@ -189,7 +189,7 @@
"HeaderCodecProfileHelp": "Profili kodeka definiraju ograničenja kada uređaji izvode sadržaj u specifičnom kodeku. Ako se ograničenja podudaraju tada će sadržaj biti transkodiran, iako je kodek konfiguriran za direktno izvođenje.",
"HeaderConfirmPluginInstallation": "Potvrdi instalaciju dodatka",
"HeaderConfirmProfileDeletion": "Potvrdite brisanje profila",
"HeaderConfirmRevokeApiKey": "Opozovi Api ključ",
"HeaderConfirmRevokeApiKey": "Opozovi API ključ",
"HeaderConnectToServer": "Spoji se na Server",
"HeaderConnectionFailure": "Neuspjelo spajanje",
"HeaderContainerProfile": "Profil spremnika",
@ -221,7 +221,7 @@
"HeaderForgotPassword": "Zaboravili ste lozinku",
"HeaderFrequentlyPlayed": "Često izvođeno",
"HeaderGuideProviders": "Pružatelji vodiča",
"HeaderHttpHeaders": "Http zaglavlja",
"HeaderHttpHeaders": "HTTP zaglavlja",
"HeaderIdentification": "Identifikacija",
"HeaderIdentificationCriteriaHelp": "Unesite barem jedan kriterij za identifikaciju.",
"HeaderIdentificationHeader": "Identifikacija zaglavlja",
@ -244,7 +244,7 @@
"HeaderLoginFailure": "Neuspjela prijava",
"HeaderMedia": "Medij",
"HeaderMediaFolders": "Medijska mapa",
"HeaderMediaInfo": "Info medija:",
"HeaderMediaInfo": "Info medija",
"HeaderMetadataSettings": "Postavke meta-podataka",
"HeaderMoreLikeThis": "Više ovakvih",
"HeaderMovies": "Filmovi",
@ -278,8 +278,8 @@
"HeaderScenes": "Scene",
"HeaderSchedule": "Raspored",
"HeaderSeasons": "Sezone",
"HeaderSelectCertificatePath": "Odaberi put certifikata:",
"HeaderSelectMetadataPath": "Odaberite putanju meta-podataka:",
"HeaderSelectCertificatePath": "Odaberi putanju certifikata",
"HeaderSelectMetadataPath": "Odaberite putanju meta-podataka",
"HeaderSelectMetadataPathHelp": "Pregledajte ili unesite putanju za pohranu meta-podataka. U mapu se mora moći pisati.",
"HeaderSelectPath": "Odaberi putanju",
"HeaderSelectServer": "Odaberi Server",
@ -288,7 +288,7 @@
"HeaderSelectTranscodingPath": "Odaberite privremenu putanju konvertiranja",
"HeaderSelectTranscodingPathHelp": "Pregledajte ili unesite putanju za korištenje konvertiranja privremenih datoteka. U mapu se mora moći pisati.",
"HeaderSendMessage": "Pošalji poruku",
"HeaderSeries": "Series:",
"HeaderSeries": "Serija",
"HeaderSeriesOptions": "Opcije serija",
"HeaderServerSettings": "Postavke Servera",
"HeaderSettings": "Postavke",
@ -325,7 +325,7 @@
"Identify": "Identificiraj",
"Images": "Slike",
"ImportFavoriteChannelsHelp": "Ako je omogućeno, samo kanali koji su označeni kao omiljeni na uređaju TV/radio pretraživača će se uvesti.",
"InstallingPackage": "Instaliranje {0}",
"InstallingPackage": "Instaliranje {0} (verzija {1})",
"InstantMix": "Trenutno miješanje",
"ItemCount": "{0} stavaka",
"Kids": "Djeca",
@ -344,13 +344,13 @@
"LabelAlbumArtMaxWidth": "Maksimalna širina Album art-a:",
"LabelAlbumArtMaxWidthHelp": "Maksimalna rezolucija albuma izloženih putem UPnP:albumArtURI.",
"LabelAlbumArtPN": "Grafika albuma PN:",
"LabelAlbumArtists": "Izvođači albuma",
"LabelAlbumArtists": "Izvođači albuma:",
"LabelAll": "Sve",
"LabelAllowHWTranscoding": "Dopusti hardversko konvertiranje",
"LabelAllowServerAutoRestart": "Dopusti serveru da se automatski resetira kako bi proveo nadogradnje",
"LabelAllowServerAutoRestartHelp": "Server će se resetirati dok je u statusu mirovanja, odnosno kada nema aktivnih korisnika.",
"LabelAllowServerAutoRestartHelp": "Server će se resetirati samo dok je u statusu mirovanja kada nema aktivnih korisnika.",
"LabelAppName": "Ime aplikacije",
"LabelAppNameExample": "Primjer: Sickbeard, NzbDrone",
"LabelAppNameExample": "Primjer: Sickbeard, Sonarr",
"LabelArtists": "Izvođači:",
"LabelArtistsHelp": "Odvoji višestruko koristeći ;",
"LabelAudioLanguagePreference": "Postavke audio jezika:",
@ -362,7 +362,7 @@
"LabelBlastMessageIntervalHelp": "Određuje trajanje u sekundama između svake poruke dostupnosti servera.",
"LabelCache": "Predmemorija:",
"LabelCachePath": "Putanja predmemorije:",
"LabelCachePathHelp": "Odredite prilagođenu lokaciju za predmemorijske datoteke servera, kao što su slike. Ostavite prazno za korištenje zadanog poslužitelja.",
"LabelCachePathHelp": "Odredite prilagođenu lokaciju za predmemorijske datoteke servera kao što su slike. Ostavite prazno za korištenje zadanog poslužitelja.",
"LabelCancelled": "Otkazan",
"LabelChannels": "Kanali:",
"LabelCollection": "Kolekcija:",
@ -371,12 +371,12 @@
"LabelCountry": "Zemlja:",
"LabelCriticRating": "Ocjene kritike:",
"LabelCurrentPassword": "Sadašnja lozinka:",
"LabelCustomCss": "Prilagođen css:",
"LabelCustomCssHelp": "Primijenite svoj vlastiti prilagođeni css na web sučelje.",
"LabelCustomCss": "Prilagođeni CSS:",
"LabelCustomCssHelp": "Primijenite svoj vlastiti prilagođeni stil na web sučelje.",
"LabelCustomDeviceDisplayName": "Prikaz naziva:",
"LabelCustomDeviceDisplayNameHelp": "Navedite naziv prilagođenog prikaza ili ostaviti prazno za korištenje naziva koji je izvijestio uređaj.",
"LabelCustomRating": "Prilagođena ocjena:",
"LabelDateAdded": "Datumu dodavanja",
"LabelDateAdded": "Datum dodavanja:",
"LabelDateAddedBehavior": "Ponašanje datuma dodanog za novi sadržaj:",
"LabelDateAddedBehaviorHelp": "Ako je prisutna vrijednost meta-podataka uvijek će se koristiti prije bilo kojih od ovih opcija.",
"LabelDay": "Dan:",
@ -384,29 +384,29 @@
"LabelDefaultUser": "Zadani korisnik:",
"LabelDefaultUserHelp": "Određuje koja će biblioteka biti prikazana na spojenim uređajima. Ovo se može zaobići za svaki uređaj koristeći profile.",
"LabelDeviceDescription": "Opis uređaja",
"LabelDidlMode": "Didl način:",
"LabelDidlMode": "DIDL način:",
"LabelDisplayMissingEpisodesWithinSeasons": "Prikaži epizode koje nedostaju unutar sezone",
"LabelDisplayName": "Prikaz naziva:",
"LabelDisplayOrder": "Poredak prikaza:",
"LabelDisplaySpecialsWithinSeasons": "Prikaz specijalnih dodataka unutar sezona u kojima su emitirani",
"LabelDownMixAudioScale": "Pojačaj zvuk kada radiš downmix:",
"LabelDownMixAudioScaleHelp": "Pojačaj zvuk kada radiš downmix. Postavi na 1 ako želiš zadržati orginalnu jačinu zvuka.",
"LabelDownMixAudioScaleHelp": "Pojačaj zvuk prilikom downmix-a. Vrijednost 1 će zadržati originalnu jačinu zvuka.",
"LabelDownloadLanguages": "Jezici za preuzimanje:",
"LabelEasyPinCode": "Lagan PIN kod:",
"LabelEmbedAlbumArtDidl": "Ugradi grafike albuma u Didl",
"LabelEmbedAlbumArtDidlHelp": "Neki uređaji podržavaju ovu metodu za prikaz grafike albuma. Drugi bi mogli imati problema sa ovom opcijom uključenom.",
"LabelEnableAutomaticPortMap": "Omogući automatsko mapiranje porta",
"LabelEnableAutomaticPortMapHelp": "Pokušaj automatski mapirati javni port za lokalni port preko UPnP. Možda neće raditi s nekim modelima router-a.",
"LabelEnableAutomaticPortMapHelp": "Automatski proslijedi javni port na svom ruteru na lokalni port preko UPnP. Možda neće raditi sa nekim modelima router-a ili mrežnim konfiguracijama. Promjene se neće primijeniti do restarta servera.",
"LabelEnableBlastAliveMessages": "Objavi poruke dostupnosti",
"LabelEnableBlastAliveMessagesHelp": "Omogući ovo ako server nije prikazan kao siguran za druge UPnP uređaje na mreži.",
"LabelEnableDlnaClientDiscoveryInterval": "Interval za otkrivanje kljenata (sekunde)",
"LabelEnableDlnaClientDiscoveryIntervalHelp": "Određuje trajanje u sekundama između SSDP pretraživanja obavljenih od Jellyfin-a.",
"LabelEnableDlnaDebugLogging": "Omogući DLNA logiranje grešaka.",
"LabelEnableDlnaDebugLoggingHelp": "Ovo će kreirati iznimno velike log datoteke i jedino se preporuča koristiti u slučaju problema.",
"LabelEnableDlnaDebugLogging": "Omogući DLNA logiranje grešaka",
"LabelEnableDlnaDebugLoggingHelp": "Kreiraj iznimno velike log datoteke i preporuča se koristiti jedino u slučaju problema.",
"LabelEnableDlnaPlayTo": "Omogući DLNA izvođenje na",
"LabelEnableDlnaPlayToHelp": "Jellyfin može otkriti uređaje unutar svoje mreže i ponuditi mogućnost da ih daljinski upravlja.",
"LabelEnableDlnaServer": "Omogući Dlna server",
"LabelEnableDlnaServerHelp": "Omogućuje UPnP uređajima na mreži da pregledavaju i pokreću Jellyfin sadržaj.",
"LabelEnableDlnaPlayToHelp": "Otkrij uređaje unutar svoje mreže i ponudi mogućnost da ih daljinski upravlja.",
"LabelEnableDlnaServer": "Omogući DLNA server",
"LabelEnableDlnaServerHelp": "Omogućuje UPnP uređajima na mreži da pregledavaju i pokreću sadržaj.",
"LabelEnableRealtimeMonitor": "Omogući nadgledanje u realnom vremenu",
"LabelEnableRealtimeMonitorHelp": "Promjene će biti procesuirane odmah, nad podržanim datotekama sistema.",
"LabelEnableSingleImageInDidlLimit": "Ograničenje na jednu ugrađenu sliku",
@ -416,12 +416,12 @@
"LabelEvent": "Događaj:",
"LabelEveryXMinutes": "Svaki:",
"LabelExtractChaptersDuringLibraryScan": "Izvadi slike poglavlja dok traje skeniranje biblioteke",
"LabelExtractChaptersDuringLibraryScanHelp": "Ako je omogućeno, slike poglavlje će se izdvojiti kad se videozapisi uvezu tijekom skeniranja biblioteke. Ako je onemogućeno izdvojiti će se u rasporedu zadatka slika poglavlja, čime se omogućuje da se skeniranje redovne biblioteke završiti brže.",
"LabelExtractChaptersDuringLibraryScanHelp": "Generiraj slike poglavlje kad se videozapisi uvezu tijekom skeniranja biblioteke. U suprotnom, izdvajanje će se odraditi u rasporedu zadatka slika poglavlja, čime se omogućuje da se skeniranje redovne biblioteke završi brže.",
"LabelFailed": "Neuspješno",
"LabelFileOrUrl": "Datoteka ili url:",
"LabelFinish": "Kraj",
"LabelForgotPasswordUsernameHelp": "Unesite korisničko ime, ako se sjećate.",
"LabelFriendlyName": "Prijateljsko ime",
"LabelFriendlyName": "Prijateljsko ime:",
"LabelServerNameHelp": "Ovo ime će se koristiti za identifikaciju servera. Ako ostavite prazno, ime računala će se koristi kao identifikator.",
"LabelGroupMoviesIntoCollections": "Grupiraj filmove u kolekciju",
"LabelGroupMoviesIntoCollectionsHelp": "Kada se prikazuje lista filmova, filmovi koji pripadaju kolekciji biti će prikazani kao jedna stavka.",
@ -475,7 +475,7 @@
"LabelMetadataDownloadersHelp": "Omogućite i poredajte željene preuzimatelje meta-podataka po redu prioriteta. Manjeg prioriteta preuzimatelji koristit će se samo za ispunjavanje nedostajućih informacija.",
"LabelMetadataPath": "Put meta-podataka:",
"LabelMetadataPathHelp": "Odredite prilagođenu lokaciju za preuzete ilustracije i meta-podatke.",
"LabelMetadataReaders": "Čitači meta-podataka",
"LabelMetadataReaders": "Čitači meta-podataka:",
"LabelMetadataReadersHelp": "Poredajte željene lokalne izvore meta-podataka po redu prioriteta. Prva nađena datoteka biti će čitana.",
"LabelMetadataSavers": "Snimači meta-podataka:",
"LabelMetadataSaversHelp": "Odaberite formate datoteka za spremanje meta-podataka.",
@ -567,7 +567,7 @@
"LabelStopWhenPossible": "Zaustavi kada je moguće:",
"LabelStopping": "Zaustavljanje",
"LabelSubtitleFormatHelp": "Npr.: srt",
"LabelSubtitlePlaybackMode": "Način titlova prijevoda",
"LabelSubtitlePlaybackMode": "Način prijevoda:",
"LabelSupportedMediaTypes": "Podržani tipovi medija:",
"LabelTag": "Oznaka:",
"LabelTagline": "Slogan:",
@ -652,15 +652,15 @@
"MessageDirectoryPickerBSDInstruction": "Za BSD možda ćete morati podesiti pohranu unutar vašega FreeNAS kako bi se omogućilo Jellyfin-u pristup.",
"MessageDirectoryPickerInstruction": "Mrežne putanje mogu se unijeti ručno u slučaju da gumb Mreže ne uspije locirati vaše uređaje. Na primjer, {0} ili {1}.",
"MessageDirectoryPickerLinuxInstruction": "Za Linux na Arch Linux, CentOS, Debian, Fedora, OpenSuse ili Ubuntu morate dati korisniku Jellyfin sistema barem pristup čitanja vašim lokacijama za skladištenje.",
"MessageDownloadQueued": "Preuzimanje na čekanju",
"MessageFileReadError": "Prilikom učitavanja datoteke desila se greška",
"MessageDownloadQueued": "Preuzimanje na čekanju.",
"MessageFileReadError": "Prilikom učitavanja datoteke desila se greška. Pokušajte ponovno.",
"MessageForgotPasswordFileCreated": "Sljedeća datoteka je stvorena na vašem poslužitelju i sadrži upute o tome kako postupiti:",
"MessageForgotPasswordInNetworkRequired": "Molim pokušajte ponovno unutar kućne mreže za pokretanje postupka za poništavanje zaporke.",
"MessageInstallPluginFromApp": "Ovaj dodatak mora biti instaliran unutar aplikacije u kojoj ga namjeravate koristiti.",
"MessageInvalidForgotPasswordPin": "Upisan je neispravan ili zastarjele pin. Molim, pokušajte ponovno.",
"MessageInvalidUser": "Pogrešno korisničko ime ili lozinka. Molim, pokušajte ponovo.",
"MessageItemSaved": "Stavka je snimljena.",
"MessageItemsAdded": "Stavke su dodane",
"MessageItemsAdded": "Stavke su dodane.",
"MessageLeaveEmptyToInherit": "Ostavite prazno da naslijedi postavke od roditelja stavke ili globalnu zadanu vrijednost.",
"MessageNoAvailablePlugins": "Nema odgovarajućih dodataka.",
"MessageNoMovieSuggestionsAvailable": "Filmski prijedlozi nisu trenutno dostupni. Počnite s gledanjem i ocjenjivanjem svoje filmove, a zatim se vratite da biste vidjeli svoje preporuke.",
@ -672,7 +672,7 @@
"MessagePluginConfigurationRequiresLocalAccess": "Za podešavanje ovog dodatka prijavite se izravno na lokalni server.",
"MessagePluginInstallDisclaimer": "Dodaci izgrađeni od strane članova Jellyfin zajednice su sjajan način kako bi unaprijedili Vaše iskustvo Jellyfin s dodatnim značajkama i prednostima. Prije instaliranja budite svjesni učinaka koje mogu imati na vaš Jellyfin Server, kao što je duže skeniranje biblioteke, dodatna pozadinska obrada, a smanjena stabilnost sustava.",
"MessageReenableUser": "Pogledajte dolje za ponovno omogućenje",
"MessageSettingsSaved": "Postavke snimljene",
"MessageSettingsSaved": "Postavke spremljene.",
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "Sljedeće lokacije medija biti će uklonjene iz vaše Jellyfin biblioteke:",
"MessageUnableToConnectToServer": "Nismo u mogućnosti spojiti se na odabrani poslužitelj. Provjerite dali je pokrenut i pokušajte ponovno.",
"MessageUnsetContentHelp": "Sadržaj će biti prikazan kao obične mape. Za najbolje rezultate upotrijebite upravitelj meta-podataka za postavljanje vrste sadržaja pod-mapa.",
@ -785,14 +785,14 @@
"OptionMissingEpisode": "Epizode koje nedostaju",
"OptionMonday": "Ponedjeljak",
"OptionNameSort": "Nazivu",
"OptionNew": "Novo...",
"OptionNew": "Novo",
"OptionNone": "Ništa",
"OptionOnAppStartup": "Kada se aplikacija pokrene",
"OptionOnInterval": "U intervalu",
"OptionParentalRating": "Roditeljska ocjena",
"OptionPlainStorageFolders": "Prikaži sve mape kako jednostavne mape za skladištenje",
"OptionPlainStorageFoldersHelp": "Ako je omogućeno, sve mape se prezentiraju u DIDL-u kao \"objekt.spremnik.skladišnaMapa\" umjesto više specijaliziranog tipa kao \"objekt.spremnik.osoba.glazbaIzvođač\".",
"OptionPlainVideoItems": "Prikaži sav video kao jednostavne video stavke.",
"OptionPlainVideoItems": "Prikaži sve video zapise kao jednostavne video stavke",
"OptionPlainVideoItemsHelp": "Ako je omogućeno, sav video se prezentira u DIDL-u kao \"objekt.stavka.videoStavka\" umjesto više specijaliziranog tipa kao \"objekt.stavka.videoStavka.film\".",
"OptionPlayCount": "Broju izvođenja",
"OptionPlayed": "Izvođeni",
@ -862,7 +862,7 @@
"RecordingScheduled": "Snimka je zakazana.",
"Refresh": "Osviježi",
"RefreshDialogHelp": "Meta-podaci se osvježavaju na temelju postavki i internet usluga koje su omogućene u nadzornoj ploči Jellyfin Server-a.",
"RefreshQueued": "Osviježi stavke na čekanju",
"RefreshQueued": "Osviježi stavke na čekanju.",
"ReleaseDate": "Datum izdavanja",
"RememberMe": "Zapamti me",
"RemoveFromCollection": "Ukloni iz kolekcije",
@ -890,7 +890,7 @@
"ServerNameIsShuttingDown": "Jellyfin Server - {0} se gasi.",
"ServerUpdateNeeded": "Jellyfin Server treba ažurirati. Da biste preuzeli najnoviju verziju, posjetite {0}",
"Settings": "Postavke",
"SettingsSaved": "Postavke snimljene",
"SettingsSaved": "Postavke spremljene.",
"SettingsWarning": "Mijenjanje ove vrijednosti može uzrokovati nestabilnost ili kvarove na povezivanju. Ako naiđete na bilo kakve probleme, preporučamo da ih promijenite natrag na zadane.",
"Share": "Dijeli",
"ShowIndicatorsFor": "Prikaži pokazatelja za:",
@ -1006,9 +1006,49 @@
"AccessRestrictedTryAgainLater": "Dostup je trenutačno ograničen. Pokušajte poslije ponovno.",
"Albums": "Albumi",
"All": "Sve",
"AllComplexFormats": "Svi kompleksni formati (ASS, SSA, VOBSUB, PGS, SUB/IDX, itd.)",
"AllComplexFormats": "Svi kompleksni formati (ASS, SSA, VOBSUB, PGS, SUB, IDX, ...)",
"Books": "Knjige",
"Channels": "Kanali",
"Collections": "Kolekcije",
"Artists": "Izvođači"
"Artists": "Izvođači",
"DownloadsValue": "{0} preuzimanja",
"Down": "Dolje",
"Playlists": "Popis za reprodukciju",
"AllowMediaConversionHelp": "Dopusti ili odbij pristup mogućnosti konverzije datoteke.",
"AllLibraries": "Sve biblioteke",
"Aired": "Prikazano",
"AirDate": "Datum prikazivanja",
"AddedOnValue": "Dodano {0}",
"Songs": "Pjesme",
"Shows": "Serije",
"Photos": "Slike",
"HeaderFavoriteSongs": "Omiljene pjesme",
"HeaderFavoriteArtists": "Omiljeni izvođači",
"HeaderFavoriteAlbums": "Omiljeni albumi",
"HeaderFavoriteEpisodes": "Omiljene epizode",
"HeaderFavoriteShows": "Omiljene serije",
"HeaderContinueWatching": "Nastavi gledati",
"HeaderAlbumArtists": "Izvođači na albumu",
"Folders": "Mape",
"Favorites": "Favoriti",
"ButtonCast": "Uloge",
"EveryXHours": "Svakih {0} sati",
"EveryHour": "Svaki sat",
"OnApplicationStartup": "Prilikom pokretanja aplikacije",
"Backdrop": "Pozadina",
"Auto": "Automatski",
"Audio": "Audio",
"Artist": "Izvođač",
"AnyLanguage": "Bilo koji jezik",
"AlwaysPlaySubtitlesHelp": "Prijevodi koji odgovaraju odabranom jeziku će uvijek biti odabrani unatoč jeziku audio zapisa.",
"AlwaysPlaySubtitles": "Uvijek prikaži prijevod",
"AllowRemoteAccessHelp": "Ako je odznačeno, svi udaljeni pristupi će biti blokirani.",
"AllowRemoteAccess": "Dopusti udaljene pristupe na ovaj Jellyfin server.",
"AllowOnTheFlySubtitleExtraction": "Dopusti izvlačenje prijevoda u hodu",
"AllowMediaConversion": "Dopusti konverziju datoteke",
"AllLanguages": "Svi jezici",
"Alerts": "Upozorenja",
"AlbumArtist": "Izvođač na albumu",
"Album": "Album",
"AddToPlayQueue": "Dodaj u red izvođenja"
}

View File

@ -1127,7 +1127,7 @@
"AddToPlayQueue": "Hozzáadás a lejátszási sorhoz",
"AllowHWTranscodingHelp": "Lehetővé teszi a tuner számára, hogy át tudja kódolni a streameket valós időben. Ez segíthet csökkenteni a Szerver által igényelt átkódolást.",
"AllowOnTheFlySubtitleExtraction": "Felirat kinyerésének engedélyezése valós időben",
"MessageNoTrailersFound": "Nincsenek előzetesek. Telepítsd a Trailer csatornát, hogy javítsd a filmélményt az internetes előzetesek könyvtárának hozzáadásával.",
"MessageNoTrailersFound": "Telepítsd a Trailer csatornát, hogy javítsd a filmélményt az internetes előzetesek könyvtárának hozzáadásával.",
"OptionEnableM2tsMode": "M2ts mód engedélyezése",
"OptionEnableM2tsModeHelp": "Engedélyezze az m2ts módot amikor mpegts kódolás történik.",
"OptionEnded": "Befejezett",
@ -1200,7 +1200,6 @@
"RemoveFromPlaylist": "Lejátszási listáról eltávolítani",
"RepeatEpisodes": "Epizódok ismétlése",
"RequiredForAllRemoteConnections": "Minden távoli kapcsolathoz szükséges",
"RestartPleaseWaitMessage": "Kérlek várj, amíg a Jellyfin Szerver leáll és újraindul. Ez eltarthat egy-két percig.",
"ResumeAt": "Folytatás: {0}",
"RunAtStartup": "Futtassa indításkor",
"SaveSubtitlesIntoMediaFolders": "Mentse a feliratokat a média mappákba",
@ -1324,7 +1323,6 @@
"HeaderFavoriteVideos": "Kedvenc Videók",
"HeaderGuideProviders": "TV műsorújság Szolgáltatók",
"HeaderHome": "Kezdőlap",
"HeaderRestartingServer": "Szerver újraindítása",
"HeaderUpcomingOnTV": "Következő TV műsorok",
"ImportFavoriteChannelsHelp": "Ha engedélyezve van, csak a tuner eszközön kedvencként megjelölt csatornák kerülnek importálásra.",
"LabelAlbumArtHelp": "A használandó PN érték az albumborítók esetében, mely a upnp:albumArtURI dlna:profileID tulajdonságában szerepel. Néhány eszköz meghatározott értéket vár el, függetlenül a kép méretétől.",
@ -1558,5 +1556,12 @@
"EnableBlurhashHelp": "A még betöltés alatt álló képek helyén egy elmosódott helyettesítő képet jelenít meg",
"EnableBlurhash": "Elmosódott helyettesítőképek engedélyezése",
"ShowMore": "Továbbiak megtekintése",
"ShowLess": "Kevesebb mutatása"
"ShowLess": "Kevesebb mutatása",
"ButtonCast": "Vetítés",
"ButtonSyncPlay": "SyncPlay",
"MessageNoGenresAvailable": "Engedélyezz néhány metaadat szolgáltatót, hogy műfaj adatokat tölthess le az internetről.",
"EnableFasterAnimationsHelp": "Gyorsabb animációk és áttűnések használata",
"EnableFasterAnimations": "Gyorsabb animációk",
"EnableDecodingColorDepth10Vp9": "10 bites hardveres dekódolás engedélyezése Vp9-hez",
"EnableDecodingColorDepth10Hevc": "10 bites hardveres dekódolás engedélyezése HEVC-hez"
}

View File

@ -543,5 +543,9 @@
"LabelAllowServerAutoRestart": "Leyfa netþjóni að endurræsa sig sjálfkrafa til þess að uppfæra sig",
"LabelAllowHWTranscoding": "Leyfa vélbúnaðarumkóðun",
"Label3DFormat": "3D snið:",
"HeaderIdentification": "Auðkenning"
"HeaderIdentification": "Auðkenning",
"ConfirmDeleteItems": "Ef þessum skrám er eytt verða þær fjarlægðar úr bæði stýrikerfinu og miðlasafninu. Ertu viss um að þú viljir halda áfram?",
"CommunityRating": "Mat samfélagsins",
"ButtonStart": "Byrja",
"BoxSet": "Kassasett"
}

View File

@ -861,7 +861,7 @@
"MessageNoAvailablePlugins": "Nessun plugin disponibile.",
"MessageNoMovieSuggestionsAvailable": "Nessun suggerimento di film attualmente disponibile. Iniziare a guardare e valutare i vostri film, e poi tornare per i suggerimenti.",
"MessageNoPluginsInstalled": "Non hai plugin installati.",
"MessageNoTrailersFound": "Nessun trailer trovato. Installa il canale dei Trailer per migliorare la tua esperienza cinematografica importando una libreria di trailer da internet.",
"MessageNoTrailersFound": "Installa il canale dei trailer per migliorare la tua esperienza cinematografica aggiungendo una libreria di trailer da internet.",
"MessageNothingHere": "Non c'è niente qui.",
"MessagePasswordResetForUsers": "I seguenti utenti havvo avuto le loro password resettate. Adesso possono accedere con i codici pin che sono stati utilizzati per eseguire il reset.",
"MessagePlayAccessRestricted": "Le riproduzione di questi contenuti è bloccata. Per favore contatta il tuo amministratore del server per maggiori informazioni.",
@ -1105,7 +1105,6 @@
"ReplaceAllMetadata": "Sostituisci tutti i metadati",
"ReplaceExistingImages": "Sovrascrivi immagini esistenti",
"RequiredForAllRemoteConnections": "Richiesto per tutte le connessioni remote",
"RestartPleaseWaitMessage": "Per piacere aspetta mentre Jellyfin Server si arresta e riavvia. Questo può richiedere un minuto o due.",
"ResumeAt": "Riprendi da {0}",
"Rewind": "Riavvolgi",
"RunAtStartup": "Esegui all'avvio",
@ -1314,7 +1313,6 @@
"HeaderFavoriteVideos": "Video Preferiti",
"HeaderFetcherSettings": "Impostazioni del Fetcher",
"HeaderImageOptions": "Opzioni Immagine",
"HeaderRestartingServer": "Riavvio Server",
"Home": "Home",
"LabelAlbum": "Album:",
"LabelAudio": "Audio",
@ -1510,7 +1508,7 @@
"LabelChromecastVersion": "Versione Chromecast",
"LabelRequireHttpsHelp": "Se selezionata, il server reindirizzerà tutte le richieste HTTP a HTTPS. Vale solo se il sever è configurato per l'ascolto in HTTPS.",
"LabelRequireHttps": "Richiede HTTPS",
"LabelEnableHttpsHelp": "Abilita il server all'ascolto sulla porta HTTPS. Il certificato deve essere configurato e valido per l'abilitazione.",
"LabelEnableHttpsHelp": "Abilita il server all'ascolto sulla porta HTTPS configurata. Il certificato deve essere configurato e valido per l'abilitazione.",
"LabelEnableHttps": "Abilita HTTPS",
"HeaderServerAddressSettings": "Configurazione Indirizzo Server",
"HeaderRemoteAccessSettings": "Configurazione Access Remoto",
@ -1519,7 +1517,7 @@
"SaveChanges": "Salva modifiche",
"HeaderDVR": "DVR",
"LabelNightly": "Nightly",
"SyncPlayAccessHelp": "Scegli il livello d'accesso di questo utente a SyncPlay. SyncPlay ti permette di riprodurre contemporaneamente su diversi dispositivi.",
"SyncPlayAccessHelp": "Selezionare il livello d'accesso di questo utente a SyncPlay che permetterà 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.",
@ -1554,5 +1552,20 @@
"EnableBlurhashHelp": "Le immagini ancora da caricare saranno mostrate inizialmente sfocate",
"EnableBlurhash": "Abilita i segnaposto sfocati per le immagini",
"ShowMore": "Mostra di più",
"ShowLess": "Mostra meno"
"ShowLess": "Mostra meno",
"ButtonCast": "Cast",
"ButtonSyncPlay": "SyncPlay",
"EnableFasterAnimationsHelp": "Utilizza animazioni e transizioni veloci",
"EnableFasterAnimations": "Animazioni veloci",
"EnableDecodingColorDepth10Vp9": "Abilita la decodifica hardware 10-Bit per VP9",
"EnableDecodingColorDepth10Hevc": "Abilita la decodifica hardware 10-Bit per HEVC",
"TabRepositories": "Repository",
"MessageNoGenresAvailable": "Abilita un metadata provider per recuperare i generi da internet.",
"MessageAddRepository": "Cliccare sul bottone vicino all'header se si intende aggiungere un nuovo repository.",
"LabelRepositoryNameHelp": "Nome personalizzato per distinguere questo repository dagli altri sul tuo server.",
"LabelRepositoryName": "Nome Repository",
"LabelRepositoryUrlHelp": "URL del repository manifest che si vuole includere.",
"LabelRepositoryUrl": "URL Repository",
"HeaderNewRepository": "Nuovo Repository",
"MessageNoRepositories": "Nessun repository."
}

View File

@ -435,7 +435,6 @@
"HeaderResponseProfile": "レスポンスプロファイル",
"HeaderResponseProfileHelp": "レスポンスプロファイルは、特定の種類のメディアを再生するときにデバイスに送信される情報をカスタマイズする方法を提供します。",
"HeaderRestart": "リスタート",
"HeaderRestartingServer": "サーバーの再起動",
"HeaderRevisionHistory": "更新履歴",
"HeaderRunningTasks": "実行中のタスク",
"HeaderScenes": "シーン",

View File

@ -1205,7 +1205,6 @@
"ReplaceAllMetadata": "Barlyq metaderekterdi aýystyrý",
"ReplaceExistingImages": "Bar sýretterdi aýystyrý",
"RequiredForAllRemoteConnections": "Barlyq qashyqtaǵy qosylymdar úshin qajet",
"RestartPleaseWaitMessage": "Jellyfin Server jumysy aıaqtalyp, qaıta iske qosylǵansha deıin kúte turyńyz. Bul bir-eki mınótqa sozylýy múmkin.",
"ResumeAt": "{0} bastap jalǵastyrý",
"Rewind": "Shegindirý",
"RunAtStartup": "Iske qosylýdan bastap oryndaý",
@ -1411,7 +1410,6 @@
"HeaderFavoriteSongs": "Tańdaýly áýender",
"HeaderFavoriteVideos": "Tandaýly beıneler",
"HeaderHome": "Basqy",
"HeaderRestartingServer": "Serverdi qaıta iske qosý",
"LabelAuthProvider": "Túpnusqalyq rastamasyn jetkizýshi:",
"LabelPasswordResetProvider": "Paróldi ysyrý jetkizýshisi:",
"LabelServerName": "Server aty:",

View File

@ -1093,7 +1093,6 @@
"HeaderTuners": "튜너",
"HeaderStopRecording": "녹화 중지",
"HeaderStartNow": "지금 시작",
"HeaderRestartingServer": "서버 재시작",
"HeaderPhotoAlbums": "사진 앨범",
"HeaderNewDevices": "새 장치",
"HeaderMyDevice": "내 장치",
@ -1267,7 +1266,6 @@
"RefreshQueued": "새로 고침 대기 중",
"NoPluginConfigurationMessage": "이 플러그인은 설정할 것이 없습니다.",
"OptionExtractChapterImage": "챕터 이미지 추출 활성화",
"RestartPleaseWaitMessage": "Jellyfin 서버가 종료되었다가 다시 시작될 때까지 기다리십시오. 1-2분 정도 걸릴 수 있습니다.",
"Up": "위",
"EasyPasswordHelp": "쉬운 핀 코드는 지원되는 기기에서 오프라인 접근을 할 때나 내부 내트워크 로그인에서 사용됩니다.",
"CriticRating": "평점",

View File

@ -780,7 +780,6 @@
"LabelAllowHWTranscoding": "Leisti naudoti aparatinę įrangą perkodavimui",
"LabelAllowedRemoteAddresses": "Nuotolinis IP adresų filtras:",
"LabelAllowedRemoteAddressesMode": "Nuotolinio IP adresų filtro režimas:",
"HeaderRestartingServer": "Serveris perkraunamas",
"HeaderLoginFailure": "Prisijungimo klaida",
"Hide": "Paslėpti",
"LabelAll": "Visi",

View File

@ -266,7 +266,6 @@
"HeaderSeasons": "Sezonas",
"HeaderSchedule": "Grafiks",
"HeaderRevisionHistory": "Revīziju Vēsture",
"HeaderRestartingServer": "Restartē Serveri",
"HeaderRestart": "Restartēt",
"HeaderRemoveMediaLocation": "Noņemt Multvides Atrašanās Vietu",
"HeaderRemoveMediaFolder": "Noņemt Multvides Mapi",

View File

@ -1226,7 +1226,6 @@
"HeaderKodiMetadataHelp": "For å aktivere eller deaktivere NFO-metadata, gå til bibliotekoppsettet i Jellyfin og finn valgene for lagring av metadata.",
"OptionArtist": "Artist",
"HeaderPhotoAlbums": "Fotoalbum",
"HeaderRestartingServer": "Serveren starter på nytt",
"HeaderSecondsValue": "{0} sekunder",
"LabelAllowedRemoteAddresses": "Filter for eksterne IP-adresser:",
"LabelAllowedRemoteAddressesMode": "Modus for filter for eksterne IP-adresser:",
@ -1407,7 +1406,6 @@
"Previous": "Forrige",
"Primary": "Primær",
"RequiredForAllRemoteConnections": "Påkrevd for alle eksterne tilkoblinger",
"RestartPleaseWaitMessage": "Vennligst vent mens Jellyfin-serveren skrus av og restartes. Dette kan ta et minutt eller to.",
"RunAtStartup": "Kjør ved oppstart",
"SaveSubtitlesIntoMediaFolders": "Lagre undertekster i mediemapper",
"SaveSubtitlesIntoMediaFoldersHelp": "Lagring av undertekster ved siden av videofilene vil gjøre det lettere å behandle dem.",

View File

@ -1090,7 +1090,6 @@
"ReplaceAllMetadata": "Alle metadata vervangen",
"ReplaceExistingImages": "Bestaande afbeeldingen vervangen",
"RequiredForAllRemoteConnections": "Vereist voor alle externe verbindingen",
"RestartPleaseWaitMessage": "Wacht totdat Jellyfin Server is afgesloten en opnieuw is gestart. Dit kan een paar minuten duren.",
"ResumeAt": "Hervatten vanaf {0}",
"Rewind": "Terugspoelen",
"RunAtStartup": "Uitvoeren bij opstarten",
@ -1301,7 +1300,6 @@
"HeaderJellyfinServer": "Jellyfin Server",
"HeaderLiveTv": "Live TV",
"HeaderMedia": "Media",
"HeaderRestartingServer": "Server wordt herstart",
"HeaderTracks": "Nummers",
"HeaderTuners": "Stemmers",
"InstantMix": "Instant mix",

View File

@ -1171,7 +1171,6 @@
"ReplaceAllMetadata": "Zastępuj wszystkie metadane",
"ReplaceExistingImages": "Zastępuj istniejące obrazy",
"RequiredForAllRemoteConnections": "Wymagane dla wszystkich zdalnych połączeń",
"RestartPleaseWaitMessage": "Czekaj na zamknięcie i ponowne uruchomienie serwera Jellyfin. To może trwać ok. jednej, dwóch minut.",
"ResumeAt": "Wznów odtwarzanie od {0}",
"Rewind": "Do tyłu",
"RunAtStartup": "Uruchamiaj po starcie",
@ -1368,7 +1367,6 @@
"HeaderFavoriteSongs": "Ulubione utwory",
"HeaderFavoriteVideos": "Ulubione Filmy",
"HeaderHome": "Strona główna",
"HeaderRestartingServer": "Ponowne uruchamianie serwera",
"LabelAuthProvider": "Dostawca autentykacji:",
"LabelDynamicExternalId": "{0} Id:",
"LabelFormat": "Format:",

View File

@ -1132,7 +1132,6 @@
"ReplaceAllMetadata": "Substituir todos os metadados",
"ReplaceExistingImages": "Substituir imagens existentes",
"RequiredForAllRemoteConnections": "Necessário para todas as conexões remotas",
"RestartPleaseWaitMessage": "Por favor, aguarde enquanto o Servidor Jellyfin reinicia. Isto pode levar um ou dois minutos.",
"ResumeAt": "Retomar de {0}",
"Rewind": "Retroceder",
"RunAtStartup": "Executar ao iniciar",
@ -1350,7 +1349,6 @@
"HeaderFavoriteSongs": "Músicas favoritas",
"HeaderFavoriteVideos": "Videos favoritos",
"HeaderHome": "Inicio",
"HeaderRestartingServer": "Reiniciando servidor",
"LabelAuthProvider": "Provedor de autenticação:",
"LabelServerName": "Nome do servidor:",
"LabelTranscodePath": "Pasta de transcodificação:",
@ -1561,5 +1559,13 @@
"EnableFasterAnimationsHelp": "Usar animações e transições mais rápidas",
"EnableFasterAnimations": "Animações mais rápidas",
"EnableDecodingColorDepth10Vp9": "Habilitar decodificação de hardware de 10 bits para VP9",
"EnableDecodingColorDepth10Hevc": "Habilitar decodificação de hardware de 10 bits para HEVC"
"EnableDecodingColorDepth10Hevc": "Habilitar decodificação de hardware de 10 bits para HEVC",
"TabRepositories": "Repositórios",
"MessageAddRepository": "Se você deseja adicionar um repositório, clique no botão próximo ao cabeçalho e preencha as informações requisitadas.",
"LabelRepositoryNameHelp": "Um nome personalizado para distinguir esse repositório dos outros adicionados ao seu servidor.",
"LabelRepositoryName": "Nome do repositório",
"LabelRepositoryUrlHelp": "A localização do manifesto do repositório que você deseja incluir.",
"LabelRepositoryUrl": "URL do repositório",
"HeaderNewRepository": "Novo repositório",
"MessageNoRepositories": "Não há repositórios."
}

View File

@ -997,7 +997,6 @@
"Runtime": "Duração",
"RunAtStartup": "Executar no arranque",
"ResumeAt": "Retomar a partir de {0}",
"RestartPleaseWaitMessage": "Por favor aguarde enquanto o Servidor Jellyfin reinicia. Poderá demorar alguns minutos.",
"RequiredForAllRemoteConnections": "Necessário para todas as ligações externas",
"ReplaceAllMetadata": "Substituir todos os metadados",
"RepeatOne": "Repetir este",
@ -1182,7 +1181,6 @@
"CopyStreamURL": "Copiar URL da transmissão",
"Disc": "Disco",
"EnableBackdrops": "Imagens de Fundo",
"HeaderRestartingServer": "A reiniciar o Servidor",
"HeaderTags": "Etiquetas",
"LabelLogs": "Registos:",
"LabelSortTitle": "Título para ordenação:",

View File

@ -1,7 +1,6 @@
{
"HeaderTypeImageFetchers": "{0} Pesquisadores de Imagens",
"HeaderSubtitleDownloads": "Transferências de Legendas",
"HeaderRestartingServer": "A reiniciar o servidor",
"HeaderKodiMetadataHelp": "Para ativar ou desativar metadados, editar uma biblioteca nas configurações e localizar a seção dos metadados.",
"HeaderFetcherSettings": "Definições do Pesquisador",
"HeaderFavoritePeople": "Pessoas Preferidas",
@ -121,7 +120,6 @@
"RunAtStartup": "Executar no arranque",
"Rewind": "Retroceder",
"ResumeAt": "Retomar a partir de {0}",
"RestartPleaseWaitMessage": "Por favor aguarde enquanto o Servidor Jellyfin reinicia. Isto poderá demorar alguns minutos.",
"RequiredForAllRemoteConnections": "Necessário para todas as ligações externas",
"ReplaceExistingImages": "Substituir imagens existentes",
"ReplaceAllMetadata": "Substituir todos os metadados",

View File

@ -493,7 +493,6 @@
"HeaderRemoveMediaLocation": "Eliminați locația Media",
"HeaderResponseProfile": "Profilul de răspuns",
"HeaderRestart": "Repornire",
"HeaderRestartingServer": "Se repornește serverul",
"HeaderRevisionHistory": "Istoricul reviziilor",
"HeaderRunningTasks": "În desfășurare",
"HeaderScenes": "Scene",
@ -1049,7 +1048,7 @@
"MessagePleaseWait": "Te rog așteaptă. Poate dura un minut.",
"MessagePlayAccessRestricted": "Redarea acestui conținut este în prezent restricționată. Vă rugăm să contactați administratorul serverului pentru mai multe informații.",
"MessagePasswordResetForUsers": "Următorii utilizatori au resetat parolele. Acum se pot conecta cu codurile pin care au fost utilizate pentru a efectua resetarea.",
"MessageNoTrailersFound": "Nu s-au găsit trailere. Instalați canalul Trailer pentru a îmbunătăți experiența dvs. de film adăugând o bibliotecă de trailere din internet.",
"MessageNoTrailersFound": "Instalați canalul Trailer pentru a îmbunătăți experiența dvs. de film adăugând o bibliotecă de trailere din internet.",
"MessageNoServersAvailable": "Nu au fost găsite servere folosind descoperirea automată de servere.",
"MessageNoPluginsInstalled": "Nu aveți plugin-uri instalate.",
"MessageNoMovieSuggestionsAvailable": "În prezent, nu există sugestii de film. Începeți să vizionați și să evaluați filmele, apoi reveniți pentru a vedea recomandările dvs.",
@ -1227,7 +1226,6 @@
"RunAtStartup": "Rulați la pornire",
"Rewind": "Derulează",
"ResumeAt": "Reluați de la {0}",
"RestartPleaseWaitMessage": "Vă rugăm să așteptați cât Jellyfin Server se închide și repornește. Acest lucru poate dura un minut sau două.",
"RequiredForAllRemoteConnections": "Obligatoriu pentru toate conexiunile distante",
"ReplaceExistingImages": "Înlocuiți toate imaginile",
"ReplaceAllMetadata": "Înlocuiți toate metadatele",
@ -1553,5 +1551,12 @@
"EnableBlurhashHelp": "Imaginile care sunt în curs de încărcare vor fi afișate cu un marcaj întinat",
"EnableBlurhash": "Activați marcatoarele întinate pentru imagini",
"ShowMore": "Arată mai mult",
"ShowLess": "Arată mai puțin"
"ShowLess": "Arată mai puțin",
"ButtonCast": "Proiectează",
"ButtonSyncPlay": "SyncPlay",
"MessageNoGenresAvailable": "Permiteți unor furnizori de metadate să tragă genul media de pe internet.",
"EnableFasterAnimationsHelp": "Utilizați animații și tranziții mai rapide",
"EnableFasterAnimations": "Animații mai rapide",
"EnableDecodingColorDepth10Vp9": "Activați decodarea hardware pe 10 biți pentru VP9",
"EnableDecodingColorDepth10Hevc": "Activați decodarea hardware pe 10 biți pentru HEVC"
}

View File

@ -919,7 +919,7 @@
"MessageNoAvailablePlugins": "Плагинов не имеется.",
"MessageNoMovieSuggestionsAvailable": "В настоящее время предложений фильмов не имеются. Начните смотреть и оценивать свои фильмы, а затем вернитесь, чтобы просмотреть рекомендации.",
"MessageNoPluginsInstalled": "Нет установленных плагинов.",
"MessageNoTrailersFound": "Трейлеры не найдены. Установите канал трейлеров, чтобы повысить своё впечатление от фильма путём добавления собрания интернет-трейлеров.",
"MessageNoTrailersFound": "Установите канал трейлеров, чтобы повысить своё впечатление от фильма путём добавления собрания интернет-трейлеров.",
"MessageNothingHere": "Здесь ничего нет.",
"MessagePasswordResetForUsers": "Следующие пользователи сбросили свои пароли. Теперь они могут войти с помощью PIN-кодов, которые использовались для сброса.",
"MessagePlayAccessRestricted": "Воспроизведение данного содержания в настоящее время ограничено. За дополнительными сведениями обратитесь к администратору сервера.",
@ -1183,7 +1183,6 @@
"ReplaceAllMetadata": "Замена всех метаданных",
"ReplaceExistingImages": "Замена имеющихся изображений",
"RequiredForAllRemoteConnections": "Требуется для всех внешних подключений",
"RestartPleaseWaitMessage": "Подождите, пока Jellyfin Server выключится и перезапустится. Это может занять минуту или две.",
"ResumeAt": "Возобновить с {0}",
"Rewind": "Отмотать",
"RunAtStartup": "Запускать при старте системы",
@ -1388,7 +1387,6 @@
"HeaderFavoriteSongs": "Избранные композиции",
"HeaderFavoriteVideos": "Избранные видео",
"HeaderHome": "Главное",
"HeaderRestartingServer": "Перезапустить сервер",
"LabelAuthProvider": "Поставщик аутентификации:",
"LabelPasswordResetProvider": "Поставщик сброса пароля:",
"LabelServerName": "Имя сервера:",

View File

@ -236,7 +236,7 @@
"HeaderMedia": "Médiá",
"HeaderMediaInfo": "Informácie o médiu",
"HeaderMetadataSettings": "Nastavenia metadát",
"HeaderMoreLikeThis": "Podobné ako toto",
"HeaderMoreLikeThis": "Podobné položky",
"HeaderMovies": "Filmy",
"HeaderMusicQuality": "Kvalita hudby",
"HeaderMusicVideos": "Hudobné videá",
@ -728,7 +728,6 @@
"RepeatOne": "Opakovať jedno",
"ReplaceAllMetadata": "Nahradiť všetky metadáta",
"ReplaceExistingImages": "Nahradiť existujúce obrázky",
"RestartPleaseWaitMessage": "Počkajte prosím kým sa Jellyfin Server vypne a znova naštartuje. Môže to trvať minútu alebo dve.",
"ResumeAt": "Pokračovať od {0}",
"RunAtStartup": "Spustiť pri štarte",
"Saturday": "Sobota",
@ -777,7 +776,7 @@
"TabCatalog": "Katalóg",
"TabChannels": "Kanály",
"TabCodecs": "Kodeky",
"TabCollections": "Zbierky",
"TabCollections": "Kolekcie",
"TabContainers": "Kontajnery",
"TabDashboard": "Dashboard",
"TabDevices": "Zariadenia",
@ -1045,7 +1044,6 @@
"HideWatchedContentFromLatestMedia": "Skryť pozreté položky zo zoznamu najnovších médií",
"HeaderTranscodingProfile": "Profil prekódovania",
"HeaderSeriesOptions": "Nastavenia seriálov",
"HeaderRestartingServer": "Server sa reštartuje",
"HeaderParentalRatings": "Rodičovské hodnotenia",
"HeaderEnabledFields": "Povolené polia",
"HeaderAudioLanguages": "Jazyk zvuku",
@ -1269,7 +1267,7 @@
"OptionAllowVideoPlaybackRemuxing": "Povoliť prehrávanie videa, ktoré vyžaduje konverziu bez opätovného enkódovania",
"OptionAllowSyncTranscoding": "Povoliť sťahovanie a synchronizáciu medií, ktoré vyžadujú transkódovanie",
"OptionAllowMediaPlaybackTranscodingHelp": "Obmedzenie prístupu ku transkódovaniu môže spôsobiť zlyhania prehrávania v Jellyfin aplikáciách kvôli nepodporovaným formátom medií.",
"MessageNoTrailersFound": "Neboli nájdené žiadne trailery. Nainštalujte Trailer kanál pre rozšírenie vášho filmového zážitku pridaním knižnice trailerov z internetu.",
"MessageNoTrailersFound": "Nainštalujte Trailer kanál pre rozšírenie vášho filmového zážitku pridaním knižnice trailerov z internetu.",
"LanNetworksHelp": "Zoznam IP adries alebo IP/netmask záznamov pre všetky siete oddelené čiarkami ktoré budú považované za lokálnu sieť pri vynucovaní obmedzenia šírky pásma. Pokiaľ je toto nastavené, všetky ostatné IP adresy budú považované za vonkajšiu sieť a budú podliehať obmedzeniam šírky pásma vonkajšej siete. Pokiaľ pole ostane prázdne, podsieť serveru bude považovaná za lokálnu sieť.",
"LabelUserAgent": "User agent:",
"LabelEnableBlastAliveMessagesHelp": "Povolte v prípade, že server nie je viditeľný inými UPnP zariadeniami na vašej sieti.",
@ -1292,7 +1290,7 @@
"MessagePlayAccessRestricted": "Prehrávanie tohoto obsahuje je aktuálne obmedzené. Prosím, kontaktujte svojho administrátora servera pre viac informácií.",
"MessagePasswordResetForUsers": "Nasledujúci používatelia si nechali obnoviť heslo. Teraz sa môžu prihlásiť s PIN kódom, ktorý použijú k vykonaniu obnovy hesla.",
"MessageNoServersAvailable": "Žiadne servery neboli nájdené pomocou automatického objavovania serverov.",
"MessageNoMovieSuggestionsAvailable": "Žiadne filmové návrhy nie sú v súčastnosti k dispozícií. Začnite pozerať a hodnotiť vaše filmy, potom sa sem vráťte pre vaše odporúčania.",
"MessageNoMovieSuggestionsAvailable": "V súčastnosti nie sú k dispozícií žiadne filmové návrhy. Začnite pozerať a hodnotiť vaše filmy, potom sa sem vráťte pre Vaše odporúčania.",
"MessageNoCollectionsAvailable": "Kolekcie vám umožnia užiť si vlastné zoskupenia filmov, seriálov a albumov. Kliknite na tlačítko + pre začatie vytvárania kolekcie.",
"MessageInstallPluginFromApp": "Tento zásuvný modul musí byť nainštalovaný z aplikácie, ktorú chcete používať.",
"MessageImageTypeNotSelected": "Prosím, vyberte typ obrázku z rozbalovacieho menu.",
@ -1520,12 +1518,12 @@
"HeaderHttpsSettings": "Nastavenia HTTPS",
"HeaderDVR": "DVR",
"SaveChanges": "Uložiť zmeny",
"MessageSyncPlayErrorMedia": "Povolenie synchronizácie prehrávania zlyhalo! Chyba média.",
"MessageSyncPlayErrorMissingSession": "Zapnutie synchronizácie prehrávania zlyhalo! Aktívna relácia nebola nájdená.",
"MessageSyncPlayErrorNoActivePlayer": "Nebol nájdený žiadny aktívny prehrávač. Synchronizácia prehrávania bola vypnutá.",
"MessageSyncPlayErrorMedia": "Povolenie funkcie SyncPlay zlyhalo! Chyba média.",
"MessageSyncPlayErrorMissingSession": "Zapnutie funkcie SyncPlay zlyhalo! Aktívna relácia nebola nájdená.",
"MessageSyncPlayErrorNoActivePlayer": "Nebol nájdený žiadny aktívny prehrávač. Funkcia SyncPlay bola vypnutá.",
"MessageSyncPlayErrorAccessingGroups": "Pri načítaní zoznamu skupín sa vyskytla chyba.",
"MessageSyncPlayLibraryAccessDenied": "Prístup k tomuto obsahuje je obmedzený.",
"MessageSyncPlayJoinGroupDenied": "K použitiu synchronizácie prehrávania je vyžadované povolenie.",
"MessageSyncPlayJoinGroupDenied": "K použitiu funkcie SyncPlay je požadované povolenie.",
"MessageSyncPlayCreateGroupDenied": "K vytvoreniu skupiny je požadované povolenie.",
"MessageSyncPlayGroupDoesNotExist": "Pripojenie ku skupine zlyhalo, pretože skupina neexistuje.",
"MessageSyncPlayPlaybackPermissionRequired": "K prehrávaniu je potrebné povolenie.",
@ -1533,13 +1531,13 @@
"MessageSyncPlayGroupWait": "Prehrávanie používateľa <b>{0}</b> sa načítava...",
"MessageSyncPlayUserLeft": "Používateľ <b>{0}</b> opustil skupinu.",
"MessageSyncPlayUserJoined": "Používateľ <b>{0}</b> sa pripojil k skupine.",
"MessageSyncPlayDisabled": "Synchronizácia prehrávania zakázana.",
"MessageSyncPlayEnabled": "Synchronizácia prehrávania povolená.",
"LabelSyncPlayAccess": "Prístup k synchronizácií prehrávania",
"MessageSyncPlayDisabled": "SyncPlay zakázaný.",
"MessageSyncPlayEnabled": "SyncPlay povolený.",
"LabelSyncPlayAccess": "Prístup k funkcií SyncPlay",
"LabelSyncPlayAccessNone": "Zakázať pre tohoto používateľa",
"LabelSyncPlayAccessJoinGroups": "Povoliť použivateľovi pripájať sa do skupín",
"LabelSyncPlayAccessCreateAndJoinGroups": "Povoliť používateľovi vytvárať a pripájať sa do skupín",
"LabelSyncPlayLeaveGroupDescription": "Zakázať synchronizáciu prehrávania",
"LabelSyncPlayLeaveGroupDescription": "Zakázať SyncPlay",
"LabelSyncPlayLeaveGroup": "Opustiť skupinu",
"LabelSyncPlayNewGroupDescription": "Vytvoriť novú skupinu",
"LabelSyncPlayNewGroup": "Nová skupina",
@ -1547,13 +1545,28 @@
"LabelSyncPlayPlaybackDiff": "Rozdiel v dobe prehrávania:",
"MillisecondsUnit": "ms",
"LabelSyncPlayTimeOffset": "Časový rozdiel so serverom:",
"HeaderSyncPlayEnabled": "Synchronizácia prehrávania je povolená",
"HeaderSyncPlayEnabled": "SyncPlay je povolené",
"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.",
"SyncPlayAccessHelp": "Vyberte úroveň prístupu pre tohto používateľa k funkcií SyncPlay. SyncPlay umožňuje zosynchronizovať prehrávanie s ostatnými zariadeniami.",
"EnableDetailsBannerHelp": "Zobrazí banner na vrchnej časti detailu položky.",
"EnableDetailsBanner": "Detail banneru",
"EnableBlurhashHelp": "Obrázky, ktoré sa stále načítavajú budú zobrazené ako dočasný obrázok s rozmazaným pozadím",
"EnableBlurhash": "Povoliť obrázok s rozmazaným pozadím pre chýbajúce obrázky",
"ShowMore": "Zobraziť viac",
"ShowLess": "Zobraziť menej"
"ShowLess": "Zobraziť menej",
"ButtonCast": "Prenášať",
"ButtonSyncPlay": "SyncPlay",
"MessageNoGenresAvailable": "Povoliť vybraným metadáta poskytovateľom stiahnuť žánre z internetu.",
"EnableFasterAnimationsHelp": "Použiť rýchlejšiu animáciu a prechody",
"EnableFasterAnimations": "Rýchlejšia animácia",
"EnableDecodingColorDepth10Vp9": "Povoliť 10-Bitové hardvérové dekódovanie pre VP9",
"EnableDecodingColorDepth10Hevc": "Povoliť 10-Bitové hardvérové dekódovanie pre HEVC",
"LabelRepositoryUrl": "URL adresa repozitára",
"HeaderNewRepository": "Nový repozitár",
"MessageNoRepositories": "Neexistujú žiadne repozitáre.",
"TabRepositories": "Repozitáre",
"MessageAddRepository": "Pokiaľ chcete pridať repozitár, kliknite na tlačidlo vedľa hlavičky a vyplňte požadované informácie.",
"LabelRepositoryNameHelp": "Vlastné pomenovanie, ktoré slúži na odlíšenie tohto repozitára od ostatných repozitárov pridaných na vašom serveri.",
"LabelRepositoryName": "Názov repozitára",
"LabelRepositoryUrlHelp": "Umiestnenie manifestu repozitára, ktorý chcete zahrnúť."
}

View File

@ -312,7 +312,6 @@
"HeaderSchedule": "Urnik",
"HeaderScenes": "Scene",
"HeaderRunningTasks": "Aktivni procesi",
"HeaderRestartingServer": "Ponovno zaganjanje",
"HeaderRestart": "Ponovni zagon",
"HeaderResponseProfileHelp": "Profili odziva omogočajo prilagoditev informacij poslanih sprejemniku pri predvajanju določenih vrst predstavnosti.",
"HeaderResponseProfile": "Profil odziva",

View File

@ -1097,7 +1097,6 @@
"RepeatOne": "Upprepa en gång",
"ReplaceAllMetadata": "Ersätt all metadata",
"ReplaceExistingImages": "Skriv över befintliga bilder",
"RestartPleaseWaitMessage": "Vänligen vänta medan Jellyfin-servern stängs av och startar om. Detta kan ta en minut eller två.",
"ResumeAt": "Återuppta från {0}",
"RunAtStartup": "Kör vid uppstart",
"Runtime": "Speltid",
@ -1317,7 +1316,6 @@
"HeaderImageOptions": "Bildalternativ",
"Absolute": "Komplett",
"HeaderFavoritePeople": "Favoritmänniskor",
"HeaderRestartingServer": "Startar om server",
"HeaderStatus": "Status",
"LabelPostProcessor": "Program för efterbehandling:",
"LabelPleaseRestart": "Ändringar genomförs efter att webbklienten manuellt har laddats om .",

View File

@ -569,7 +569,6 @@
"HeaderSchedule": "Zamanla",
"HeaderRunningTasks": "Çalışan Görevler",
"HeaderRevisionHistory": "Revizyon Geçmişi",
"HeaderRestartingServer": "Sunucu Yeniden Başlıyor",
"HeaderRestart": "Yeniden Başlat",
"HeaderRemoveMediaLocation": "Medya Konumunu Kaldır",
"HeaderRemoveMediaFolder": "Medya Klasörünü Kaldır",

View File

@ -553,7 +553,6 @@
"HeaderScenes": "Phân Cảnh",
"HeaderRunningTasks": "Những Tác Vụ Hoạt Động",
"HeaderRevisionHistory": "Lịch Sử Chỉnh Sửa",
"HeaderRestartingServer": "Đang Khởi Động Lại Máy Chủ",
"HeaderRestart": "Khởi Động Lại",
"HeaderResponseProfileHelp": "Hồ sơ phản hồi là phương thức tuỳ chỉnh thông tin gửi về thiết bị phát khi phát một số nội dung nhất định.",
"HeaderResponseProfile": "Hồ Sơ Phản Hồi",

View File

@ -871,7 +871,7 @@
"MessageNoAvailablePlugins": "没有可用的插件。",
"MessageNoMovieSuggestionsAvailable": "没有可用的电影建议。开始观看你的电影并进行评分,再回过头来查看你的建议。",
"MessageNoPluginsInstalled": "你没有安装插件。",
"MessageNoTrailersFound": "未发现任何预告片。安装 Trailer channel 以通过添加一个网络预告片媒体库来增强你的电影体验。",
"MessageNoTrailersFound": "安装 Trailer channel 以通过添加一个网络预告片媒体库来增强你的电影体验。",
"MessageNothingHere": "这里没有可显示的内容。",
"MessagePasswordResetForUsers": "下列用户的密码已被重置。他们现在可以用执行复位的pin码登录。",
"MessagePleaseEnsureInternetMetadata": "请确认已启用从网络上下载媒体资料的选项。",
@ -1313,7 +1313,7 @@
"Directors": "导演",
"ColorTransfer": "色彩转换",
"ConfirmDeleteItem": "这将同时在磁盘和媒体库中删除这个项目。确认删除?",
"ConfirmDeleteItems": "这将同时在磁盘和媒体库中删除这些项目。确认删除",
"ConfirmDeleteItems": "从媒体库中删除这些项目时,也会同时从文件系统中删除。确定要删除吗",
"ConfirmEndPlayerSession": "确认要关闭位于{0}的Jellyfin吗",
"ValueSeconds": "{0}秒",
"Features": "功能",
@ -1350,7 +1350,6 @@
"HeaderNextEpisodePlayingInValue": "下一集在 {0} 后播放",
"HeaderNextVideoPlayingInValue": "下一部影片在 {0} 后播放",
"HeaderPlayOn": "播放在",
"HeaderRestartingServer": "服务器重启中",
"HeaderSeriesStatus": "系列状态",
"HeaderStopRecording": "停止录制",
"Horizontal": "横向",
@ -1358,7 +1357,7 @@
"LabelKeepUpTo": "保持:",
"LabelPasswordResetProvider": "密码重置提供者:",
"LabelPersonRoleHelp": "示例:冰淇淋卡车司机",
"LabelSelectFolderGroups": "自动将下列文件夹中的内容分组到视图中,如电影、音乐、剧集:",
"LabelSelectFolderGroups": "自动将来自下列文件夹的内容分组至电影、音乐、电视等视图中",
"LabelSelectFolderGroupsHelp": "未选中的文件夹将显示在自身的视图中。",
"LabelUserLoginAttemptsBeforeLockout": "用户被封禁前可尝试的次数:",
"DashboardVersionNumber": "版本:{0}",
@ -1398,7 +1397,6 @@
"Recordings": "录音",
"RefreshDialogHelp": "元数据根据设置和Jellyfin服务器中启用的网络服务进行刷新。",
"RepeatEpisodes": "重复剧集",
"RestartPleaseWaitMessage": "请等待Jellyfin服务关闭和重启这将花费几分钟时间。",
"Schedule": "日程",
"Screenshot": "屏幕截图",
"SeriesDisplayOrderHelp": "按播出日期、DVD 顺序或编号对剧集进行排序。",
@ -1524,19 +1522,19 @@
"HeaderDVR": "DVR",
"LabelNightly": "开发版",
"MessageSyncPlayErrorAccessingGroups": "访问群组列表时发生错误。",
"MessageSyncPlayLibraryAccessDenied": "搜限制的访问权限。",
"MessageSyncPlayCreateGroupDenied": "需要权限创建该组。",
"MessageSyncPlayGroupDoesNotExist": "无法加入群组,该群组不存在。",
"MessageSyncPlayLibraryAccessDenied": "对此内容的访问受到限制。",
"MessageSyncPlayCreateGroupDenied": "需要权限以创建群组。",
"MessageSyncPlayGroupDoesNotExist": "无法加入群组,因为该群组不存在。",
"MessageSyncPlayPlaybackPermissionRequired": "需要播放权限。",
"MessageSyncPlayGroupWait": "<b>{0}</b> 正在缓冲...",
"MessageSyncPlayUserLeft": "<b>{0}</b> 已离开组。",
"MessageSyncPlayUserJoined": "<b>{0}</b> 已加入该组。",
"MessageSyncPlayUserLeft": "<b>{0}</b> 已离开组。",
"MessageSyncPlayUserJoined": "<b>{0}</b> 已加入该组。",
"LabelSyncPlayAccessNone": "禁用此用户",
"LabelSyncPlayAccessJoinGroups": "允许用户加入群组",
"LabelSyncPlayAccessCreateAndJoinGroups": "允许用户创建和加入群组",
"LabelSyncPlayLeaveGroup": "离开组",
"LabelSyncPlayNewGroupDescription": "创建一个新组",
"LabelSyncPlayNewGroup": "新组",
"LabelSyncPlayLeaveGroup": "离开组",
"LabelSyncPlayNewGroupDescription": "创建一个新的群组",
"LabelSyncPlayNewGroup": "新建群组",
"LabelSyncPlaySyncMethod": "同步方式:",
"MillisecondsUnit": "毫秒",
"LabelSyncPlayTimeOffset": "服务器时间偏移:",
@ -1544,5 +1542,36 @@
"HeaderSyncPlaySelectGroup": "加入群组",
"EnableDetailsBannerHelp": "在项目详细信息页面的顶部显示横幅图片。",
"EnableDecodingColorDepth10": "启用 10-Bit 硬件解码",
"EnableDecodingColorDepth10Help" : "在支持的硬件上启用 10-Bit 硬件解码。仅对 HEVC 和 VP9 格式起作用。如果你遇到了播放问题,请关闭这个选项。"
"EnableDecodingColorDepth10Help": "在支持的硬件上启用 10-Bit 硬件解码。仅对 HEVC 和 VP9 格式起作用。如果你遇到了播放问题,请关闭这个选项。",
"LabelSyncPlayLeaveGroupDescription": "关闭同步播放",
"EnableDetailsBanner": "详细信息页面的横幅",
"ButtonCast": "投射",
"ButtonSyncPlay": "同步播放",
"EnableBlurhashHelp": "仍在加载的图片将显示带有模糊的占位符",
"EnableBlurhash": "为图片启用模糊的占位符",
"SyncPlayAccessHelp": "为此用户选择对同步播放功能的访问级别。同步播放让你可以和其他设备同步播放进度。",
"ShowMore": "显示更多",
"ShowLess": "显示更少",
"MessageSyncPlayErrorMedia": "同步播放启用失败!媒体错误。",
"MessageSyncPlayErrorMissingSession": "同步播放启用失败!找不到 Session。",
"MessageSyncPlayErrorNoActivePlayer": "未找到活动的用户。同步播放已被关闭。",
"MessageSyncPlayJoinGroupDenied": "需要权限以使用同步播放。",
"MessageSyncPlayNoGroupsAvailable": "暂无可用的群组。先播放点什么吧。",
"MessageSyncPlayDisabled": "同步播放已关闭。",
"MessageSyncPlayEnabled": "同步播放已开启。",
"LabelSyncPlayPlaybackDiff": "播放时间差距:",
"EnableFasterAnimationsHelp": "使用更快的动画和转场效果",
"EnableFasterAnimations": "更快的动画",
"EnableDecodingColorDepth10Vp9": "启用 VP9 10-Bit 硬件解码",
"EnableDecodingColorDepth10Hevc": "启用 HEVC 10-Bit 硬件解码",
"HeaderNewRepository": "新建存储库",
"TabRepositories": "存储库",
"MessageNoGenresAvailable": "启用一些元数据提供程序以便从互联网获取媒体风格。",
"MessageAddRepository": "如果要添加存储库,请单击标题旁边的按钮,然后填写所需的信息。",
"LabelRepositoryNameHelp": "一个自定义名称,用于区分该存储库和添加到服务器的任何其他存储库。",
"LabelRepositoryName": "存储库名称",
"LabelRepositoryUrlHelp": "您要添加的存储库清单的位置。",
"LabelRepositoryUrl": "存储库 URL",
"MessageNoRepositories": "暂无存储库。",
"LabelSyncPlayAccess": "同步播放访问控制"
}

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