mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge branch 'master' into migrate-to-ES6-57
This commit is contained in:
commit
4fa691d80d
81 changed files with 3983 additions and 3826 deletions
24
package.json
24
package.json
|
@ -63,7 +63,7 @@
|
||||||
"fast-text-encoding": "^1.0.3",
|
"fast-text-encoding": "^1.0.3",
|
||||||
"flv.js": "^1.5.0",
|
"flv.js": "^1.5.0",
|
||||||
"headroom.js": "^0.11.0",
|
"headroom.js": "^0.11.0",
|
||||||
"hls.js": "^0.14.7",
|
"hls.js": "^0.14.8",
|
||||||
"howler": "^2.2.0",
|
"howler": "^2.2.0",
|
||||||
"intersection-observer": "^0.11.0",
|
"intersection-observer": "^0.11.0",
|
||||||
"jellyfin-apiclient": "^1.4.1",
|
"jellyfin-apiclient": "^1.4.1",
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
"sortablejs": "^1.10.2",
|
"sortablejs": "^1.10.2",
|
||||||
"swiper": "^5.4.5",
|
"swiper": "^5.4.5",
|
||||||
"webcomponents.js": "^0.7.24",
|
"webcomponents.js": "^0.7.24",
|
||||||
"whatwg-fetch": "^3.3.1"
|
"whatwg-fetch": "^3.4.0"
|
||||||
},
|
},
|
||||||
"babel": {
|
"babel": {
|
||||||
"presets": [
|
"presets": [
|
||||||
|
@ -127,6 +127,8 @@
|
||||||
"src/components/itemHelper.js",
|
"src/components/itemHelper.js",
|
||||||
"src/components/itemidentifier/itemidentifier.js",
|
"src/components/itemidentifier/itemidentifier.js",
|
||||||
"src/components/itemMediaInfo/itemMediaInfo.js",
|
"src/components/itemMediaInfo/itemMediaInfo.js",
|
||||||
|
"src/components/itemsrefresher.js",
|
||||||
|
"src/components/layoutManager.js",
|
||||||
"src/components/lazyLoader/lazyLoaderIntersectionObserver.js",
|
"src/components/lazyLoader/lazyLoaderIntersectionObserver.js",
|
||||||
"src/components/libraryoptionseditor/libraryoptionseditor.js",
|
"src/components/libraryoptionseditor/libraryoptionseditor.js",
|
||||||
"src/components/listview/listview.js",
|
"src/components/listview/listview.js",
|
||||||
|
@ -158,19 +160,28 @@
|
||||||
"src/components/recordingcreator/seriesrecordingeditor.js",
|
"src/components/recordingcreator/seriesrecordingeditor.js",
|
||||||
"src/components/recordingcreator/recordinghelper.js",
|
"src/components/recordingcreator/recordinghelper.js",
|
||||||
"src/components/refreshdialog/refreshdialog.js",
|
"src/components/refreshdialog/refreshdialog.js",
|
||||||
|
"src/components/remotecontrol/remotecontrol.js",
|
||||||
"src/components/sanatizefilename.js",
|
"src/components/sanatizefilename.js",
|
||||||
"src/components/scrollManager.js",
|
"src/components/scrollManager.js",
|
||||||
|
"src/plugins/chromecastPlayer/plugin.js",
|
||||||
|
"src/components/slideshow/slideshow.js",
|
||||||
|
"src/components/sortmenu/sortmenu.js",
|
||||||
"src/plugins/htmlVideoPlayer/plugin.js",
|
"src/plugins/htmlVideoPlayer/plugin.js",
|
||||||
|
"src/plugins/logoScreensaver/plugin.js",
|
||||||
|
"src/plugins/playAccessValidation/plugin.js",
|
||||||
"src/components/search/searchfields.js",
|
"src/components/search/searchfields.js",
|
||||||
"src/components/search/searchresults.js",
|
"src/components/search/searchresults.js",
|
||||||
"src/components/settingshelper.js",
|
"src/components/settingshelper.js",
|
||||||
"src/components/shortcuts.js",
|
"src/components/shortcuts.js",
|
||||||
|
"src/components/subtitleeditor/subtitleeditor.js",
|
||||||
|
"src/components/subtitlesync/subtitlesync.js",
|
||||||
"src/components/subtitlesettings/subtitleappearancehelper.js",
|
"src/components/subtitlesettings/subtitleappearancehelper.js",
|
||||||
"src/components/subtitlesettings/subtitlesettings.js",
|
"src/components/subtitlesettings/subtitlesettings.js",
|
||||||
"src/components/syncPlay/groupSelectionMenu.js",
|
"src/components/syncPlay/groupSelectionMenu.js",
|
||||||
"src/components/syncPlay/playbackPermissionManager.js",
|
"src/components/syncPlay/playbackPermissionManager.js",
|
||||||
"src/components/syncPlay/syncPlayManager.js",
|
"src/components/syncPlay/syncPlayManager.js",
|
||||||
"src/components/syncPlay/timeSyncManager.js",
|
"src/components/syncPlay/timeSyncManager.js",
|
||||||
|
"src/components/tabbedview/tabbedview.js",
|
||||||
"src/components/viewManager/viewManager.js",
|
"src/components/viewManager/viewManager.js",
|
||||||
"src/components/tvproviders/schedulesdirect.js",
|
"src/components/tvproviders/schedulesdirect.js",
|
||||||
"src/components/tvproviders/xmltv.js",
|
"src/components/tvproviders/xmltv.js",
|
||||||
|
@ -200,13 +211,16 @@
|
||||||
"src/controllers/music/musicplaylists.js",
|
"src/controllers/music/musicplaylists.js",
|
||||||
"src/controllers/music/musicrecommended.js",
|
"src/controllers/music/musicrecommended.js",
|
||||||
"src/controllers/music/songs.js",
|
"src/controllers/music/songs.js",
|
||||||
"src/controllers/dashboard/mediaLibrary.js",
|
"src/controllers/dashboard/library.js",
|
||||||
"src/controllers/dashboard/metadataImages.js",
|
"src/controllers/dashboard/metadataImages.js",
|
||||||
"src/controllers/dashboard/metadatanfo.js",
|
"src/controllers/dashboard/metadatanfo.js",
|
||||||
"src/controllers/dashboard/networking.js",
|
"src/controllers/dashboard/networking.js",
|
||||||
"src/controllers/dashboard/notifications/notification.js",
|
"src/controllers/dashboard/notifications/notification.js",
|
||||||
"src/controllers/dashboard/notifications/notifications.js",
|
"src/controllers/dashboard/notifications/notifications.js",
|
||||||
"src/controllers/dashboard/playback.js",
|
"src/controllers/dashboard/playback.js",
|
||||||
|
"src/controllers/dashboard/plugins/add/index.js",
|
||||||
|
"src/controllers/dashboard/plugins/installed/index.js",
|
||||||
|
"src/controllers/dashboard/plugins/available/index.js",
|
||||||
"src/controllers/dashboard/plugins/repositories/index.js",
|
"src/controllers/dashboard/plugins/repositories/index.js",
|
||||||
"src/controllers/dashboard/scheduledtasks/scheduledtask.js",
|
"src/controllers/dashboard/scheduledtasks/scheduledtask.js",
|
||||||
"src/controllers/dashboard/scheduledtasks/scheduledtasks.js",
|
"src/controllers/dashboard/scheduledtasks/scheduledtasks.js",
|
||||||
|
@ -218,6 +232,8 @@
|
||||||
"src/controllers/dashboard/users/userparentalcontrol.js",
|
"src/controllers/dashboard/users/userparentalcontrol.js",
|
||||||
"src/controllers/dashboard/users/userpasswordpage.js",
|
"src/controllers/dashboard/users/userpasswordpage.js",
|
||||||
"src/controllers/dashboard/users/userprofilespage.js",
|
"src/controllers/dashboard/users/userprofilespage.js",
|
||||||
|
"src/controllers/home.js",
|
||||||
|
"src/controllers/list.js",
|
||||||
"src/controllers/edititemmetadata.js",
|
"src/controllers/edititemmetadata.js",
|
||||||
"src/controllers/favorites.js",
|
"src/controllers/favorites.js",
|
||||||
"src/controllers/hometab.js",
|
"src/controllers/hometab.js",
|
||||||
|
@ -278,6 +294,7 @@
|
||||||
"src/elements/emby-tabs/emby-tabs.js",
|
"src/elements/emby-tabs/emby-tabs.js",
|
||||||
"src/elements/emby-textarea/emby-textarea.js",
|
"src/elements/emby-textarea/emby-textarea.js",
|
||||||
"src/elements/emby-toggle/emby-toggle.js",
|
"src/elements/emby-toggle/emby-toggle.js",
|
||||||
|
"src/libraries/screensavermanager.js",
|
||||||
"src/libraries/navdrawer/navdrawer.js",
|
"src/libraries/navdrawer/navdrawer.js",
|
||||||
"src/libraries/scroller.js",
|
"src/libraries/scroller.js",
|
||||||
"src/plugins/backdropScreensaver/plugin.js",
|
"src/plugins/backdropScreensaver/plugin.js",
|
||||||
|
@ -301,6 +318,7 @@
|
||||||
"src/scripts/autoThemes.js",
|
"src/scripts/autoThemes.js",
|
||||||
"src/scripts/themeManager.js",
|
"src/scripts/themeManager.js",
|
||||||
"src/scripts/keyboardNavigation.js",
|
"src/scripts/keyboardNavigation.js",
|
||||||
|
"src/scripts/libraryMenu.js",
|
||||||
"src/scripts/libraryBrowser.js",
|
"src/scripts/libraryBrowser.js",
|
||||||
"src/scripts/mouseManager.js",
|
"src/scripts/mouseManager.js",
|
||||||
"src/scripts/multiDownload.js",
|
"src/scripts/multiDownload.js",
|
||||||
|
|
|
@ -2,6 +2,8 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
||||||
'use strict';
|
'use strict';
|
||||||
focusManager = focusManager.default || focusManager;
|
focusManager = focusManager.default || focusManager;
|
||||||
|
|
||||||
|
layoutManager = layoutManager.default || layoutManager;
|
||||||
|
|
||||||
function onSubmit(e) {
|
function onSubmit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -8,7 +8,6 @@ import browser from 'browser';
|
||||||
import layoutManager from 'layoutManager';
|
import layoutManager from 'layoutManager';
|
||||||
import scrollHelper from 'scrollHelper';
|
import scrollHelper from 'scrollHelper';
|
||||||
import globalize from 'globalize';
|
import globalize from 'globalize';
|
||||||
import require from 'require';
|
|
||||||
import 'emby-checkbox';
|
import 'emby-checkbox';
|
||||||
import 'paper-icon-button-light';
|
import 'paper-icon-button-light';
|
||||||
import 'emby-button';
|
import 'emby-button';
|
||||||
|
@ -317,7 +316,7 @@ import 'cardStyle';
|
||||||
function showEditor(itemId, serverId, itemType) {
|
function showEditor(itemId, serverId, itemType) {
|
||||||
loading.show();
|
loading.show();
|
||||||
|
|
||||||
require(['text!./imageDownloader.template.html'], function (template) {
|
import('text!./imageDownloader.template.html').then(({default: template}) => {
|
||||||
const apiClient = connectionManager.getApiClient(serverId);
|
const apiClient = connectionManager.getApiClient(serverId);
|
||||||
|
|
||||||
currentItemId = itemId;
|
currentItemId = itemId;
|
||||||
|
|
|
@ -1,131 +1,130 @@
|
||||||
define(['playbackManager', 'serverNotifications', 'events'], function (playbackManager, serverNotifications, events) {
|
import playbackManager from 'playbackManager';
|
||||||
'use strict';
|
import serverNotifications from 'serverNotifications';
|
||||||
|
import events from 'events';
|
||||||
|
|
||||||
serverNotifications = serverNotifications.default || serverNotifications;
|
function onUserDataChanged(e, apiClient, userData) {
|
||||||
playbackManager = playbackManager.default || playbackManager;
|
const instance = this;
|
||||||
|
|
||||||
function onUserDataChanged(e, apiClient, userData) {
|
const eventsToMonitor = getEventsToMonitor(instance);
|
||||||
var instance = this;
|
|
||||||
|
|
||||||
var eventsToMonitor = getEventsToMonitor(instance);
|
|
||||||
|
|
||||||
// TODO: Check user data change reason?
|
|
||||||
if (eventsToMonitor.indexOf('markfavorite') !== -1) {
|
|
||||||
instance.notifyRefreshNeeded();
|
|
||||||
} else if (eventsToMonitor.indexOf('markplayed') !== -1) {
|
|
||||||
instance.notifyRefreshNeeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getEventsToMonitor(instance) {
|
|
||||||
var options = instance.options;
|
|
||||||
var monitor = options ? options.monitorEvents : null;
|
|
||||||
if (monitor) {
|
|
||||||
return monitor.split(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function onTimerCreated(e, apiClient, data) {
|
|
||||||
var instance = this;
|
|
||||||
|
|
||||||
if (getEventsToMonitor(instance).indexOf('timers') !== -1) {
|
|
||||||
instance.notifyRefreshNeeded();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onSeriesTimerCreated(e, apiClient, data) {
|
|
||||||
var instance = this;
|
|
||||||
if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) {
|
|
||||||
instance.notifyRefreshNeeded();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onTimerCancelled(e, apiClient, data) {
|
|
||||||
var instance = this;
|
|
||||||
|
|
||||||
if (getEventsToMonitor(instance).indexOf('timers') !== -1) {
|
|
||||||
instance.notifyRefreshNeeded();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onSeriesTimerCancelled(e, apiClient, data) {
|
|
||||||
var instance = this;
|
|
||||||
if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) {
|
|
||||||
instance.notifyRefreshNeeded();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onLibraryChanged(e, apiClient, data) {
|
|
||||||
var instance = this;
|
|
||||||
var eventsToMonitor = getEventsToMonitor(instance);
|
|
||||||
if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) {
|
|
||||||
// yes this is an assumption
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var itemsAdded = data.ItemsAdded || [];
|
|
||||||
var itemsRemoved = data.ItemsRemoved || [];
|
|
||||||
if (!itemsAdded.length && !itemsRemoved.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var options = instance.options || {};
|
|
||||||
var parentId = options.parentId;
|
|
||||||
if (parentId) {
|
|
||||||
var foldersAddedTo = data.FoldersAddedTo || [];
|
|
||||||
var foldersRemovedFrom = data.FoldersRemovedFrom || [];
|
|
||||||
var collectionFolders = data.CollectionFolders || [];
|
|
||||||
|
|
||||||
if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// TODO: Check user data change reason?
|
||||||
|
if (eventsToMonitor.indexOf('markfavorite') !== -1) {
|
||||||
|
instance.notifyRefreshNeeded();
|
||||||
|
} else if (eventsToMonitor.indexOf('markplayed') !== -1) {
|
||||||
instance.notifyRefreshNeeded();
|
instance.notifyRefreshNeeded();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onPlaybackStopped(e, stopInfo) {
|
function getEventsToMonitor(instance) {
|
||||||
var instance = this;
|
const options = instance.options;
|
||||||
|
const monitor = options ? options.monitorEvents : null;
|
||||||
|
if (monitor) {
|
||||||
|
return monitor.split(',');
|
||||||
|
}
|
||||||
|
|
||||||
var state = stopInfo.state;
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
var eventsToMonitor = getEventsToMonitor(instance);
|
function onTimerCreated(e, apiClient, data) {
|
||||||
if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') {
|
const instance = this;
|
||||||
if (eventsToMonitor.indexOf('videoplayback') !== -1) {
|
|
||||||
instance.notifyRefreshNeeded(true);
|
if (getEventsToMonitor(instance).indexOf('timers') !== -1) {
|
||||||
return;
|
instance.notifyRefreshNeeded();
|
||||||
}
|
return;
|
||||||
} else if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Audio') {
|
}
|
||||||
if (eventsToMonitor.indexOf('audioplayback') !== -1) {
|
}
|
||||||
instance.notifyRefreshNeeded(true);
|
|
||||||
return;
|
function onSeriesTimerCreated(e, apiClient, data) {
|
||||||
}
|
const instance = this;
|
||||||
|
if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) {
|
||||||
|
instance.notifyRefreshNeeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTimerCancelled(e, apiClient, data) {
|
||||||
|
const instance = this;
|
||||||
|
|
||||||
|
if (getEventsToMonitor(instance).indexOf('timers') !== -1) {
|
||||||
|
instance.notifyRefreshNeeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSeriesTimerCancelled(e, apiClient, data) {
|
||||||
|
const instance = this;
|
||||||
|
if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) {
|
||||||
|
instance.notifyRefreshNeeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onLibraryChanged(e, apiClient, data) {
|
||||||
|
const instance = this;
|
||||||
|
const eventsToMonitor = getEventsToMonitor(instance);
|
||||||
|
if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) {
|
||||||
|
// yes this is an assumption
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const itemsAdded = data.ItemsAdded || [];
|
||||||
|
const itemsRemoved = data.ItemsRemoved || [];
|
||||||
|
if (!itemsAdded.length && !itemsRemoved.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = instance.options || {};
|
||||||
|
const parentId = options.parentId;
|
||||||
|
if (parentId) {
|
||||||
|
const foldersAddedTo = data.FoldersAddedTo || [];
|
||||||
|
const foldersRemovedFrom = data.FoldersRemovedFrom || [];
|
||||||
|
const collectionFolders = data.CollectionFolders || [];
|
||||||
|
|
||||||
|
if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addNotificationEvent(instance, name, handler, owner) {
|
instance.notifyRefreshNeeded();
|
||||||
var localHandler = handler.bind(instance);
|
}
|
||||||
|
|
||||||
|
function onPlaybackStopped(e, stopInfo) {
|
||||||
|
const instance = this;
|
||||||
|
|
||||||
|
const state = stopInfo.state;
|
||||||
|
|
||||||
|
const eventsToMonitor = getEventsToMonitor(instance);
|
||||||
|
if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') {
|
||||||
|
if (eventsToMonitor.indexOf('videoplayback') !== -1) {
|
||||||
|
instance.notifyRefreshNeeded(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Audio') {
|
||||||
|
if (eventsToMonitor.indexOf('audioplayback') !== -1) {
|
||||||
|
instance.notifyRefreshNeeded(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addNotificationEvent(instance, name, handler, owner) {
|
||||||
|
const localHandler = handler.bind(instance);
|
||||||
|
owner = owner || serverNotifications;
|
||||||
|
events.on(owner, name, localHandler);
|
||||||
|
instance['event_' + name] = localHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeNotificationEvent(instance, name, owner) {
|
||||||
|
const handler = instance['event_' + name];
|
||||||
|
if (handler) {
|
||||||
owner = owner || serverNotifications;
|
owner = owner || serverNotifications;
|
||||||
events.on(owner, name, localHandler);
|
events.off(owner, name, handler);
|
||||||
instance['event_' + name] = localHandler;
|
instance['event_' + name] = null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function removeNotificationEvent(instance, name, owner) {
|
class ItemsRefresher {
|
||||||
var handler = instance['event_' + name];
|
constructor(options) {
|
||||||
if (handler) {
|
|
||||||
owner = owner || serverNotifications;
|
|
||||||
events.off(owner, name, handler);
|
|
||||||
instance['event_' + name] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function ItemsRefresher(options) {
|
|
||||||
this.options = options || {};
|
this.options = options || {};
|
||||||
|
|
||||||
addNotificationEvent(this, 'UserDataChanged', onUserDataChanged);
|
addNotificationEvent(this, 'UserDataChanged', onUserDataChanged);
|
||||||
|
@ -137,18 +136,18 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||||
addNotificationEvent(this, 'playbackstop', onPlaybackStopped, playbackManager);
|
addNotificationEvent(this, 'playbackstop', onPlaybackStopped, playbackManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemsRefresher.prototype.pause = function () {
|
pause() {
|
||||||
clearRefreshInterval(this, true);
|
clearRefreshInterval(this, true);
|
||||||
|
|
||||||
this.paused = true;
|
this.paused = true;
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsRefresher.prototype.resume = function (options) {
|
resume(options) {
|
||||||
this.paused = false;
|
this.paused = false;
|
||||||
|
|
||||||
var refreshIntervalEndTime = this.refreshIntervalEndTime;
|
const refreshIntervalEndTime = this.refreshIntervalEndTime;
|
||||||
if (refreshIntervalEndTime) {
|
if (refreshIntervalEndTime) {
|
||||||
var remainingMs = refreshIntervalEndTime - new Date().getTime();
|
const remainingMs = refreshIntervalEndTime - new Date().getTime();
|
||||||
if (remainingMs > 0 && !this.needsRefresh) {
|
if (remainingMs > 0 && !this.needsRefresh) {
|
||||||
resetRefreshInterval(this, remainingMs);
|
resetRefreshInterval(this, remainingMs);
|
||||||
} else {
|
} else {
|
||||||
|
@ -162,9 +161,9 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsRefresher.prototype.refreshItems = function () {
|
refreshItems() {
|
||||||
if (!this.fetchData) {
|
if (!this.fetchData) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
@ -177,15 +176,15 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||||
this.needsRefresh = false;
|
this.needsRefresh = false;
|
||||||
|
|
||||||
return this.fetchData().then(onDataFetched.bind(this));
|
return this.fetchData().then(onDataFetched.bind(this));
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsRefresher.prototype.notifyRefreshNeeded = function (isInForeground) {
|
notifyRefreshNeeded(isInForeground) {
|
||||||
if (this.paused) {
|
if (this.paused) {
|
||||||
this.needsRefresh = true;
|
this.needsRefresh = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var timeout = this.refreshTimeout;
|
const timeout = this.refreshTimeout;
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
}
|
}
|
||||||
|
@ -195,44 +194,9 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||||
} else {
|
} else {
|
||||||
this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 10000);
|
this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 10000);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
function clearRefreshInterval(instance, isPausing) {
|
|
||||||
if (instance.refreshInterval) {
|
|
||||||
clearInterval(instance.refreshInterval);
|
|
||||||
instance.refreshInterval = null;
|
|
||||||
|
|
||||||
if (!isPausing) {
|
|
||||||
instance.refreshIntervalEndTime = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetRefreshInterval(instance, intervalMs) {
|
destroy() {
|
||||||
clearRefreshInterval(instance);
|
|
||||||
|
|
||||||
if (!intervalMs) {
|
|
||||||
var options = instance.options;
|
|
||||||
if (options) {
|
|
||||||
intervalMs = options.refreshIntervalMs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (intervalMs) {
|
|
||||||
instance.refreshInterval = setInterval(instance.notifyRefreshNeeded.bind(instance), intervalMs);
|
|
||||||
instance.refreshIntervalEndTime = new Date().getTime() + intervalMs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onDataFetched(result) {
|
|
||||||
resetRefreshInterval(this);
|
|
||||||
|
|
||||||
if (this.afterRefresh) {
|
|
||||||
this.afterRefresh(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemsRefresher.prototype.destroy = function () {
|
|
||||||
clearRefreshInterval(this);
|
clearRefreshInterval(this);
|
||||||
|
|
||||||
removeNotificationEvent(this, 'UserDataChanged');
|
removeNotificationEvent(this, 'UserDataChanged');
|
||||||
|
@ -245,7 +209,42 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||||
|
|
||||||
this.fetchData = null;
|
this.fetchData = null;
|
||||||
this.options = null;
|
this.options = null;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ItemsRefresher;
|
function clearRefreshInterval(instance, isPausing) {
|
||||||
});
|
if (instance.refreshInterval) {
|
||||||
|
clearInterval(instance.refreshInterval);
|
||||||
|
instance.refreshInterval = null;
|
||||||
|
|
||||||
|
if (!isPausing) {
|
||||||
|
instance.refreshIntervalEndTime = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetRefreshInterval(instance, intervalMs) {
|
||||||
|
clearRefreshInterval(instance);
|
||||||
|
|
||||||
|
if (!intervalMs) {
|
||||||
|
const options = instance.options;
|
||||||
|
if (options) {
|
||||||
|
intervalMs = options.refreshIntervalMs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intervalMs) {
|
||||||
|
instance.refreshInterval = setInterval(instance.notifyRefreshNeeded.bind(instance), intervalMs);
|
||||||
|
instance.refreshIntervalEndTime = new Date().getTime() + intervalMs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDataFetched(result) {
|
||||||
|
resetRefreshInterval(this);
|
||||||
|
|
||||||
|
if (this.afterRefresh) {
|
||||||
|
this.afterRefresh(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ItemsRefresher;
|
||||||
|
|
|
@ -1,23 +1,19 @@
|
||||||
define(['browser', 'appSettings', 'events'], function (browser, appSettings, events) {
|
import browser from 'browser';
|
||||||
'use strict';
|
import appSettings from 'appSettings';
|
||||||
|
import events from 'events';
|
||||||
|
|
||||||
browser = browser.default || browser;
|
function setLayout(instance, layout, selectedLayout) {
|
||||||
|
if (layout === selectedLayout) {
|
||||||
function setLayout(instance, layout, selectedLayout) {
|
instance[layout] = true;
|
||||||
if (layout === selectedLayout) {
|
document.documentElement.classList.add('layout-' + layout);
|
||||||
instance[layout] = true;
|
} else {
|
||||||
document.documentElement.classList.add('layout-' + layout);
|
instance[layout] = false;
|
||||||
} else {
|
document.documentElement.classList.remove('layout-' + layout);
|
||||||
instance[layout] = false;
|
|
||||||
document.documentElement.classList.remove('layout-' + layout);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function LayoutManager() {
|
class LayoutManager {
|
||||||
|
setLayout(layout, save) {
|
||||||
}
|
|
||||||
|
|
||||||
LayoutManager.prototype.setLayout = function (layout, save) {
|
|
||||||
if (!layout || layout === 'auto') {
|
if (!layout || layout === 'auto') {
|
||||||
this.autoLayout();
|
this.autoLayout();
|
||||||
|
|
||||||
|
@ -35,13 +31,13 @@ define(['browser', 'appSettings', 'events'], function (browser, appSettings, eve
|
||||||
}
|
}
|
||||||
|
|
||||||
events.trigger(this, 'modechange');
|
events.trigger(this, 'modechange');
|
||||||
};
|
}
|
||||||
|
|
||||||
LayoutManager.prototype.getSavedLayout = function (layout) {
|
getSavedLayout(layout) {
|
||||||
return appSettings.get('layout');
|
return appSettings.get('layout');
|
||||||
};
|
}
|
||||||
|
|
||||||
LayoutManager.prototype.autoLayout = function () {
|
autoLayout() {
|
||||||
// Take a guess at initial layout. The consuming app can override
|
// Take a guess at initial layout. The consuming app can override
|
||||||
if (browser.mobile) {
|
if (browser.mobile) {
|
||||||
this.setLayout('mobile', false);
|
this.setLayout('mobile', false);
|
||||||
|
@ -50,16 +46,16 @@ define(['browser', 'appSettings', 'events'], function (browser, appSettings, eve
|
||||||
} else {
|
} else {
|
||||||
this.setLayout(this.defaultLayout || 'tv', false);
|
this.setLayout(this.defaultLayout || 'tv', false);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
LayoutManager.prototype.init = function () {
|
init() {
|
||||||
var saved = this.getSavedLayout();
|
const saved = this.getSavedLayout();
|
||||||
if (saved) {
|
if (saved) {
|
||||||
this.setLayout(saved, false);
|
this.setLayout(saved, false);
|
||||||
} else {
|
} else {
|
||||||
this.autoLayout();
|
this.autoLayout();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new LayoutManager();
|
export default new LayoutManager();
|
||||||
});
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import loading from 'loading';
|
||||||
import focusManager from 'focusManager';
|
import focusManager from 'focusManager';
|
||||||
import connectionManager from 'connectionManager';
|
import connectionManager from 'connectionManager';
|
||||||
import globalize from 'globalize';
|
import globalize from 'globalize';
|
||||||
import require from 'require';
|
|
||||||
import shell from 'shell';
|
import shell from 'shell';
|
||||||
import 'emby-checkbox';
|
import 'emby-checkbox';
|
||||||
import 'emby-input';
|
import 'emby-input';
|
||||||
|
@ -37,7 +36,7 @@ import 'flexStyles';
|
||||||
|
|
||||||
function submitUpdatedItem(form, item) {
|
function submitUpdatedItem(form, item) {
|
||||||
function afterContentTypeUpdated() {
|
function afterContentTypeUpdated() {
|
||||||
require(['toast'], function (toast) {
|
import('toast').then(({default: toast}) => {
|
||||||
toast(globalize.translate('MessageItemSaved'));
|
toast(globalize.translate('MessageItemSaved'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -227,7 +226,7 @@ import 'flexStyles';
|
||||||
}
|
}
|
||||||
|
|
||||||
function editPerson(context, person, index) {
|
function editPerson(context, person, index) {
|
||||||
require(['personEditor'], function (personEditor) {
|
import('personEditor').then(({default: personEditor}) => {
|
||||||
personEditor.show(person).then(function (updatedPerson) {
|
personEditor.show(person).then(function (updatedPerson) {
|
||||||
const isNew = index === -1;
|
const isNew = index === -1;
|
||||||
|
|
||||||
|
@ -246,14 +245,14 @@ import 'flexStyles';
|
||||||
if (parentId) {
|
if (parentId) {
|
||||||
reload(context, parentId, item.ServerId);
|
reload(context, parentId, item.ServerId);
|
||||||
} else {
|
} else {
|
||||||
require(['appRouter'], function (appRouter) {
|
import('appRouter').then(({default: appRouter}) => {
|
||||||
appRouter.goHome();
|
appRouter.goHome();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMoreMenu(context, button, user) {
|
function showMoreMenu(context, button, user) {
|
||||||
require(['itemContextMenu'], function (itemContextMenu) {
|
import('itemContextMenu').then(({default: itemContextMenu}) => {
|
||||||
var item = currentItem;
|
var item = currentItem;
|
||||||
|
|
||||||
itemContextMenu.show({
|
itemContextMenu.show({
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'datetime', 'imageLoader', 'recordingFields', 'events', 'emby-checkbox', 'emby-button', 'emby-collapse', 'emby-input', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, datetime, imageLoader, recordingFields, events) {
|
define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'datetime', 'imageLoader', 'recordingFields', 'events', 'emby-checkbox', 'emby-button', 'emby-collapse', 'emby-input', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, datetime, imageLoader, recordingFields, events) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
layoutManager = layoutManager.default || layoutManager;
|
||||||
scrollHelper = scrollHelper.default || scrollHelper;
|
scrollHelper = scrollHelper.default || scrollHelper;
|
||||||
|
|
||||||
var currentDialog;
|
var currentDialog;
|
||||||
|
|
|
@ -3,6 +3,7 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c
|
||||||
|
|
||||||
scrollHelper = scrollHelper.default || scrollHelper;
|
scrollHelper = scrollHelper.default || scrollHelper;
|
||||||
loading = loading.default || loading;
|
loading = loading.default || loading;
|
||||||
|
layoutManager = layoutManager.default || layoutManager;
|
||||||
|
|
||||||
var currentDialog;
|
var currentDialog;
|
||||||
var recordingDeleted = false;
|
var recordingDeleted = false;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,49 +1,51 @@
|
||||||
define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'layoutManager', 'connectionManager', 'globalize', 'userSettings', 'emby-select', 'paper-icon-button-light', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (require, dom, focusManager, dialogHelper, loading, layoutManager, connectionManager, globalize, userSettings) {
|
import dialogHelper from 'dialogHelper';
|
||||||
'use strict';
|
import layoutManager from 'layoutManager';
|
||||||
|
import globalize from 'globalize';
|
||||||
|
import * as userSettings from 'userSettings';
|
||||||
|
import 'emby-select';
|
||||||
|
import 'paper-icon-button-light';
|
||||||
|
import 'material-icons';
|
||||||
|
import 'css!./../formdialog';
|
||||||
|
import 'emby-button';
|
||||||
|
import 'flexStyles';
|
||||||
|
|
||||||
focusManager = focusManager.default || focusManager;
|
function onSubmit(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function onSubmit(e) {
|
function initEditor(context, settings) {
|
||||||
e.preventDefault();
|
context.querySelector('form').addEventListener('submit', onSubmit);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function initEditor(context, settings) {
|
context.querySelector('.selectSortOrder').value = settings.sortOrder;
|
||||||
context.querySelector('form').addEventListener('submit', onSubmit);
|
context.querySelector('.selectSortBy').value = settings.sortBy;
|
||||||
|
}
|
||||||
|
|
||||||
context.querySelector('.selectSortOrder').value = settings.sortOrder;
|
function centerFocus(elem, horiz, on) {
|
||||||
context.querySelector('.selectSortBy').value = settings.sortBy;
|
import('scrollHelper').then(({default: scrollHelper}) => {
|
||||||
}
|
const fn = on ? 'on' : 'off';
|
||||||
|
scrollHelper.centerFocus[fn](elem, horiz);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function centerFocus(elem, horiz, on) {
|
function fillSortBy(context, options) {
|
||||||
require(['scrollHelper'], function (scrollHelper) {
|
const selectSortBy = context.querySelector('.selectSortBy');
|
||||||
scrollHelper = scrollHelper.default || scrollHelper;
|
|
||||||
var fn = on ? 'on' : 'off';
|
|
||||||
scrollHelper.centerFocus[fn](elem, horiz);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function fillSortBy(context, options) {
|
selectSortBy.innerHTML = options.map(function (o) {
|
||||||
var selectSortBy = context.querySelector('.selectSortBy');
|
return '<option value="' + o.value + '">' + o.name + '</option>';
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
selectSortBy.innerHTML = options.map(function (o) {
|
function saveValues(context, settingsKey) {
|
||||||
return '<option value="' + o.value + '">' + o.name + '</option>';
|
userSettings.setFilter(settingsKey + '-sortorder', context.querySelector('.selectSortOrder').value);
|
||||||
}).join('');
|
userSettings.setFilter(settingsKey + '-sortby', context.querySelector('.selectSortBy').value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveValues(context, settings, settingsKey) {
|
class SortMenu {
|
||||||
userSettings.setFilter(settingsKey + '-sortorder', context.querySelector('.selectSortOrder').value);
|
show(options) {
|
||||||
userSettings.setFilter(settingsKey + '-sortby', context.querySelector('.selectSortBy').value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SortMenu() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SortMenu.prototype.show = function (options) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
require(['text!./sortmenu.template.html'], function (template) {
|
import('text!./sortmenu.template.html').then(({default: template}) => {
|
||||||
var dialogOptions = {
|
const dialogOptions = {
|
||||||
removeOnClose: true,
|
removeOnClose: true,
|
||||||
scrollY: false
|
scrollY: false
|
||||||
};
|
};
|
||||||
|
@ -54,11 +56,11 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'layoutMana
|
||||||
dialogOptions.size = 'small';
|
dialogOptions.size = 'small';
|
||||||
}
|
}
|
||||||
|
|
||||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||||
|
|
||||||
dlg.classList.add('formDialog');
|
dlg.classList.add('formDialog');
|
||||||
|
|
||||||
var html = '';
|
let html = '';
|
||||||
|
|
||||||
html += '<div class="formDialogHeader">';
|
html += '<div class="formDialogHeader">';
|
||||||
html += '<button is="paper-icon-button-light" class="btnCancel hide-mouse-idle-tv" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
|
html += '<button is="paper-icon-button-light" class="btnCancel hide-mouse-idle-tv" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
|
||||||
|
@ -81,7 +83,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'layoutMana
|
||||||
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
|
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
var submitted;
|
let submitted;
|
||||||
|
|
||||||
dlg.querySelector('form').addEventListener('change', function () {
|
dlg.querySelector('form').addEventListener('change', function () {
|
||||||
submitted = true;
|
submitted = true;
|
||||||
|
@ -93,7 +95,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'layoutMana
|
||||||
}
|
}
|
||||||
|
|
||||||
if (submitted) {
|
if (submitted) {
|
||||||
saveValues(dlg, options.settings, options.settingsKey);
|
saveValues(dlg, options.settingsKey);
|
||||||
resolve();
|
resolve();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -102,7 +104,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'layoutMana
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return SortMenu;
|
export default SortMenu;
|
||||||
});
|
|
||||||
|
|
|
@ -1,428 +1,437 @@
|
||||||
define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', 'connectionManager', 'loading', 'focusManager', 'dom', 'apphost', 'emby-select', 'listViewStyle', 'paper-icon-button-light', 'css!./../formdialog', 'material-icons', 'css!./subtitleeditor', 'emby-button', 'flexStyles'], function (dialogHelper, require, layoutManager, globalize, userSettings, connectionManager, loading, focusManager, dom, appHost) {
|
import dialogHelper from 'dialogHelper';
|
||||||
'use strict';
|
import layoutManager from 'layoutManager';
|
||||||
|
import globalize from 'globalize';
|
||||||
|
import * as userSettings from 'userSettings';
|
||||||
|
import connectionManager from 'connectionManager';
|
||||||
|
import loading from 'loading';
|
||||||
|
import focusManager from 'focusManager';
|
||||||
|
import dom from 'dom';
|
||||||
|
import 'emby-select';
|
||||||
|
import 'listViewStyle';
|
||||||
|
import 'paper-icon-button-light';
|
||||||
|
import 'css!./../formdialog';
|
||||||
|
import 'material-icons';
|
||||||
|
import 'css!./subtitleeditor';
|
||||||
|
import 'emby-button';
|
||||||
|
import 'flexStyles';
|
||||||
|
|
||||||
loading = loading.default || loading;
|
let currentItem;
|
||||||
focusManager = focusManager.default || focusManager;
|
let hasChanges;
|
||||||
|
|
||||||
var currentItem;
|
function downloadRemoteSubtitles(context, id) {
|
||||||
var hasChanges;
|
let url = 'Items/' + currentItem.Id + '/RemoteSearch/Subtitles/' + id;
|
||||||
|
|
||||||
function downloadRemoteSubtitles(context, id) {
|
let apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||||
var url = 'Items/' + currentItem.Id + '/RemoteSearch/Subtitles/' + id;
|
apiClient.ajax({
|
||||||
|
|
||||||
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
type: 'POST',
|
||||||
apiClient.ajax({
|
url: apiClient.getUrl(url)
|
||||||
|
|
||||||
type: 'POST',
|
}).then(function () {
|
||||||
url: apiClient.getUrl(url)
|
hasChanges = true;
|
||||||
|
|
||||||
|
import('toast').then(({default: toast}) => {
|
||||||
|
toast(globalize.translate('MessageDownloadQueued'));
|
||||||
|
});
|
||||||
|
|
||||||
|
focusManager.autoFocus(context);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteLocalSubtitle(context, index) {
|
||||||
|
let msg = globalize.translate('MessageAreYouSureDeleteSubtitles');
|
||||||
|
|
||||||
|
import('confirm').then(({default: confirm}) => {
|
||||||
|
confirm({
|
||||||
|
|
||||||
|
title: globalize.translate('ConfirmDeletion'),
|
||||||
|
text: msg,
|
||||||
|
confirmText: globalize.translate('Delete'),
|
||||||
|
primary: 'delete'
|
||||||
|
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
hasChanges = true;
|
loading.show();
|
||||||
|
|
||||||
require(['toast'], function (toast) {
|
let itemId = currentItem.Id;
|
||||||
toast(globalize.translate('MessageDownloadQueued'));
|
let url = 'Videos/' + itemId + '/Subtitles/' + index;
|
||||||
});
|
|
||||||
|
|
||||||
focusManager.autoFocus(context);
|
let apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteLocalSubtitle(context, index) {
|
apiClient.ajax({
|
||||||
var msg = globalize.translate('MessageAreYouSureDeleteSubtitles');
|
|
||||||
|
|
||||||
require(['confirm'], function (confirm) {
|
type: 'DELETE',
|
||||||
confirm.default({
|
url: apiClient.getUrl(url)
|
||||||
|
|
||||||
title: globalize.translate('ConfirmDeletion'),
|
|
||||||
text: msg,
|
|
||||||
confirmText: globalize.translate('Delete'),
|
|
||||||
primary: 'delete'
|
|
||||||
|
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
loading.show();
|
hasChanges = true;
|
||||||
|
reload(context, apiClient, itemId);
|
||||||
var itemId = currentItem.Id;
|
|
||||||
var url = 'Videos/' + itemId + '/Subtitles/' + index;
|
|
||||||
|
|
||||||
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
|
||||||
|
|
||||||
apiClient.ajax({
|
|
||||||
|
|
||||||
type: 'DELETE',
|
|
||||||
url: apiClient.getUrl(url)
|
|
||||||
|
|
||||||
}).then(function () {
|
|
||||||
hasChanges = true;
|
|
||||||
reload(context, apiClient, itemId);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function fillSubtitleList(context, item) {
|
function fillSubtitleList(context, item) {
|
||||||
var streams = item.MediaStreams || [];
|
let streams = item.MediaStreams || [];
|
||||||
|
|
||||||
var subs = streams.filter(function (s) {
|
let subs = streams.filter(function (s) {
|
||||||
return s.Type === 'Subtitle';
|
return s.Type === 'Subtitle';
|
||||||
});
|
});
|
||||||
|
|
||||||
var html = '';
|
let html = '';
|
||||||
|
|
||||||
if (subs.length) {
|
if (subs.length) {
|
||||||
html += '<h2>' + globalize.translate('MySubtitles') + '</h2>';
|
html += '<h2>' + globalize.translate('MySubtitles') + '</h2>';
|
||||||
|
|
||||||
html += '<div>';
|
html += '<div>';
|
||||||
|
|
||||||
html += subs.map(function (s) {
|
html += subs.map(function (s) {
|
||||||
var itemHtml = '';
|
let itemHtml = '';
|
||||||
|
|
||||||
var tagName = layoutManager.tv ? 'button' : 'div';
|
let tagName = layoutManager.tv ? 'button' : 'div';
|
||||||
var className = layoutManager.tv && s.Path ? 'listItem listItem-border btnDelete' : 'listItem listItem-border';
|
let className = layoutManager.tv && s.Path ? 'listItem listItem-border btnDelete' : 'listItem listItem-border';
|
||||||
|
|
||||||
if (layoutManager.tv) {
|
|
||||||
className += ' listItem-focusscale listItem-button';
|
|
||||||
}
|
|
||||||
|
|
||||||
className += ' listItem-noborder';
|
|
||||||
|
|
||||||
itemHtml += '<' + tagName + ' class="' + className + '" data-index="' + s.Index + '">';
|
|
||||||
|
|
||||||
itemHtml += '<span class="listItemIcon material-icons closed_caption"></span>';
|
|
||||||
|
|
||||||
itemHtml += '<div class="listItemBody two-line">';
|
|
||||||
|
|
||||||
itemHtml += '<div>';
|
|
||||||
itemHtml += s.DisplayTitle || '';
|
|
||||||
itemHtml += '</div>';
|
|
||||||
|
|
||||||
if (s.Path) {
|
|
||||||
itemHtml += '<div class="secondary listItemBodyText">' + (s.Path) + '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
itemHtml += '</a>';
|
|
||||||
itemHtml += '</div>';
|
|
||||||
|
|
||||||
if (!layoutManager.tv) {
|
|
||||||
if (s.Path) {
|
|
||||||
itemHtml += '<button is="paper-icon-button-light" data-index="' + s.Index + '" title="' + globalize.translate('Delete') + '" class="btnDelete listItemButton"><span class="material-icons delete"></span></button>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
itemHtml += '</' + tagName + '>';
|
|
||||||
|
|
||||||
return itemHtml;
|
|
||||||
}).join('');
|
|
||||||
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
var elem = context.querySelector('.subtitleList');
|
|
||||||
|
|
||||||
if (subs.length) {
|
|
||||||
elem.classList.remove('hide');
|
|
||||||
} else {
|
|
||||||
elem.classList.add('hide');
|
|
||||||
}
|
|
||||||
elem.innerHTML = html;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fillLanguages(context, apiClient, languages) {
|
|
||||||
var selectLanguage = context.querySelector('#selectLanguage');
|
|
||||||
|
|
||||||
selectLanguage.innerHTML = languages.map(function (l) {
|
|
||||||
return '<option value="' + l.ThreeLetterISOLanguageName + '">' + l.DisplayName + '</option>';
|
|
||||||
});
|
|
||||||
|
|
||||||
var lastLanguage = userSettings.get('subtitleeditor-language');
|
|
||||||
if (lastLanguage) {
|
|
||||||
selectLanguage.value = lastLanguage;
|
|
||||||
} else {
|
|
||||||
apiClient.getCurrentUser().then(function (user) {
|
|
||||||
var lang = user.Configuration.SubtitleLanguagePreference;
|
|
||||||
|
|
||||||
if (lang) {
|
|
||||||
selectLanguage.value = lang;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderSearchResults(context, results) {
|
|
||||||
var lastProvider = '';
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
if (!results.length) {
|
|
||||||
context.querySelector('.noSearchResults').classList.remove('hide');
|
|
||||||
context.querySelector('.subtitleResults').innerHTML = '';
|
|
||||||
loading.hide();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.querySelector('.noSearchResults').classList.add('hide');
|
|
||||||
|
|
||||||
for (var i = 0, length = results.length; i < length; i++) {
|
|
||||||
var result = results[i];
|
|
||||||
|
|
||||||
var provider = result.ProviderName;
|
|
||||||
|
|
||||||
if (provider !== lastProvider) {
|
|
||||||
if (i > 0) {
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
html += '<h2>' + provider + '</h2>';
|
|
||||||
html += '<div>';
|
|
||||||
lastProvider = provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
var tagName = layoutManager.tv ? 'button' : 'div';
|
|
||||||
var className = layoutManager.tv ? 'listItem listItem-border btnOptions' : 'listItem listItem-border';
|
|
||||||
if (layoutManager.tv) {
|
if (layoutManager.tv) {
|
||||||
className += ' listItem-focusscale listItem-button';
|
className += ' listItem-focusscale listItem-button';
|
||||||
}
|
}
|
||||||
|
|
||||||
html += '<' + tagName + ' class="' + className + '" data-subid="' + result.Id + '">';
|
className += ' listItem-noborder';
|
||||||
|
|
||||||
html += '<span class="listItemIcon material-icons closed_caption"></span>';
|
itemHtml += '<' + tagName + ' class="' + className + '" data-index="' + s.Index + '">';
|
||||||
|
|
||||||
var bodyClass = result.Comment || result.IsHashMatch ? 'three-line' : 'two-line';
|
itemHtml += '<span class="listItemIcon material-icons closed_caption"></span>';
|
||||||
|
|
||||||
html += '<div class="listItemBody ' + bodyClass + '">';
|
itemHtml += '<div class="listItemBody two-line">';
|
||||||
|
|
||||||
html += '<div>' + (result.Name) + '</div>';
|
itemHtml += '<div>';
|
||||||
html += '<div class="secondary listItemBodyText">';
|
itemHtml += s.DisplayTitle || '';
|
||||||
|
itemHtml += '</div>';
|
||||||
|
|
||||||
if (result.Format) {
|
if (s.Path) {
|
||||||
html += '<span style="margin-right:1em;">' + globalize.translate('FormatValue', result.Format) + '</span>';
|
itemHtml += '<div class="secondary listItemBodyText">' + (s.Path) + '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.DownloadCount != null) {
|
itemHtml += '</a>';
|
||||||
html += '<span>' + globalize.translate('DownloadsValue', result.DownloadCount) + '</span>';
|
itemHtml += '</div>';
|
||||||
}
|
|
||||||
html += '</div>';
|
|
||||||
|
|
||||||
if (result.Comment) {
|
|
||||||
html += '<div class="secondary listItemBodyText">' + (result.Comment) + '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.IsHashMatch) {
|
|
||||||
html += '<div class="secondary listItemBodyText"><div class="inline-flex align-items-center justify-content-center" style="background:#3388cc;color:#fff;padding: .3em 1em;border-radius:1000em;">' + globalize.translate('PerfectMatch') + '</div></div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</div>';
|
|
||||||
|
|
||||||
if (!layoutManager.tv) {
|
if (!layoutManager.tv) {
|
||||||
html += '<button type="button" is="paper-icon-button-light" data-subid="' + result.Id + '" class="btnDownload listItemButton"><span class="material-icons file_download"></span></button>';
|
if (s.Path) {
|
||||||
|
itemHtml += '<button is="paper-icon-button-light" data-index="' + s.Index + '" title="' + globalize.translate('Delete') + '" class="btnDelete listItemButton"><span class="material-icons delete"></span></button>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
html += '</' + tagName + '>';
|
itemHtml += '</' + tagName + '>';
|
||||||
|
|
||||||
|
return itemHtml;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
html += '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
let elem = context.querySelector('.subtitleList');
|
||||||
|
|
||||||
|
if (subs.length) {
|
||||||
|
elem.classList.remove('hide');
|
||||||
|
} else {
|
||||||
|
elem.classList.add('hide');
|
||||||
|
}
|
||||||
|
elem.innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillLanguages(context, apiClient, languages) {
|
||||||
|
let selectLanguage = context.querySelector('#selectLanguage');
|
||||||
|
|
||||||
|
selectLanguage.innerHTML = languages.map(function (l) {
|
||||||
|
return '<option value="' + l.ThreeLetterISOLanguageName + '">' + l.DisplayName + '</option>';
|
||||||
|
});
|
||||||
|
|
||||||
|
let lastLanguage = userSettings.get('subtitleeditor-language');
|
||||||
|
if (lastLanguage) {
|
||||||
|
selectLanguage.value = lastLanguage;
|
||||||
|
} else {
|
||||||
|
apiClient.getCurrentUser().then(function (user) {
|
||||||
|
let lang = user.Configuration.SubtitleLanguagePreference;
|
||||||
|
|
||||||
|
if (lang) {
|
||||||
|
selectLanguage.value = lang;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSearchResults(context, results) {
|
||||||
|
let lastProvider = '';
|
||||||
|
let html = '';
|
||||||
|
|
||||||
|
if (!results.length) {
|
||||||
|
context.querySelector('.noSearchResults').classList.remove('hide');
|
||||||
|
context.querySelector('.subtitleResults').innerHTML = '';
|
||||||
|
loading.hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.querySelector('.noSearchResults').classList.add('hide');
|
||||||
|
|
||||||
|
for (let i = 0, length = results.length; i < length; i++) {
|
||||||
|
let result = results[i];
|
||||||
|
|
||||||
|
let provider = result.ProviderName;
|
||||||
|
|
||||||
|
if (provider !== lastProvider) {
|
||||||
|
if (i > 0) {
|
||||||
|
html += '</div>';
|
||||||
|
}
|
||||||
|
html += '<h2>' + provider + '</h2>';
|
||||||
|
html += '<div>';
|
||||||
|
lastProvider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (results.length) {
|
let tagName = layoutManager.tv ? 'button' : 'div';
|
||||||
html += '</div>';
|
let className = layoutManager.tv ? 'listItem listItem-border btnOptions' : 'listItem listItem-border';
|
||||||
|
if (layoutManager.tv) {
|
||||||
|
className += ' listItem-focusscale listItem-button';
|
||||||
}
|
}
|
||||||
|
|
||||||
var elem = context.querySelector('.subtitleResults');
|
html += '<' + tagName + ' class="' + className + '" data-subid="' + result.Id + '">';
|
||||||
elem.innerHTML = html;
|
|
||||||
|
html += '<span class="listItemIcon material-icons closed_caption"></span>';
|
||||||
|
|
||||||
|
let bodyClass = result.Comment || result.IsHashMatch ? 'three-line' : 'two-line';
|
||||||
|
|
||||||
|
html += '<div class="listItemBody ' + bodyClass + '">';
|
||||||
|
|
||||||
|
html += '<div>' + (result.Name) + '</div>';
|
||||||
|
html += '<div class="secondary listItemBodyText">';
|
||||||
|
|
||||||
|
if (result.Format) {
|
||||||
|
html += '<span style="margin-right:1em;">' + globalize.translate('FormatValue', result.Format) + '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.DownloadCount != null) {
|
||||||
|
html += '<span>' + globalize.translate('DownloadsValue', result.DownloadCount) + '</span>';
|
||||||
|
}
|
||||||
|
html += '</div>';
|
||||||
|
|
||||||
|
if (result.Comment) {
|
||||||
|
html += '<div class="secondary listItemBodyText">' + (result.Comment) + '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.IsHashMatch) {
|
||||||
|
html += '<div class="secondary listItemBodyText"><div class="inline-flex align-items-center justify-content-center" style="background:#3388cc;color:#fff;padding: .3em 1em;border-radius:1000em;">' + globalize.translate('PerfectMatch') + '</div></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
html += '</div>';
|
||||||
|
|
||||||
|
if (!layoutManager.tv) {
|
||||||
|
html += '<button type="button" is="paper-icon-button-light" data-subid="' + result.Id + '" class="btnDownload listItemButton"><span class="material-icons file_download"></span></button>';
|
||||||
|
}
|
||||||
|
|
||||||
|
html += '</' + tagName + '>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (results.length) {
|
||||||
|
html += '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
let elem = context.querySelector('.subtitleResults');
|
||||||
|
elem.innerHTML = html;
|
||||||
|
|
||||||
|
loading.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchForSubtitles(context, language) {
|
||||||
|
userSettings.set('subtitleeditor-language', language);
|
||||||
|
|
||||||
|
loading.show();
|
||||||
|
|
||||||
|
let apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||||
|
let url = apiClient.getUrl('Items/' + currentItem.Id + '/RemoteSearch/Subtitles/' + language);
|
||||||
|
|
||||||
|
apiClient.getJSON(url).then(function (results) {
|
||||||
|
renderSearchResults(context, results);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function reload(context, apiClient, itemId) {
|
||||||
|
context.querySelector('.noSearchResults').classList.add('hide');
|
||||||
|
|
||||||
|
function onGetItem(item) {
|
||||||
|
currentItem = item;
|
||||||
|
|
||||||
|
fillSubtitleList(context, item);
|
||||||
|
let file = item.Path || '';
|
||||||
|
let index = Math.max(file.lastIndexOf('/'), file.lastIndexOf('\\'));
|
||||||
|
if (index > -1) {
|
||||||
|
file = file.substring(index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
context.querySelector('.pathValue').innerHTML = file;
|
||||||
|
context.querySelector('.originalFile').classList.remove('hide');
|
||||||
|
} else {
|
||||||
|
context.querySelector('.pathValue').innerHTML = '';
|
||||||
|
context.querySelector('.originalFile').classList.add('hide');
|
||||||
|
}
|
||||||
|
|
||||||
loading.hide();
|
loading.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchForSubtitles(context, language) {
|
if (typeof itemId === 'string') {
|
||||||
userSettings.set('subtitleeditor-language', language);
|
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(onGetItem);
|
||||||
|
} else {
|
||||||
|
onGetItem(itemId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loading.show();
|
function onSearchSubmit(e) {
|
||||||
|
let form = this;
|
||||||
|
|
||||||
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
let lang = form.querySelector('#selectLanguage', form).value;
|
||||||
var url = apiClient.getUrl('Items/' + currentItem.Id + '/RemoteSearch/Subtitles/' + language);
|
|
||||||
|
|
||||||
apiClient.getJSON(url).then(function (results) {
|
searchForSubtitles(dom.parentWithClass(form, 'formDialogContent'), lang);
|
||||||
renderSearchResults(context, results);
|
|
||||||
});
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSubtitleListClick(e) {
|
||||||
|
let btnDelete = dom.parentWithClass(e.target, 'btnDelete');
|
||||||
|
if (btnDelete) {
|
||||||
|
let index = btnDelete.getAttribute('data-index');
|
||||||
|
let context = dom.parentWithClass(btnDelete, 'subtitleEditorDialog');
|
||||||
|
deleteLocalSubtitle(context, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSubtitleResultsClick(e) {
|
||||||
|
let subtitleId;
|
||||||
|
let context;
|
||||||
|
|
||||||
|
let btnOptions = dom.parentWithClass(e.target, 'btnOptions');
|
||||||
|
if (btnOptions) {
|
||||||
|
subtitleId = btnOptions.getAttribute('data-subid');
|
||||||
|
context = dom.parentWithClass(btnOptions, 'subtitleEditorDialog');
|
||||||
|
showDownloadOptions(btnOptions, context, subtitleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function reload(context, apiClient, itemId) {
|
let btnDownload = dom.parentWithClass(e.target, 'btnDownload');
|
||||||
context.querySelector('.noSearchResults').classList.add('hide');
|
if (btnDownload) {
|
||||||
|
subtitleId = btnDownload.getAttribute('data-subid');
|
||||||
|
context = dom.parentWithClass(btnDownload, 'subtitleEditorDialog');
|
||||||
|
downloadRemoteSubtitles(context, subtitleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onGetItem(item) {
|
function showDownloadOptions(button, context, subtitleId) {
|
||||||
currentItem = item;
|
let items = [];
|
||||||
|
|
||||||
fillSubtitleList(context, item);
|
items.push({
|
||||||
var file = item.Path || '';
|
name: globalize.translate('Download'),
|
||||||
var index = Math.max(file.lastIndexOf('/'), file.lastIndexOf('\\'));
|
id: 'download'
|
||||||
if (index > -1) {
|
});
|
||||||
file = file.substring(index + 1);
|
|
||||||
|
import('actionsheet').then(({default: actionsheet}) => {
|
||||||
|
actionsheet.show({
|
||||||
|
items: items,
|
||||||
|
positionTo: button
|
||||||
|
|
||||||
|
}).then(function (id) {
|
||||||
|
switch (id) {
|
||||||
|
case 'download':
|
||||||
|
downloadRemoteSubtitles(context, subtitleId);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (file) {
|
function centerFocus(elem, horiz, on) {
|
||||||
context.querySelector('.pathValue').innerHTML = file;
|
import('scrollHelper').then(({default: scrollHelper}) => {
|
||||||
context.querySelector('.originalFile').classList.remove('hide');
|
let fn = on ? 'on' : 'off';
|
||||||
} else {
|
scrollHelper.centerFocus[fn](elem, horiz);
|
||||||
context.querySelector('.pathValue').innerHTML = '';
|
});
|
||||||
context.querySelector('.originalFile').classList.add('hide');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
loading.hide();
|
function showEditorInternal(itemId, serverId, template) {
|
||||||
}
|
hasChanges = false;
|
||||||
|
|
||||||
if (typeof itemId === 'string') {
|
let apiClient = connectionManager.getApiClient(serverId);
|
||||||
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(onGetItem);
|
return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
|
||||||
|
let dialogOptions = {
|
||||||
|
removeOnClose: true,
|
||||||
|
scrollY: false
|
||||||
|
};
|
||||||
|
|
||||||
|
if (layoutManager.tv) {
|
||||||
|
dialogOptions.size = 'fullscreen';
|
||||||
} else {
|
} else {
|
||||||
onGetItem(itemId);
|
dialogOptions.size = 'small';
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onSearchSubmit(e) {
|
|
||||||
var form = this;
|
|
||||||
|
|
||||||
var lang = form.querySelector('#selectLanguage', form).value;
|
|
||||||
|
|
||||||
searchForSubtitles(dom.parentWithClass(form, 'formDialogContent'), lang);
|
|
||||||
|
|
||||||
e.preventDefault();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onSubtitleListClick(e) {
|
|
||||||
var btnDelete = dom.parentWithClass(e.target, 'btnDelete');
|
|
||||||
if (btnDelete) {
|
|
||||||
var index = btnDelete.getAttribute('data-index');
|
|
||||||
var context = dom.parentWithClass(btnDelete, 'subtitleEditorDialog');
|
|
||||||
deleteLocalSubtitle(context, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onSubtitleResultsClick(e) {
|
|
||||||
var subtitleId;
|
|
||||||
var context;
|
|
||||||
|
|
||||||
var btnOptions = dom.parentWithClass(e.target, 'btnOptions');
|
|
||||||
if (btnOptions) {
|
|
||||||
subtitleId = btnOptions.getAttribute('data-subid');
|
|
||||||
context = dom.parentWithClass(btnOptions, 'subtitleEditorDialog');
|
|
||||||
showDownloadOptions(btnOptions, context, subtitleId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var btnDownload = dom.parentWithClass(e.target, 'btnDownload');
|
let dlg = dialogHelper.createDialog(dialogOptions);
|
||||||
if (btnDownload) {
|
|
||||||
subtitleId = btnDownload.getAttribute('data-subid');
|
dlg.classList.add('formDialog');
|
||||||
context = dom.parentWithClass(btnDownload, 'subtitleEditorDialog');
|
dlg.classList.add('subtitleEditorDialog');
|
||||||
downloadRemoteSubtitles(context, subtitleId);
|
|
||||||
|
dlg.innerHTML = globalize.translateHtml(template, 'core');
|
||||||
|
|
||||||
|
dlg.querySelector('.originalSubtitleFileLabel').innerHTML = globalize.translate('File');
|
||||||
|
|
||||||
|
dlg.querySelector('.subtitleSearchForm').addEventListener('submit', onSearchSubmit);
|
||||||
|
|
||||||
|
let btnSubmit = dlg.querySelector('.btnSubmit');
|
||||||
|
|
||||||
|
if (layoutManager.tv) {
|
||||||
|
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
|
||||||
|
dlg.querySelector('.btnSearchSubtitles').classList.add('hide');
|
||||||
|
} else {
|
||||||
|
btnSubmit.classList.add('hide');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function showDownloadOptions(button, context, subtitleId) {
|
let editorContent = dlg.querySelector('.formDialogContent');
|
||||||
var items = [];
|
|
||||||
|
|
||||||
items.push({
|
dlg.querySelector('.subtitleList').addEventListener('click', onSubtitleListClick);
|
||||||
name: globalize.translate('Download'),
|
dlg.querySelector('.subtitleResults').addEventListener('click', onSubtitleResultsClick);
|
||||||
id: 'download'
|
|
||||||
|
apiClient.getCultures().then(function (languages) {
|
||||||
|
fillLanguages(editorContent, apiClient, languages);
|
||||||
});
|
});
|
||||||
|
|
||||||
require(['actionsheet'], function (actionsheet) {
|
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||||
actionsheet.show({
|
dialogHelper.close(dlg);
|
||||||
items: items,
|
|
||||||
positionTo: button
|
|
||||||
|
|
||||||
}).then(function (id) {
|
|
||||||
switch (id) {
|
|
||||||
case 'download':
|
|
||||||
downloadRemoteSubtitles(context, subtitleId);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
function centerFocus(elem, horiz, on) {
|
|
||||||
require(['scrollHelper'], function (scrollHelper) {
|
|
||||||
scrollHelper = scrollHelper.default || scrollHelper;
|
|
||||||
var fn = on ? 'on' : 'off';
|
|
||||||
scrollHelper.centerFocus[fn](elem, horiz);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function showEditorInternal(itemId, serverId, template) {
|
|
||||||
hasChanges = false;
|
|
||||||
|
|
||||||
var apiClient = connectionManager.getApiClient(serverId);
|
|
||||||
return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
|
|
||||||
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');
|
|
||||||
dlg.classList.add('subtitleEditorDialog');
|
|
||||||
|
|
||||||
dlg.innerHTML = globalize.translateHtml(template, 'core');
|
|
||||||
|
|
||||||
dlg.querySelector('.originalSubtitleFileLabel').innerHTML = globalize.translate('File');
|
|
||||||
|
|
||||||
dlg.querySelector('.subtitleSearchForm').addEventListener('submit', onSearchSubmit);
|
|
||||||
|
|
||||||
var btnSubmit = dlg.querySelector('.btnSubmit');
|
|
||||||
|
|
||||||
if (layoutManager.tv) {
|
|
||||||
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
|
|
||||||
dlg.querySelector('.btnSearchSubtitles').classList.add('hide');
|
|
||||||
} else {
|
|
||||||
btnSubmit.classList.add('hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
var editorContent = dlg.querySelector('.formDialogContent');
|
|
||||||
|
|
||||||
dlg.querySelector('.subtitleList').addEventListener('click', onSubtitleListClick);
|
|
||||||
dlg.querySelector('.subtitleResults').addEventListener('click', onSubtitleResultsClick);
|
|
||||||
|
|
||||||
apiClient.getCultures().then(function (languages) {
|
|
||||||
fillLanguages(editorContent, apiClient, languages);
|
|
||||||
});
|
|
||||||
|
|
||||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
|
||||||
dialogHelper.close(dlg);
|
|
||||||
});
|
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
dlg.addEventListener('close', function () {
|
|
||||||
if (layoutManager.tv) {
|
|
||||||
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasChanges) {
|
|
||||||
resolve();
|
|
||||||
} else {
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dialogHelper.open(dlg);
|
|
||||||
|
|
||||||
reload(editorContent, apiClient, item);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function showEditor(itemId, serverId) {
|
|
||||||
loading.show();
|
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
require(['text!./subtitleeditor.template.html'], function (template) {
|
dlg.addEventListener('close', function () {
|
||||||
showEditorInternal(itemId, serverId, template).then(resolve, reject);
|
if (layoutManager.tv) {
|
||||||
});
|
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
if (hasChanges) {
|
||||||
show: showEditor
|
resolve();
|
||||||
};
|
} else {
|
||||||
});
|
reject();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogHelper.open(dlg);
|
||||||
|
|
||||||
|
reload(editorContent, apiClient, item);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showEditor(itemId, serverId) {
|
||||||
|
loading.show();
|
||||||
|
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
import('text!./subtitleeditor.template.html').then(({default: template}) => {
|
||||||
|
showEditorInternal(itemId, serverId, template).then(resolve, reject);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
show: showEditor
|
||||||
|
};
|
||||||
|
|
|
@ -1,147 +1,148 @@
|
||||||
define(['playbackManager', 'layoutManager', 'text!./subtitlesync.template.html', 'css!./subtitlesync'], function (playbackManager, layoutManager, template, css) {
|
import playbackManager from 'playbackManager';
|
||||||
'use strict';
|
import layoutManager from 'layoutManager';
|
||||||
|
import template from 'text!./subtitlesync.template.html';
|
||||||
|
import 'css!./subtitlesync';
|
||||||
|
|
||||||
playbackManager = playbackManager.default || playbackManager;
|
let player;
|
||||||
|
let subtitleSyncSlider;
|
||||||
|
let subtitleSyncTextField;
|
||||||
|
let subtitleSyncCloseButton;
|
||||||
|
let subtitleSyncContainer;
|
||||||
|
|
||||||
var player;
|
function init(instance) {
|
||||||
var subtitleSyncSlider;
|
const parent = document.createElement('div');
|
||||||
var subtitleSyncTextField;
|
document.body.appendChild(parent);
|
||||||
var subtitleSyncCloseButton;
|
parent.innerHTML = template;
|
||||||
var subtitleSyncContainer;
|
|
||||||
|
|
||||||
function init(instance) {
|
subtitleSyncSlider = parent.querySelector('.subtitleSyncSlider');
|
||||||
var parent = document.createElement('div');
|
subtitleSyncTextField = parent.querySelector('.subtitleSyncTextField');
|
||||||
document.body.appendChild(parent);
|
subtitleSyncCloseButton = parent.querySelector('.subtitleSync-closeButton');
|
||||||
parent.innerHTML = template;
|
subtitleSyncContainer = parent.querySelector('.subtitleSyncContainer');
|
||||||
|
|
||||||
subtitleSyncSlider = parent.querySelector('.subtitleSyncSlider');
|
if (layoutManager.tv) {
|
||||||
subtitleSyncTextField = parent.querySelector('.subtitleSyncTextField');
|
subtitleSyncSlider.classList.add('focusable');
|
||||||
subtitleSyncCloseButton = parent.querySelector('.subtitleSync-closeButton');
|
// HACK: Delay to give time for registered element attach (Firefox)
|
||||||
subtitleSyncContainer = parent.querySelector('.subtitleSyncContainer');
|
setTimeout(function () {
|
||||||
|
subtitleSyncSlider.enableKeyboardDragging();
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (layoutManager.tv) {
|
subtitleSyncContainer.classList.add('hide');
|
||||||
subtitleSyncSlider.classList.add('focusable');
|
|
||||||
// HACK: Delay to give time for registered element attach (Firefox)
|
|
||||||
setTimeout(function () {
|
|
||||||
subtitleSyncSlider.enableKeyboardDragging();
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
subtitleSyncContainer.classList.add('hide');
|
subtitleSyncTextField.updateOffset = function (offset) {
|
||||||
|
this.textContent = offset + 's';
|
||||||
|
};
|
||||||
|
|
||||||
subtitleSyncTextField.updateOffset = function(offset) {
|
subtitleSyncTextField.addEventListener('click', function () {
|
||||||
this.textContent = offset + 's';
|
// keep focus to prevent fade with osd
|
||||||
};
|
this.hasFocus = true;
|
||||||
|
});
|
||||||
|
|
||||||
subtitleSyncTextField.addEventListener('click', function () {
|
subtitleSyncTextField.addEventListener('keydown', function (event) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
// if input key is enter search for float pattern
|
||||||
|
let inputOffset = /[-+]?\d+\.?\d*/g.exec(this.textContent);
|
||||||
|
if (inputOffset) {
|
||||||
|
inputOffset = inputOffset[0];
|
||||||
|
|
||||||
|
// replace current text by considered offset
|
||||||
|
this.textContent = inputOffset + 's';
|
||||||
|
|
||||||
|
inputOffset = parseFloat(inputOffset);
|
||||||
|
// set new offset
|
||||||
|
playbackManager.setSubtitleOffset(inputOffset, player);
|
||||||
|
// synchronize with slider value
|
||||||
|
subtitleSyncSlider.updateOffset(
|
||||||
|
getPercentageFromOffset(inputOffset));
|
||||||
|
} else {
|
||||||
|
this.textContent = (playbackManager.getPlayerSubtitleOffset(player) || 0) + 's';
|
||||||
|
}
|
||||||
|
this.hasFocus = false;
|
||||||
|
event.preventDefault();
|
||||||
|
} else {
|
||||||
// keep focus to prevent fade with osd
|
// keep focus to prevent fade with osd
|
||||||
this.hasFocus = true;
|
this.hasFocus = true;
|
||||||
});
|
if (event.key.match(/[+-\d.s]/) === null) {
|
||||||
|
|
||||||
subtitleSyncTextField.addEventListener('keydown', function(event) {
|
|
||||||
if (event.key === 'Enter') {
|
|
||||||
// if input key is enter search for float pattern
|
|
||||||
var inputOffset = /[-+]?\d+\.?\d*/g.exec(this.textContent);
|
|
||||||
if (inputOffset) {
|
|
||||||
inputOffset = inputOffset[0];
|
|
||||||
|
|
||||||
// replace current text by considered offset
|
|
||||||
this.textContent = inputOffset + 's';
|
|
||||||
|
|
||||||
inputOffset = parseFloat(inputOffset);
|
|
||||||
// set new offset
|
|
||||||
playbackManager.setSubtitleOffset(inputOffset, player);
|
|
||||||
// synchronize with slider value
|
|
||||||
subtitleSyncSlider.updateOffset(
|
|
||||||
getPercentageFromOffset(inputOffset));
|
|
||||||
} else {
|
|
||||||
this.textContent = (playbackManager.getPlayerSubtitleOffset(player) || 0) + 's';
|
|
||||||
}
|
|
||||||
this.hasFocus = false;
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
} else {
|
|
||||||
// keep focus to prevent fade with osd
|
|
||||||
this.hasFocus = true;
|
|
||||||
if (event.key.match(/[+-\d.s]/) === null) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: TV layout will require special handling for navigation keys. But now field is not focusable
|
// FIXME: TV layout will require special handling for navigation keys. But now field is not focusable
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
});
|
});
|
||||||
|
|
||||||
subtitleSyncTextField.blur = function() {
|
subtitleSyncTextField.blur = function () {
|
||||||
// prevent textfield to blur while element has focus
|
// prevent textfield to blur while element has focus
|
||||||
if (!this.hasFocus && this.prototype) {
|
if (!this.hasFocus && this.prototype) {
|
||||||
this.prototype.blur();
|
this.prototype.blur();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
subtitleSyncSlider.updateOffset = function(percent) {
|
subtitleSyncSlider.updateOffset = function (percent) {
|
||||||
// default value is 0s = 50%
|
// default value is 0s = 50%
|
||||||
this.value = percent === undefined ? 50 : percent;
|
this.value = percent === undefined ? 50 : percent;
|
||||||
};
|
};
|
||||||
|
|
||||||
subtitleSyncSlider.addEventListener('change', function () {
|
subtitleSyncSlider.addEventListener('change', function () {
|
||||||
// set new offset
|
// set new offset
|
||||||
playbackManager.setSubtitleOffset(getOffsetFromPercentage(this.value), player);
|
playbackManager.setSubtitleOffset(getOffsetFromPercentage(this.value), player);
|
||||||
// synchronize with textField value
|
// synchronize with textField value
|
||||||
subtitleSyncTextField.updateOffset(
|
subtitleSyncTextField.updateOffset(
|
||||||
getOffsetFromPercentage(this.value));
|
getOffsetFromPercentage(this.value));
|
||||||
});
|
});
|
||||||
|
|
||||||
subtitleSyncSlider.getBubbleHtml = function (value) {
|
subtitleSyncSlider.getBubbleHtml = function (value) {
|
||||||
var newOffset = getOffsetFromPercentage(value);
|
const newOffset = getOffsetFromPercentage(value);
|
||||||
return '<h1 class="sliderBubbleText">' +
|
return '<h1 class="sliderBubbleText">' +
|
||||||
(newOffset > 0 ? '+' : '') + parseFloat(newOffset) + 's' +
|
(newOffset > 0 ? '+' : '') + parseFloat(newOffset) + 's' +
|
||||||
'</h1>';
|
'</h1>';
|
||||||
};
|
};
|
||||||
|
|
||||||
subtitleSyncCloseButton.addEventListener('click', function() {
|
subtitleSyncCloseButton.addEventListener('click', function () {
|
||||||
playbackManager.disableShowingSubtitleOffset(player);
|
playbackManager.disableShowingSubtitleOffset(player);
|
||||||
SubtitleSync.prototype.toggle('forceToHide');
|
SubtitleSync.prototype.toggle('forceToHide');
|
||||||
});
|
});
|
||||||
|
|
||||||
instance.element = parent;
|
instance.element = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOffsetFromPercentage(value) {
|
function getOffsetFromPercentage(value) {
|
||||||
// convert percent to fraction
|
// convert percent to fraction
|
||||||
var offset = (value - 50) / 50;
|
let offset = (value - 50) / 50;
|
||||||
// multiply by offset min/max range value (-x to +x) :
|
// multiply by offset min/max range value (-x to +x) :
|
||||||
offset *= 30;
|
offset *= 30;
|
||||||
return offset.toFixed(1);
|
return offset.toFixed(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPercentageFromOffset(value) {
|
function getPercentageFromOffset(value) {
|
||||||
// divide by offset min/max range value (-x to +x) :
|
// divide by offset min/max range value (-x to +x) :
|
||||||
var percentValue = value / 30;
|
let percentValue = value / 30;
|
||||||
// convert fraction to percent
|
// convert fraction to percent
|
||||||
percentValue *= 50;
|
percentValue *= 50;
|
||||||
percentValue += 50;
|
percentValue += 50;
|
||||||
return Math.min(100, Math.max(0, percentValue.toFixed()));
|
return Math.min(100, Math.max(0, percentValue.toFixed()));
|
||||||
}
|
}
|
||||||
|
|
||||||
function SubtitleSync(currentPlayer) {
|
class SubtitleSync {
|
||||||
|
constructor(currentPlayer) {
|
||||||
player = currentPlayer;
|
player = currentPlayer;
|
||||||
init(this);
|
init(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SubtitleSync.prototype.destroy = function() {
|
destroy() {
|
||||||
SubtitleSync.prototype.toggle('forceToHide');
|
SubtitleSync.prototype.toggle('forceToHide');
|
||||||
if (player) {
|
if (player) {
|
||||||
playbackManager.disableShowingSubtitleOffset(player);
|
playbackManager.disableShowingSubtitleOffset(player);
|
||||||
playbackManager.setSubtitleOffset(0, player);
|
playbackManager.setSubtitleOffset(0, player);
|
||||||
}
|
}
|
||||||
var elem = this.element;
|
const elem = this.element;
|
||||||
if (elem) {
|
if (elem) {
|
||||||
elem.parentNode.removeChild(elem);
|
elem.parentNode.removeChild(elem);
|
||||||
this.element = null;
|
this.element = null;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
SubtitleSync.prototype.toggle = function(action) {
|
toggle(action) {
|
||||||
if (player && playbackManager.supportSubtitleOffset(player)) {
|
if (player && playbackManager.supportSubtitleOffset(player)) {
|
||||||
/* eslint-disable no-fallthrough */
|
/* eslint-disable no-fallthrough */
|
||||||
switch (action) {
|
switch (action) {
|
||||||
|
@ -170,7 +171,7 @@ define(['playbackManager', 'layoutManager', 'text!./subtitlesync.template.html',
|
||||||
}
|
}
|
||||||
/* eslint-enable no-fallthrough */
|
/* eslint-enable no-fallthrough */
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return SubtitleSync;
|
export default SubtitleSync;
|
||||||
});
|
|
||||||
|
|
|
@ -1,30 +1,33 @@
|
||||||
define(['backdrop', 'mainTabsManager', 'layoutManager', 'emby-tabs'], function (backdrop, mainTabsManager, layoutManager) {
|
import backdrop from 'backdrop';
|
||||||
'use strict';
|
import * as mainTabsManager from 'mainTabsManager';
|
||||||
|
import layoutManager from 'layoutManager';
|
||||||
|
import 'emby-tabs';
|
||||||
|
|
||||||
function onViewDestroy(e) {
|
function onViewDestroy(e) {
|
||||||
var tabControllers = this.tabControllers;
|
var tabControllers = this.tabControllers;
|
||||||
|
|
||||||
if (tabControllers) {
|
if (tabControllers) {
|
||||||
tabControllers.forEach(function (t) {
|
tabControllers.forEach(function (t) {
|
||||||
if (t.destroy) {
|
if (t.destroy) {
|
||||||
t.destroy();
|
t.destroy();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.tabControllers = null;
|
this.tabControllers = null;
|
||||||
}
|
|
||||||
|
|
||||||
this.view = null;
|
|
||||||
this.params = null;
|
|
||||||
this.currentTabController = null;
|
|
||||||
this.initialTabIndex = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onBeforeTabChange() {
|
this.view = null;
|
||||||
|
this.params = null;
|
||||||
|
this.currentTabController = null;
|
||||||
|
this.initialTabIndex = null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
function onBeforeTabChange() {
|
||||||
|
|
||||||
function TabbedView(view, params) {
|
}
|
||||||
|
|
||||||
|
class TabbedView {
|
||||||
|
constructor(view, params) {
|
||||||
this.tabControllers = [];
|
this.tabControllers = [];
|
||||||
this.view = view;
|
this.view = view;
|
||||||
this.params = params;
|
this.params = params;
|
||||||
|
@ -85,7 +88,7 @@ define(['backdrop', 'mainTabsManager', 'layoutManager', 'emby-tabs'], function (
|
||||||
view.addEventListener('viewdestroy', onViewDestroy.bind(this));
|
view.addEventListener('viewdestroy', onViewDestroy.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
TabbedView.prototype.onResume = function (options) {
|
onResume(options) {
|
||||||
this.setTitle();
|
this.setTitle();
|
||||||
backdrop.clearBackdrop();
|
backdrop.clearBackdrop();
|
||||||
|
|
||||||
|
@ -96,19 +99,18 @@ define(['backdrop', 'mainTabsManager', 'layoutManager', 'emby-tabs'], function (
|
||||||
} else if (currentTabController && currentTabController.onResume) {
|
} else if (currentTabController && currentTabController.onResume) {
|
||||||
currentTabController.onResume({});
|
currentTabController.onResume({});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
TabbedView.prototype.onPause = function () {
|
onPause() {
|
||||||
var currentTabController = this.currentTabController;
|
var currentTabController = this.currentTabController;
|
||||||
|
|
||||||
if (currentTabController && currentTabController.onPause) {
|
if (currentTabController && currentTabController.onPause) {
|
||||||
currentTabController.onPause();
|
currentTabController.onPause();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
setTitle() {
|
||||||
TabbedView.prototype.setTitle = function () {
|
|
||||||
Emby.Page.setTitle('');
|
Emby.Page.setTitle('');
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return TabbedView;
|
export default TabbedView;
|
||||||
});
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ define(['dialogHelper', 'dom', 'layoutManager', 'connectionManager', 'globalize'
|
||||||
|
|
||||||
browser = browser.default || browser;
|
browser = browser.default || browser;
|
||||||
loading = loading.default || loading;
|
loading = loading.default || loading;
|
||||||
|
layoutManager = layoutManager.default || layoutManager;
|
||||||
focusManager = focusManager.default || focusManager;
|
focusManager = focusManager.default || focusManager;
|
||||||
scrollHelper = scrollHelper.default || scrollHelper;
|
scrollHelper = scrollHelper.default || scrollHelper;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
define(['require', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'userSettings', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (require, dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize, userSettings) {
|
define(['require', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'userSettings', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (require, dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize, userSettings) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
layoutManager = layoutManager.default || layoutManager;
|
||||||
|
|
||||||
function onSubmit(e) {
|
function onSubmit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,143 +1,146 @@
|
||||||
define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'connectionManager', 'emby-button'], function ($, loading, libraryMenu, globalize, connectionManager) {
|
import $ from 'jQuery';
|
||||||
'use strict';
|
import loading from 'loading';
|
||||||
|
import globalize from 'globalize';
|
||||||
|
import 'emby-button';
|
||||||
|
|
||||||
loading = loading.default || loading;
|
function populateHistory(packageInfo, page) {
|
||||||
|
let html = '';
|
||||||
|
const length = Math.min(packageInfo.versions.length, 10);
|
||||||
|
|
||||||
function populateHistory(packageInfo, page) {
|
for (let i = 0; i < length; i++) {
|
||||||
var html = '';
|
let version = packageInfo.versions[i];
|
||||||
var length = Math.min(packageInfo.versions.length, 10);
|
html += '<h2 style="margin:.5em 0;">' + version.version + '</h2>';
|
||||||
|
html += '<div style="margin-bottom:1.5em;">' + version.changelog + '</div>';
|
||||||
for (var i = 0; i < length; i++) {
|
|
||||||
var version = packageInfo.versions[i];
|
|
||||||
html += '<h2 style="margin:.5em 0;">' + version.version + '</h2>';
|
|
||||||
html += '<div style="margin-bottom:1.5em;">' + version.changelog + '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#revisionHistory', page).html(html);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function populateVersions(packageInfo, page, installedPlugin) {
|
$('#revisionHistory', page).html(html);
|
||||||
var html = '';
|
}
|
||||||
|
|
||||||
for (var i = 0; i < packageInfo.versions.length; i++) {
|
function populateVersions(packageInfo, page, installedPlugin) {
|
||||||
var version = packageInfo.versions[i];
|
let html = '';
|
||||||
html += '<option value="' + version.version + '">' + version.version + '</option>';
|
|
||||||
}
|
|
||||||
|
|
||||||
var selectmenu = $('#selectVersion', page).html(html);
|
for (let i = 0; i < packageInfo.versions.length; i++) {
|
||||||
|
const version = packageInfo.versions[i];
|
||||||
if (!installedPlugin) {
|
html += '<option value="' + version.version + '">' + version.version + '</option>';
|
||||||
$('#pCurrentVersion', page).hide().html('');
|
|
||||||
}
|
|
||||||
|
|
||||||
var packageVersion = packageInfo.versions[0];
|
|
||||||
if (packageVersion) {
|
|
||||||
selectmenu.val(packageVersion.version);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPackage(pkg, installedPlugins, page) {
|
const selectmenu = $('#selectVersion', page).html(html);
|
||||||
var installedPlugin = installedPlugins.filter(function (ip) {
|
|
||||||
return ip.Name == pkg.name;
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
populateVersions(pkg, page, installedPlugin);
|
if (!installedPlugin) {
|
||||||
populateHistory(pkg, page);
|
$('#pCurrentVersion', page).hide().html('');
|
||||||
|
|
||||||
$('.pluginName', page).html(pkg.name);
|
|
||||||
$('#btnInstallDiv', page).removeClass('hide');
|
|
||||||
$('#pSelectVersion', page).removeClass('hide');
|
|
||||||
|
|
||||||
if (pkg.overview) {
|
|
||||||
$('#overview', page).show().html(pkg.overview);
|
|
||||||
} else {
|
|
||||||
$('#overview', page).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#description', page).html(pkg.description);
|
|
||||||
$('#developer', page).html(pkg.owner);
|
|
||||||
|
|
||||||
if (installedPlugin) {
|
|
||||||
var currentVersionText = globalize.translate('MessageYouHaveVersionInstalled', '<strong>' + installedPlugin.Version + '</strong>');
|
|
||||||
$('#pCurrentVersion', page).show().html(currentVersionText);
|
|
||||||
} else {
|
|
||||||
$('#pCurrentVersion', page).hide().html('');
|
|
||||||
}
|
|
||||||
|
|
||||||
loading.hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function alertText(options) {
|
const packageVersion = packageInfo.versions[0];
|
||||||
require(['alert'], function ({default: alert}) {
|
if (packageVersion) {
|
||||||
alert(options);
|
selectmenu.val(packageVersion.version);
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPackage(pkg, installedPlugins, page) {
|
||||||
|
const installedPlugin = installedPlugins.filter(function (ip) {
|
||||||
|
return ip.Name == pkg.name;
|
||||||
|
})[0];
|
||||||
|
|
||||||
|
populateVersions(pkg, page, installedPlugin);
|
||||||
|
populateHistory(pkg, page);
|
||||||
|
|
||||||
|
$('.pluginName', page).html(pkg.name);
|
||||||
|
$('#btnInstallDiv', page).removeClass('hide');
|
||||||
|
$('#pSelectVersion', page).removeClass('hide');
|
||||||
|
|
||||||
|
if (pkg.overview) {
|
||||||
|
$('#overview', page).show().html(pkg.overview);
|
||||||
|
} else {
|
||||||
|
$('#overview', page).hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
function performInstallation(page, name, guid, version) {
|
$('#description', page).html(pkg.description);
|
||||||
var developer = $('#developer', page).html().toLowerCase();
|
$('#developer', page).html(pkg.owner);
|
||||||
|
|
||||||
var alertCallback = function () {
|
if (installedPlugin) {
|
||||||
loading.show();
|
const currentVersionText = globalize.translate('MessageYouHaveVersionInstalled', '<strong>' + installedPlugin.Version + '</strong>');
|
||||||
page.querySelector('#btnInstall').disabled = true;
|
$('#pCurrentVersion', page).show().html(currentVersionText);
|
||||||
ApiClient.installPlugin(name, guid, version).then(function () {
|
} else {
|
||||||
loading.hide();
|
$('#pCurrentVersion', page).hide().html('');
|
||||||
alertText(globalize.translate('MessagePluginInstalled'));
|
}
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (developer !== 'jellyfin') {
|
loading.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function alertText(options) {
|
||||||
|
import('alert').then(({default: alert}) => {
|
||||||
|
alert(options);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function performInstallation(page, name, guid, version) {
|
||||||
|
const developer = $('#developer', page).html().toLowerCase();
|
||||||
|
|
||||||
|
const alertCallback = function () {
|
||||||
|
loading.show();
|
||||||
|
page.querySelector('#btnInstall').disabled = true;
|
||||||
|
ApiClient.installPlugin(name, guid, version).then(() => {
|
||||||
loading.hide();
|
loading.hide();
|
||||||
var msg = globalize.translate('MessagePluginInstallDisclaimer');
|
alertText(globalize.translate('MessagePluginInstalled'));
|
||||||
msg += '<br/>';
|
}).catch(() => {
|
||||||
msg += '<br/>';
|
alertText(globalize.translate('MessagePluginInstallError'));
|
||||||
msg += globalize.translate('PleaseConfirmPluginInstallation');
|
|
||||||
|
|
||||||
require(['confirm'], function (confirm) {
|
|
||||||
confirm.default(msg, globalize.translate('HeaderConfirmPluginInstallation')).then(function () {
|
|
||||||
alertCallback();
|
|
||||||
}, function () {
|
|
||||||
console.debug('plugin not installed');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
alertCallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return function (view, params) {
|
|
||||||
$('.addPluginForm', view).on('submit', function () {
|
|
||||||
loading.show();
|
|
||||||
var page = $(this).parents('#addPluginPage')[0];
|
|
||||||
var name = params.name;
|
|
||||||
var guid = params.guid;
|
|
||||||
ApiClient.getInstalledPlugins().then(function (plugins) {
|
|
||||||
var installedPlugin = plugins.filter(function (plugin) {
|
|
||||||
return plugin.Name == name;
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
var version = $('#selectVersion', page).val();
|
|
||||||
if (installedPlugin && installedPlugin.Version === version) {
|
|
||||||
loading.hide();
|
|
||||||
Dashboard.alert({
|
|
||||||
message: globalize.translate('MessageAlreadyInstalled'),
|
|
||||||
title: globalize.translate('HeaderPluginInstallation')
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
performInstallation(page, name, guid, version);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
view.addEventListener('viewshow', function () {
|
|
||||||
var page = this;
|
|
||||||
loading.show();
|
|
||||||
var name = params.name;
|
|
||||||
var guid = params.guid;
|
|
||||||
var promise1 = ApiClient.getPackageInfo(name, guid);
|
|
||||||
var promise2 = ApiClient.getInstalledPlugins();
|
|
||||||
Promise.all([promise1, promise2]).then(function (responses) {
|
|
||||||
renderPackage(responses[0], responses[1], page);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
});
|
|
||||||
|
if (developer !== 'jellyfin') {
|
||||||
|
loading.hide();
|
||||||
|
let msg = globalize.translate('MessagePluginInstallDisclaimer');
|
||||||
|
msg += '<br/>';
|
||||||
|
msg += '<br/>';
|
||||||
|
msg += globalize.translate('PleaseConfirmPluginInstallation');
|
||||||
|
|
||||||
|
import('confirm').then(({default: confirm}) => {
|
||||||
|
confirm(msg, globalize.translate('HeaderConfirmPluginInstallation')).then(function () {
|
||||||
|
alertCallback();
|
||||||
|
}).catch(() => {
|
||||||
|
console.debug('plugin not installed');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
alertCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function(view, params) {
|
||||||
|
$('.addPluginForm', view).on('submit', function () {
|
||||||
|
loading.show();
|
||||||
|
const page = $(this).parents('#addPluginPage')[0];
|
||||||
|
const name = params.name;
|
||||||
|
const guid = params.guid;
|
||||||
|
ApiClient.getInstalledPlugins().then(function (plugins) {
|
||||||
|
const installedPlugin = plugins.filter(function (plugin) {
|
||||||
|
return plugin.Name == name;
|
||||||
|
})[0];
|
||||||
|
|
||||||
|
const version = $('#selectVersion', page).val();
|
||||||
|
if (installedPlugin && installedPlugin.Version === version) {
|
||||||
|
loading.hide();
|
||||||
|
Dashboard.alert({
|
||||||
|
message: globalize.translate('MessageAlreadyInstalled'),
|
||||||
|
title: globalize.translate('HeaderPluginInstallation')
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
performInstallation(page, name, guid, version);
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
alertText(globalize.translate('MessageGetInstalledPluginsError'));
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
view.addEventListener('viewshow', function () {
|
||||||
|
const page = this;
|
||||||
|
loading.show();
|
||||||
|
const name = params.name;
|
||||||
|
const guid = params.guid;
|
||||||
|
const promise1 = ApiClient.getPackageInfo(name, guid);
|
||||||
|
const promise2 = ApiClient.getInstalledPlugins();
|
||||||
|
Promise.all([promise1, promise2]).then(function (responses) {
|
||||||
|
renderPackage(responses[0], responses[1], page);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -1,143 +1,142 @@
|
||||||
define(['loading', 'libraryMenu', 'globalize', 'cardStyle', 'emby-button', 'emby-checkbox', 'emby-select'], function (loading, libraryMenu, globalize) {
|
import loading from 'loading';
|
||||||
'use strict';
|
import libraryMenu from 'libraryMenu';
|
||||||
|
import globalize from 'globalize';
|
||||||
|
import 'cardStyle';
|
||||||
|
import 'emby-button';
|
||||||
|
import 'emby-checkbox';
|
||||||
|
import 'emby-select';
|
||||||
|
|
||||||
loading = loading.default || loading;
|
function reloadList(page) {
|
||||||
|
loading.show();
|
||||||
function reloadList(page) {
|
const promise1 = ApiClient.getAvailablePlugins();
|
||||||
loading.show();
|
const promise2 = ApiClient.getInstalledPlugins();
|
||||||
var promise1 = ApiClient.getAvailablePlugins();
|
Promise.all([promise1, promise2]).then(function (responses) {
|
||||||
var promise2 = ApiClient.getInstalledPlugins();
|
populateList({
|
||||||
Promise.all([promise1, promise2]).then(function (responses) {
|
catalogElement: page.querySelector('#pluginTiles'),
|
||||||
populateList({
|
noItemsElement: page.querySelector('#noPlugins'),
|
||||||
catalogElement: page.querySelector('#pluginTiles'),
|
availablePlugins: responses[0],
|
||||||
noItemsElement: page.querySelector('#noPlugins'),
|
installedPlugins: responses[1]
|
||||||
availablePlugins: responses[0],
|
|
||||||
installedPlugins: responses[1]
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHeaderText(category) {
|
||||||
|
category = category.replace(' ', '');
|
||||||
|
// TODO: Replace with switch
|
||||||
|
if (category === 'Channel') {
|
||||||
|
category = 'Channels';
|
||||||
|
} else if (category === 'Theme') {
|
||||||
|
category = 'Themes';
|
||||||
|
} else if (category === 'LiveTV') {
|
||||||
|
category = 'HeaderLiveTV';
|
||||||
|
} else if (category === 'ScreenSaver') {
|
||||||
|
category = 'HeaderScreenSavers';
|
||||||
}
|
}
|
||||||
|
|
||||||
function getHeaderText(category) {
|
return globalize.translate(category);
|
||||||
category = category.replace(' ', '');
|
}
|
||||||
if (category === 'Channel') {
|
|
||||||
category = 'Channels';
|
function populateList(options) {
|
||||||
} else if (category === 'Theme') {
|
const availablePlugins = options.availablePlugins;
|
||||||
category = 'Themes';
|
const installedPlugins = options.installedPlugins;
|
||||||
} else if (category === 'LiveTV') {
|
|
||||||
category = 'HeaderLiveTV';
|
availablePlugins.forEach(function (plugin, index, array) {
|
||||||
} else if (category === 'ScreenSaver') {
|
plugin.category = plugin.category || 'General';
|
||||||
category = 'HeaderScreenSavers';
|
plugin.categoryDisplayName = getHeaderText(plugin.category);
|
||||||
|
array[index] = plugin;
|
||||||
|
});
|
||||||
|
|
||||||
|
availablePlugins.sort(function (a, b) {
|
||||||
|
if (a.category > b.category) {
|
||||||
|
return 1;
|
||||||
|
} else if (b.category > a.category) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (a.name > b.name) {
|
||||||
|
return 1;
|
||||||
|
} else if (b.name > a.name) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
return globalize.translate(category);
|
let currentCategory = null;
|
||||||
}
|
let html = '';
|
||||||
|
|
||||||
function populateList(options) {
|
for (let i = 0; i < availablePlugins.length; i++) {
|
||||||
var availablePlugins = options.availablePlugins;
|
const plugin = availablePlugins[i];
|
||||||
var installedPlugins = options.installedPlugins;
|
const category = plugin.categoryDisplayName;
|
||||||
|
if (category != currentCategory) {
|
||||||
availablePlugins.forEach(function (plugin, index, array) {
|
if (currentCategory) {
|
||||||
plugin.category = plugin.category || 'General';
|
html += '</div>';
|
||||||
plugin.categoryDisplayName = getHeaderText(plugin.category);
|
html += '</div>';
|
||||||
array[index] = plugin;
|
|
||||||
});
|
|
||||||
|
|
||||||
availablePlugins.sort(function (a, b) {
|
|
||||||
if (a.category > b.category) {
|
|
||||||
return 1;
|
|
||||||
} else if (b.category > a.category) {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
if (a.name > b.name) {
|
html += '<div class="verticalSection">';
|
||||||
return 1;
|
html += '<h2 class="sectionTitle sectionTitle-cards">' + category + '</h2>';
|
||||||
} else if (b.name > a.name) {
|
html += '<div class="itemsContainer vertical-wrap">';
|
||||||
return -1;
|
currentCategory = category;
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
var currentCategory = null;
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
for (var i = 0; i < availablePlugins.length; i++) {
|
|
||||||
var plugin = availablePlugins[i];
|
|
||||||
var category = plugin.categoryDisplayName;
|
|
||||||
if (category != currentCategory) {
|
|
||||||
if (currentCategory) {
|
|
||||||
html += '</div>';
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
html += '<div class="verticalSection">';
|
|
||||||
html += '<h2 class="sectionTitle sectionTitle-cards">' + category + '</h2>';
|
|
||||||
html += '<div class="itemsContainer vertical-wrap">';
|
|
||||||
currentCategory = category;
|
|
||||||
}
|
|
||||||
html += getPluginHtml(plugin, options, installedPlugins);
|
|
||||||
}
|
}
|
||||||
html += '</div>';
|
html += getPluginHtml(plugin, options, installedPlugins);
|
||||||
html += '</div>';
|
}
|
||||||
|
html += '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
|
||||||
if (!availablePlugins.length && options.noItemsElement) {
|
if (!availablePlugins.length && options.noItemsElement) {
|
||||||
options.noItemsElement.classList.remove('hide');
|
options.noItemsElement.classList.remove('hide');
|
||||||
}
|
|
||||||
|
|
||||||
options.catalogElement.innerHTML = html;
|
|
||||||
loading.hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPluginHtml(plugin, options, installedPlugins) {
|
options.catalogElement.innerHTML = html;
|
||||||
var html = '';
|
loading.hide();
|
||||||
var href = plugin.externalUrl ? plugin.externalUrl : 'addplugin.html?name=' + encodeURIComponent(plugin.name) + '&guid=' + plugin.guid;
|
}
|
||||||
|
|
||||||
if (options.context) {
|
function getPluginHtml(plugin, options, installedPlugins) {
|
||||||
href += '&context=' + options.context;
|
let html = '';
|
||||||
}
|
let href = plugin.externalUrl ? plugin.externalUrl : 'addplugin.html?name=' + encodeURIComponent(plugin.name) + '&guid=' + plugin.guid;
|
||||||
|
|
||||||
var target = plugin.externalUrl ? ' target="_blank"' : '';
|
if (options.context) {
|
||||||
html += "<div class='card backdropCard'>";
|
href += '&context=' + options.context;
|
||||||
html += '<div class="cardBox visualCardBox">';
|
|
||||||
html += '<div class="cardScalable visualCardBox-cardScalable">';
|
|
||||||
html += '<div class="cardPadder cardPadder-backdrop"></div>';
|
|
||||||
html += '<a class="cardContent cardImageContainer" is="emby-linkbutton" href="' + href + '"' + target + '>';
|
|
||||||
html += '<span class="cardImageIcon material-icons folder"></span>';
|
|
||||||
html += '</a>';
|
|
||||||
html += '</div>';
|
|
||||||
html += '<div class="cardFooter">';
|
|
||||||
html += "<div class='cardText'>";
|
|
||||||
html += plugin.name;
|
|
||||||
html += '</div>';
|
|
||||||
var installedPlugin = installedPlugins.filter(function (ip) {
|
|
||||||
return ip.Id == plugin.guid;
|
|
||||||
})[0];
|
|
||||||
html += "<div class='cardText cardText-secondary'>";
|
|
||||||
html += installedPlugin ? globalize.translate('LabelVersionInstalled', installedPlugin.Version) : ' ';
|
|
||||||
html += '</div>';
|
|
||||||
html += '</div>';
|
|
||||||
html += '</div>';
|
|
||||||
return html += '</div>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTabs() {
|
const target = plugin.externalUrl ? ' target="_blank"' : '';
|
||||||
return [{
|
html += "<div class='card backdropCard'>";
|
||||||
href: 'installedplugins.html',
|
html += '<div class="cardBox visualCardBox">';
|
||||||
name: globalize.translate('TabMyPlugins')
|
html += '<div class="cardScalable visualCardBox-cardScalable">';
|
||||||
}, {
|
html += '<div class="cardPadder cardPadder-backdrop"></div>';
|
||||||
href: 'availableplugins.html',
|
html += '<a class="cardContent cardImageContainer" is="emby-linkbutton" href="' + href + '"' + target + '>';
|
||||||
name: globalize.translate('TabCatalog')
|
html += '<span class="cardImageIcon material-icons folder"></span>';
|
||||||
}, {
|
html += '</a>';
|
||||||
href: 'repositories.html',
|
html += '</div>';
|
||||||
name: globalize.translate('TabRepositories')
|
html += '<div class="cardFooter">';
|
||||||
}];
|
html += "<div class='cardText'>";
|
||||||
}
|
html += plugin.name;
|
||||||
|
html += '</div>';
|
||||||
|
const installedPlugin = installedPlugins.filter(function (ip) {
|
||||||
|
return ip.Id == plugin.guid;
|
||||||
|
})[0];
|
||||||
|
html += "<div class='cardText cardText-secondary'>";
|
||||||
|
html += installedPlugin ? globalize.translate('LabelVersionInstalled', installedPlugin.Version) : ' ';
|
||||||
|
html += '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
return html += '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
window.PluginCatalog = {
|
function getTabs() {
|
||||||
renderCatalog: populateList
|
return [{
|
||||||
};
|
href: 'installedplugins.html',
|
||||||
|
name: globalize.translate('TabMyPlugins')
|
||||||
|
}, {
|
||||||
|
href: 'availableplugins.html',
|
||||||
|
name: globalize.translate('TabCatalog')
|
||||||
|
}, {
|
||||||
|
href: 'repositories.html',
|
||||||
|
name: globalize.translate('TabRepositories')
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
return function (view, params) {
|
export default function (view) {
|
||||||
view.addEventListener('viewshow', function () {
|
view.addEventListener('viewshow', function () {
|
||||||
libraryMenu.setTabs('plugins', 1, getTabs);
|
libraryMenu.setTabs('plugins', 1, getTabs);
|
||||||
reloadList(this);
|
reloadList(this);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
|
|
@ -1,192 +1,193 @@
|
||||||
define(['loading', 'libraryMenu', 'dom', 'globalize', 'cardStyle', 'emby-button'], function (loading, libraryMenu, dom, globalize) {
|
import loading from 'loading';
|
||||||
'use strict';
|
import libraryMenu from 'libraryMenu';
|
||||||
|
import dom from 'dom';
|
||||||
|
import globalize from 'globalize';
|
||||||
|
import 'cardStyle';
|
||||||
|
import 'emby-button';
|
||||||
|
|
||||||
loading = loading.default || loading;
|
function deletePlugin(page, uniqueid, name) {
|
||||||
|
const msg = globalize.translate('UninstallPluginConfirmation', name);
|
||||||
|
|
||||||
function deletePlugin(page, uniqueid, name) {
|
import('confirm').then(({default: confirm}) => {
|
||||||
var msg = globalize.translate('UninstallPluginConfirmation', name);
|
confirm.default({
|
||||||
|
title: globalize.translate('HeaderUninstallPlugin'),
|
||||||
require(['confirm'], function (confirm) {
|
text: msg,
|
||||||
confirm.default({
|
primary: 'delete',
|
||||||
title: globalize.translate('HeaderUninstallPlugin'),
|
confirmText: globalize.translate('HeaderUninstallPlugin')
|
||||||
text: msg,
|
}).then(function () {
|
||||||
primary: 'delete',
|
loading.show();
|
||||||
confirmText: globalize.translate('HeaderUninstallPlugin')
|
ApiClient.uninstallPlugin(uniqueid).then(function () {
|
||||||
}).then(function () {
|
reloadList(page);
|
||||||
loading.show();
|
|
||||||
ApiClient.uninstallPlugin(uniqueid).then(function () {
|
|
||||||
reloadList(page);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function showNoConfigurationMessage() {
|
function showNoConfigurationMessage() {
|
||||||
Dashboard.alert({
|
Dashboard.alert({
|
||||||
message: globalize.translate('MessageNoPluginConfiguration')
|
message: globalize.translate('MessageNoPluginConfiguration')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showConnectMessage() {
|
function showConnectMessage() {
|
||||||
Dashboard.alert({
|
Dashboard.alert({
|
||||||
message: globalize.translate('MessagePluginConfigurationRequiresLocalAccess')
|
message: globalize.translate('MessagePluginConfigurationRequiresLocalAccess')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPluginCardHtml(plugin, pluginConfigurationPages) {
|
function getPluginCardHtml(plugin, pluginConfigurationPages) {
|
||||||
var configPage = pluginConfigurationPages.filter(function (pluginConfigurationPage) {
|
const configPage = pluginConfigurationPages.filter(function (pluginConfigurationPage) {
|
||||||
return pluginConfigurationPage.PluginId == plugin.Id;
|
return pluginConfigurationPage.PluginId == plugin.Id;
|
||||||
})[0];
|
})[0];
|
||||||
var configPageUrl = configPage ? Dashboard.getConfigurationPageUrl(configPage.Name) : null;
|
const configPageUrl = configPage ? Dashboard.getConfigurationPageUrl(configPage.Name) : null;
|
||||||
var html = '';
|
let html = '';
|
||||||
html += "<div data-id='" + plugin.Id + "' data-name='" + plugin.Name + "' data-removable='" + plugin.CanUninstall + "' 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="cardBox visualCardBox">';
|
||||||
html += '<div class="cardScalable">';
|
html += '<div class="cardScalable">';
|
||||||
html += '<div class="cardPadder cardPadder-backdrop"></div>';
|
html += '<div class="cardPadder cardPadder-backdrop"></div>';
|
||||||
html += configPageUrl ? '<a class="cardContent cardImageContainer" is="emby-linkbutton" href="' + configPageUrl + '">' : '<div class="cardContent noConfigPluginCard noHoverEffect cardImageContainer emby-button">';
|
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 += '<span class="cardImageIcon material-icons folder"></span>';
|
||||||
html += configPageUrl ? '</a>' : '</div>';
|
html += configPageUrl ? '</a>' : '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
html += '<div class="cardFooter">';
|
||||||
|
|
||||||
|
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>';
|
||||||
html += '<div class="cardFooter">';
|
}
|
||||||
|
|
||||||
if (configPage || plugin.CanUninstall) {
|
html += "<div class='cardText'>";
|
||||||
html += '<div style="text-align:right; float:right;padding-top:5px;">';
|
html += configPage && configPage.DisplayName ? configPage.DisplayName : plugin.Name;
|
||||||
html += '<button type="button" is="paper-icon-button-light" class="btnCardMenu autoSize"><span class="material-icons more_vert"></span></button>';
|
html += '</div>';
|
||||||
html += '</div>';
|
html += "<div class='cardText cardText-secondary'>";
|
||||||
|
html += plugin.Version;
|
||||||
|
html += '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPlugins(page, plugins) {
|
||||||
|
ApiClient.getJSON(ApiClient.getUrl('web/configurationpages') + '?pageType=PluginConfiguration').then(function (configPages) {
|
||||||
|
populateList(page, plugins, configPages);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function populateList(page, plugins, pluginConfigurationPages) {
|
||||||
|
plugins = plugins.sort(function (plugin1, plugin2) {
|
||||||
|
if (plugin1.Name > plugin2.Name) {
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
html += "<div class='cardText'>";
|
return -1;
|
||||||
html += configPage && configPage.DisplayName ? configPage.DisplayName : plugin.Name;
|
|
||||||
html += '</div>';
|
|
||||||
html += "<div class='cardText cardText-secondary'>";
|
|
||||||
html += plugin.Version;
|
|
||||||
html += '</div>';
|
|
||||||
html += '</div>';
|
|
||||||
html += '</div>';
|
|
||||||
html += '</div>';
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderPlugins(page, plugins) {
|
|
||||||
ApiClient.getJSON(ApiClient.getUrl('web/configurationpages') + '?pageType=PluginConfiguration').then(function (configPages) {
|
|
||||||
populateList(page, plugins, configPages);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function populateList(page, plugins, pluginConfigurationPages) {
|
|
||||||
plugins = plugins.sort(function (plugin1, plugin2) {
|
|
||||||
if (plugin1.Name > plugin2.Name) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
});
|
|
||||||
|
|
||||||
var html = plugins.map(function (p) {
|
|
||||||
return getPluginCardHtml(p, pluginConfigurationPages);
|
|
||||||
}).join('');
|
|
||||||
|
|
||||||
var installedPluginsElement = page.querySelector('.installedPlugins');
|
|
||||||
installedPluginsElement.removeEventListener('click', onInstalledPluginsClick);
|
|
||||||
installedPluginsElement.addEventListener('click', onInstalledPluginsClick);
|
|
||||||
|
|
||||||
if (plugins.length) {
|
|
||||||
installedPluginsElement.classList.add('itemsContainer');
|
|
||||||
installedPluginsElement.classList.add('vertical-wrap');
|
|
||||||
} else {
|
|
||||||
html += '<div class="centerMessage">';
|
|
||||||
html += '<h1>' + globalize.translate('MessageNoPluginsInstalled') + '</h1>';
|
|
||||||
html += '<p><a is="emby-linkbutton" class="button-link" href="availableplugins.html">';
|
|
||||||
html += globalize.translate('MessageBrowsePluginCatalog');
|
|
||||||
html += '</a></p>';
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
installedPluginsElement.innerHTML = html;
|
|
||||||
loading.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
function showPluginMenu(page, elem) {
|
|
||||||
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 = [];
|
|
||||||
|
|
||||||
if (configHref) {
|
|
||||||
menuItems.push({
|
|
||||||
name: globalize.translate('ButtonSettings'),
|
|
||||||
id: 'open',
|
|
||||||
icon: 'mode_edit'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (removable === 'true') {
|
|
||||||
menuItems.push({
|
|
||||||
name: globalize.translate('ButtonUninstall'),
|
|
||||||
id: 'delete',
|
|
||||||
icon: 'delete'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
require(['actionsheet'], function (actionsheet) {
|
|
||||||
actionsheet.show({
|
|
||||||
items: menuItems,
|
|
||||||
positionTo: elem,
|
|
||||||
callback: function (resultId) {
|
|
||||||
switch (resultId) {
|
|
||||||
case 'open':
|
|
||||||
Dashboard.navigate(configHref);
|
|
||||||
break;
|
|
||||||
case 'delete':
|
|
||||||
deletePlugin(page, id, name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function reloadList(page) {
|
|
||||||
loading.show();
|
|
||||||
ApiClient.getInstalledPlugins().then(function (plugins) {
|
|
||||||
renderPlugins(page, plugins);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTabs() {
|
|
||||||
return [{
|
|
||||||
href: 'installedplugins.html',
|
|
||||||
name: globalize.translate('TabMyPlugins')
|
|
||||||
}, {
|
|
||||||
href: 'availableplugins.html',
|
|
||||||
name: globalize.translate('TabCatalog')
|
|
||||||
}, {
|
|
||||||
href: 'repositories.html',
|
|
||||||
name: globalize.translate('TabRepositories')
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
function onInstalledPluginsClick(e) {
|
|
||||||
if (dom.parentWithClass(e.target, 'noConfigPluginCard')) {
|
|
||||||
showNoConfigurationMessage();
|
|
||||||
} else if (dom.parentWithClass(e.target, 'connectModePluginCard')) {
|
|
||||||
showConnectMessage();
|
|
||||||
} else {
|
|
||||||
var btnCardMenu = dom.parentWithClass(e.target, 'btnCardMenu');
|
|
||||||
if (btnCardMenu) {
|
|
||||||
showPluginMenu(dom.parentWithClass(btnCardMenu, 'page'), btnCardMenu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pageIdOn('pageshow', 'pluginsPage', function () {
|
|
||||||
libraryMenu.setTabs('plugins', 0, getTabs);
|
|
||||||
reloadList(this);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
window.PluginsPage = {
|
let html = plugins.map(function (p) {
|
||||||
renderPlugins: renderPlugins
|
return getPluginCardHtml(p, pluginConfigurationPages);
|
||||||
};
|
}).join('');
|
||||||
|
|
||||||
|
const installedPluginsElement = page.querySelector('.installedPlugins');
|
||||||
|
installedPluginsElement.removeEventListener('click', onInstalledPluginsClick);
|
||||||
|
installedPluginsElement.addEventListener('click', onInstalledPluginsClick);
|
||||||
|
|
||||||
|
if (plugins.length) {
|
||||||
|
installedPluginsElement.classList.add('itemsContainer');
|
||||||
|
installedPluginsElement.classList.add('vertical-wrap');
|
||||||
|
} else {
|
||||||
|
html += '<div class="centerMessage">';
|
||||||
|
html += '<h1>' + globalize.translate('MessageNoPluginsInstalled') + '</h1>';
|
||||||
|
html += '<p><a is="emby-linkbutton" class="button-link" href="availableplugins.html">';
|
||||||
|
html += globalize.translate('MessageBrowsePluginCatalog');
|
||||||
|
html += '</a></p>';
|
||||||
|
html += '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
installedPluginsElement.innerHTML = html;
|
||||||
|
loading.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPluginMenu(page, elem) {
|
||||||
|
const card = dom.parentWithClass(elem, 'card');
|
||||||
|
const id = card.getAttribute('data-id');
|
||||||
|
const name = card.getAttribute('data-name');
|
||||||
|
const removable = card.getAttribute('data-removable');
|
||||||
|
const configHref = card.querySelector('.cardContent').getAttribute('href');
|
||||||
|
const menuItems = [];
|
||||||
|
|
||||||
|
if (configHref) {
|
||||||
|
menuItems.push({
|
||||||
|
name: globalize.translate('ButtonSettings'),
|
||||||
|
id: 'open',
|
||||||
|
icon: 'mode_edit'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removable === 'true') {
|
||||||
|
menuItems.push({
|
||||||
|
name: globalize.translate('ButtonUninstall'),
|
||||||
|
id: 'delete',
|
||||||
|
icon: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
import('actionsheet').then(({default: actionsheet}) => {
|
||||||
|
actionsheet.show({
|
||||||
|
items: menuItems,
|
||||||
|
positionTo: elem,
|
||||||
|
callback: function (resultId) {
|
||||||
|
switch (resultId) {
|
||||||
|
case 'open':
|
||||||
|
Dashboard.navigate(configHref);
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
deletePlugin(page, id, name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadList(page) {
|
||||||
|
loading.show();
|
||||||
|
ApiClient.getInstalledPlugins().then(function (plugins) {
|
||||||
|
renderPlugins(page, plugins);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTabs() {
|
||||||
|
return [{
|
||||||
|
href: 'installedplugins.html',
|
||||||
|
name: globalize.translate('TabMyPlugins')
|
||||||
|
}, {
|
||||||
|
href: 'availableplugins.html',
|
||||||
|
name: globalize.translate('TabCatalog')
|
||||||
|
}, {
|
||||||
|
href: 'repositories.html',
|
||||||
|
name: globalize.translate('TabRepositories')
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
function onInstalledPluginsClick(e) {
|
||||||
|
if (dom.parentWithClass(e.target, 'noConfigPluginCard')) {
|
||||||
|
showNoConfigurationMessage();
|
||||||
|
} else if (dom.parentWithClass(e.target, 'connectModePluginCard')) {
|
||||||
|
showConnectMessage();
|
||||||
|
} else {
|
||||||
|
const btnCardMenu = dom.parentWithClass(e.target, 'btnCardMenu');
|
||||||
|
if (btnCardMenu) {
|
||||||
|
showPluginMenu(dom.parentWithClass(btnCardMenu, 'page'), btnCardMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pageIdOn('pageshow', 'pluginsPage', function () {
|
||||||
|
libraryMenu.setTabs('plugins', 0, getTabs);
|
||||||
|
reloadList(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.PluginsPage = {
|
||||||
|
renderPlugins: renderPlugins
|
||||||
|
};
|
||||||
|
|
|
@ -1,7 +1,33 @@
|
||||||
define(['tabbedView', 'globalize', 'require', 'emby-tabs', 'emby-button', 'emby-scroller'], function (TabbedView, globalize, require) {
|
import TabbedView from 'tabbedView';
|
||||||
'use strict';
|
import globalize from 'globalize';
|
||||||
|
import 'emby-tabs';
|
||||||
|
import 'emby-button';
|
||||||
|
import 'emby-scroller';
|
||||||
|
|
||||||
function getTabs() {
|
class HomeView extends TabbedView {
|
||||||
|
constructor(view, params) {
|
||||||
|
super(view, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTitle() {
|
||||||
|
Emby.Page.setTitle(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
onPause() {
|
||||||
|
super.onPause(this);
|
||||||
|
document.querySelector('.skinHeader').classList.remove('noHomeButtonHeader');
|
||||||
|
}
|
||||||
|
|
||||||
|
onResume(options) {
|
||||||
|
super.onResume(this, options);
|
||||||
|
document.querySelector('.skinHeader').classList.add('noHomeButtonHeader');
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefaultTabIndex() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTabs() {
|
||||||
return [{
|
return [{
|
||||||
name: globalize.translate('Home')
|
name: globalize.translate('Home')
|
||||||
}, {
|
}, {
|
||||||
|
@ -9,67 +35,34 @@ define(['tabbedView', 'globalize', 'require', 'emby-tabs', 'emby-button', 'emby-
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDefaultTabIndex() {
|
getTabController(index) {
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRequirePromise(deps) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
require(deps, resolve);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTabController(index) {
|
|
||||||
if (index == null) {
|
if (index == null) {
|
||||||
throw new Error('index cannot be null');
|
throw new Error('index cannot be null');
|
||||||
}
|
}
|
||||||
|
|
||||||
var depends = [];
|
let depends = '';
|
||||||
|
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
depends.push('controllers/hometab');
|
depends = 'controllers/hometab';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
depends.push('controllers/favorites');
|
depends = 'controllers/favorites';
|
||||||
}
|
}
|
||||||
|
|
||||||
var instance = this;
|
const instance = this;
|
||||||
return getRequirePromise(depends).then(function (controllerFactory) {
|
return import(depends).then(({ default: controllerFactory }) => {
|
||||||
var controller = instance.tabControllers[index];
|
let controller = instance.tabControllers[index];
|
||||||
|
|
||||||
if (!controller) {
|
if (!controller) {
|
||||||
controller = new controllerFactory.default(instance.view.querySelector(".tabContent[data-index='" + index + "']"), instance.params);
|
controller = new controllerFactory(instance.view.querySelector(".tabContent[data-index='" + index + "']"), instance.params);
|
||||||
instance.tabControllers[index] = controller;
|
instance.tabControllers[index] = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
return controller;
|
return controller;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function HomeView(view, params) {
|
export default HomeView;
|
||||||
TabbedView.call(this, view, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.assign(HomeView.prototype, TabbedView.prototype);
|
|
||||||
HomeView.prototype.getTabs = getTabs;
|
|
||||||
HomeView.prototype.getDefaultTabIndex = getDefaultTabIndex;
|
|
||||||
HomeView.prototype.getTabController = getTabController;
|
|
||||||
|
|
||||||
HomeView.prototype.setTitle = function () {
|
|
||||||
Emby.Page.setTitle(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
HomeView.prototype.onPause = function () {
|
|
||||||
TabbedView.prototype.onPause.call(this);
|
|
||||||
document.querySelector('.skinHeader').classList.remove('noHomeButtonHeader');
|
|
||||||
};
|
|
||||||
|
|
||||||
HomeView.prototype.onResume = function (options) {
|
|
||||||
TabbedView.prototype.onResume.call(this, options);
|
|
||||||
document.querySelector('.skinHeader').classList.add('noHomeButtonHeader');
|
|
||||||
};
|
|
||||||
|
|
||||||
return HomeView;
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import appHost from 'apphost';
|
||||||
import loading from 'loading';
|
import loading from 'loading';
|
||||||
import appRouter from 'appRouter';
|
import appRouter from 'appRouter';
|
||||||
import layoutManager from 'layoutManager';
|
import layoutManager from 'layoutManager';
|
||||||
|
@ -657,7 +658,7 @@ import 'emby-select';
|
||||||
setPeopleHeader(page, item);
|
setPeopleHeader(page, item);
|
||||||
loading.hide();
|
loading.hide();
|
||||||
|
|
||||||
if (item.Type === 'Book') {
|
if (item.Type === 'Book' && item.CanDownload && appHost.supports('filedownload')) {
|
||||||
hideAll(page, 'btnDownload', true);
|
hideAll(page, 'btnDownload', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager', 'cardBuilder', 'loading', 'connectionManager', 'alphaNumericShortcuts', 'playbackManager', 'alphaPicker', 'emby-itemscontainer', 'emby-scroller'], function (globalize, listView, layoutManager, userSettings, focusManager, cardBuilder, loading, connectionManager, AlphaNumericShortcuts, playbackManager, AlphaPicker) {
|
import globalize from 'globalize';
|
||||||
'use strict';
|
import listView from 'listView';
|
||||||
|
import layoutManager from 'layoutManager';
|
||||||
|
import * as userSettings from 'userSettings';
|
||||||
|
import focusManager from 'focusManager';
|
||||||
|
import cardBuilder from 'cardBuilder';
|
||||||
|
import loading from 'loading';
|
||||||
|
import connectionManager from 'connectionManager';
|
||||||
|
import AlphaNumericShortcuts from 'alphaNumericShortcuts';
|
||||||
|
import playbackManager from 'playbackManager';
|
||||||
|
import AlphaPicker from 'alphaPicker';
|
||||||
|
import 'emby-itemscontainer';
|
||||||
|
import 'emby-scroller';
|
||||||
|
|
||||||
playbackManager = playbackManager.default || playbackManager;
|
/* eslint-disable indent */
|
||||||
loading = loading.default || loading;
|
|
||||||
focusManager = focusManager.default || focusManager;
|
|
||||||
|
|
||||||
function getInitialLiveTvQuery(instance, params) {
|
function getInitialLiveTvQuery(instance, params) {
|
||||||
var query = {
|
const query = {
|
||||||
UserId: connectionManager.getApiClient(params.serverId).getCurrentUserId(),
|
UserId: connectionManager.getApiClient(params.serverId).getCurrentUserId(),
|
||||||
StartIndex: 0,
|
StartIndex: 0,
|
||||||
Fields: 'ChannelInfo,PrimaryImageAspectRatio',
|
Fields: 'ChannelInfo,PrimaryImageAspectRatio',
|
||||||
|
@ -63,7 +72,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
function modifyQueryWithFilters(instance, query) {
|
function modifyQueryWithFilters(instance, query) {
|
||||||
var sortValues = instance.getSortValues();
|
const sortValues = instance.getSortValues();
|
||||||
|
|
||||||
if (!query.SortBy) {
|
if (!query.SortBy) {
|
||||||
query.SortBy = sortValues.sortBy;
|
query.SortBy = sortValues.sortBy;
|
||||||
|
@ -72,9 +81,9 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
|
|
||||||
query.Fields = query.Fields ? query.Fields + ',PrimaryImageAspectRatio' : 'PrimaryImageAspectRatio';
|
query.Fields = query.Fields ? query.Fields + ',PrimaryImageAspectRatio' : 'PrimaryImageAspectRatio';
|
||||||
query.ImageTypeLimit = 1;
|
query.ImageTypeLimit = 1;
|
||||||
var hasFilters;
|
let hasFilters;
|
||||||
var queryFilters = [];
|
const queryFilters = [];
|
||||||
var filters = instance.getFilters();
|
const filters = instance.getFilters();
|
||||||
|
|
||||||
if (filters.IsPlayed) {
|
if (filters.IsPlayed) {
|
||||||
queryFilters.push('IsPlayed');
|
queryFilters.push('IsPlayed');
|
||||||
|
@ -168,21 +177,21 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSortText(instance) {
|
function updateSortText(instance) {
|
||||||
var btnSortText = instance.btnSortText;
|
const btnSortText = instance.btnSortText;
|
||||||
|
|
||||||
if (btnSortText) {
|
if (btnSortText) {
|
||||||
var options = instance.getSortMenuOptions();
|
const options = instance.getSortMenuOptions();
|
||||||
var values = instance.getSortValues();
|
const values = instance.getSortValues();
|
||||||
var sortBy = values.sortBy;
|
const sortBy = values.sortBy;
|
||||||
|
|
||||||
for (var i = 0, length = options.length; i < length; i++) {
|
for (const option of options) {
|
||||||
if (sortBy === options[i].value) {
|
if (sortBy === option.value) {
|
||||||
btnSortText.innerHTML = globalize.translate('SortByValue', options[i].name);
|
btnSortText.innerHTML = globalize.translate('SortByValue', option.name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var btnSortIcon = instance.btnSortIcon;
|
const btnSortIcon = instance.btnSortIcon;
|
||||||
|
|
||||||
if (btnSortIcon) {
|
if (btnSortIcon) {
|
||||||
setSortButtonIcon(btnSortIcon, values.sortOrder === 'Descending' ? 'arrow_downward' : 'arrow_upward');
|
setSortButtonIcon(btnSortIcon, values.sortOrder === 'Descending' ? 'arrow_downward' : 'arrow_upward');
|
||||||
|
@ -202,10 +211,10 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
|
|
||||||
function updateAlphaPickerState(instance, numItems) {
|
function updateAlphaPickerState(instance, numItems) {
|
||||||
if (instance.alphaPicker) {
|
if (instance.alphaPicker) {
|
||||||
var alphaPicker = instance.alphaPickerElement;
|
const alphaPicker = instance.alphaPickerElement;
|
||||||
|
|
||||||
if (alphaPicker) {
|
if (alphaPicker) {
|
||||||
var values = instance.getSortValues();
|
const values = instance.getSortValues();
|
||||||
|
|
||||||
if (numItems == null) {
|
if (numItems == null) {
|
||||||
numItems = 100;
|
numItems = 100;
|
||||||
|
@ -223,7 +232,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
function getItems(instance, params, item, sortBy, startIndex, limit) {
|
function getItems(instance, params, item, sortBy, startIndex, limit) {
|
||||||
var apiClient = connectionManager.getApiClient(params.serverId);
|
const apiClient = connectionManager.getApiClient(params.serverId);
|
||||||
|
|
||||||
instance.queryRecursive = false;
|
instance.queryRecursive = false;
|
||||||
if (params.type === 'Recordings') {
|
if (params.type === 'Recordings') {
|
||||||
|
@ -252,7 +261,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
|
|
||||||
if (!item) {
|
if (!item) {
|
||||||
instance.queryRecursive = true;
|
instance.queryRecursive = true;
|
||||||
var method = 'getItems';
|
let method = 'getItems';
|
||||||
|
|
||||||
if (params.type === 'MusicArtist') {
|
if (params.type === 'MusicArtist') {
|
||||||
method = 'getArtists';
|
method = 'getArtists';
|
||||||
|
@ -275,7 +284,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
|
|
||||||
if (item.Type === 'Genre' || item.Type === 'MusicGenre' || item.Type === 'Studio' || item.Type === 'Person') {
|
if (item.Type === 'Genre' || item.Type === 'MusicGenre' || item.Type === 'Studio' || item.Type === 'Person') {
|
||||||
instance.queryRecursive = true;
|
instance.queryRecursive = true;
|
||||||
var query = {
|
const query = {
|
||||||
StartIndex: startIndex,
|
StartIndex: startIndex,
|
||||||
Limit: limit,
|
Limit: limit,
|
||||||
Fields: 'PrimaryImageAspectRatio,SortName',
|
Fields: 'PrimaryImageAspectRatio,SortName',
|
||||||
|
@ -324,8 +333,8 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
var apiClient = connectionManager.getApiClient(params.serverId);
|
const apiClient = connectionManager.getApiClient(params.serverId);
|
||||||
var itemId = params.genreId || params.musicGenreId || params.studioId || params.personId || params.parentId;
|
const itemId = params.genreId || params.musicGenreId || params.studioId || params.personId || params.parentId;
|
||||||
|
|
||||||
if (itemId) {
|
if (itemId) {
|
||||||
return apiClient.getItem(apiClient.getCurrentUserId(), itemId);
|
return apiClient.getItem(apiClient.getCurrentUserId(), itemId);
|
||||||
|
@ -335,9 +344,9 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
function showViewSettingsMenu() {
|
function showViewSettingsMenu() {
|
||||||
var instance = this;
|
const instance = this;
|
||||||
|
|
||||||
require(['viewSettings'], function (ViewSettings) {
|
import('viewSettings').then(({default: ViewSettings}) => {
|
||||||
new ViewSettings().show({
|
new ViewSettings().show({
|
||||||
settingsKey: instance.getSettingsKey(),
|
settingsKey: instance.getSettingsKey(),
|
||||||
settings: instance.getViewSettings(),
|
settings: instance.getViewSettings(),
|
||||||
|
@ -350,9 +359,9 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
function showFilterMenu() {
|
function showFilterMenu() {
|
||||||
var instance = this;
|
const instance = this;
|
||||||
|
|
||||||
require(['filterMenu'], function (FilterMenu) {
|
import('filterMenu').then(({default: FilterMenu}) => {
|
||||||
new FilterMenu().show({
|
new FilterMenu().show({
|
||||||
settingsKey: instance.getSettingsKey(),
|
settingsKey: instance.getSettingsKey(),
|
||||||
settings: instance.getFilters(),
|
settings: instance.getFilters(),
|
||||||
|
@ -369,9 +378,9 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
function showSortMenu() {
|
function showSortMenu() {
|
||||||
var instance = this;
|
const instance = this;
|
||||||
|
|
||||||
require(['sortMenu'], function (SortMenu) {
|
import('sortMenu').then(({default: SortMenu}) => {
|
||||||
new SortMenu().show({
|
new SortMenu().show({
|
||||||
settingsKey: instance.getSettingsKey(),
|
settingsKey: instance.getSettingsKey(),
|
||||||
settings: instance.getSortValues(),
|
settings: instance.getSortValues(),
|
||||||
|
@ -387,10 +396,10 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
function onNewItemClick() {
|
function onNewItemClick() {
|
||||||
var instance = this;
|
const instance = this;
|
||||||
|
|
||||||
require(['playlistEditor'], function (playlistEditor) {
|
import('playlistEditor').then(({default: playlistEditor}) => {
|
||||||
new playlistEditor.showEditor({
|
new playlistEditor({
|
||||||
items: [],
|
items: [],
|
||||||
serverId: instance.params.serverId
|
serverId: instance.params.serverId
|
||||||
});
|
});
|
||||||
|
@ -398,22 +407,23 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideOrShowAll(elems, hide) {
|
function hideOrShowAll(elems, hide) {
|
||||||
for (var i = 0, length = elems.length; i < length; i++) {
|
for (const elem of elems) {
|
||||||
if (hide) {
|
if (hide) {
|
||||||
elems[i].classList.add('hide');
|
elem.classList.add('hide');
|
||||||
} else {
|
} else {
|
||||||
elems[i].classList.remove('hide');
|
elem.classList.remove('hide');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function bindAll(elems, eventName, fn) {
|
function bindAll(elems, eventName, fn) {
|
||||||
for (var i = 0, length = elems.length; i < length; i++) {
|
for (const elem of elems) {
|
||||||
elems[i].addEventListener(eventName, fn);
|
elem.addEventListener(eventName, fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ItemsView(view, params) {
|
class ItemsView {
|
||||||
|
constructor(view, params) {
|
||||||
function fetchData() {
|
function fetchData() {
|
||||||
return getItems(self, params, self.currentItem).then(function (result) {
|
return getItems(self, params, self.currentItem).then(function (result) {
|
||||||
if (self.totalItemCount == null) {
|
if (self.totalItemCount == null) {
|
||||||
|
@ -426,7 +436,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
function getItemsHtml(items) {
|
function getItemsHtml(items) {
|
||||||
var settings = self.getViewSettings();
|
const settings = self.getViewSettings();
|
||||||
|
|
||||||
if (settings.imageType === 'list') {
|
if (settings.imageType === 'list') {
|
||||||
return listView.getListViewHtml({
|
return listView.getListViewHtml({
|
||||||
|
@ -434,13 +444,13 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var shape;
|
let shape;
|
||||||
var preferThumb;
|
let preferThumb;
|
||||||
var preferDisc;
|
let preferDisc;
|
||||||
var preferLogo;
|
let preferLogo;
|
||||||
var defaultShape;
|
let defaultShape;
|
||||||
var item = self.currentItem;
|
const item = self.currentItem;
|
||||||
var lines = settings.showTitle ? 2 : 0;
|
let lines = settings.showTitle ? 2 : 0;
|
||||||
|
|
||||||
if (settings.imageType === 'banner') {
|
if (settings.imageType === 'banner') {
|
||||||
shape = 'banner';
|
shape = 'banner';
|
||||||
|
@ -464,7 +474,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
shape = 'autoVertical';
|
shape = 'autoVertical';
|
||||||
}
|
}
|
||||||
|
|
||||||
var posterOptions = {
|
let posterOptions = {
|
||||||
shape: shape,
|
shape: shape,
|
||||||
showTitle: settings.showTitle,
|
showTitle: settings.showTitle,
|
||||||
showYear: settings.showTitle,
|
showYear: settings.showTitle,
|
||||||
|
@ -497,19 +507,19 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
lines = 1;
|
lines = 1;
|
||||||
} else if (params.type === 'Programs') {
|
} else if (params.type === 'Programs') {
|
||||||
lines = settings.showTitle ? 1 : 0;
|
lines = settings.showTitle ? 1 : 0;
|
||||||
var showParentTitle = settings.showTitle && params.IsMovie !== 'true';
|
const showParentTitle = settings.showTitle && params.IsMovie !== 'true';
|
||||||
|
|
||||||
if (showParentTitle) {
|
if (showParentTitle) {
|
||||||
lines++;
|
lines++;
|
||||||
}
|
}
|
||||||
|
|
||||||
var showAirTime = settings.showTitle && params.type !== 'Recordings';
|
const showAirTime = settings.showTitle && params.type !== 'Recordings';
|
||||||
|
|
||||||
if (showAirTime) {
|
if (showAirTime) {
|
||||||
lines++;
|
lines++;
|
||||||
}
|
}
|
||||||
|
|
||||||
var showYear = settings.showTitle && params.IsMovie === 'true' && params.type === 'Recordings';
|
const showYear = settings.showTitle && params.IsMovie === 'true' && params.type === 'Recordings';
|
||||||
|
|
||||||
if (showYear) {
|
if (showYear) {
|
||||||
lines++;
|
lines++;
|
||||||
|
@ -542,13 +552,13 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
|
|
||||||
function initAlphaPicker() {
|
function initAlphaPicker() {
|
||||||
self.scroller = view.querySelector('.scrollFrameY');
|
self.scroller = view.querySelector('.scrollFrameY');
|
||||||
var alphaPickerElement = self.alphaPickerElement;
|
const alphaPickerElement = self.alphaPickerElement;
|
||||||
|
|
||||||
alphaPickerElement.classList.add('alphaPicker-fixed-right');
|
alphaPickerElement.classList.add('alphaPicker-fixed-right');
|
||||||
alphaPickerElement.classList.add('focuscontainer-right');
|
alphaPickerElement.classList.add('focuscontainer-right');
|
||||||
self.itemsContainer.parentNode.classList.add('padded-right-withalphapicker');
|
self.itemsContainer.parentNode.classList.add('padded-right-withalphapicker');
|
||||||
|
|
||||||
self.alphaPicker = new AlphaPicker.default({
|
self.alphaPicker = new AlphaPicker({
|
||||||
element: alphaPickerElement,
|
element: alphaPickerElement,
|
||||||
itemsContainer: layoutManager.tv ? self.itemsContainer : null,
|
itemsContainer: layoutManager.tv ? self.itemsContainer : null,
|
||||||
itemClass: 'card',
|
itemClass: 'card',
|
||||||
|
@ -653,7 +663,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
function play() {
|
function play() {
|
||||||
var currentItem = self.currentItem;
|
const currentItem = self.currentItem;
|
||||||
|
|
||||||
if (currentItem && !self.hasFilters) {
|
if (currentItem && !self.hasFilters) {
|
||||||
playbackManager.play({
|
playbackManager.play({
|
||||||
|
@ -669,7 +679,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
function queue() {
|
function queue() {
|
||||||
var currentItem = self.currentItem;
|
const currentItem = self.currentItem;
|
||||||
|
|
||||||
if (currentItem && !self.hasFilters) {
|
if (currentItem && !self.hasFilters) {
|
||||||
playbackManager.queue({
|
playbackManager.queue({
|
||||||
|
@ -685,7 +695,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
function shuffle() {
|
function shuffle() {
|
||||||
var currentItem = self.currentItem;
|
const currentItem = self.currentItem;
|
||||||
|
|
||||||
if (currentItem && !self.hasFilters) {
|
if (currentItem && !self.hasFilters) {
|
||||||
playbackManager.shuffle(currentItem);
|
playbackManager.shuffle(currentItem);
|
||||||
|
@ -698,7 +708,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var self = this;
|
const self = this;
|
||||||
self.params = params;
|
self.params = params;
|
||||||
this.itemsContainer = view.querySelector('.itemsContainer');
|
this.itemsContainer = view.querySelector('.itemsContainer');
|
||||||
|
|
||||||
|
@ -712,20 +722,17 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
this.itemsContainer.setAttribute('data-refreshinterval', '300000');
|
this.itemsContainer.setAttribute('data-refreshinterval', '300000');
|
||||||
}
|
}
|
||||||
|
|
||||||
var i;
|
const btnViewSettings = view.querySelectorAll('.btnViewSettings');
|
||||||
var length;
|
|
||||||
var btnViewSettings = view.querySelectorAll('.btnViewSettings');
|
|
||||||
|
|
||||||
for (i = 0, length = btnViewSettings.length; i < length; i++) {
|
for (const btnViewSetting of btnViewSettings) {
|
||||||
btnViewSettings[i].addEventListener('click', showViewSettingsMenu.bind(this));
|
btnViewSetting.addEventListener('click', showViewSettingsMenu.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
var filterButtons = view.querySelectorAll('.btnFilter');
|
const filterButtons = view.querySelectorAll('.btnFilter');
|
||||||
this.filterButtons = filterButtons;
|
this.filterButtons = filterButtons;
|
||||||
var hasVisibleFilters = this.getVisibleFilters().length;
|
const hasVisibleFilters = this.getVisibleFilters().length;
|
||||||
|
|
||||||
for (i = 0, length = filterButtons.length; i < length; i++) {
|
for (const btnFilter of filterButtons) {
|
||||||
var btnFilter = filterButtons[i];
|
|
||||||
btnFilter.addEventListener('click', showFilterMenu.bind(this));
|
btnFilter.addEventListener('click', showFilterMenu.bind(this));
|
||||||
|
|
||||||
if (hasVisibleFilters) {
|
if (hasVisibleFilters) {
|
||||||
|
@ -735,10 +742,10 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var sortButtons = view.querySelectorAll('.btnSort');
|
const sortButtons = view.querySelectorAll('.btnSort');
|
||||||
|
|
||||||
for (this.sortButtons = sortButtons, i = 0, length = sortButtons.length; i < length; i++) {
|
this.sortButtons = sortButtons;
|
||||||
var sortButton = sortButtons[i];
|
for (const sortButton of sortButtons) {
|
||||||
sortButton.addEventListener('click', showSortMenu.bind(this));
|
sortButton.addEventListener('click', showSortMenu.bind(this));
|
||||||
|
|
||||||
if (params.type !== 'nextup') {
|
if (params.type !== 'nextup') {
|
||||||
|
@ -753,7 +760,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
self.itemsContainer.fetchData = fetchData;
|
self.itemsContainer.fetchData = fetchData;
|
||||||
self.itemsContainer.getItemsHtml = getItemsHtml;
|
self.itemsContainer.getItemsHtml = getItemsHtml;
|
||||||
view.addEventListener('viewshow', function (e) {
|
view.addEventListener('viewshow', function (e) {
|
||||||
var isRestored = e.detail.isRestored;
|
const isRestored = e.detail.isRestored;
|
||||||
|
|
||||||
if (!isRestored) {
|
if (!isRestored) {
|
||||||
loading.show();
|
loading.show();
|
||||||
|
@ -765,7 +772,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
getItem(params).then(function (item) {
|
getItem(params).then(function (item) {
|
||||||
setTitle(item);
|
setTitle(item);
|
||||||
self.currentItem = item;
|
self.currentItem = item;
|
||||||
var refresh = !isRestored;
|
const refresh = !isRestored;
|
||||||
self.itemsContainer.resume({
|
self.itemsContainer.resume({
|
||||||
refresh: refresh
|
refresh: refresh
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
|
@ -780,7 +787,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
initAlphaPicker();
|
initAlphaPicker();
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemType = item ? item.Type : null;
|
const itemType = item ? item.Type : null;
|
||||||
|
|
||||||
if (itemType === 'MusicGenre' || params.type !== 'Programs' && itemType !== 'Channel') {
|
if (itemType === 'MusicGenre' || params.type !== 'Programs' && itemType !== 'Channel') {
|
||||||
hideOrShowAll(view.querySelectorAll('.btnPlay'), false);
|
hideOrShowAll(view.querySelectorAll('.btnPlay'), false);
|
||||||
|
@ -807,18 +814,18 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
bindAll(view.querySelectorAll('.btnShuffle'), 'click', shuffle);
|
bindAll(view.querySelectorAll('.btnShuffle'), 'click', shuffle);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.alphaNumericShortcuts = new AlphaNumericShortcuts.default({
|
self.alphaNumericShortcuts = new AlphaNumericShortcuts({
|
||||||
itemsContainer: self.itemsContainer
|
itemsContainer: self.itemsContainer
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
view.addEventListener('viewhide', function (e) {
|
view.addEventListener('viewhide', function (e) {
|
||||||
var itemsContainer = self.itemsContainer;
|
const itemsContainer = self.itemsContainer;
|
||||||
|
|
||||||
if (itemsContainer) {
|
if (itemsContainer) {
|
||||||
itemsContainer.pause();
|
itemsContainer.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
var alphaNumericShortcuts = self.alphaNumericShortcuts;
|
const alphaNumericShortcuts = self.alphaNumericShortcuts;
|
||||||
|
|
||||||
if (alphaNumericShortcuts) {
|
if (alphaNumericShortcuts) {
|
||||||
alphaNumericShortcuts.destroy();
|
alphaNumericShortcuts.destroy();
|
||||||
|
@ -846,8 +853,8 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getFilters = function () {
|
getFilters() {
|
||||||
var basekey = this.getSettingsKey();
|
const basekey = this.getSettingsKey();
|
||||||
return {
|
return {
|
||||||
IsPlayed: userSettings.getFilter(basekey + '-filter-IsPlayed') === 'true',
|
IsPlayed: userSettings.getFilter(basekey + '-filter-IsPlayed') === 'true',
|
||||||
IsUnplayed: userSettings.getFilter(basekey + '-filter-IsUnplayed') === 'true',
|
IsUnplayed: userSettings.getFilter(basekey + '-filter-IsUnplayed') === 'true',
|
||||||
|
@ -866,39 +873,37 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
HasThemeVideo: userSettings.getFilter(basekey + '-filter-HasThemeVideo'),
|
HasThemeVideo: userSettings.getFilter(basekey + '-filter-HasThemeVideo'),
|
||||||
GenreIds: userSettings.getFilter(basekey + '-filter-GenreIds')
|
GenreIds: userSettings.getFilter(basekey + '-filter-GenreIds')
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getSortValues = function () {
|
getSortValues() {
|
||||||
var basekey = this.getSettingsKey();
|
const basekey = this.getSettingsKey();
|
||||||
return {
|
return {
|
||||||
sortBy: userSettings.getFilter(basekey + '-sortby') || this.getDefaultSortBy(),
|
sortBy: userSettings.getFilter(basekey + '-sortby') || this.getDefaultSortBy(),
|
||||||
sortOrder: userSettings.getFilter(basekey + '-sortorder') === 'Descending' ? 'Descending' : 'Ascending'
|
sortOrder: userSettings.getFilter(basekey + '-sortorder') === 'Descending' ? 'Descending' : 'Ascending'
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getDefaultSortBy = function () {
|
getDefaultSortBy() {
|
||||||
var params = this.params;
|
const sortNameOption = this.getNameSortOption(this.params);
|
||||||
var sortNameOption = this.getNameSortOption(params);
|
|
||||||
|
|
||||||
if (params.type) {
|
if (this.params.type) {
|
||||||
return sortNameOption.value;
|
return sortNameOption.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'IsFolder,' + sortNameOption.value;
|
return 'IsFolder,' + sortNameOption.value;
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getSortMenuOptions = function () {
|
getSortMenuOptions() {
|
||||||
var sortBy = [];
|
const sortBy = [];
|
||||||
var params = this.params;
|
|
||||||
|
|
||||||
if (params.type === 'Programs') {
|
if (this.params.type === 'Programs') {
|
||||||
sortBy.push({
|
sortBy.push({
|
||||||
name: globalize.translate('AirDate'),
|
name: globalize.translate('AirDate'),
|
||||||
value: 'StartDate,SortName'
|
value: 'StartDate,SortName'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var option = this.getNameSortOption(params);
|
let option = this.getNameSortOption(this.params);
|
||||||
|
|
||||||
if (option) {
|
if (option) {
|
||||||
sortBy.push(option);
|
sortBy.push(option);
|
||||||
|
@ -916,7 +921,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
sortBy.push(option);
|
sortBy.push(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.type !== 'Programs') {
|
if (this.params.type !== 'Programs') {
|
||||||
sortBy.push({
|
sortBy.push({
|
||||||
name: globalize.translate('DateAdded'),
|
name: globalize.translate('DateAdded'),
|
||||||
value: 'DateCreated,SortName'
|
value: 'DateCreated,SortName'
|
||||||
|
@ -929,8 +934,8 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
sortBy.push(option);
|
sortBy.push(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!params.type) {
|
if (!this.params.type) {
|
||||||
option = this.getNameSortOption(params);
|
option = this.getNameSortOption(this.params);
|
||||||
sortBy.push({
|
sortBy.push({
|
||||||
name: globalize.translate('Folders'),
|
name: globalize.translate('Folders'),
|
||||||
value: 'IsFolder,' + option.value
|
value: 'IsFolder,' + option.value
|
||||||
|
@ -956,9 +961,9 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
value: 'Runtime,SortName'
|
value: 'Runtime,SortName'
|
||||||
});
|
});
|
||||||
return sortBy;
|
return sortBy;
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getNameSortOption = function (params) {
|
getNameSortOption(params) {
|
||||||
if (params.type === 'Episode') {
|
if (params.type === 'Episode') {
|
||||||
return {
|
return {
|
||||||
name: globalize.translate('Name'),
|
name: globalize.translate('Name'),
|
||||||
|
@ -970,9 +975,9 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
name: globalize.translate('Name'),
|
name: globalize.translate('Name'),
|
||||||
value: 'SortName'
|
value: 'SortName'
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getPlayCountSortOption = function () {
|
getPlayCountSortOption() {
|
||||||
if (this.params.type === 'Programs') {
|
if (this.params.type === 'Programs') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -981,9 +986,9 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
name: globalize.translate('PlayCount'),
|
name: globalize.translate('PlayCount'),
|
||||||
value: 'PlayCount,SortName'
|
value: 'PlayCount,SortName'
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getDatePlayedSortOption = function () {
|
getDatePlayedSortOption() {
|
||||||
if (this.params.type === 'Programs') {
|
if (this.params.type === 'Programs') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -992,9 +997,9 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
name: globalize.translate('DatePlayed'),
|
name: globalize.translate('DatePlayed'),
|
||||||
value: 'DatePlayed,SortName'
|
value: 'DatePlayed,SortName'
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getCriticRatingSortOption = function () {
|
getCriticRatingSortOption() {
|
||||||
if (this.params.type === 'Programs') {
|
if (this.params.type === 'Programs') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1003,18 +1008,18 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
name: globalize.translate('CriticRating'),
|
name: globalize.translate('CriticRating'),
|
||||||
value: 'CriticRating,SortName'
|
value: 'CriticRating,SortName'
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getCommunityRatingSortOption = function () {
|
getCommunityRatingSortOption() {
|
||||||
return {
|
return {
|
||||||
name: globalize.translate('CommunityRating'),
|
name: globalize.translate('CommunityRating'),
|
||||||
value: 'CommunityRating,SortName'
|
value: 'CommunityRating,SortName'
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getVisibleFilters = function () {
|
getVisibleFilters() {
|
||||||
var filters = [];
|
const filters = [];
|
||||||
var params = this.params;
|
const params = this.params;
|
||||||
|
|
||||||
if (!(params.type === 'nextup')) {
|
if (!(params.type === 'nextup')) {
|
||||||
if (params.type === 'Programs') {
|
if (params.type === 'Programs') {
|
||||||
|
@ -1038,16 +1043,15 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
return filters;
|
return filters;
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.setFilterStatus = function (hasFilters) {
|
setFilterStatus(hasFilters) {
|
||||||
this.hasFilters = hasFilters;
|
this.hasFilters = hasFilters;
|
||||||
var filterButtons = this.filterButtons;
|
const filterButtons = this.filterButtons;
|
||||||
|
|
||||||
if (filterButtons.length) {
|
if (filterButtons.length) {
|
||||||
for (var i = 0, length = filterButtons.length; i < length; i++) {
|
for (const btnFilter of filterButtons) {
|
||||||
var btnFilter = filterButtons[i];
|
let bubble = btnFilter.querySelector('.filterButtonBubble');
|
||||||
var bubble = btnFilter.querySelector('.filterButtonBubble');
|
|
||||||
|
|
||||||
if (!bubble) {
|
if (!bubble) {
|
||||||
if (!hasFilters) {
|
if (!hasFilters) {
|
||||||
|
@ -1066,10 +1070,10 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getFilterMenuOptions = function () {
|
getFilterMenuOptions() {
|
||||||
var params = this.params;
|
const params = this.params;
|
||||||
return {
|
return {
|
||||||
IsAiring: params.IsAiring,
|
IsAiring: params.IsAiring,
|
||||||
IsMovie: params.IsMovie,
|
IsMovie: params.IsMovie,
|
||||||
|
@ -1079,11 +1083,11 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
IsSeries: params.IsSeries,
|
IsSeries: params.IsSeries,
|
||||||
Recursive: this.queryRecursive
|
Recursive: this.queryRecursive
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getVisibleViewSettings = function () {
|
getVisibleViewSettings() {
|
||||||
var item = (this.params, this.currentItem);
|
const item = (this.params, this.currentItem);
|
||||||
var fields = ['showTitle'];
|
const fields = ['showTitle'];
|
||||||
|
|
||||||
if (!item || item.Type !== 'PhotoAlbum' && item.Type !== 'ChannelFolderItem') {
|
if (!item || item.Type !== 'PhotoAlbum' && item.Type !== 'ChannelFolderItem') {
|
||||||
fields.push('imageType');
|
fields.push('imageType');
|
||||||
|
@ -1091,13 +1095,13 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
|
|
||||||
fields.push('viewType');
|
fields.push('viewType');
|
||||||
return fields;
|
return fields;
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getViewSettings = function () {
|
getViewSettings() {
|
||||||
var basekey = this.getSettingsKey();
|
const basekey = this.getSettingsKey();
|
||||||
var params = this.params;
|
const params = this.params;
|
||||||
var item = this.currentItem;
|
const item = this.currentItem;
|
||||||
var showTitle = userSettings.get(basekey + '-showTitle');
|
let showTitle = userSettings.get(basekey + '-showTitle');
|
||||||
|
|
||||||
if (showTitle === 'true') {
|
if (showTitle === 'true') {
|
||||||
showTitle = true;
|
showTitle = true;
|
||||||
|
@ -1109,7 +1113,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
showTitle = true;
|
showTitle = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var imageType = userSettings.get(basekey + '-imageType');
|
let imageType = userSettings.get(basekey + '-imageType');
|
||||||
|
|
||||||
if (!imageType && params.type === 'nextup') {
|
if (!imageType && params.type === 'nextup') {
|
||||||
imageType = 'thumb';
|
imageType = 'thumb';
|
||||||
|
@ -1121,10 +1125,10 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
imageType: imageType || 'primary',
|
imageType: imageType || 'primary',
|
||||||
viewType: userSettings.get(basekey + '-viewType') || 'images'
|
viewType: userSettings.get(basekey + '-viewType') || 'images'
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getItemTypes = function () {
|
getItemTypes() {
|
||||||
var params = this.params;
|
const params = this.params;
|
||||||
|
|
||||||
if (params.type === 'nextup') {
|
if (params.type === 'nextup') {
|
||||||
return ['Episode'];
|
return ['Episode'];
|
||||||
|
@ -1135,12 +1139,12 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
};
|
}
|
||||||
|
|
||||||
ItemsView.prototype.getSettingsKey = function () {
|
getSettingsKey() {
|
||||||
var values = [];
|
const values = [];
|
||||||
values.push('items');
|
values.push('items');
|
||||||
var params = this.params;
|
const params = this.params;
|
||||||
|
|
||||||
if (params.type) {
|
if (params.type) {
|
||||||
values.push(params.type);
|
values.push(params.type);
|
||||||
|
@ -1197,7 +1201,9 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
|
||||||
}
|
}
|
||||||
|
|
||||||
return values.join('-');
|
return values.join('-');
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ItemsView;
|
export default ItemsView;
|
||||||
});
|
|
||||||
|
/* eslint-enable indent */
|
||||||
|
|
|
@ -2,6 +2,7 @@ define(['layoutManager', 'userSettings', 'inputManager', 'loading', 'globalize',
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
loading = loading.default || loading;
|
loading = loading.default || loading;
|
||||||
|
layoutManager = layoutManager.default || layoutManager;
|
||||||
|
|
||||||
function enableScrollX() {
|
function enableScrollX() {
|
||||||
return !layoutManager.desktop;
|
return !layoutManager.desktop;
|
||||||
|
|
|
@ -137,8 +137,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen
|
@media screen
|
||||||
and (min-device-width: 992px)
|
and (min-device-width: 992px) {
|
||||||
and (-webkit-min-device-pixel-ratio: 1) {
|
|
||||||
.splashLogo {
|
.splashLogo {
|
||||||
background-image: url(assets/img/banner-light.png);
|
background-image: url(assets/img/banner-light.png);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,134 +1,128 @@
|
||||||
define(["events", "playbackManager", "pluginManager", "inputManager", "connectionManager", "userSettings"], function (events, playbackManager, pluginManager, inputManager, connectionManager, userSettings) {
|
import events from 'events';
|
||||||
"use strict";
|
import playbackManager from 'playbackManager';
|
||||||
|
import pluginManager from 'pluginManager';
|
||||||
|
import inputManager from 'inputManager';
|
||||||
|
import connectionManager from 'connectionManager';
|
||||||
|
import * as userSettings from 'userSettings';
|
||||||
|
|
||||||
playbackManager = playbackManager.default || playbackManager;
|
function getMinIdleTime() {
|
||||||
|
// Returns the minimum amount of idle time required before the screen saver can be displayed
|
||||||
|
//time units used Millisecond
|
||||||
|
return 180000;
|
||||||
|
}
|
||||||
|
|
||||||
function getMinIdleTime() {
|
let lastFunctionalEvent = 0;
|
||||||
// Returns the minimum amount of idle time required before the screen saver can be displayed
|
|
||||||
//time units used Millisecond
|
function getFunctionalEventIdleTime() {
|
||||||
return 180000;
|
return new Date().getTime() - lastFunctionalEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
events.on(playbackManager, 'playbackstop', function (e, stopInfo) {
|
||||||
|
const state = stopInfo.state;
|
||||||
|
if (state.NowPlayingItem && state.NowPlayingItem.MediaType == 'Video') {
|
||||||
|
lastFunctionalEvent = new Date().getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastFunctionalEvent = 0;
|
|
||||||
|
|
||||||
function getFunctionalEventIdleTime() {
|
|
||||||
return new Date().getTime() - lastFunctionalEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
events.on(playbackManager, "playbackstop", function (e, stopInfo) {
|
|
||||||
var state = stopInfo.state;
|
|
||||||
if (state.NowPlayingItem && state.NowPlayingItem.MediaType == "Video") {
|
|
||||||
lastFunctionalEvent = new Date().getTime();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function getScreensaverPlugin(isLoggedIn) {
|
|
||||||
|
|
||||||
var option;
|
|
||||||
try {
|
|
||||||
option = userSettings.get("screensaver", false);
|
|
||||||
} catch (err) {
|
|
||||||
option = isLoggedIn ? "backdropscreensaver" : "logoscreensaver";
|
|
||||||
}
|
|
||||||
|
|
||||||
var plugins = pluginManager.ofType("screensaver");
|
|
||||||
|
|
||||||
for (var i = 0, length = plugins.length; i < length; i++) {
|
|
||||||
var plugin = plugins[i];
|
|
||||||
|
|
||||||
if (plugin.id === option) {
|
|
||||||
return plugin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function ScreenSaverManager() {
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
var activeScreenSaver;
|
|
||||||
|
|
||||||
function showScreenSaver(screensaver) {
|
|
||||||
|
|
||||||
if (activeScreenSaver) {
|
|
||||||
throw new Error("An existing screensaver is already active.");
|
|
||||||
}
|
|
||||||
|
|
||||||
console.debug("Showing screensaver " + screensaver.name);
|
|
||||||
|
|
||||||
screensaver.show();
|
|
||||||
activeScreenSaver = screensaver;
|
|
||||||
|
|
||||||
if (screensaver.hideOnClick !== false) {
|
|
||||||
window.addEventListener("click", hide, true);
|
|
||||||
}
|
|
||||||
if (screensaver.hideOnMouse !== false) {
|
|
||||||
window.addEventListener("mousemove", hide, true);
|
|
||||||
}
|
|
||||||
if (screensaver.hideOnKey !== false) {
|
|
||||||
window.addEventListener("keydown", hide, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function hide() {
|
|
||||||
if (activeScreenSaver) {
|
|
||||||
console.debug("Hiding screensaver");
|
|
||||||
activeScreenSaver.hide();
|
|
||||||
activeScreenSaver = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.removeEventListener("click", hide, true);
|
|
||||||
window.removeEventListener("mousemove", hide, true);
|
|
||||||
window.removeEventListener("keydown", hide, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.isShowing = function () {
|
|
||||||
return activeScreenSaver != null;
|
|
||||||
};
|
|
||||||
|
|
||||||
self.show = function () {
|
|
||||||
var isLoggedIn;
|
|
||||||
var apiClient = connectionManager.currentApiClient();
|
|
||||||
|
|
||||||
if (apiClient && apiClient.isLoggedIn()) {
|
|
||||||
isLoggedIn = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var screensaver = getScreensaverPlugin(isLoggedIn);
|
|
||||||
|
|
||||||
if (screensaver) {
|
|
||||||
showScreenSaver(screensaver);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.hide = function () {
|
|
||||||
hide();
|
|
||||||
};
|
|
||||||
|
|
||||||
function onInterval() {
|
|
||||||
|
|
||||||
if (self.isShowing()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputManager.idleTime() < getMinIdleTime()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getFunctionalEventIdleTime < getMinIdleTime()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playbackManager.isPlayingVideo()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
setInterval(onInterval, 10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ScreenSaverManager();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getScreensaverPlugin(isLoggedIn) {
|
||||||
|
let option;
|
||||||
|
try {
|
||||||
|
option = userSettings.get('screensaver', false);
|
||||||
|
} catch (err) {
|
||||||
|
option = isLoggedIn ? 'backdropscreensaver' : 'logoscreensaver';
|
||||||
|
}
|
||||||
|
|
||||||
|
const plugins = pluginManager.ofType('screensaver');
|
||||||
|
|
||||||
|
for (const plugin of plugins) {
|
||||||
|
if (plugin.id === option) {
|
||||||
|
return plugin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ScreenSaverManager() {
|
||||||
|
let activeScreenSaver;
|
||||||
|
|
||||||
|
function showScreenSaver(screensaver) {
|
||||||
|
if (activeScreenSaver) {
|
||||||
|
throw new Error('An existing screensaver is already active.');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.debug('Showing screensaver ' + screensaver.name);
|
||||||
|
|
||||||
|
screensaver.show();
|
||||||
|
activeScreenSaver = screensaver;
|
||||||
|
|
||||||
|
if (screensaver.hideOnClick !== false) {
|
||||||
|
window.addEventListener('click', hide, true);
|
||||||
|
}
|
||||||
|
if (screensaver.hideOnMouse !== false) {
|
||||||
|
window.addEventListener('mousemove', hide, true);
|
||||||
|
}
|
||||||
|
if (screensaver.hideOnKey !== false) {
|
||||||
|
window.addEventListener('keydown', hide, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
if (activeScreenSaver) {
|
||||||
|
console.debug('Hiding screensaver');
|
||||||
|
activeScreenSaver.hide();
|
||||||
|
activeScreenSaver = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.removeEventListener('click', hide, true);
|
||||||
|
window.removeEventListener('mousemove', hide, true);
|
||||||
|
window.removeEventListener('keydown', hide, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isShowing = () => {
|
||||||
|
return activeScreenSaver != null;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.show = function () {
|
||||||
|
let isLoggedIn;
|
||||||
|
const apiClient = connectionManager.currentApiClient();
|
||||||
|
|
||||||
|
if (apiClient && apiClient.isLoggedIn()) {
|
||||||
|
isLoggedIn = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const screensaver = getScreensaverPlugin(isLoggedIn);
|
||||||
|
|
||||||
|
if (screensaver) {
|
||||||
|
showScreenSaver(screensaver);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.hide = function () {
|
||||||
|
hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onInterval = () => {
|
||||||
|
if (this.isShowing()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputManager.idleTime() < getMinIdleTime()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getFunctionalEventIdleTime < getMinIdleTime()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playbackManager.isPlayingVideo()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.show();
|
||||||
|
};
|
||||||
|
|
||||||
|
setInterval(onInterval, 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new ScreenSaverManager;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,165 +1,165 @@
|
||||||
define(['pluginManager'], function (pluginManager) {
|
import pluginManager from 'pluginManager';
|
||||||
return function () {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
self.name = 'Logo ScreenSaver';
|
export default function () {
|
||||||
self.type = 'screensaver';
|
const self = this;
|
||||||
self.id = 'logoscreensaver';
|
|
||||||
self.supportsAnonymous = true;
|
|
||||||
|
|
||||||
var interval;
|
self.name = 'Logo ScreenSaver';
|
||||||
|
self.type = 'screensaver';
|
||||||
|
self.id = 'logoscreensaver';
|
||||||
|
self.supportsAnonymous = true;
|
||||||
|
|
||||||
function animate() {
|
let interval;
|
||||||
var animations = [
|
|
||||||
|
|
||||||
bounceInLeft,
|
function animate() {
|
||||||
bounceInRight,
|
const animations = [
|
||||||
swing,
|
|
||||||
tada,
|
|
||||||
wobble,
|
|
||||||
rotateIn,
|
|
||||||
rotateOut
|
|
||||||
];
|
|
||||||
|
|
||||||
var elem = document.querySelector('.logoScreenSaverImage');
|
bounceInLeft,
|
||||||
|
bounceInRight,
|
||||||
|
swing,
|
||||||
|
tada,
|
||||||
|
wobble,
|
||||||
|
rotateIn,
|
||||||
|
rotateOut
|
||||||
|
];
|
||||||
|
|
||||||
if (elem && elem.animate) {
|
const elem = document.querySelector('.logoScreenSaverImage');
|
||||||
var random = getRandomInt(0, animations.length - 1);
|
|
||||||
|
|
||||||
animations[random](elem, 1);
|
if (elem && elem.animate) {
|
||||||
|
const random = getRandomInt(0, animations.length - 1);
|
||||||
|
|
||||||
|
animations[random](elem, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRandomInt(min, max) {
|
||||||
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bounceInLeft(elem, iterations) {
|
||||||
|
const keyframes = [
|
||||||
|
{ transform: 'translate3d(-3000px, 0, 0)', opacity: '0', offset: 0 },
|
||||||
|
{ transform: 'translate3d(25px, 0, 0)', opacity: '1', offset: 0.6 },
|
||||||
|
{ transform: 'translate3d(-100px, 0, 0)', offset: 0.75 },
|
||||||
|
{ transform: 'translate3d(5px, 0, 0)', offset: 0.9 },
|
||||||
|
{ transform: 'none', opacity: '1', offset: 1 }];
|
||||||
|
const timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' };
|
||||||
|
return elem.animate(keyframes, timing);
|
||||||
|
}
|
||||||
|
|
||||||
|
function bounceInRight(elem, iterations) {
|
||||||
|
const keyframes = [
|
||||||
|
{ transform: 'translate3d(3000px, 0, 0)', opacity: '0', offset: 0 },
|
||||||
|
{ transform: 'translate3d(-25px, 0, 0)', opacity: '1', offset: 0.6 },
|
||||||
|
{ transform: 'translate3d(100px, 0, 0)', offset: 0.75 },
|
||||||
|
{ transform: 'translate3d(-5px, 0, 0)', offset: 0.9 },
|
||||||
|
{ transform: 'none', opacity: '1', offset: 1 }];
|
||||||
|
const timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' };
|
||||||
|
return elem.animate(keyframes, timing);
|
||||||
|
}
|
||||||
|
|
||||||
|
function swing(elem, iterations) {
|
||||||
|
const keyframes = [
|
||||||
|
{ transform: 'translate(0%)', offset: 0 },
|
||||||
|
{ transform: 'rotate3d(0, 0, 1, 15deg)', offset: 0.2 },
|
||||||
|
{ transform: 'rotate3d(0, 0, 1, -10deg)', offset: 0.4 },
|
||||||
|
{ transform: 'rotate3d(0, 0, 1, 5deg)', offset: 0.6 },
|
||||||
|
{ transform: 'rotate3d(0, 0, 1, -5deg)', offset: 0.8 },
|
||||||
|
{ transform: 'rotate3d(0, 0, 1, 0deg)', offset: 1 }];
|
||||||
|
const timing = { duration: 900, iterations: iterations };
|
||||||
|
return elem.animate(keyframes, timing);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tada(elem, iterations) {
|
||||||
|
const keyframes = [
|
||||||
|
{ transform: 'scale3d(1, 1, 1)', offset: 0 },
|
||||||
|
{ transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.1 },
|
||||||
|
{ transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.2 },
|
||||||
|
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.3 },
|
||||||
|
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.4 },
|
||||||
|
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.5 },
|
||||||
|
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.6 },
|
||||||
|
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.7 },
|
||||||
|
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.8 },
|
||||||
|
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.9 },
|
||||||
|
{ transform: 'scale3d(1, 1, 1)', offset: 1 }];
|
||||||
|
const timing = { duration: 900, iterations: iterations };
|
||||||
|
return elem.animate(keyframes, timing);
|
||||||
|
}
|
||||||
|
|
||||||
|
function wobble(elem, iterations) {
|
||||||
|
const keyframes = [
|
||||||
|
{ transform: 'translate(0%)', offset: 0 },
|
||||||
|
{ transform: 'translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg)', offset: 0.15 },
|
||||||
|
{ transform: 'translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg)', offset: 0.45 },
|
||||||
|
{ transform: 'translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg)', offset: 0.6 },
|
||||||
|
{ transform: 'translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg)', offset: 0.75 },
|
||||||
|
{ transform: 'translateX(0%)', offset: 1 }];
|
||||||
|
const timing = { duration: 900, iterations: iterations };
|
||||||
|
return elem.animate(keyframes, timing);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rotateIn(elem, iterations) {
|
||||||
|
const keyframes = [{ transform: 'rotate3d(0, 0, 1, -200deg)', opacity: '0', transformOrigin: 'center', offset: 0 },
|
||||||
|
{ transform: 'none', opacity: '1', transformOrigin: 'center', offset: 1 }];
|
||||||
|
const timing = { duration: 900, iterations: iterations };
|
||||||
|
return elem.animate(keyframes, timing);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rotateOut(elem, iterations) {
|
||||||
|
const keyframes = [{ transform: 'none', opacity: '1', transformOrigin: 'center', offset: 0 },
|
||||||
|
{ transform: 'rotate3d(0, 0, 1, 200deg)', opacity: '0', transformOrigin: 'center', offset: 1 }];
|
||||||
|
const timing = { duration: 900, iterations: iterations };
|
||||||
|
return elem.animate(keyframes, timing);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fadeOut(elem, iterations) {
|
||||||
|
const keyframes = [
|
||||||
|
{ opacity: '1', offset: 0 },
|
||||||
|
{ opacity: '0', offset: 1 }];
|
||||||
|
const timing = { duration: 400, iterations: iterations };
|
||||||
|
return elem.animate(keyframes, timing);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopInterval() {
|
||||||
|
if (interval) {
|
||||||
|
clearInterval(interval);
|
||||||
|
interval = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.show = function () {
|
||||||
|
import('css!' + pluginManager.mapPath(self, 'style.css')).then(() => {
|
||||||
|
let elem = document.querySelector('.logoScreenSaver');
|
||||||
|
|
||||||
|
if (!elem) {
|
||||||
|
elem = document.createElement('div');
|
||||||
|
elem.classList.add('logoScreenSaver');
|
||||||
|
document.body.appendChild(elem);
|
||||||
|
|
||||||
|
elem.innerHTML = '<img class="logoScreenSaverImage" src="assets/img/banner-light.png" />';
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function getRandomInt(min, max) {
|
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
||||||
}
|
|
||||||
|
|
||||||
function bounceInLeft(elem, iterations) {
|
|
||||||
var keyframes = [
|
|
||||||
{ transform: 'translate3d(-3000px, 0, 0)', opacity: '0', offset: 0 },
|
|
||||||
{ transform: 'translate3d(25px, 0, 0)', opacity: '1', offset: 0.6 },
|
|
||||||
{ transform: 'translate3d(-100px, 0, 0)', offset: 0.75 },
|
|
||||||
{ transform: 'translate3d(5px, 0, 0)', offset: 0.9 },
|
|
||||||
{ transform: 'none', opacity: '1', offset: 1 }];
|
|
||||||
var timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' };
|
|
||||||
return elem.animate(keyframes, timing);
|
|
||||||
}
|
|
||||||
|
|
||||||
function bounceInRight(elem, iterations) {
|
|
||||||
var keyframes = [
|
|
||||||
{ transform: 'translate3d(3000px, 0, 0)', opacity: '0', offset: 0 },
|
|
||||||
{ transform: 'translate3d(-25px, 0, 0)', opacity: '1', offset: 0.6 },
|
|
||||||
{ transform: 'translate3d(100px, 0, 0)', offset: 0.75 },
|
|
||||||
{ transform: 'translate3d(-5px, 0, 0)', offset: 0.9 },
|
|
||||||
{ transform: 'none', opacity: '1', offset: 1 }];
|
|
||||||
var timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' };
|
|
||||||
return elem.animate(keyframes, timing);
|
|
||||||
}
|
|
||||||
|
|
||||||
function swing(elem, iterations) {
|
|
||||||
var keyframes = [
|
|
||||||
{ transform: 'translate(0%)', offset: 0 },
|
|
||||||
{ transform: 'rotate3d(0, 0, 1, 15deg)', offset: 0.2 },
|
|
||||||
{ transform: 'rotate3d(0, 0, 1, -10deg)', offset: 0.4 },
|
|
||||||
{ transform: 'rotate3d(0, 0, 1, 5deg)', offset: 0.6 },
|
|
||||||
{ transform: 'rotate3d(0, 0, 1, -5deg)', offset: 0.8 },
|
|
||||||
{ transform: 'rotate3d(0, 0, 1, 0deg)', offset: 1 }];
|
|
||||||
var timing = { duration: 900, iterations: iterations };
|
|
||||||
return elem.animate(keyframes, timing);
|
|
||||||
}
|
|
||||||
|
|
||||||
function tada(elem, iterations) {
|
|
||||||
var keyframes = [
|
|
||||||
{ transform: 'scale3d(1, 1, 1)', offset: 0 },
|
|
||||||
{ transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.1 },
|
|
||||||
{ transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.2 },
|
|
||||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.3 },
|
|
||||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.4 },
|
|
||||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.5 },
|
|
||||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.6 },
|
|
||||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.7 },
|
|
||||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.8 },
|
|
||||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.9 },
|
|
||||||
{ transform: 'scale3d(1, 1, 1)', offset: 1 }];
|
|
||||||
var timing = { duration: 900, iterations: iterations };
|
|
||||||
return elem.animate(keyframes, timing);
|
|
||||||
}
|
|
||||||
|
|
||||||
function wobble(elem, iterations) {
|
|
||||||
var keyframes = [
|
|
||||||
{ transform: 'translate(0%)', offset: 0 },
|
|
||||||
{ transform: 'translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg)', offset: 0.15 },
|
|
||||||
{ transform: 'translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg)', offset: 0.45 },
|
|
||||||
{ transform: 'translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg)', offset: 0.6 },
|
|
||||||
{ transform: 'translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg)', offset: 0.75 },
|
|
||||||
{ transform: 'translateX(0%)', offset: 1 }];
|
|
||||||
var timing = { duration: 900, iterations: iterations };
|
|
||||||
return elem.animate(keyframes, timing);
|
|
||||||
}
|
|
||||||
|
|
||||||
function rotateIn(elem, iterations) {
|
|
||||||
var keyframes = [{ transform: 'rotate3d(0, 0, 1, -200deg)', opacity: '0', transformOrigin: 'center', offset: 0 },
|
|
||||||
{ transform: 'none', opacity: '1', transformOrigin: 'center', offset: 1 }];
|
|
||||||
var timing = { duration: 900, iterations: iterations };
|
|
||||||
return elem.animate(keyframes, timing);
|
|
||||||
}
|
|
||||||
|
|
||||||
function rotateOut(elem, iterations) {
|
|
||||||
var keyframes = [{ transform: 'none', opacity: '1', transformOrigin: 'center', offset: 0 },
|
|
||||||
{ transform: 'rotate3d(0, 0, 1, 200deg)', opacity: '0', transformOrigin: 'center', offset: 1 }];
|
|
||||||
var timing = { duration: 900, iterations: iterations };
|
|
||||||
return elem.animate(keyframes, timing);
|
|
||||||
}
|
|
||||||
|
|
||||||
function fadeOut(elem, iterations) {
|
|
||||||
var keyframes = [
|
|
||||||
{ opacity: '1', offset: 0 },
|
|
||||||
{ opacity: '0', offset: 1 }];
|
|
||||||
var timing = { duration: 400, iterations: iterations };
|
|
||||||
return elem.animate(keyframes, timing);
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopInterval() {
|
|
||||||
if (interval) {
|
|
||||||
clearInterval(interval);
|
|
||||||
interval = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.show = function () {
|
|
||||||
require(['css!' + pluginManager.mapPath(self, 'style.css')], function () {
|
|
||||||
var elem = document.querySelector('.logoScreenSaver');
|
|
||||||
|
|
||||||
if (!elem) {
|
|
||||||
elem = document.createElement('div');
|
|
||||||
elem.classList.add('logoScreenSaver');
|
|
||||||
document.body.appendChild(elem);
|
|
||||||
|
|
||||||
elem.innerHTML = '<img class="logoScreenSaverImage" src="assets/img/banner-light.png" />';
|
|
||||||
}
|
|
||||||
|
|
||||||
stopInterval();
|
|
||||||
interval = setInterval(animate, 3000);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
self.hide = function () {
|
|
||||||
stopInterval();
|
stopInterval();
|
||||||
|
interval = setInterval(animate, 3000);
|
||||||
var elem = document.querySelector('.logoScreenSaver');
|
});
|
||||||
|
|
||||||
if (elem) {
|
|
||||||
var onAnimationFinish = function () {
|
|
||||||
elem.parentNode.removeChild(elem);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (elem.animate) {
|
|
||||||
var animation = fadeOut(elem, 1);
|
|
||||||
animation.onfinish = onAnimationFinish;
|
|
||||||
} else {
|
|
||||||
onAnimationFinish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
});
|
|
||||||
|
self.hide = function () {
|
||||||
|
stopInterval();
|
||||||
|
|
||||||
|
const elem = document.querySelector('.logoScreenSaver');
|
||||||
|
|
||||||
|
if (elem) {
|
||||||
|
const onAnimationFinish = function () {
|
||||||
|
elem.parentNode.removeChild(elem);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (elem.animate) {
|
||||||
|
const animation = fadeOut(elem, 1);
|
||||||
|
animation.onfinish = onAnimationFinish;
|
||||||
|
} else {
|
||||||
|
onAnimationFinish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,33 +1,26 @@
|
||||||
define(['connectionManager', 'globalize'], function (connectionManager, globalize) {
|
import connectionManager from 'connectionManager';
|
||||||
'use strict';
|
import globalize from 'globalize';
|
||||||
|
|
||||||
function getRequirePromise(deps) {
|
function showErrorMessage() {
|
||||||
return new Promise(function (resolve, reject) {
|
return import('alert').then(({default: alert}) => {
|
||||||
require(deps, resolve);
|
return alert(globalize.translate('MessagePlayAccessRestricted'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showErrorMessage() {
|
class PlayAccessValidation {
|
||||||
return getRequirePromise(['alert']).then(function (alert) {
|
constructor() {
|
||||||
return alert(globalize.translate('MessagePlayAccessRestricted')).then(function () {
|
|
||||||
return Promise.reject();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function PlayAccessValidation() {
|
|
||||||
this.name = 'Playback validation';
|
this.name = 'Playback validation';
|
||||||
this.type = 'preplayintercept';
|
this.type = 'preplayintercept';
|
||||||
this.id = 'playaccessvalidation';
|
this.id = 'playaccessvalidation';
|
||||||
this.order = -2;
|
this.order = -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayAccessValidation.prototype.intercept = function (options) {
|
intercept(options) {
|
||||||
var item = options.item;
|
const item = options.item;
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
var serverId = item.ServerId;
|
const serverId = item.ServerId;
|
||||||
if (!serverId) {
|
if (!serverId) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
@ -44,7 +37,7 @@ define(['connectionManager', 'globalize'], function (connectionManager, globaliz
|
||||||
|
|
||||||
return showErrorMessage();
|
return showErrorMessage();
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return PlayAccessValidation;
|
export default PlayAccessValidation;
|
||||||
});
|
|
||||||
|
|
|
@ -119,7 +119,10 @@ export function getQueryPagingHtml (options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function showSortMenu (options) {
|
export function showSortMenu (options) {
|
||||||
require(['dialogHelper', 'emby-radio'], function (dialogHelper) {
|
Promise.all([
|
||||||
|
import('dialogHelper'),
|
||||||
|
import('emby-radio')
|
||||||
|
]).then(([{default: dialogHelper}]) => {
|
||||||
function onSortByChange() {
|
function onSortByChange() {
|
||||||
var newValue = this.value;
|
var newValue = this.value;
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,26 @@
|
||||||
define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', 'viewManager', 'libraryBrowser', 'appRouter', 'apphost', 'playbackManager', 'syncPlayManager', 'groupSelectionMenu', 'browser', 'globalize', 'scripts/imagehelper', 'paper-icon-button-light', 'material-icons', 'scrollStyles', 'flexStyles'], function (dom, layoutManager, inputManager, connectionManager, events, viewManager, libraryBrowser, appRouter, appHost, playbackManager, syncPlayManager, groupSelectionMenu, browser, globalize, imageHelper) {
|
import dom from 'dom';
|
||||||
'use strict';
|
import layoutManager from 'layoutManager';
|
||||||
|
import inputManager from 'inputManager';
|
||||||
|
import connectionManager from 'connectionManager';
|
||||||
|
import events from 'events';
|
||||||
|
import viewManager from 'viewManager';
|
||||||
|
import appRouter from 'appRouter';
|
||||||
|
import appHost from 'apphost';
|
||||||
|
import playbackManager from 'playbackManager';
|
||||||
|
import syncPlayManager from 'syncPlayManager';
|
||||||
|
import groupSelectionMenu from 'groupSelectionMenu';
|
||||||
|
import browser from 'browser';
|
||||||
|
import globalize from 'globalize';
|
||||||
|
import imageHelper from 'scripts/imagehelper';
|
||||||
|
import 'paper-icon-button-light';
|
||||||
|
import 'material-icons';
|
||||||
|
import 'scrollStyles';
|
||||||
|
import 'flexStyles';
|
||||||
|
|
||||||
viewManager = viewManager.default || viewManager;
|
/* eslint-disable indent */
|
||||||
playbackManager = playbackManager.default || playbackManager;
|
|
||||||
browser = browser.default || browser;
|
|
||||||
|
|
||||||
function renderHeader() {
|
function renderHeader() {
|
||||||
var html = '';
|
let html = '';
|
||||||
html += '<div class="flex align-items-center flex-grow headerTop">';
|
html += '<div class="flex align-items-center flex-grow headerTop">';
|
||||||
html += '<div class="headerLeft">';
|
html += '<div class="headerLeft">';
|
||||||
html += '<button type="button" is="paper-icon-button-light" class="headerButton headerButtonLeft headerBackButton hide"><span class="material-icons ' + (browser.safari ? 'chevron_left' : 'arrow_back') + '"></span></button>';
|
html += '<button type="button" is="paper-icon-button-light" class="headerButton headerButtonLeft headerBackButton hide"><span class="material-icons ' + (browser.safari ? 'chevron_left' : 'arrow_back') + '"></span></button>';
|
||||||
|
@ -50,7 +64,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function lazyLoadViewMenuBarImages() {
|
function lazyLoadViewMenuBarImages() {
|
||||||
require(['imageLoader'], function (imageLoader) {
|
import('imageLoader').then(({default: imageLoader}) => {
|
||||||
imageLoader.lazyChildren(skinHeader);
|
imageLoader.lazyChildren(skinHeader);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -60,11 +74,11 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateUserInHeader(user) {
|
function updateUserInHeader(user) {
|
||||||
var hasImage;
|
let hasImage;
|
||||||
|
|
||||||
if (user && user.name) {
|
if (user && user.name) {
|
||||||
if (user.imageUrl) {
|
if (user.imageUrl) {
|
||||||
var url = user.imageUrl;
|
const url = user.imageUrl;
|
||||||
updateHeaderUserButton(url);
|
updateHeaderUserButton(url);
|
||||||
hasImage = true;
|
hasImage = true;
|
||||||
}
|
}
|
||||||
|
@ -91,9 +105,9 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
headerCastButton.classList.remove('hide');
|
headerCastButton.classList.remove('hide');
|
||||||
}
|
}
|
||||||
|
|
||||||
var policy = user.Policy ? user.Policy : user.localUser.Policy;
|
const policy = user.Policy ? user.Policy : user.localUser.Policy;
|
||||||
|
|
||||||
var apiClient = getCurrentApiClient();
|
const apiClient = getCurrentApiClient();
|
||||||
if (headerSyncButton && policy && policy.SyncPlayAccess !== 'None' && apiClient.isMinServerVersion('10.6.0')) {
|
if (headerSyncButton && policy && policy.SyncPlayAccess !== 'None' && apiClient.isMinServerVersion('10.6.0')) {
|
||||||
headerSyncButton.classList.remove('hide');
|
headerSyncButton.classList.remove('hide');
|
||||||
}
|
}
|
||||||
|
@ -143,7 +157,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
mainDrawerButton.addEventListener('click', toggleMainDrawer);
|
mainDrawerButton.addEventListener('click', toggleMainDrawer);
|
||||||
}
|
}
|
||||||
|
|
||||||
var headerBackButton = skinHeader.querySelector('.headerBackButton');
|
const headerBackButton = skinHeader.querySelector('.headerBackButton');
|
||||||
|
|
||||||
if (headerBackButton) {
|
if (headerBackButton) {
|
||||||
headerBackButton.addEventListener('click', onBackClick);
|
headerBackButton.addEventListener('click', onBackClick);
|
||||||
|
@ -185,20 +199,20 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCastButtonClicked() {
|
function onCastButtonClicked() {
|
||||||
var btn = this;
|
const btn = this;
|
||||||
|
|
||||||
require(['playerSelectionMenu'], function (playerSelectionMenu) {
|
import('playerSelectionMenu').then(({default: playerSelectionMenu}) => {
|
||||||
playerSelectionMenu.show(btn);
|
playerSelectionMenu.show(btn);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSyncButtonClicked() {
|
function onSyncButtonClicked() {
|
||||||
var btn = this;
|
const btn = this;
|
||||||
groupSelectionMenu.show(btn);
|
groupSelectionMenu.show(btn);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSyncPlayEnabled(event, enabled) {
|
function onSyncPlayEnabled(event, enabled) {
|
||||||
var icon = headerSyncButton.querySelector('span');
|
const icon = headerSyncButton.querySelector('span');
|
||||||
icon.classList.remove('sync', 'sync_disabled', 'sync_problem');
|
icon.classList.remove('sync', 'sync_disabled', 'sync_problem');
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
icon.classList.add('sync');
|
icon.classList.add('sync');
|
||||||
|
@ -208,7 +222,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSyncPlaySyncing(event, is_syncing, syncMethod) {
|
function onSyncPlaySyncing(event, is_syncing, syncMethod) {
|
||||||
var icon = headerSyncButton.querySelector('span');
|
const icon = headerSyncButton.querySelector('span');
|
||||||
icon.classList.remove('sync', 'sync_disabled', 'sync_problem');
|
icon.classList.remove('sync', 'sync_disabled', 'sync_problem');
|
||||||
if (is_syncing) {
|
if (is_syncing) {
|
||||||
icon.classList.add('sync_problem');
|
icon.classList.add('sync_problem');
|
||||||
|
@ -254,7 +268,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshLibraryInfoInDrawer(user, drawer) {
|
function refreshLibraryInfoInDrawer(user, drawer) {
|
||||||
var html = '';
|
let html = '';
|
||||||
html += '<div style="height:.5em;"></div>';
|
html += '<div style="height:.5em;"></div>';
|
||||||
html += '<a is="emby-linkbutton" class="navMenuOption lnkMediaFolder" href="home.html"><span class="material-icons navMenuOptionIcon home"></span><span class="navMenuOptionText">' + globalize.translate('ButtonHome') + '</span></a>';
|
html += '<a is="emby-linkbutton" class="navMenuOption lnkMediaFolder" href="home.html"><span class="material-icons navMenuOptionIcon home"></span><span class="navMenuOptionText">' + globalize.translate('ButtonHome') + '</span></a>';
|
||||||
|
|
||||||
|
@ -290,12 +304,12 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
// add buttons to navigation drawer
|
// add buttons to navigation drawer
|
||||||
navDrawerScrollContainer.innerHTML = html;
|
navDrawerScrollContainer.innerHTML = html;
|
||||||
|
|
||||||
var btnSettings = navDrawerScrollContainer.querySelector('.btnSettings');
|
const btnSettings = navDrawerScrollContainer.querySelector('.btnSettings');
|
||||||
if (btnSettings) {
|
if (btnSettings) {
|
||||||
btnSettings.addEventListener('click', onSettingsClick);
|
btnSettings.addEventListener('click', onSettingsClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
var btnLogout = navDrawerScrollContainer.querySelector('.btnLogout');
|
const btnLogout = navDrawerScrollContainer.querySelector('.btnLogout');
|
||||||
if (btnLogout) {
|
if (btnLogout) {
|
||||||
btnLogout.addEventListener('click', onLogoutClick);
|
btnLogout.addEventListener('click', onLogoutClick);
|
||||||
}
|
}
|
||||||
|
@ -317,20 +331,20 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateDashboardMenuSelectedItem() {
|
function updateDashboardMenuSelectedItem() {
|
||||||
var links = navDrawerScrollContainer.querySelectorAll('.navMenuOption');
|
const links = navDrawerScrollContainer.querySelectorAll('.navMenuOption');
|
||||||
var currentViewId = viewManager.currentView().id;
|
const currentViewId = viewManager.currentView().id;
|
||||||
|
|
||||||
for (var i = 0, length = links.length; i < length; i++) {
|
for (let i = 0, length = links.length; i < length; i++) {
|
||||||
var link = links[i];
|
let link = links[i];
|
||||||
var selected = false;
|
let selected = false;
|
||||||
var pageIds = link.getAttribute('data-pageids');
|
let pageIds = link.getAttribute('data-pageids');
|
||||||
|
|
||||||
if (pageIds) {
|
if (pageIds) {
|
||||||
pageIds = pageIds.split('|');
|
pageIds = pageIds.split('|');
|
||||||
selected = pageIds.indexOf(currentViewId) != -1;
|
selected = pageIds.indexOf(currentViewId) != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pageUrls = link.getAttribute('data-pageurls');
|
let pageUrls = link.getAttribute('data-pageurls');
|
||||||
|
|
||||||
if (pageUrls) {
|
if (pageUrls) {
|
||||||
pageUrls = pageUrls.split('|');
|
pageUrls = pageUrls.split('|');
|
||||||
|
@ -339,7 +353,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
link.classList.add('navMenuOption-selected');
|
link.classList.add('navMenuOption-selected');
|
||||||
var title = '';
|
let title = '';
|
||||||
link = link.querySelector('.navMenuOptionText') || link;
|
link = link.querySelector('.navMenuOptionText') || link;
|
||||||
title += (link.innerText || link.textContent).trim();
|
title += (link.innerText || link.textContent).trim();
|
||||||
LibraryMenu.setTitle(title);
|
LibraryMenu.setTitle(title);
|
||||||
|
@ -350,7 +364,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function createToolsMenuList(pluginItems) {
|
function createToolsMenuList(pluginItems) {
|
||||||
var links = [{
|
const links = [{
|
||||||
name: globalize.translate('TabServer')
|
name: globalize.translate('TabServer')
|
||||||
}, {
|
}, {
|
||||||
name: globalize.translate('TabDashboard'),
|
name: globalize.translate('TabDashboard'),
|
||||||
|
@ -462,8 +476,8 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPluginPagesToMainMenu(links, pluginItems, section) {
|
function addPluginPagesToMainMenu(links, pluginItems, section) {
|
||||||
for (var i = 0, length = pluginItems.length; i < length; i++) {
|
for (let i = 0, length = pluginItems.length; i < length; i++) {
|
||||||
var pluginItem = pluginItems[i];
|
const pluginItem = pluginItems[i];
|
||||||
|
|
||||||
if (pluginItem.EnableInMainMenu && pluginItem.MenuSection === section) {
|
if (pluginItem.EnableInMainMenu && pluginItem.MenuSection === section) {
|
||||||
links.push({
|
links.push({
|
||||||
|
@ -483,10 +497,10 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function getToolsLinkHtml(item) {
|
function getToolsLinkHtml(item) {
|
||||||
var menuHtml = '';
|
let menuHtml = '';
|
||||||
var pageIds = item.pageIds ? item.pageIds.join('|') : '';
|
let pageIds = item.pageIds ? item.pageIds.join('|') : '';
|
||||||
pageIds = pageIds ? ' data-pageids="' + pageIds + '"' : '';
|
pageIds = pageIds ? ' data-pageids="' + pageIds + '"' : '';
|
||||||
var pageUrls = item.pageUrls ? item.pageUrls.join('|') : '';
|
let pageUrls = item.pageUrls ? item.pageUrls.join('|') : '';
|
||||||
pageUrls = pageUrls ? ' data-pageurls="' + pageUrls + '"' : '';
|
pageUrls = pageUrls ? ' data-pageurls="' + pageUrls + '"' : '';
|
||||||
menuHtml += '<a is="emby-linkbutton" class="navMenuOption" href="' + item.href + '"' + pageIds + pageUrls + '>';
|
menuHtml += '<a is="emby-linkbutton" class="navMenuOption" href="' + item.href + '"' + pageIds + pageUrls + '>';
|
||||||
|
|
||||||
|
@ -502,11 +516,11 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
|
|
||||||
function getToolsMenuHtml(apiClient) {
|
function getToolsMenuHtml(apiClient) {
|
||||||
return getToolsMenuLinks(apiClient).then(function (items) {
|
return getToolsMenuLinks(apiClient).then(function (items) {
|
||||||
var item;
|
let item;
|
||||||
var menuHtml = '';
|
let menuHtml = '';
|
||||||
menuHtml += '<div class="drawerContent">';
|
menuHtml += '<div class="drawerContent">';
|
||||||
|
|
||||||
for (var i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
item = items[i];
|
item = items[i];
|
||||||
|
|
||||||
if (item.href) {
|
if (item.href) {
|
||||||
|
@ -524,7 +538,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
|
|
||||||
function createDashboardMenu(apiClient) {
|
function createDashboardMenu(apiClient) {
|
||||||
return getToolsMenuHtml(apiClient).then(function (toolsMenuHtml) {
|
return getToolsMenuHtml(apiClient).then(function (toolsMenuHtml) {
|
||||||
var html = '';
|
let html = '';
|
||||||
html += '<a class="adminDrawerLogo clearLink" is="emby-linkbutton" href="home.html">';
|
html += '<a class="adminDrawerLogo clearLink" is="emby-linkbutton" href="home.html">';
|
||||||
html += '<img src="assets/img/icon-transparent.png" />';
|
html += '<img src="assets/img/icon-transparent.png" />';
|
||||||
html += '</a>';
|
html += '</a>';
|
||||||
|
@ -535,24 +549,24 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSidebarLinkClick() {
|
function onSidebarLinkClick() {
|
||||||
var section = this.getElementsByClassName('sectionName')[0];
|
const section = this.getElementsByClassName('sectionName')[0];
|
||||||
var text = section ? section.innerHTML : this.innerHTML;
|
const text = section ? section.innerHTML : this.innerHTML;
|
||||||
LibraryMenu.setTitle(text);
|
LibraryMenu.setTitle(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUserViews(apiClient, userId) {
|
function getUserViews(apiClient, userId) {
|
||||||
return apiClient.getUserViews({}, userId).then(function (result) {
|
return apiClient.getUserViews({}, userId).then(function (result) {
|
||||||
var items = result.Items;
|
const items = result.Items;
|
||||||
var list = [];
|
const list = [];
|
||||||
|
|
||||||
for (var i = 0, length = items.length; i < length; i++) {
|
for (let i = 0, length = items.length; i < length; i++) {
|
||||||
var view = items[i];
|
const view = items[i];
|
||||||
list.push(view);
|
list.push(view);
|
||||||
|
|
||||||
if (view.CollectionType == 'livetv') {
|
if (view.CollectionType == 'livetv') {
|
||||||
view.ImageTags = {};
|
view.ImageTags = {};
|
||||||
view.icon = 'live_tv';
|
view.icon = 'live_tv';
|
||||||
var guideView = Object.assign({}, view);
|
const guideView = Object.assign({}, view);
|
||||||
guideView.Name = globalize.translate('ButtonGuide');
|
guideView.Name = globalize.translate('ButtonGuide');
|
||||||
guideView.ImageTags = {};
|
guideView.ImageTags = {};
|
||||||
guideView.icon = 'dvr';
|
guideView.icon = 'dvr';
|
||||||
|
@ -566,7 +580,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function showBySelector(selector, show) {
|
function showBySelector(selector, show) {
|
||||||
var elem = document.querySelector(selector);
|
const elem = document.querySelector(selector);
|
||||||
|
|
||||||
if (elem) {
|
if (elem) {
|
||||||
if (show) {
|
if (show) {
|
||||||
|
@ -596,17 +610,17 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
showBySelector('.libraryMenuDownloads', false);
|
showBySelector('.libraryMenuDownloads', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var userId = Dashboard.getCurrentUserId();
|
const userId = Dashboard.getCurrentUserId();
|
||||||
var apiClient = getCurrentApiClient();
|
const apiClient = getCurrentApiClient();
|
||||||
var libraryMenuOptions = document.querySelector('.libraryMenuOptions');
|
const libraryMenuOptions = document.querySelector('.libraryMenuOptions');
|
||||||
|
|
||||||
if (libraryMenuOptions) {
|
if (libraryMenuOptions) {
|
||||||
getUserViews(apiClient, userId).then(function (result) {
|
getUserViews(apiClient, userId).then(function (result) {
|
||||||
var items = result;
|
const items = result;
|
||||||
var html = `<h3 class="sidebarHeader">${globalize.translate('HeaderMedia')}</h3>`;
|
let html = `<h3 class="sidebarHeader">${globalize.translate('HeaderMedia')}</h3>`;
|
||||||
html += items.map(function (i) {
|
html += items.map(function (i) {
|
||||||
var icon = i.icon || imageHelper.getLibraryIcon(i.CollectionType);
|
const icon = i.icon || imageHelper.getLibraryIcon(i.CollectionType);
|
||||||
var itemId = i.Id;
|
const itemId = i.Id;
|
||||||
|
|
||||||
return `<a is="emby-linkbutton" data-itemid="${itemId}" class="lnkMediaFolder navMenuOption" href="${getItemHref(i, i.CollectionType)}">
|
return `<a is="emby-linkbutton" data-itemid="${itemId}" class="lnkMediaFolder navMenuOption" href="${getItemHref(i, i.CollectionType)}">
|
||||||
<span class="material-icons navMenuOptionIcon ${icon}"></span>
|
<span class="material-icons navMenuOptionIcon ${icon}"></span>
|
||||||
|
@ -614,8 +628,8 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
</a>`;
|
</a>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
libraryMenuOptions.innerHTML = html;
|
libraryMenuOptions.innerHTML = html;
|
||||||
var elem = libraryMenuOptions;
|
const elem = libraryMenuOptions;
|
||||||
var sidebarLinks = elem.querySelectorAll('.navMenuOption');
|
const sidebarLinks = elem.querySelectorAll('.navMenuOption');
|
||||||
|
|
||||||
for (const sidebarLink of sidebarLinks) {
|
for (const sidebarLink of sidebarLinks) {
|
||||||
sidebarLink.removeEventListener('click', onSidebarLinkClick);
|
sidebarLink.removeEventListener('click', onSidebarLinkClick);
|
||||||
|
@ -644,9 +658,9 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCastIcon() {
|
function updateCastIcon() {
|
||||||
var context = document;
|
const context = document;
|
||||||
var info = playbackManager.getPlayerInfo();
|
const info = playbackManager.getPlayerInfo();
|
||||||
var icon = headerCastButton.querySelector('.material-icons');
|
const icon = headerCastButton.querySelector('.material-icons');
|
||||||
|
|
||||||
icon.classList.remove('cast_connected', 'cast');
|
icon.classList.remove('cast_connected', 'cast');
|
||||||
|
|
||||||
|
@ -662,18 +676,16 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateLibraryNavLinks(page) {
|
function updateLibraryNavLinks(page) {
|
||||||
var i;
|
const isLiveTvPage = page.classList.contains('liveTvPage');
|
||||||
var length;
|
const isChannelsPage = page.classList.contains('channelsPage');
|
||||||
var isLiveTvPage = page.classList.contains('liveTvPage');
|
const isEditorPage = page.classList.contains('metadataEditorPage');
|
||||||
var isChannelsPage = page.classList.contains('channelsPage');
|
const isMySyncPage = page.classList.contains('mySyncPage');
|
||||||
var isEditorPage = page.classList.contains('metadataEditorPage');
|
const id = isLiveTvPage || isChannelsPage || isEditorPage || isMySyncPage || page.classList.contains('allLibraryPage') ? '' : getTopParentId() || '';
|
||||||
var isMySyncPage = page.classList.contains('mySyncPage');
|
const elems = document.getElementsByClassName('lnkMediaFolder');
|
||||||
var id = isLiveTvPage || isChannelsPage || isEditorPage || isMySyncPage || page.classList.contains('allLibraryPage') ? '' : getTopParentId() || '';
|
|
||||||
var elems = document.getElementsByClassName('lnkMediaFolder');
|
|
||||||
|
|
||||||
for (var i = 0, length = elems.length; i < length; i++) {
|
for (let i = 0, length = elems.length; i < length; i++) {
|
||||||
var lnkMediaFolder = elems[i];
|
const lnkMediaFolder = elems[i];
|
||||||
var itemId = lnkMediaFolder.getAttribute('data-itemid');
|
const itemId = lnkMediaFolder.getAttribute('data-itemid');
|
||||||
|
|
||||||
if (isChannelsPage && itemId === 'channels') {
|
if (isChannelsPage && itemId === 'channels') {
|
||||||
lnkMediaFolder.classList.add('navMenuOption-selected');
|
lnkMediaFolder.classList.add('navMenuOption-selected');
|
||||||
|
@ -694,7 +706,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateMenuForPageType(isDashboardPage, isLibraryPage) {
|
function updateMenuForPageType(isDashboardPage, isLibraryPage) {
|
||||||
var newPageType = isDashboardPage ? 2 : isLibraryPage ? 1 : 3;
|
const newPageType = isDashboardPage ? 2 : isLibraryPage ? 1 : 3;
|
||||||
|
|
||||||
if (currentPageType !== newPageType) {
|
if (currentPageType !== newPageType) {
|
||||||
currentPageType = newPageType;
|
currentPageType = newPageType;
|
||||||
|
@ -705,7 +717,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
skinHeader.classList.remove('headroomDisabled');
|
skinHeader.classList.remove('headroomDisabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
var bodyClassList = document.body.classList;
|
const bodyClassList = document.body.classList;
|
||||||
|
|
||||||
if (isLibraryPage) {
|
if (isLibraryPage) {
|
||||||
bodyClassList.add('libraryDocument');
|
bodyClassList.add('libraryDocument');
|
||||||
|
@ -742,7 +754,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTitle(page) {
|
function updateTitle(page) {
|
||||||
var title = page.getAttribute('data-title');
|
const title = page.getAttribute('data-title');
|
||||||
|
|
||||||
if (title) {
|
if (title) {
|
||||||
LibraryMenu.setTitle(title);
|
LibraryMenu.setTitle(title);
|
||||||
|
@ -766,8 +778,8 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function initHeadRoom(elem) {
|
function initHeadRoom(elem) {
|
||||||
require(['headroom'], function (Headroom) {
|
import('headroom').then(({default: Headroom}) => {
|
||||||
var headroom = new Headroom(elem);
|
const headroom = new Headroom(elem);
|
||||||
headroom.init();
|
headroom.init();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -787,7 +799,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNavDrawerOptions() {
|
function getNavDrawerOptions() {
|
||||||
var drawerWidth = screen.availWidth - 50;
|
let drawerWidth = screen.availWidth - 50;
|
||||||
drawerWidth = Math.max(drawerWidth, 240);
|
drawerWidth = Math.max(drawerWidth, 240);
|
||||||
drawerWidth = Math.min(drawerWidth, 320);
|
drawerWidth = Math.min(drawerWidth, 320);
|
||||||
return {
|
return {
|
||||||
|
@ -806,9 +818,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
navDrawerScrollContainer = navDrawerElement.querySelector('.scrollContainer');
|
navDrawerScrollContainer = navDrawerElement.querySelector('.scrollContainer');
|
||||||
navDrawerScrollContainer.addEventListener('click', onMainDrawerClick);
|
navDrawerScrollContainer.addEventListener('click', onMainDrawerClick);
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
require(['navdrawer'], function (navdrawer) {
|
import('navdrawer').then(({default: navdrawer}) => {
|
||||||
navdrawer = navdrawer.default || navdrawer;
|
|
||||||
|
|
||||||
navDrawerInstance = new navdrawer(getNavDrawerOptions());
|
navDrawerInstance = new navdrawer(getNavDrawerOptions());
|
||||||
|
|
||||||
if (!layoutManager.tv) {
|
if (!layoutManager.tv) {
|
||||||
|
@ -820,98 +830,98 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var navDrawerElement;
|
let navDrawerElement;
|
||||||
var navDrawerScrollContainer;
|
let navDrawerScrollContainer;
|
||||||
var navDrawerInstance;
|
let navDrawerInstance;
|
||||||
var mainDrawerButton;
|
let mainDrawerButton;
|
||||||
var headerHomeButton;
|
let headerHomeButton;
|
||||||
var currentDrawerType;
|
let currentDrawerType;
|
||||||
var pageTitleElement;
|
let pageTitleElement;
|
||||||
var headerBackButton;
|
let headerBackButton;
|
||||||
var headerUserButton;
|
let headerUserButton;
|
||||||
var currentUser;
|
let currentUser;
|
||||||
var headerCastButton;
|
let headerCastButton;
|
||||||
var headerSearchButton;
|
let headerSearchButton;
|
||||||
var headerAudioPlayerButton;
|
let headerAudioPlayerButton;
|
||||||
var headerSyncButton;
|
let headerSyncButton;
|
||||||
var enableLibraryNavDrawer = layoutManager.desktop;
|
const enableLibraryNavDrawer = layoutManager.desktop;
|
||||||
var enableLibraryNavDrawerHome = !layoutManager.tv;
|
const enableLibraryNavDrawerHome = !layoutManager.tv;
|
||||||
var skinHeader = document.querySelector('.skinHeader');
|
const skinHeader = document.querySelector('.skinHeader');
|
||||||
var requiresUserRefresh = true;
|
let requiresUserRefresh = true;
|
||||||
window.LibraryMenu = {
|
|
||||||
getTopParentId: getTopParentId,
|
|
||||||
onHardwareMenuButtonClick: function () {
|
|
||||||
toggleMainDrawer();
|
|
||||||
},
|
|
||||||
setTabs: function (type, selectedIndex, builder) {
|
|
||||||
require(['mainTabsManager'], function (mainTabsManager) {
|
|
||||||
if (type) {
|
|
||||||
mainTabsManager.setTabs(viewManager.currentView(), selectedIndex, builder, function () {
|
|
||||||
return [];
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
mainTabsManager.setTabs(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
setDefaultTitle: function () {
|
|
||||||
if (!pageTitleElement) {
|
|
||||||
pageTitleElement = document.querySelector('.pageTitle');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pageTitleElement) {
|
function setTabs (type, selectedIndex, builder) {
|
||||||
pageTitleElement.classList.add('pageTitleWithLogo');
|
import('mainTabsManager').then(({default: mainTabsManager}) => {
|
||||||
pageTitleElement.classList.add('pageTitleWithDefaultLogo');
|
if (type) {
|
||||||
pageTitleElement.style.backgroundImage = null;
|
mainTabsManager.setTabs(viewManager.currentView(), selectedIndex, builder, function () {
|
||||||
pageTitleElement.innerHTML = '';
|
return [];
|
||||||
}
|
});
|
||||||
|
|
||||||
document.title = 'Jellyfin';
|
|
||||||
},
|
|
||||||
setTitle: function (title) {
|
|
||||||
if (title == null) {
|
|
||||||
return void LibraryMenu.setDefaultTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (title === '-') {
|
|
||||||
title = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
var html = title;
|
|
||||||
|
|
||||||
if (!pageTitleElement) {
|
|
||||||
pageTitleElement = document.querySelector('.pageTitle');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pageTitleElement) {
|
|
||||||
pageTitleElement.classList.remove('pageTitleWithLogo');
|
|
||||||
pageTitleElement.classList.remove('pageTitleWithDefaultLogo');
|
|
||||||
pageTitleElement.style.backgroundImage = null;
|
|
||||||
pageTitleElement.innerHTML = html || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
document.title = title || 'Jellyfin';
|
|
||||||
},
|
|
||||||
setTransparentMenu: function (transparent) {
|
|
||||||
if (transparent) {
|
|
||||||
skinHeader.classList.add('semiTransparent');
|
|
||||||
} else {
|
} else {
|
||||||
skinHeader.classList.remove('semiTransparent');
|
mainTabsManager.setTabs(null);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDefaultTitle () {
|
||||||
|
if (!pageTitleElement) {
|
||||||
|
pageTitleElement = document.querySelector('.pageTitle');
|
||||||
}
|
}
|
||||||
};
|
|
||||||
var currentPageType;
|
if (pageTitleElement) {
|
||||||
|
pageTitleElement.classList.add('pageTitleWithLogo');
|
||||||
|
pageTitleElement.classList.add('pageTitleWithDefaultLogo');
|
||||||
|
pageTitleElement.style.backgroundImage = null;
|
||||||
|
pageTitleElement.innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.title = 'Jellyfin';
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTitle (title) {
|
||||||
|
if (title == null) {
|
||||||
|
return void LibraryMenu.setDefaultTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (title === '-') {
|
||||||
|
title = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const html = title;
|
||||||
|
|
||||||
|
if (!pageTitleElement) {
|
||||||
|
pageTitleElement = document.querySelector('.pageTitle');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageTitleElement) {
|
||||||
|
pageTitleElement.classList.remove('pageTitleWithLogo');
|
||||||
|
pageTitleElement.classList.remove('pageTitleWithDefaultLogo');
|
||||||
|
pageTitleElement.style.backgroundImage = null;
|
||||||
|
pageTitleElement.innerHTML = html || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.title = title || 'Jellyfin';
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTransparentMenu (transparent) {
|
||||||
|
if (transparent) {
|
||||||
|
skinHeader.classList.add('semiTransparent');
|
||||||
|
} else {
|
||||||
|
skinHeader.classList.remove('semiTransparent');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentPageType;
|
||||||
pageClassOn('pagebeforeshow', 'page', function (e) {
|
pageClassOn('pagebeforeshow', 'page', function (e) {
|
||||||
if (!this.classList.contains('withTabs')) {
|
if (!this.classList.contains('withTabs')) {
|
||||||
LibraryMenu.setTabs(null);
|
LibraryMenu.setTabs(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
pageClassOn('pageshow', 'page', function (e) {
|
pageClassOn('pageshow', 'page', function (e) {
|
||||||
var page = this;
|
const page = this;
|
||||||
var isDashboardPage = page.classList.contains('type-interior');
|
const isDashboardPage = page.classList.contains('type-interior');
|
||||||
var isHomePage = page.classList.contains('homePage');
|
const isHomePage = page.classList.contains('homePage');
|
||||||
var isLibraryPage = !isDashboardPage && page.classList.contains('libraryPage');
|
const isLibraryPage = !isDashboardPage && page.classList.contains('libraryPage');
|
||||||
var apiClient = getCurrentApiClient();
|
const apiClient = getCurrentApiClient();
|
||||||
|
|
||||||
if (isDashboardPage) {
|
if (isDashboardPage) {
|
||||||
if (mainDrawerButton) {
|
if (mainDrawerButton) {
|
||||||
|
@ -948,7 +958,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
renderHeader();
|
renderHeader();
|
||||||
|
|
||||||
events.on(connectionManager, 'localusersignedin', function (e, user) {
|
events.on(connectionManager, 'localusersignedin', function (e, user) {
|
||||||
var currentApiClient = connectionManager.getApiClient(user.ServerId);
|
const currentApiClient = connectionManager.getApiClient(user.ServerId);
|
||||||
|
|
||||||
currentDrawerType = null;
|
currentDrawerType = null;
|
||||||
currentUser = {
|
currentUser = {
|
||||||
|
@ -962,15 +972,32 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
updateUserInHeader(user);
|
updateUserInHeader(user);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
events.on(connectionManager, 'localusersignedout', function () {
|
events.on(connectionManager, 'localusersignedout', function () {
|
||||||
currentUser = {};
|
currentUser = {};
|
||||||
updateUserInHeader();
|
updateUserInHeader();
|
||||||
});
|
});
|
||||||
|
|
||||||
events.on(playbackManager, 'playerchange', updateCastIcon);
|
events.on(playbackManager, 'playerchange', updateCastIcon);
|
||||||
|
|
||||||
events.on(syncPlayManager, 'enabled', onSyncPlayEnabled);
|
events.on(syncPlayManager, 'enabled', onSyncPlayEnabled);
|
||||||
events.on(syncPlayManager, 'syncing', onSyncPlaySyncing);
|
events.on(syncPlayManager, 'syncing', onSyncPlaySyncing);
|
||||||
|
|
||||||
loadNavDrawer();
|
loadNavDrawer();
|
||||||
return LibraryMenu;
|
|
||||||
});
|
const LibraryMenu = {
|
||||||
|
getTopParentId: getTopParentId,
|
||||||
|
onHardwareMenuButtonClick: function () {
|
||||||
|
toggleMainDrawer();
|
||||||
|
},
|
||||||
|
setTabs: setTabs,
|
||||||
|
setDefaultTitle: setDefaultTitle,
|
||||||
|
setTitle: setTitle,
|
||||||
|
setTransparentMenu: setTransparentMenu
|
||||||
|
};
|
||||||
|
|
||||||
|
window.LibraryMenu = LibraryMenu;
|
||||||
|
|
||||||
|
export default LibraryMenu;
|
||||||
|
|
||||||
|
/* eslint-enable indent */
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
define(['layoutManager', 'datetime', 'cardBuilder', 'apphost'], function (layoutManager, datetime, cardBuilder, appHost) {
|
define(['layoutManager', 'datetime', 'cardBuilder', 'apphost'], function (layoutManager, datetime, cardBuilder, appHost) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
layoutManager = layoutManager.default || layoutManager;
|
||||||
|
|
||||||
function enableScrollX() {
|
function enableScrollX() {
|
||||||
return !layoutManager.desktop;
|
return !layoutManager.desktop;
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,54 +112,69 @@ import 'detailtablecss';
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/dashboard.html',
|
alias: '/dashboard.html',
|
||||||
|
path: '/controllers/dashboard/dashboard.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/dashboard'
|
controller: 'dashboard/dashboard'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/dashboardgeneral.html',
|
alias: '/dashboardgeneral.html',
|
||||||
|
path: '/controllers/dashboard/general.html',
|
||||||
controller: 'dashboard/general',
|
controller: 'dashboard/general',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin'
|
roles: 'admin'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/networking.html',
|
alias: '/networking.html',
|
||||||
|
path: '/controllers/dashboard/networking.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/networking'
|
controller: 'dashboard/networking'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/devices.html',
|
alias: '/devices.html',
|
||||||
|
path: '/controllers/dashboard/devices/devices.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/devices/devices'
|
controller: 'dashboard/devices/devices'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/device.html',
|
alias: '/device.html',
|
||||||
|
path: '/controllers/dashboard/devices/device.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/devices/device'
|
controller: 'dashboard/devices/device'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/dlnaprofile.html',
|
alias: '/dlnaprofile.html',
|
||||||
|
path: '/controllers/dashboard/dlna/profile.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/dlna/profile'
|
controller: 'dashboard/dlna/profile'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/dlnaprofiles.html',
|
alias: '/dlnaprofiles.html',
|
||||||
|
path: '/controllers/dashboard/dlna/profiles.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/dlna/profiles'
|
controller: 'dashboard/dlna/profiles'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
defineRoute({
|
||||||
|
alias: '/dlnasettings.html',
|
||||||
|
path: '/controllers/dashboard/dlna/settings.html',
|
||||||
|
autoFocus: false,
|
||||||
|
roles: 'admin',
|
||||||
|
controller: 'dashboard/dlna/settings'
|
||||||
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
alias: '/addplugin.html',
|
alias: '/addplugin.html',
|
||||||
path: '/controllers/dashboard/plugins/add/index.html',
|
path: '/controllers/dashboard/plugins/add/index.html',
|
||||||
|
@ -169,54 +184,54 @@ import 'detailtablecss';
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/library.html',
|
alias: '/library.html',
|
||||||
|
path: '/controllers/dashboard/library.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/mediaLibrary'
|
controller: 'dashboard/library'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/librarydisplay.html',
|
alias: '/librarydisplay.html',
|
||||||
|
path: '/controllers/dashboard/librarydisplay.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/librarydisplay'
|
controller: 'dashboard/librarydisplay'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/dlnasettings.html',
|
alias: '/edititemmetadata.html',
|
||||||
autoFocus: false,
|
path: '/controllers/edititemmetadata.html',
|
||||||
roles: 'admin',
|
|
||||||
controller: 'dashboard/dlna/settings'
|
|
||||||
});
|
|
||||||
|
|
||||||
defineRoute({
|
|
||||||
path: '/edititemmetadata.html',
|
|
||||||
controller: 'edititemmetadata',
|
controller: 'edititemmetadata',
|
||||||
autoFocus: false
|
autoFocus: false
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/encodingsettings.html',
|
alias: '/encodingsettings.html',
|
||||||
|
path: '/controllers/dashboard/encodingsettings.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/encodingsettings'
|
controller: 'dashboard/encodingsettings'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/log.html',
|
alias: '/log.html',
|
||||||
|
path: '/controllers/dashboard/logs.html',
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/logs'
|
controller: 'dashboard/logs'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/metadataimages.html',
|
alias: '/metadataimages.html',
|
||||||
|
path: '/controllers/dashboard/metadataimages.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/metadataImages'
|
controller: 'dashboard/metadataImages'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/metadatanfo.html',
|
alias: '/metadatanfo.html',
|
||||||
|
path: '/controllers/dashboard/metadatanfo.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/metadatanfo'
|
controller: 'dashboard/metadatanfo'
|
||||||
|
@ -239,7 +254,8 @@ import 'detailtablecss';
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/playbackconfiguration.html',
|
alias: '/playbackconfiguration.html',
|
||||||
|
path: '/controllers/dashboard/playback.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/playback'
|
controller: 'dashboard/playback'
|
||||||
|
@ -262,19 +278,22 @@ import 'detailtablecss';
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/home.html',
|
alias: '/home.html',
|
||||||
|
path: '/controllers/home.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
controller: 'home',
|
controller: 'home',
|
||||||
type: 'home'
|
type: 'home'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/search.html',
|
alias: '/search.html',
|
||||||
|
path: '/controllers/search.html',
|
||||||
controller: 'searchpage'
|
controller: 'searchpage'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/list.html',
|
alias: '/list.html',
|
||||||
|
path: '/controllers/list.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
controller: 'list'
|
controller: 'list'
|
||||||
});
|
});
|
||||||
|
@ -287,46 +306,53 @@ import 'detailtablecss';
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/livetv.html',
|
alias: '/livetv.html',
|
||||||
|
path: '/controllers/livetv.html',
|
||||||
controller: 'livetv/livetvsuggested',
|
controller: 'livetv/livetvsuggested',
|
||||||
autoFocus: false
|
autoFocus: false
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/livetvguideprovider.html',
|
alias: '/livetvguideprovider.html',
|
||||||
|
path: '/controllers/livetvguideprovider.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'livetvguideprovider'
|
controller: 'livetvguideprovider'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/livetvsettings.html',
|
alias: '/livetvsettings.html',
|
||||||
|
path: '/controllers/livetvsettings.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
controller: 'livetvsettings'
|
controller: 'livetvsettings'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/livetvstatus.html',
|
alias: '/livetvstatus.html',
|
||||||
|
path: '/controllers/livetvstatus.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'livetvstatus'
|
controller: 'livetvstatus'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/livetvtuner.html',
|
alias: '/livetvtuner.html',
|
||||||
|
path: '/controllers/livetvtuner.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'livetvtuner'
|
controller: 'livetvtuner'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/movies.html',
|
alias: '/movies.html',
|
||||||
|
path: '/controllers/movies/movies.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
controller: 'movies/moviesrecommended'
|
controller: 'movies/moviesrecommended'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/music.html',
|
alias: '/music.html',
|
||||||
|
path: '/controllers/music/music.html',
|
||||||
controller: 'music/musicrecommended',
|
controller: 'music/musicrecommended',
|
||||||
autoFocus: false
|
autoFocus: false
|
||||||
});
|
});
|
||||||
|
@ -340,82 +366,94 @@ import 'detailtablecss';
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/scheduledtask.html',
|
alias: '/scheduledtask.html',
|
||||||
|
path: '/controllers/dashboard/scheduledtasks/scheduledtask.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/scheduledtasks/scheduledtask'
|
controller: 'dashboard/scheduledtasks/scheduledtask'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/scheduledtasks.html',
|
alias: '/scheduledtasks.html',
|
||||||
|
path: '/controllers/dashboard/scheduledtasks/scheduledtasks.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/scheduledtasks/scheduledtasks'
|
controller: 'dashboard/scheduledtasks/scheduledtasks'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/serveractivity.html',
|
alias: '/serveractivity.html',
|
||||||
|
path: '/controllers/dashboard/serveractivity.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/serveractivity'
|
controller: 'dashboard/serveractivity'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/apikeys.html',
|
alias: '/apikeys.html',
|
||||||
|
path: '/controllers/dashboard/apikeys.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/apikeys'
|
controller: 'dashboard/apikeys'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/streamingsettings.html',
|
alias: '/streamingsettings.html',
|
||||||
|
path: '/controllers/dashboard/streaming.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/streaming'
|
controller: 'dashboard/streaming'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/tv.html',
|
alias: '/tv.html',
|
||||||
|
path: '/controllers/shows/tvrecommended.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
controller: 'shows/tvrecommended'
|
controller: 'shows/tvrecommended'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/useredit.html',
|
alias: '/useredit.html',
|
||||||
|
path: '/controllers/dashboard/users/useredit.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/users/useredit'
|
controller: 'dashboard/users/useredit'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/userlibraryaccess.html',
|
alias: '/userlibraryaccess.html',
|
||||||
|
path: '/controllers/dashboard/users/userlibraryaccess.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/users/userlibraryaccess'
|
controller: 'dashboard/users/userlibraryaccess'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/usernew.html',
|
alias: '/usernew.html',
|
||||||
|
path: '/controllers/dashboard/users/usernew.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/users/usernew'
|
controller: 'dashboard/users/usernew'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/userparentalcontrol.html',
|
alias: '/userparentalcontrol.html',
|
||||||
|
path: '/controllers/dashboard/users/userparentalcontrol.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/users/userparentalcontrol'
|
controller: 'dashboard/users/userparentalcontrol'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/userpassword.html',
|
alias: '/userpassword.html',
|
||||||
|
path: '/controllers/dashboard/users/userpassword.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
controller: 'dashboard/users/userpasswordpage'
|
controller: 'dashboard/users/userpasswordpage'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/userprofiles.html',
|
alias: '/userprofiles.html',
|
||||||
|
path: '/controllers/dashboard/users/userprofiles.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
roles: 'admin',
|
roles: 'admin',
|
||||||
controller: 'dashboard/users/userprofilespage'
|
controller: 'dashboard/users/userprofilespage'
|
||||||
|
@ -438,10 +476,11 @@ import 'detailtablecss';
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/wizardlibrary.html',
|
alias: '/wizardlibrary.html',
|
||||||
|
path: '/controllers/wizard/library.html',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
anonymous: true,
|
anonymous: true,
|
||||||
controller: 'dashboard/mediaLibrary'
|
controller: 'dashboard/library'
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
|
|
|
@ -350,6 +350,7 @@ function initClient() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLayoutManager(layoutManager, appHost) {
|
function getLayoutManager(layoutManager, appHost) {
|
||||||
|
layoutManager = layoutManager.default || layoutManager;
|
||||||
if (appHost.getDefaultLayout) {
|
if (appHost.getDefaultLayout) {
|
||||||
layoutManager.defaultLayout = appHost.getDefaultLayout();
|
layoutManager.defaultLayout = appHost.getDefaultLayout();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1542,5 +1542,10 @@
|
||||||
"ViewAlbumArtist": "Zeige Albumkünstler",
|
"ViewAlbumArtist": "Zeige Albumkünstler",
|
||||||
"PreviousTrack": "Zum Vorherigen springen",
|
"PreviousTrack": "Zum Vorherigen springen",
|
||||||
"NextTrack": "Zum Nächsten springen",
|
"NextTrack": "Zum Nächsten springen",
|
||||||
"LabelUnstable": "Instabil"
|
"LabelUnstable": "Instabil",
|
||||||
|
"SubtitleVerticalPositionHelp": "Zeilennummer, in der der Text angezeigt wird. Positive Zahlen geben die Zeile von oben an. Negative Zahlen geben die Zeile von unten an.",
|
||||||
|
"Preview": "Vorschau",
|
||||||
|
"LabelSubtitleVerticalPosition": "Vertikale Position:",
|
||||||
|
"MessageGetInstalledPluginsError": "Beim Abrufen der Liste der derzeit installierten Plugins ist ein Fehler aufgetreten.",
|
||||||
|
"MessagePluginInstallError": "Bei der Installation des Plugins ist ein Fehler aufgetreten."
|
||||||
}
|
}
|
||||||
|
|
|
@ -1282,6 +1282,8 @@
|
||||||
"PleaseRestartServerName": "Please restart Jellyfin Server - {0}.",
|
"PleaseRestartServerName": "Please restart Jellyfin Server - {0}.",
|
||||||
"PleaseSelectTwoItems": "Please select at least two items.",
|
"PleaseSelectTwoItems": "Please select at least two items.",
|
||||||
"MessagePluginInstalled": "The plugin has been successfully installed. Jellyfin Server will need to be restarted for changes to take effect.",
|
"MessagePluginInstalled": "The plugin has been successfully installed. Jellyfin Server will need to be restarted for changes to take effect.",
|
||||||
|
"MessagePluginInstallError": "An error occured while installing the plugin.",
|
||||||
|
"MessageGetInstalledPluginsError": "An error occured while getting the list of currently installed plugins.",
|
||||||
"PreferEmbeddedTitlesOverFileNames": "Prefer embedded titles over filenames",
|
"PreferEmbeddedTitlesOverFileNames": "Prefer embedded titles over filenames",
|
||||||
"PreferEmbeddedTitlesOverFileNamesHelp": "This determines the default display title when no internet metadata or local metadata is available.",
|
"PreferEmbeddedTitlesOverFileNamesHelp": "This determines the default display title when no internet metadata or local metadata is available.",
|
||||||
"PreferEmbeddedEpisodeInfosOverFileNamesHelp": "This uses the episode information from the embedded metadata if available.",
|
"PreferEmbeddedEpisodeInfosOverFileNamesHelp": "This uses the episode information from the embedded metadata if available.",
|
||||||
|
|
|
@ -1542,5 +1542,8 @@
|
||||||
"ViewAlbumArtist": "Voir l'album de l'artiste",
|
"ViewAlbumArtist": "Voir l'album de l'artiste",
|
||||||
"PreviousTrack": "Revenir au précédent",
|
"PreviousTrack": "Revenir au précédent",
|
||||||
"NextTrack": "Passer au prochain",
|
"NextTrack": "Passer au prochain",
|
||||||
"LabelUnstable": "Instable"
|
"LabelUnstable": "Instable",
|
||||||
|
"Preview": "Aperçu",
|
||||||
|
"SubtitleVerticalPositionHelp": "Numéro de ligne où le texte apparaît. Un nombre positif compte les lignes de haut en bas. Un nombre négatif, de bas en haut.",
|
||||||
|
"LabelSubtitleVerticalPosition": "Position verticale :"
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@
|
||||||
"DeviceAccessHelp": "Dit geldt alleen voor apparaten die uniek geïdentificeerd kunnen worden en voorkomen niet toegang via een webbrowser. Filteren van apparaat toegang voor gebruikers voorkomt dat zij nieuwe apparaten gebruiken totdat deze hier zijn goedgekeurd.",
|
"DeviceAccessHelp": "Dit geldt alleen voor apparaten die uniek geïdentificeerd kunnen worden en voorkomen niet toegang via een webbrowser. Filteren van apparaat toegang voor gebruikers voorkomt dat zij nieuwe apparaten gebruiken totdat deze hier zijn goedgekeurd.",
|
||||||
"DirectPlaying": "Direct afspelen",
|
"DirectPlaying": "Direct afspelen",
|
||||||
"DirectStreamHelp1": "De resolutie en codec (bijv. H.264, AC3, etc.) wordt ondersteund door het apparaat, maar het medium is in een niet-ondersteunde bestandscontainer (bijv. mkv, avi, wmv). De video zal tijdens het afspelen opnieuw verpakt worden naar een andere bestandscontainer.",
|
"DirectStreamHelp1": "De resolutie en codec (bijv. H.264, AC3, etc.) wordt ondersteund door het apparaat, maar het medium is in een niet-ondersteunde bestandscontainer (bijv. mkv, avi, wmv). De video zal tijdens het afspelen opnieuw verpakt worden naar een andere bestandscontainer.",
|
||||||
"DirectStreamHelp2": "Direct streamen van een bestand gebruikt weinig processor kracht zonder verlies van beeldkwaliteit.",
|
"DirectStreamHelp2": "Direct streamen van een bestand gebruikt weinig processorkracht zonder verlies van beeldkwaliteit.",
|
||||||
"DirectStreaming": "Direct streamen",
|
"DirectStreaming": "Direct streamen",
|
||||||
"Director": "Regiseur",
|
"Director": "Regiseur",
|
||||||
"Directors": "Regisseurs",
|
"Directors": "Regisseurs",
|
||||||
|
@ -378,7 +378,7 @@
|
||||||
"HeaderPreferredMetadataLanguage": "Gewenste metadata taal",
|
"HeaderPreferredMetadataLanguage": "Gewenste metadata taal",
|
||||||
"HeaderProfile": "Profiel",
|
"HeaderProfile": "Profiel",
|
||||||
"HeaderProfileInformation": "Profiel Informatie",
|
"HeaderProfileInformation": "Profiel Informatie",
|
||||||
"HeaderProfileServerSettingsHelp": "Deze waarden bepalen hoe Jellyfin Server zich zal presenteren aan het apparaat.",
|
"HeaderProfileServerSettingsHelp": "Deze waarden bepalen hoe de server zich zal presenteren aan het apparaat.",
|
||||||
"HeaderRecentlyPlayed": "Recent afgespeeld",
|
"HeaderRecentlyPlayed": "Recent afgespeeld",
|
||||||
"HeaderRecordingOptions": "Opname instellingen",
|
"HeaderRecordingOptions": "Opname instellingen",
|
||||||
"HeaderRecordingPostProcessing": "Opname nabewerking",
|
"HeaderRecordingPostProcessing": "Opname nabewerking",
|
||||||
|
@ -396,13 +396,13 @@
|
||||||
"HeaderSecondsValue": "{0} Seconden",
|
"HeaderSecondsValue": "{0} Seconden",
|
||||||
"HeaderSelectCertificatePath": "Selecteer Certificaat Pad",
|
"HeaderSelectCertificatePath": "Selecteer Certificaat Pad",
|
||||||
"HeaderSelectMetadataPath": "Selecteer Metadata Pad",
|
"HeaderSelectMetadataPath": "Selecteer Metadata Pad",
|
||||||
"HeaderSelectMetadataPathHelp": "Blader of voer het pad in dat u wilt gebruiken om metadata in op te slaan. De map moet beschrijfbaar zijn.",
|
"HeaderSelectMetadataPathHelp": "Blader of voer het pad in dat u wilt gebruiken om metadata in op te slaan. De map moet schrijfbaar zijn.",
|
||||||
"HeaderSelectPath": "Selecteer Pad",
|
"HeaderSelectPath": "Selecteer Pad",
|
||||||
"HeaderSelectServer": "Selecteer server",
|
"HeaderSelectServer": "Selecteer server",
|
||||||
"HeaderSelectServerCachePath": "Selecteer Server Cache Pad",
|
"HeaderSelectServerCachePath": "Selecteer Server Cache Pad",
|
||||||
"HeaderSelectServerCachePathHelp": "Bladeren of voer het pad in om te gebruiken voor server cache-bestanden. De map moet beschrijfbaar zijn.",
|
"HeaderSelectServerCachePathHelp": "Bladeren of voer het pad in om te gebruiken voor server cache-bestanden. De map moet beschrijfbaar zijn.",
|
||||||
"HeaderSelectTranscodingPath": "Selecteer Tijdelijke Transcodeer Pad",
|
"HeaderSelectTranscodingPath": "Selecteer Tijdelijke Transcodeer Pad",
|
||||||
"HeaderSelectTranscodingPathHelp": "Bladeren of voer het pad in om te gebruiken voor het transcoderen van tijdelijke bestanden. De map moet beschrijfbaar zijn.",
|
"HeaderSelectTranscodingPathHelp": "Blader of voer het pad in om te gebruiken voor het transcoderen van tijdelijke bestanden. De map moet schrijfbaar zijn.",
|
||||||
"HeaderSendMessage": "Stuur bericht",
|
"HeaderSendMessage": "Stuur bericht",
|
||||||
"HeaderSeries": "Series",
|
"HeaderSeries": "Series",
|
||||||
"HeaderSeriesOptions": "Series Opties",
|
"HeaderSeriesOptions": "Series Opties",
|
||||||
|
@ -1255,7 +1255,7 @@
|
||||||
"HeaderGenres": "Genres",
|
"HeaderGenres": "Genres",
|
||||||
"HeaderHttpHeaders": "HTTP Headers",
|
"HeaderHttpHeaders": "HTTP Headers",
|
||||||
"HeaderStatus": "Status",
|
"HeaderStatus": "Status",
|
||||||
"AuthProviderHelp": "Selecteer een Authenticatie Provider om het wachtwoord van deze gebruiker te verifiëren.",
|
"AuthProviderHelp": "Selecteer een authenticatie provider om het wachtwoord van deze gebruiker te verifiëren.",
|
||||||
"HeaderFavoriteMovies": "Favoriete Films",
|
"HeaderFavoriteMovies": "Favoriete Films",
|
||||||
"HeaderFavoriteShows": "Favoriete shows",
|
"HeaderFavoriteShows": "Favoriete shows",
|
||||||
"HeaderFavoriteEpisodes": "Favoriete afleveringen",
|
"HeaderFavoriteEpisodes": "Favoriete afleveringen",
|
||||||
|
|
|
@ -61,9 +61,9 @@
|
||||||
"HeaderTaskTriggers": "Declanșatori Sarcini",
|
"HeaderTaskTriggers": "Declanșatori Sarcini",
|
||||||
"HeaderUsers": "Utilizatori",
|
"HeaderUsers": "Utilizatori",
|
||||||
"Help": "Ajutor",
|
"Help": "Ajutor",
|
||||||
"ImportMissingEpisodesHelp": "Dacă este activată, informația despre episoadele lipsă va fi importată in baza de date Jellyfin și va fi afișată în cadrul serialelor. Aceasta poate cauza un timp semnificativ mai îndelungat la scanarea bibliotecilor.",
|
"ImportMissingEpisodesHelp": "Informația despre episoadele lipsă va fi importată în baza de date și va fi afișată în cadrul serialelor. Aceasta poate cauza un timp semnificativ mai îndelungat la scanarea bibliotecilor.",
|
||||||
"LabelArtists": "Artisti:",
|
"LabelArtists": "Artisti:",
|
||||||
"LabelArtistsHelp": "Separare multiplă utilizând ;",
|
"LabelArtistsHelp": "Separară înșiruirea artiștilor utilizând ;",
|
||||||
"LabelAudioLanguagePreference": "Preferințe de limbă pentru audio:",
|
"LabelAudioLanguagePreference": "Preferințe de limbă pentru audio:",
|
||||||
"LabelCachePath": "Cale pentru depozit:",
|
"LabelCachePath": "Cale pentru depozit:",
|
||||||
"LabelCachePathHelp": "Specificați o locație specială pentru fișierele de tip depozit, precum imagini etc. Lasați gol pentru a folosi setarea implicită.",
|
"LabelCachePathHelp": "Specificați o locație specială pentru fișierele de tip depozit, precum imagini etc. Lasați gol pentru a folosi setarea implicită.",
|
||||||
|
@ -82,7 +82,7 @@
|
||||||
"LabelMetadataPath": "Cale pentru metadata:",
|
"LabelMetadataPath": "Cale pentru metadata:",
|
||||||
"LabelMetadataPathHelp": "Specificați o locație specială pentru a descărca postere și metadata.",
|
"LabelMetadataPathHelp": "Specificați o locație specială pentru a descărca postere și metadata.",
|
||||||
"LabelMinBackdropDownloadWidth": "Lățimea maximă pentru fundalurile descărcate:",
|
"LabelMinBackdropDownloadWidth": "Lățimea maximă pentru fundalurile descărcate:",
|
||||||
"LabelMovieRecordingPath": "Calea pentru înregistrări filme (opțional):",
|
"LabelMovieRecordingPath": "Calea pentru înregistrări filme:",
|
||||||
"LabelName": "Nume:",
|
"LabelName": "Nume:",
|
||||||
"LabelNewPassword": "Parola nouă:",
|
"LabelNewPassword": "Parola nouă:",
|
||||||
"LabelNewPasswordConfirm": "Confirmă parola nouă:",
|
"LabelNewPasswordConfirm": "Confirmă parola nouă:",
|
||||||
|
@ -96,7 +96,7 @@
|
||||||
"LabelSaveLocalMetadata": "Salvează posterele si metadata în dosarele ce conțin fișierele media",
|
"LabelSaveLocalMetadata": "Salvează posterele si metadata în dosarele ce conțin fișierele media",
|
||||||
"LabelSaveLocalMetadataHelp": "Salvând posterele și metadata direct in dosarele media, acestea vor fi mai accesibile pentru a fi modificate.",
|
"LabelSaveLocalMetadataHelp": "Salvând posterele și metadata direct in dosarele media, acestea vor fi mai accesibile pentru a fi modificate.",
|
||||||
"LabelSelectUsers": "Selectare utilizatori:",
|
"LabelSelectUsers": "Selectare utilizatori:",
|
||||||
"LabelSeriesRecordingPath": "Calea pentru înregistrări seriale (opțional):",
|
"LabelSeriesRecordingPath": "Calea pentru înregistrări de seriale:",
|
||||||
"LabelStopWhenPossible": "Oprește când este posibil:",
|
"LabelStopWhenPossible": "Oprește când este posibil:",
|
||||||
"LabelTimeLimitHours": "Limită de timp(ore):",
|
"LabelTimeLimitHours": "Limită de timp(ore):",
|
||||||
"LabelTranscodingTempPathHelp": "Specificați o cale specială pentru fișierele transcodate trimise clienților. Lasați gol pentru a folosi pe cea implicită în directorul de lucru al serverului.",
|
"LabelTranscodingTempPathHelp": "Specificați o cale specială pentru fișierele transcodate trimise clienților. Lasați gol pentru a folosi pe cea implicită în directorul de lucru al serverului.",
|
||||||
|
@ -133,7 +133,7 @@
|
||||||
"OptionDatePlayed": "Dată Rulare",
|
"OptionDatePlayed": "Dată Rulare",
|
||||||
"OptionDescending": "Descrescător",
|
"OptionDescending": "Descrescător",
|
||||||
"OptionDisableUser": "Dezactivați acest utilizator",
|
"OptionDisableUser": "Dezactivați acest utilizator",
|
||||||
"OptionDisableUserHelp": "Dacă este dezactivat, serverul nu va permite nicio conexiune de la acest utilizator. Conexiunile existente vor fi terminate brusc.",
|
"OptionDisableUserHelp": "Serverul nu va permite nici o conexiune de la acest utilizator. Conexiunile existente vor fi terminate brusc.",
|
||||||
"OptionDislikes": "Dislike-uri",
|
"OptionDislikes": "Dislike-uri",
|
||||||
"OptionDownloadArtImage": "Fundal",
|
"OptionDownloadArtImage": "Fundal",
|
||||||
"OptionDownloadBackImage": "Înapoi",
|
"OptionDownloadBackImage": "Înapoi",
|
||||||
|
@ -419,7 +419,7 @@
|
||||||
"HeaderExternalIds": "ID-uri Externe:",
|
"HeaderExternalIds": "ID-uri Externe:",
|
||||||
"HeaderFavoriteBooks": "Cărți Favorite",
|
"HeaderFavoriteBooks": "Cărți Favorite",
|
||||||
"HeaderBranding": "Marca",
|
"HeaderBranding": "Marca",
|
||||||
"HeaderApiKeysHelp": "Aplicațiile externe trebuie să aibă o cheie API pentru a comunica cu Jellyfin Server. Cheile sunt emise prin conectarea cu un cont Jellyfin sau prin acordarea manuală a unei chei aplicației.",
|
"HeaderApiKeysHelp": "Aplicațiile externe trebuie să aibă o cheie API pentru a comunica cu serverul. Cheile sunt emise prin conectarea cu un cont de utilizator sau prin acordarea manuală a unei chei aplicației.",
|
||||||
"Sync": "Sincronizare",
|
"Sync": "Sincronizare",
|
||||||
"ErrorAddingXmlTvFile": "A apărut o eroare la accesarea fișierului XMLTV. Vă rugăm să vă asigurați că fișierul există și încercați din nou.",
|
"ErrorAddingXmlTvFile": "A apărut o eroare la accesarea fișierului XMLTV. Vă rugăm să vă asigurați că fișierul există și încercați din nou.",
|
||||||
"HeaderApiKey": "Cheie API",
|
"HeaderApiKey": "Cheie API",
|
||||||
|
@ -459,7 +459,7 @@
|
||||||
"HeaderMyMediaSmall": "Fișierele mele Media ( micșorat )",
|
"HeaderMyMediaSmall": "Fișierele mele Media ( micșorat )",
|
||||||
"HeaderNewApiKey": "Nouă cheie API",
|
"HeaderNewApiKey": "Nouă cheie API",
|
||||||
"HeaderNewDevices": "Dispozitive noi",
|
"HeaderNewDevices": "Dispozitive noi",
|
||||||
"HeaderKodiMetadataHelp": "Pentru a activa sau dezactiva metadatele NFO, editați o bibliotecă, în configurarea bibliotecii Jellyfin, și localizați secțiunea de salvare a metadatelor.",
|
"HeaderKodiMetadataHelp": "Pentru a activa sau dezactiva metadatele NFO, editați o bibliotecă, și localizați secțiunea de salvare a metadatelor.",
|
||||||
"HeaderNextVideoPlayingInValue": "Următorul video se redă în {0}",
|
"HeaderNextVideoPlayingInValue": "Următorul video se redă în {0}",
|
||||||
"HeaderOnNow": "Pornit Acum",
|
"HeaderOnNow": "Pornit Acum",
|
||||||
"HeaderOtherItems": "Alte Elemente",
|
"HeaderOtherItems": "Alte Elemente",
|
||||||
|
@ -475,7 +475,7 @@
|
||||||
"HeaderPlaybackError": "Eroare la redare",
|
"HeaderPlaybackError": "Eroare la redare",
|
||||||
"HeaderPluginInstallation": "Instalare Plugin",
|
"HeaderPluginInstallation": "Instalare Plugin",
|
||||||
"HeaderProfileInformation": "Informații Profil",
|
"HeaderProfileInformation": "Informații Profil",
|
||||||
"HeaderProfileServerSettingsHelp": "Aceste valori controlează modul în care Jellyfin Server va fi reprezentat in dispozitiv.",
|
"HeaderProfileServerSettingsHelp": "Aceste valori controlează modul în care serverul va fi reprezentat in dispozitivele clientilor.",
|
||||||
"HeaderRecordingOptions": "Opțiuni Înregistrare",
|
"HeaderRecordingOptions": "Opțiuni Înregistrare",
|
||||||
"HeaderRecordingPostProcessing": "Post procesarea înregistrării",
|
"HeaderRecordingPostProcessing": "Post procesarea înregistrării",
|
||||||
"HeaderRemoveMediaFolder": "Eliminați Dosarul Media",
|
"HeaderRemoveMediaFolder": "Eliminați Dosarul Media",
|
||||||
|
@ -614,7 +614,7 @@
|
||||||
"HeaderSelectServer": "Selectați Serverul",
|
"HeaderSelectServer": "Selectați Serverul",
|
||||||
"HeaderSelectServerCachePath": "Selectați ruta pentru Server Cache",
|
"HeaderSelectServerCachePath": "Selectați ruta pentru Server Cache",
|
||||||
"HeaderSelectTranscodingPath": "Selectați ruta temporară pentru transcodare",
|
"HeaderSelectTranscodingPath": "Selectați ruta temporară pentru transcodare",
|
||||||
"HeaderSelectTranscodingPathHelp": "Căutați sau introduceți ruta dosarului de utilizat pentru transcodarea fișierelor temporare. Dosarul trebuie permisiuni de scriere.",
|
"HeaderSelectTranscodingPathHelp": "Căutați sau introduceți ruta dosarului de utilizat pentru transcodarea fișierelor. Dosarul trebuie permisiuni de scriere.",
|
||||||
"HeaderSendMessage": "Trimite Mesaj",
|
"HeaderSendMessage": "Trimite Mesaj",
|
||||||
"HeaderSeriesOptions": "Opțiuni Seriale",
|
"HeaderSeriesOptions": "Opțiuni Seriale",
|
||||||
"HeaderSeriesStatus": "Starea Serialelor",
|
"HeaderSeriesStatus": "Starea Serialelor",
|
||||||
|
@ -675,7 +675,7 @@
|
||||||
"LabelSeasonNumber": "Numărul sezonului:",
|
"LabelSeasonNumber": "Numărul sezonului:",
|
||||||
"LabelScreensaver": "Protector de ecran:",
|
"LabelScreensaver": "Protector de ecran:",
|
||||||
"LabelScheduledTaskLastRan": "Ultima redare{0}, cu durata {1}.",
|
"LabelScheduledTaskLastRan": "Ultima redare{0}, cu durata {1}.",
|
||||||
"LabelRuntimeMinutes": "Timp de redare (minute):",
|
"LabelRuntimeMinutes": "Timp de redare:",
|
||||||
"LabelRemoteClientBitrateLimitHelp": "O limită de biți per-stream opțională pentru toate dispozitivele din rețea. Acest lucru este util pentru a împiedica dispozitivele să solicite un bitrate mai mare decât poate gestiona conexiunea dvs. de internet. Acest lucru poate duce la creșterea încărcării procesorului pe serverul dvs. pentru a transcoda videoclipurile din zbor la un bitrate mai mic.",
|
"LabelRemoteClientBitrateLimitHelp": "O limită de biți per-stream opțională pentru toate dispozitivele din rețea. Acest lucru este util pentru a împiedica dispozitivele să solicite un bitrate mai mare decât poate gestiona conexiunea dvs. de internet. Acest lucru poate duce la creșterea încărcării procesorului pe serverul dvs. pentru a transcoda videoclipurile din zbor la un bitrate mai mic.",
|
||||||
"LabelRemoteClientBitrateLimit": "Limită de biți pentru streaming pe Internet (Mbps):",
|
"LabelRemoteClientBitrateLimit": "Limită de biți pentru streaming pe Internet (Mbps):",
|
||||||
"LabelReleaseDate": "Data lansării:",
|
"LabelReleaseDate": "Data lansării:",
|
||||||
|
@ -720,7 +720,7 @@
|
||||||
"LabelOriginalTitle": "Titlu original:",
|
"LabelOriginalTitle": "Titlu original:",
|
||||||
"LabelOriginalAspectRatio": "Raport aspect original:",
|
"LabelOriginalAspectRatio": "Raport aspect original:",
|
||||||
"LabelOptionalNetworkPathHelp": "Dacă acest folder este partajat în rețeaua dvs., furnizarea căii de partajare a rețelei poate permite aplicațiilor Jellyfin de pe alte dispozitive să acceseze fișiere media direct.",
|
"LabelOptionalNetworkPathHelp": "Dacă acest folder este partajat în rețeaua dvs., furnizarea căii de partajare a rețelei poate permite aplicațiilor Jellyfin de pe alte dispozitive să acceseze fișiere media direct.",
|
||||||
"LabelOptionalNetworkPath": "(Optional) Dosar partajat în rețea:",
|
"LabelOptionalNetworkPath": "Dosar partajat în rețea:",
|
||||||
"LabelNumber": "Număr:",
|
"LabelNumber": "Număr:",
|
||||||
"LabelNotificationEnabled": "Activează această notificare",
|
"LabelNotificationEnabled": "Activează această notificare",
|
||||||
"LabelNewsCategories": "Categoriile știrilor:",
|
"LabelNewsCategories": "Categoriile știrilor:",
|
||||||
|
@ -741,7 +741,7 @@
|
||||||
"LabelMinResumeDurationHelp": "Cea mai scurtă lungime video în secunde, care va salva locația de redare și vă va permite să reluați.",
|
"LabelMinResumeDurationHelp": "Cea mai scurtă lungime video în secunde, care va salva locația de redare și vă va permite să reluați.",
|
||||||
"LabelMinResumeDuration": "Durata minimă a reluării:",
|
"LabelMinResumeDuration": "Durata minimă a reluării:",
|
||||||
"LabelMethod": "Metoda:",
|
"LabelMethod": "Metoda:",
|
||||||
"LabelMetadataSaversHelp": "Alegeți formatele de fișiere pentru a vă salva metadatele.",
|
"LabelMetadataSaversHelp": "Alegeți formatele de fișiere pentru salvarea metadatele.",
|
||||||
"LabelMetadataSavers": "Salvări de metadate:",
|
"LabelMetadataSavers": "Salvări de metadate:",
|
||||||
"LabelMetadataReadersHelp": "Clasificați sursele preferate de metadate locale în ordinea priorității. Primul fișier găsit va fi citit.",
|
"LabelMetadataReadersHelp": "Clasificați sursele preferate de metadate locale în ordinea priorității. Primul fișier găsit va fi citit.",
|
||||||
"LabelMetadataReaders": "Cititori de metadate:",
|
"LabelMetadataReaders": "Cititori de metadate:",
|
||||||
|
@ -761,7 +761,7 @@
|
||||||
"LabelLoginDisclaimerHelp": "Un mesaj care va fi afișat în partea de jos a paginii de conectare.",
|
"LabelLoginDisclaimerHelp": "Un mesaj care va fi afișat în partea de jos a paginii de conectare.",
|
||||||
"LabelLoginDisclaimer": "Act de renunțare la autentificare:",
|
"LabelLoginDisclaimer": "Act de renunțare la autentificare:",
|
||||||
"LabelLockItemToPreventChanges": "Blocați acest element pentru a preveni modificările viitoare",
|
"LabelLockItemToPreventChanges": "Blocați acest element pentru a preveni modificările viitoare",
|
||||||
"LabelLocalHttpServerPortNumberHelp": "Portul TCP pe care serverul HTTP Jellyfin ar trebui să îl utilizeze.",
|
"LabelLocalHttpServerPortNumberHelp": "Portul TCP pentru serverul HTTP.",
|
||||||
"LabelLocalHttpServerPortNumber": "Portul local HTTP:",
|
"LabelLocalHttpServerPortNumber": "Portul local HTTP:",
|
||||||
"LabelLineup": "Echipa:",
|
"LabelLineup": "Echipa:",
|
||||||
"LabelLanNetworks": "Rețele LAN:",
|
"LabelLanNetworks": "Rețele LAN:",
|
||||||
|
@ -788,7 +788,7 @@
|
||||||
"LabelIconMaxWidth": "Lățimea maximă a pictogramei:",
|
"LabelIconMaxWidth": "Lățimea maximă a pictogramei:",
|
||||||
"LabelIconMaxHeightHelp": "Rezoluția maximă a pictogramelor expuse via upnp:icon.",
|
"LabelIconMaxHeightHelp": "Rezoluția maximă a pictogramelor expuse via upnp:icon.",
|
||||||
"LabelIconMaxHeight": "Înălțimea maximă a pictogramei:",
|
"LabelIconMaxHeight": "Înălțimea maximă a pictogramei:",
|
||||||
"LabelHttpsPortHelp": "Portul TCP pe care serverul HTTPS Jellyfin ar trebui sa îl utilizeze.",
|
"LabelHttpsPortHelp": "Portul TCP pentru serverul HTTPS.",
|
||||||
"LabelHttpsPort": "Portul local HTTPS:",
|
"LabelHttpsPort": "Portul local HTTPS:",
|
||||||
"LabelHomeScreenSectionValue": "Secțiunea ecranului de pornire {0}:",
|
"LabelHomeScreenSectionValue": "Secțiunea ecranului de pornire {0}:",
|
||||||
"LabelHomeNetworkQuality": "Calitatea pe rețeaua de domiciliu:",
|
"LabelHomeNetworkQuality": "Calitatea pe rețeaua de domiciliu:",
|
||||||
|
@ -816,7 +816,7 @@
|
||||||
"LabelEndDate": "Data de încheiere:",
|
"LabelEndDate": "Data de încheiere:",
|
||||||
"LabelEnableSingleImageInDidlLimitHelp": "Unele dispozitive nu vor reda corect dacă mai multe imagini sunt încorporate în Didl.",
|
"LabelEnableSingleImageInDidlLimitHelp": "Unele dispozitive nu vor reda corect dacă mai multe imagini sunt încorporate în Didl.",
|
||||||
"LabelEnableSingleImageInDidlLimit": "Limitați la o singură imagine încorporată",
|
"LabelEnableSingleImageInDidlLimit": "Limitați la o singură imagine încorporată",
|
||||||
"LabelEnableRealtimeMonitorHelp": "Modificările la fișiere vor fi procesate imediat, pe sistemele de fișiere acceptate.",
|
"LabelEnableRealtimeMonitorHelp": "Modificările la fișiere vor fi procesate imediat pe sistemele de fișiere acceptate.",
|
||||||
"LabelEnableRealtimeMonitor": "Activați monitorizarea în timp real",
|
"LabelEnableRealtimeMonitor": "Activați monitorizarea în timp real",
|
||||||
"LabelEnableHardwareDecodingFor": "Activați decodarea hardware pentru:",
|
"LabelEnableHardwareDecodingFor": "Activați decodarea hardware pentru:",
|
||||||
"LabelEnableDlnaServerHelp": "Permite dispozitivelor UPnP din rețeaua dvs. să răsfoiască și să redea conținut.",
|
"LabelEnableDlnaServerHelp": "Permite dispozitivelor UPnP din rețeaua dvs. să răsfoiască și să redea conținut.",
|
||||||
|
@ -826,7 +826,7 @@
|
||||||
"LabelEnableDlnaDebugLoggingHelp": "Creați fișiere de jurnal mari și trebuie utilizate numai în funcție de necesități pentru rezolvarea problemelor.",
|
"LabelEnableDlnaDebugLoggingHelp": "Creați fișiere de jurnal mari și trebuie utilizate numai în funcție de necesități pentru rezolvarea problemelor.",
|
||||||
"LabelEnableDlnaDebugLogging": "Activați jurnalul de depanare DLNA",
|
"LabelEnableDlnaDebugLogging": "Activați jurnalul de depanare DLNA",
|
||||||
"LabelEnableDlnaClientDiscoveryIntervalHelp": "Determină durata în secunde între căutările SSDP efectuate de Jellyfin.",
|
"LabelEnableDlnaClientDiscoveryIntervalHelp": "Determină durata în secunde între căutările SSDP efectuate de Jellyfin.",
|
||||||
"LabelEnableDlnaClientDiscoveryInterval": "Interval de descoperire a clientului (secunde)",
|
"LabelEnableDlnaClientDiscoveryInterval": "Interval de descoperire a clientului",
|
||||||
"LabelEnableBlastAliveMessagesHelp": "Activați acest lucru dacă serverul nu este detectat în mod fiabil de alte dispozitive UPnP din rețeaua dvs.",
|
"LabelEnableBlastAliveMessagesHelp": "Activați acest lucru dacă serverul nu este detectat în mod fiabil de alte dispozitive UPnP din rețeaua dvs.",
|
||||||
"LabelEnableBlastAliveMessages": "Trimitere mesaje de disponibilitate",
|
"LabelEnableBlastAliveMessages": "Trimitere mesaje de disponibilitate",
|
||||||
"LabelEnableAutomaticPortMapHelp": "Încercați să mapați automat portul public către portul local prin UPnP. Este posibil să nu funcționeze cu unele modele de router. Modificările nu se vor aplica decât după repornirea serverului.",
|
"LabelEnableAutomaticPortMapHelp": "Încercați să mapați automat portul public către portul local prin UPnP. Este posibil să nu funcționeze cu unele modele de router. Modificările nu se vor aplica decât după repornirea serverului.",
|
||||||
|
@ -874,11 +874,11 @@
|
||||||
"LabelBurnSubtitles": "Imprimă subtitrările:",
|
"LabelBurnSubtitles": "Imprimă subtitrările:",
|
||||||
"LabelBlockContentWithTags": "Blochează articolele cu etichetele:",
|
"LabelBlockContentWithTags": "Blochează articolele cu etichetele:",
|
||||||
"LabelBlastMessageIntervalHelp": "Determină durata în secunde între transmiterea mesajele de viață.",
|
"LabelBlastMessageIntervalHelp": "Determină durata în secunde între transmiterea mesajele de viață.",
|
||||||
"LabelBlastMessageInterval": "Interval transmitere mesaj viu (secunde)",
|
"LabelBlastMessageInterval": "Interval transmitere mesaj viu",
|
||||||
"LabelBitrate": "Rată de biți:",
|
"LabelBitrate": "Rată de biți:",
|
||||||
"LabelBirthYear": "Anul nașterii:",
|
"LabelBirthYear": "Anul nașterii:",
|
||||||
"LabelBirthDate": "Data nașterii:",
|
"LabelBirthDate": "Data nașterii:",
|
||||||
"LabelBindToLocalNetworkAddressHelp": "Opțional. Rescrie adresa IP locală pentru a o utiliza serverul http. Dacă este lăsat gol, serverul se va lega la toate adresele disponibile. Modificarea acestei valori necesită repornirea Jellyfin Server.",
|
"LabelBindToLocalNetworkAddressHelp": "Rescrie adresa IP locală a serverului http. Dacă este lăsat gol, serverul se va lega la toate adresele disponibile. Modificarea acestei valori necesită repornirea Jellyfin Server.",
|
||||||
"LabelBindToLocalNetworkAddress": "Utilizează adresa de rețea locală:",
|
"LabelBindToLocalNetworkAddress": "Utilizează adresa de rețea locală:",
|
||||||
"LabelAutomaticallyRefreshInternetMetadataEvery": "Actualizați automat metadatele de pe internet:",
|
"LabelAutomaticallyRefreshInternetMetadataEvery": "Actualizați automat metadatele de pe internet:",
|
||||||
"LabelAuthProvider": "Furnizor de autentificare:",
|
"LabelAuthProvider": "Furnizor de autentificare:",
|
||||||
|
@ -917,7 +917,7 @@
|
||||||
"ItemCount": "{0} articole",
|
"ItemCount": "{0} articole",
|
||||||
"InstantMix": "Mix instant",
|
"InstantMix": "Mix instant",
|
||||||
"InstallingPackage": "Instalare {0} (versiune {1})",
|
"InstallingPackage": "Instalare {0} (versiune {1})",
|
||||||
"ImportFavoriteChannelsHelp": "Dacă este activat, vor fi importate numai canalele marcate ca preferate pe dispozitivul tuner.",
|
"ImportFavoriteChannelsHelp": "Vor fi importate numai canalele marcate ca preferate pe dispozitivul tuner.",
|
||||||
"Images": "Imagini",
|
"Images": "Imagini",
|
||||||
"Identify": "Identifică",
|
"Identify": "Identifică",
|
||||||
"HttpsRequiresCert": "Pentru a activa conexiunile securizate, va trebui să furnizați un certificat SSL de încredere, cum ar fi Let's Encrypt. Vă rugăm să furnizați un certificat sau să dezactivați conexiunile securizate.",
|
"HttpsRequiresCert": "Pentru a activa conexiunile securizate, va trebui să furnizați un certificat SSL de încredere, cum ar fi Let's Encrypt. Vă rugăm să furnizați un certificat sau să dezactivați conexiunile securizate.",
|
||||||
|
@ -969,14 +969,14 @@
|
||||||
"OptionBlockChannelContent": "Conținut canal Internet",
|
"OptionBlockChannelContent": "Conținut canal Internet",
|
||||||
"OptionBlockBooks": "Cărți",
|
"OptionBlockBooks": "Cărți",
|
||||||
"OptionBanner": "Steag",
|
"OptionBanner": "Steag",
|
||||||
"OptionAutomaticallyGroupSeriesHelp": "Dacă este activat, seriile distribuite pe mai multe foldere din această bibliotecă vor fi comasate automat într-o singură serie.",
|
"OptionAutomaticallyGroupSeriesHelp": "Seriile distribuite pe mai multe foldere din această bibliotecă vor fi comasate automat într-o singură serie.",
|
||||||
"OptionAutomaticallyGroupSeries": "Fuzionează automat seriile care sunt răspândite pe mai multe foldere",
|
"OptionAutomaticallyGroupSeries": "Fuzionează automat seriile care sunt răspândite pe mai multe foldere",
|
||||||
"OptionAuto": "Auto",
|
"OptionAuto": "Auto",
|
||||||
"OptionArtist": "Artist",
|
"OptionArtist": "Artist",
|
||||||
"OptionAllowVideoPlaybackTranscoding": "Permiteți redarea video care necesită transcodare",
|
"OptionAllowVideoPlaybackTranscoding": "Permiteți redarea video care necesită transcodare",
|
||||||
"OptionAllowVideoPlaybackRemuxing": "Permiteți redarea video care necesită conversie fără re-codificare",
|
"OptionAllowVideoPlaybackRemuxing": "Permiteți redarea video care necesită conversie fără re-codificare",
|
||||||
"OptionAllowSyncTranscoding": "Permiteți descărcarea și sincronizarea media care necesită transcodare",
|
"OptionAllowSyncTranscoding": "Permiteți descărcarea și sincronizarea media care necesită transcodare",
|
||||||
"OptionAllowMediaPlaybackTranscodingHelp": "Restrângerea accesului la transcodare poate provoca defecțiuni de redare în aplicațiile Jellyfin din cauza formatelor media neacceptate.",
|
"OptionAllowMediaPlaybackTranscodingHelp": "Restrângerea accesului la transcodare poate provoca defecțiuni de redare în aplicațiile client din cauza formatelor media neacceptate.",
|
||||||
"OptionAllowContentDownloading": "Permiteți descărcarea și sincronizarea media",
|
"OptionAllowContentDownloading": "Permiteți descărcarea și sincronizarea media",
|
||||||
"OptionAllowAudioPlaybackTranscoding": "Permiteți redarea audio care necesită transcodare",
|
"OptionAllowAudioPlaybackTranscoding": "Permiteți redarea audio care necesită transcodare",
|
||||||
"OptionAllUsers": "Toți utilizatorii",
|
"OptionAllUsers": "Toți utilizatorii",
|
||||||
|
@ -1113,7 +1113,7 @@
|
||||||
"LatestFromLibrary": "Ultimele {0}",
|
"LatestFromLibrary": "Ultimele {0}",
|
||||||
"Large": "Mare",
|
"Large": "Mare",
|
||||||
"LanNetworksHelp": "Lista separată de virgule a adreselor IP sau a intrărilor de tip IP/mască de rețea pentru rețelele care vor fi luate în considerare în rețeaua locală atunci când se aplică restricțiile de lățime de bandă. Dacă este setat, toate celelalte adrese IP vor fi considerate a fi în rețeaua externă și vor fi supuse restricțiilor de lățime de bandă externe. Dacă este lăsat necompletat, numai subnetul serverului este considerat a fi în rețeaua locală.",
|
"LanNetworksHelp": "Lista separată de virgule a adreselor IP sau a intrărilor de tip IP/mască de rețea pentru rețelele care vor fi luate în considerare în rețeaua locală atunci când se aplică restricțiile de lățime de bandă. Dacă este setat, toate celelalte adrese IP vor fi considerate a fi în rețeaua externă și vor fi supuse restricțiilor de lățime de bandă externe. Dacă este lăsat necompletat, numai subnetul serverului este considerat a fi în rețeaua locală.",
|
||||||
"LabelffmpegPathHelp": "Calea către executabilul ffmpeg, sau dosarul care conține ffmpeg.",
|
"LabelffmpegPathHelp": "Calea către executabilul ffmpeg sau dosarul care conține ffmpeg.",
|
||||||
"LabelffmpegPath": "Calea către FFmpeg:",
|
"LabelffmpegPath": "Calea către FFmpeg:",
|
||||||
"LabelZipCode": "Cod poștal:",
|
"LabelZipCode": "Cod poștal:",
|
||||||
"LabelYear": "Anul:",
|
"LabelYear": "Anul:",
|
||||||
|
@ -1217,7 +1217,7 @@
|
||||||
"ReleaseDate": "Data lansării",
|
"ReleaseDate": "Data lansării",
|
||||||
"RefreshQueued": "Actualizare adăugată în coadă.",
|
"RefreshQueued": "Actualizare adăugată în coadă.",
|
||||||
"RefreshMetadata": "Actualizați metadatele",
|
"RefreshMetadata": "Actualizați metadatele",
|
||||||
"RefreshDialogHelp": "Metadatele sunt actualizate pe baza setărilor și a serviciilor de internet care sunt activate în tabloul de bord Jellyfin Server.",
|
"RefreshDialogHelp": "Metadatele sunt actualizate pe baza setărilor și a serviciilor de internet care sunt activate în tabloul de bord.",
|
||||||
"Refresh": "Reîmprospătează",
|
"Refresh": "Reîmprospătează",
|
||||||
"Recordings": "Înregistrări",
|
"Recordings": "Înregistrări",
|
||||||
"RecordingScheduled": "Înregistrare programată.",
|
"RecordingScheduled": "Înregistrare programată.",
|
||||||
|
@ -1263,7 +1263,7 @@
|
||||||
"PerfectMatch": "Potrivire perfectă",
|
"PerfectMatch": "Potrivire perfectă",
|
||||||
"People": "Oameni",
|
"People": "Oameni",
|
||||||
"PasswordSaved": "Parolă salvată.",
|
"PasswordSaved": "Parolă salvată.",
|
||||||
"PasswordResetProviderHelp": "Alegeți un furnizor de resetare a parolei pentru a fi utilizat atunci când acest utilizator solicită o resetare a parolei",
|
"PasswordResetProviderHelp": "Alegeți un furnizor de resetare a parolei pentru a fi utilizat atunci când acest utilizator solicită o resetare a parolei.",
|
||||||
"HeaderResetPassword": "Resetează parola",
|
"HeaderResetPassword": "Resetează parola",
|
||||||
"PasswordResetConfirmation": "Sigur doriți să resetați parola?",
|
"PasswordResetConfirmation": "Sigur doriți să resetați parola?",
|
||||||
"PasswordResetComplete": "Parola a fost resetată.",
|
"PasswordResetComplete": "Parola a fost resetată.",
|
||||||
|
@ -1300,9 +1300,9 @@
|
||||||
"OptionProfileAudio": "Audio",
|
"OptionProfileAudio": "Audio",
|
||||||
"OptionPosterCard": "Carte de afiș",
|
"OptionPosterCard": "Carte de afiș",
|
||||||
"OptionPoster": "Afiș",
|
"OptionPoster": "Afiș",
|
||||||
"OptionPlainVideoItemsHelp": "Dacă este activat, toate videoclipurile sunt reprezentate în DIDL ca „object.item.videoItem” în loc de un tip mai specific, cum ar fi „object.item.videoItem.movie”.",
|
"OptionPlainVideoItemsHelp": "Toate videoclipurile sunt reprezentate în DIDL ca „object.item.videoItem” în loc de un tip mai specific, cum ar fi „object.item.videoItem.movie”.",
|
||||||
"OptionPlainVideoItems": "Afișați toate videoclipurile ca elemente video simple",
|
"OptionPlainVideoItems": "Afișați toate videoclipurile ca elemente video simple",
|
||||||
"OptionPlainStorageFoldersHelp": "Dacă este activat, toate folderele sunt reprezentate în DIDL ca „object.container.storageFolder” în loc de un tip mai specific, cum ar fi „object.container.person.musicArtist”.",
|
"OptionPlainStorageFoldersHelp": "Toate dosarele sunt reprezentate în DIDL ca „object.container.storageFolder” în loc de un tip mai specific, cum ar fi „object.container.person.musicArtist”.",
|
||||||
"OptionPlainStorageFolders": "Afișați toate dosarele ca dosare simple de stocare",
|
"OptionPlainStorageFolders": "Afișați toate dosarele ca dosare simple de stocare",
|
||||||
"OptionOnInterval": "La un interval",
|
"OptionOnInterval": "La un interval",
|
||||||
"OptionOnAppStartup": "La pornirea aplicației",
|
"OptionOnAppStartup": "La pornirea aplicației",
|
||||||
|
@ -1315,7 +1315,7 @@
|
||||||
"OptionList": "Listă",
|
"OptionList": "Listă",
|
||||||
"OptionIsSD": "SD",
|
"OptionIsSD": "SD",
|
||||||
"OptionIsHD": "HD",
|
"OptionIsHD": "HD",
|
||||||
"OptionIgnoreTranscodeByteRangeRequestsHelp": "Dacă sunt activate, aceste solicitări vor fi respectate, dar vor ignora antetul intervalului de octeți.",
|
"OptionIgnoreTranscodeByteRangeRequestsHelp": "Aceste solicitări vor fi respectate, dar vor ignora antetul intervalului de octeți.",
|
||||||
"OptionIgnoreTranscodeByteRangeRequests": "Ignorați solicitările pentru transcodarea intervalului de octeți",
|
"OptionIgnoreTranscodeByteRangeRequests": "Ignorați solicitările pentru transcodarea intervalului de octeți",
|
||||||
"OptionHomeVideos": "Fotografii",
|
"OptionHomeVideos": "Fotografii",
|
||||||
"OptionHlsSegmentedSubtitles": "Subtitrare segmentată HLS",
|
"OptionHlsSegmentedSubtitles": "Subtitrare segmentată HLS",
|
||||||
|
@ -1332,7 +1332,7 @@
|
||||||
"OptionEnableExternalContentInSuggestions": "Activați conținut extern în sugestii",
|
"OptionEnableExternalContentInSuggestions": "Activați conținut extern în sugestii",
|
||||||
"OptionEmbedSubtitles": "Inclus în container",
|
"OptionEmbedSubtitles": "Inclus în container",
|
||||||
"OptionDownloadLogoImage": "Siglă",
|
"OptionDownloadLogoImage": "Siglă",
|
||||||
"OptionDownloadImagesInAdvanceHelp": "În mod implicit, majoritatea imaginilor sunt descărcate numai la cererea unei aplicații din Jellyfin. Activați această opțiune pentru a descărca în prealabil toate imaginile, pe măsură ce fișierele media sunt importate. Acest lucru poate provoca scanări ale bibliotecii semnificativ mai lungi.",
|
"OptionDownloadImagesInAdvanceHelp": "În mod implicit, majoritatea imaginilor sunt descărcate numai la cererea unei aplicații Jellyfin. Activați această opțiune pentru a descărca în avans toate imaginile, pe măsură ce fișiere media noi sunt importate. Acest lucru poate duce la mărirea semnificativă a timpilor de scanare a bibliotecii.",
|
||||||
"OptionDownloadImagesInAdvance": "Descărcați imaginile în avans",
|
"OptionDownloadImagesInAdvance": "Descărcați imaginile în avans",
|
||||||
"OptionDownloadDiscImage": "Disc",
|
"OptionDownloadDiscImage": "Disc",
|
||||||
"OptionDisplayFolderViewHelp": "Afișați dosarele alături de celelalte biblioteci media. Acest lucru poate fi util dacă doriți să aveți o vizualizare direct în dosar.",
|
"OptionDisplayFolderViewHelp": "Afișați dosarele alături de celelalte biblioteci media. Acest lucru poate fi util dacă doriți să aveți o vizualizare direct în dosar.",
|
||||||
|
@ -1476,7 +1476,7 @@
|
||||||
"LabelRequireHttps": "Trebuie HTTPS",
|
"LabelRequireHttps": "Trebuie HTTPS",
|
||||||
"LabelStable": "Stabilă",
|
"LabelStable": "Stabilă",
|
||||||
"LabelChromecastVersion": "Versiunea de Chromecast",
|
"LabelChromecastVersion": "Versiunea de Chromecast",
|
||||||
"LabelEnableHttpsHelp": "Activează serverul să asculte pe portul HTTPS configurat. Un certificat valid trebuie de asemenea configurat pentru ca să funcţioneze.",
|
"LabelEnableHttpsHelp": "Ascultă pe portul HTTPS configurat. Un certificat valid trebuie de asemenea configurat pentru ca să funcţioneze.",
|
||||||
"LabelEnableHttps": "Activați HTTPS",
|
"LabelEnableHttps": "Activați HTTPS",
|
||||||
"HeaderServerAddressSettings": "Setările adresei serverului",
|
"HeaderServerAddressSettings": "Setările adresei serverului",
|
||||||
"HeaderRemoteAccessSettings": "Setări pentru aces remote",
|
"HeaderRemoteAccessSettings": "Setări pentru aces remote",
|
||||||
|
@ -1539,5 +1539,11 @@
|
||||||
"LabelRepositoryNameHelp": "Un nume personalizat pentru a distinge acest repertoriu de altele adăugate la serverul dvs.",
|
"LabelRepositoryNameHelp": "Un nume personalizat pentru a distinge acest repertoriu de altele adăugate la serverul dvs.",
|
||||||
"ClearQueue": "Golește lista de redare",
|
"ClearQueue": "Golește lista de redare",
|
||||||
"StopPlayback": "Oprește redarea",
|
"StopPlayback": "Oprește redarea",
|
||||||
"ViewAlbumArtist": "Vezi artistul albumului"
|
"ViewAlbumArtist": "Vezi artistul albumului",
|
||||||
|
"NextTrack": "Sari la următorul",
|
||||||
|
"LabelUnstable": "Instabil",
|
||||||
|
"Preview": "Previzualizare",
|
||||||
|
"SubtitleVerticalPositionHelp": "Numărul de linie unde apare textul. Numerele pozitive indică de sus în jos. Numerele negative indică de jos în sus.",
|
||||||
|
"LabelSubtitleVerticalPosition": "Poziție verticală:",
|
||||||
|
"PreviousTrack": "Sari anterior"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1429,5 +1429,23 @@
|
||||||
"OptionEnableM2tsModeHelp": "Omogoči m2ts način pri kodiranju v mpegts.",
|
"OptionEnableM2tsModeHelp": "Omogoči m2ts način pri kodiranju v mpegts.",
|
||||||
"OptionEnableM2tsMode": "Omogoči M2ts način",
|
"OptionEnableM2tsMode": "Omogoči M2ts način",
|
||||||
"OptionDisplayFolderViewHelp": "Prikaže mape poleg ostalih knjižnic predstavnosti. Uporabno za preprost ogled map.",
|
"OptionDisplayFolderViewHelp": "Prikaže mape poleg ostalih knjižnic predstavnosti. Uporabno za preprost ogled map.",
|
||||||
"OptionDisplayFolderView": "Prikaži pogled mape za prikaz navadnih map predstavnosti"
|
"OptionDisplayFolderView": "Prikaži pogled mape za prikaz navadnih map predstavnosti",
|
||||||
|
"Yesterday": "Včeraj",
|
||||||
|
"Yes": "Da",
|
||||||
|
"RecommendationStarring": "Nastopa {0}",
|
||||||
|
"Recordings": "Posnetki",
|
||||||
|
"RemoveFromCollection": "Odstrani iz zbirke",
|
||||||
|
"ResumeAt": "Nadaljuj od {0}",
|
||||||
|
"SaveSubtitlesIntoMediaFolders": "Shrani podnapise v mape predstavnosti",
|
||||||
|
"ScanForNewAndUpdatedFiles": "Poišči nove in spremenjene datoteke",
|
||||||
|
"Screenshot": "Posnetek zaslona",
|
||||||
|
"Screenshots": "Posnetki zaslona",
|
||||||
|
"Search": "Iskanje",
|
||||||
|
"ShowAdvancedSettings": "Prikaži napredne nastavitve",
|
||||||
|
"New": "Novo",
|
||||||
|
"SubtitleOffset": "Zamik podnapisev",
|
||||||
|
"Subtitles": "Podnapisi",
|
||||||
|
"Sunday": "Nedelja",
|
||||||
|
"TabAdvanced": "Napredno",
|
||||||
|
"TabAlbums": "Albumi"
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,7 @@
|
||||||
"DetectingDevices": "正在侦测设备",
|
"DetectingDevices": "正在侦测设备",
|
||||||
"DeviceAccessHelp": "这仅适用于可以唯一标识的设备,而不会阻止浏览器访问。限制用户设备访问会阻止使用未在此被批准的新增设备。",
|
"DeviceAccessHelp": "这仅适用于可以唯一标识的设备,而不会阻止浏览器访问。限制用户设备访问会阻止使用未在此被批准的新增设备。",
|
||||||
"DirectPlaying": "直接播放",
|
"DirectPlaying": "直接播放",
|
||||||
"DirectStreamHelp2": "直接串流只占用占用很少的CPU并且视频的品质不会有任何损失。",
|
"DirectStreamHelp2": "直接串流只占用占用很少的CPU并且视频的品质只会有极小程度的损失。",
|
||||||
"DirectStreaming": "直接串流",
|
"DirectStreaming": "直接串流",
|
||||||
"Director": "导演",
|
"Director": "导演",
|
||||||
"Disabled": "已禁用",
|
"Disabled": "已禁用",
|
||||||
|
@ -261,7 +261,7 @@
|
||||||
"HeaderAllowMediaDeletionFrom": "允许从中删除媒体",
|
"HeaderAllowMediaDeletionFrom": "允许从中删除媒体",
|
||||||
"HeaderApiKey": "API 密钥",
|
"HeaderApiKey": "API 密钥",
|
||||||
"HeaderApiKeys": "API 密钥",
|
"HeaderApiKeys": "API 密钥",
|
||||||
"HeaderApiKeysHelp": "外部应用程序需要 API 密钥才能与 Jellyfin Server 进行通信。使用 Jellyfin 账户进行登录时密钥将会自动生成,您也可以手动为某个应用程序分配一个密钥。",
|
"HeaderApiKeysHelp": "外部应用程序需要 API 密钥才能与服务器进行通信。密钥会在使用普通账户登录时自动生成,或是手动为应用分配。",
|
||||||
"HeaderAudioBooks": "有声读物",
|
"HeaderAudioBooks": "有声读物",
|
||||||
"HeaderAudioSettings": "声音设置",
|
"HeaderAudioSettings": "声音设置",
|
||||||
"HeaderBlockItemsWithNoRating": "通过没有评级和设置不允许的评级锁定内容:",
|
"HeaderBlockItemsWithNoRating": "通过没有评级和设置不允许的评级锁定内容:",
|
||||||
|
@ -327,7 +327,7 @@
|
||||||
"HeaderInstall": "安装",
|
"HeaderInstall": "安装",
|
||||||
"HeaderInstantMix": "速成合辑",
|
"HeaderInstantMix": "速成合辑",
|
||||||
"HeaderItems": "项目",
|
"HeaderItems": "项目",
|
||||||
"HeaderKodiMetadataHelp": "要启用或禁用 NFO 元数据, 请在 Jellyfin 库安装程序中编辑库, 然后找到“元数据储户”部分。",
|
"HeaderKodiMetadataHelp": "要启用或禁用 NFO 元数据, 请编辑库, 然后找到“元数据储户”部分。",
|
||||||
"HeaderLatestEpisodes": "最新剧集",
|
"HeaderLatestEpisodes": "最新剧集",
|
||||||
"HeaderLatestMedia": "最新媒体",
|
"HeaderLatestMedia": "最新媒体",
|
||||||
"HeaderLatestMovies": "最新电影",
|
"HeaderLatestMovies": "最新电影",
|
||||||
|
@ -372,7 +372,7 @@
|
||||||
"HeaderPreferredMetadataLanguage": "首选元数据语言",
|
"HeaderPreferredMetadataLanguage": "首选元数据语言",
|
||||||
"HeaderProfile": "配置",
|
"HeaderProfile": "配置",
|
||||||
"HeaderProfileInformation": "配置信息",
|
"HeaderProfileInformation": "配置信息",
|
||||||
"HeaderProfileServerSettingsHelp": "这些参数将控制 Jellyfin 媒体服务器如何呈现给设备。",
|
"HeaderProfileServerSettingsHelp": "这些参数将控制服务器如何将自己呈现给客户端。",
|
||||||
"HeaderRecentlyPlayed": "最近播放",
|
"HeaderRecentlyPlayed": "最近播放",
|
||||||
"HeaderRecordingOptions": "录制选项",
|
"HeaderRecordingOptions": "录制选项",
|
||||||
"HeaderRecordingPostProcessing": "记录后处理",
|
"HeaderRecordingPostProcessing": "记录后处理",
|
||||||
|
@ -396,7 +396,7 @@
|
||||||
"HeaderSelectServerCachePath": "选择服务器缓存路径",
|
"HeaderSelectServerCachePath": "选择服务器缓存路径",
|
||||||
"HeaderSelectServerCachePathHelp": "浏览或输入一个路径用于服务器缓存文件,此文件夹必须可写。",
|
"HeaderSelectServerCachePathHelp": "浏览或输入一个路径用于服务器缓存文件,此文件夹必须可写。",
|
||||||
"HeaderSelectTranscodingPath": "选择临时解码路径",
|
"HeaderSelectTranscodingPath": "选择临时解码路径",
|
||||||
"HeaderSelectTranscodingPathHelp": "浏览或输入一个路径用于临时转码,此文件夹必须可写。",
|
"HeaderSelectTranscodingPathHelp": "浏览或输入一个路径用于转码文件,此文件夹必须可写。",
|
||||||
"HeaderSendMessage": "发送消息",
|
"HeaderSendMessage": "发送消息",
|
||||||
"HeaderSeries": "电视剧",
|
"HeaderSeries": "电视剧",
|
||||||
"HeaderSeriesOptions": "系列选项",
|
"HeaderSeriesOptions": "系列选项",
|
||||||
|
@ -445,8 +445,8 @@
|
||||||
"HttpsRequiresCert": "要启用安全连接, 您需要提供一个受信任的 SSL 证书, 例如 Let's Encrypt 。请提供证书或禁用安全连接。",
|
"HttpsRequiresCert": "要启用安全连接, 您需要提供一个受信任的 SSL 证书, 例如 Let's Encrypt 。请提供证书或禁用安全连接。",
|
||||||
"Identify": "识别",
|
"Identify": "识别",
|
||||||
"Images": "图片",
|
"Images": "图片",
|
||||||
"ImportFavoriteChannelsHelp": "如果启用,只有在协调器设备中被标记为我的最爱的频道才会被导入。",
|
"ImportFavoriteChannelsHelp": "只有在协调器设备中被标记为我的最爱的频道才会被导入。",
|
||||||
"ImportMissingEpisodesHelp": "如果启用,会将缺少的剧集信息导入到你的 Jellyfin 数据库并分季分剧显示。可能会大大延长媒体库扫描时间。",
|
"ImportMissingEpisodesHelp": "缺少的剧集信息将被导入到你的数据库并分季分剧显示。可能会大大延长媒体库扫描时间。",
|
||||||
"InstallingPackage": "正在安装 {0}(版本 {1})",
|
"InstallingPackage": "正在安装 {0}(版本 {1})",
|
||||||
"InstantMix": "即时混音",
|
"InstantMix": "即时混音",
|
||||||
"ItemCount": "{0} 项",
|
"ItemCount": "{0} 项",
|
||||||
|
@ -476,14 +476,14 @@
|
||||||
"LabelAppName": "APP名称",
|
"LabelAppName": "APP名称",
|
||||||
"LabelAppNameExample": "例如:Sickbeard, Sonarr",
|
"LabelAppNameExample": "例如:Sickbeard, Sonarr",
|
||||||
"LabelArtists": "艺术家:",
|
"LabelArtists": "艺术家:",
|
||||||
"LabelArtistsHelp": "独立多功能 ;",
|
"LabelArtistsHelp": "将多个艺术家用分号分隔",
|
||||||
"LabelAudioLanguagePreference": "首选音频语言:",
|
"LabelAudioLanguagePreference": "首选音频语言:",
|
||||||
"LabelAutomaticallyRefreshInternetMetadataEvery": "自动从互联网获取元数据并刷新:",
|
"LabelAutomaticallyRefreshInternetMetadataEvery": "自动从互联网获取元数据并刷新:",
|
||||||
"LabelBindToLocalNetworkAddress": "监听的本地网络地址:",
|
"LabelBindToLocalNetworkAddress": "监听的本地网络地址:",
|
||||||
"LabelBindToLocalNetworkAddressHelp": "(可选的)覆盖 HTTP 服务器绑定的本地 IP 地址。如果留空,服务器将会监听所有可用的地址。改变这个值需要重启 Jellyfin 服务器。",
|
"LabelBindToLocalNetworkAddressHelp": "覆盖 HTTP 服务器绑定的本地 IP 地址。如果留空,服务器将会监听所有可用的地址。改变这个值需要重启 Jellyfin 服务器。",
|
||||||
"LabelBirthDate": "出生日期:",
|
"LabelBirthDate": "出生日期:",
|
||||||
"LabelBirthYear": "出生年份:",
|
"LabelBirthYear": "出生年份:",
|
||||||
"LabelBlastMessageInterval": "活动信号的时间间隔(秒)",
|
"LabelBlastMessageInterval": "活动信号的时间间隔",
|
||||||
"LabelBlastMessageIntervalHelp": "确定爆炸活动消息之间的持续时间(以秒为单位)。",
|
"LabelBlastMessageIntervalHelp": "确定爆炸活动消息之间的持续时间(以秒为单位)。",
|
||||||
"LabelBlockContentWithTags": "通过标签锁定内容:",
|
"LabelBlockContentWithTags": "通过标签锁定内容:",
|
||||||
"LabelBurnSubtitles": "烧录字幕:",
|
"LabelBurnSubtitles": "烧录字幕:",
|
||||||
|
@ -541,7 +541,7 @@
|
||||||
"LabelEnableAutomaticPortMapHelp": "通过UPnP将路由器端口自动转发到服务器端口。这可能不适用于某些型号的路由器和网络配置。需要服务器重新启动后才会应用更改。",
|
"LabelEnableAutomaticPortMapHelp": "通过UPnP将路由器端口自动转发到服务器端口。这可能不适用于某些型号的路由器和网络配置。需要服务器重新启动后才会应用更改。",
|
||||||
"LabelEnableBlastAliveMessages": "爆发活动信号",
|
"LabelEnableBlastAliveMessages": "爆发活动信号",
|
||||||
"LabelEnableBlastAliveMessagesHelp": "如果该服务器不能被网络中的其他UPnP设备检测到,请启用此选项。",
|
"LabelEnableBlastAliveMessagesHelp": "如果该服务器不能被网络中的其他UPnP设备检测到,请启用此选项。",
|
||||||
"LabelEnableDlnaClientDiscoveryInterval": "客户端搜寻时间间隔(秒)",
|
"LabelEnableDlnaClientDiscoveryInterval": "客户端搜寻时间间隔",
|
||||||
"LabelEnableDlnaClientDiscoveryIntervalHelp": "确定由 Jellyfin 执行的 SSDP 搜索之间的持续时间 (以秒为单位)。",
|
"LabelEnableDlnaClientDiscoveryIntervalHelp": "确定由 Jellyfin 执行的 SSDP 搜索之间的持续时间 (以秒为单位)。",
|
||||||
"LabelEnableDlnaDebugLogging": "启用 DLNA 调试日志",
|
"LabelEnableDlnaDebugLogging": "启用 DLNA 调试日志",
|
||||||
"LabelEnableDlnaDebugLoggingHelp": "创建一个很大的日志文件,仅应在排除故障时使用。",
|
"LabelEnableDlnaDebugLoggingHelp": "创建一个很大的日志文件,仅应在排除故障时使用。",
|
||||||
|
@ -567,9 +567,9 @@
|
||||||
"LabelForgotPasswordUsernameHelp": "输入你的用户名,如果你还记得。",
|
"LabelForgotPasswordUsernameHelp": "输入你的用户名,如果你还记得。",
|
||||||
"LabelFormat": "格式:",
|
"LabelFormat": "格式:",
|
||||||
"LabelFriendlyName": "好记的名称:",
|
"LabelFriendlyName": "好记的名称:",
|
||||||
"LabelServerNameHelp": "此名称将用做服务器名,如果留空,将使用计算机名。",
|
"LabelServerNameHelp": "此名称将用做服务器名,默认使用服务器的主机名。",
|
||||||
"LabelGroupMoviesIntoCollections": "批量添加电影到收藏",
|
"LabelGroupMoviesIntoCollections": "批量添加电影到收藏",
|
||||||
"LabelGroupMoviesIntoCollectionsHelp": "显示电影列表时,属于一个收藏的电影将显示为一个分组。",
|
"LabelGroupMoviesIntoCollectionsHelp": "显示电影列表时,同一收藏的电影将显示为一个分组。",
|
||||||
"LabelH264Crf": "H264 CRF 编码质量等级:",
|
"LabelH264Crf": "H264 CRF 编码质量等级:",
|
||||||
"LabelEncoderPreset": "H264 和 H265 编码预设:",
|
"LabelEncoderPreset": "H264 和 H265 编码预设:",
|
||||||
"LabelHardwareAccelerationType": "硬件加速:",
|
"LabelHardwareAccelerationType": "硬件加速:",
|
||||||
|
@ -577,7 +577,7 @@
|
||||||
"LabelHomeNetworkQuality": "家庭网络质量:",
|
"LabelHomeNetworkQuality": "家庭网络质量:",
|
||||||
"LabelHomeScreenSectionValue": "主屏幕模块{0}:",
|
"LabelHomeScreenSectionValue": "主屏幕模块{0}:",
|
||||||
"LabelHttpsPort": "本地 HTTPS 端口号:",
|
"LabelHttpsPort": "本地 HTTPS 端口号:",
|
||||||
"LabelHttpsPortHelp": "Jellyfin HTTPS 服务器监听端口。",
|
"LabelHttpsPortHelp": "HTTPS 服务器监听的 TCP 端口号。",
|
||||||
"LabelIconMaxHeight": "图标最大高度:",
|
"LabelIconMaxHeight": "图标最大高度:",
|
||||||
"LabelIconMaxHeightHelp": "通过UPnP显示的图标最大分辨率。",
|
"LabelIconMaxHeightHelp": "通过UPnP显示的图标最大分辨率。",
|
||||||
"LabelIconMaxWidth": "图标最大宽度:",
|
"LabelIconMaxWidth": "图标最大宽度:",
|
||||||
|
@ -604,7 +604,7 @@
|
||||||
"LabelLanguage": "语言:",
|
"LabelLanguage": "语言:",
|
||||||
"LabelLineup": "排队:",
|
"LabelLineup": "排队:",
|
||||||
"LabelLocalHttpServerPortNumber": "本地 HTTP 端口号:",
|
"LabelLocalHttpServerPortNumber": "本地 HTTP 端口号:",
|
||||||
"LabelLocalHttpServerPortNumberHelp": "Jellyfin HTTP 服务器监听的 TCP 端口。",
|
"LabelLocalHttpServerPortNumberHelp": "HTTP 服务器监听的 TCP 端口号。",
|
||||||
"LabelLockItemToPreventChanges": "锁定此项目防止改动",
|
"LabelLockItemToPreventChanges": "锁定此项目防止改动",
|
||||||
"LabelLoginDisclaimer": "登录声明:",
|
"LabelLoginDisclaimer": "登录声明:",
|
||||||
"LabelLoginDisclaimerHelp": "将在登录页面底部显示的信息。",
|
"LabelLoginDisclaimerHelp": "将在登录页面底部显示的信息。",
|
||||||
|
@ -646,9 +646,9 @@
|
||||||
"LabelMovieCategories": "电影分类:",
|
"LabelMovieCategories": "电影分类:",
|
||||||
"LabelMoviePrefix": "电影前缀:",
|
"LabelMoviePrefix": "电影前缀:",
|
||||||
"LabelMoviePrefixHelp": "如果将前缀应用于影片标题, 请在此处输入它, 以便服务器可以正确处理它。",
|
"LabelMoviePrefixHelp": "如果将前缀应用于影片标题, 请在此处输入它, 以便服务器可以正确处理它。",
|
||||||
"LabelMovieRecordingPath": "电影录制路径 (可选的):",
|
"LabelMovieRecordingPath": "电影录制路径:",
|
||||||
"LabelMusicStreamingTranscodingBitrate": "音乐转码的比特率:",
|
"LabelMusicStreamingTranscodingBitrate": "音乐转码的比特率:",
|
||||||
"LabelMusicStreamingTranscodingBitrateHelp": "请指定一个音乐媒体串流时的最大比特率。",
|
"LabelMusicStreamingTranscodingBitrateHelp": "请指定音乐媒体串流时的最大比特率。",
|
||||||
"LabelName": "名字:",
|
"LabelName": "名字:",
|
||||||
"LabelNewName": "新名字:",
|
"LabelNewName": "新名字:",
|
||||||
"LabelNewPassword": "新密码:",
|
"LabelNewPassword": "新密码:",
|
||||||
|
@ -659,7 +659,7 @@
|
||||||
"LabelNumber": "编号:",
|
"LabelNumber": "编号:",
|
||||||
"LabelNumberOfGuideDays": "下载几天的节目指南:",
|
"LabelNumberOfGuideDays": "下载几天的节目指南:",
|
||||||
"LabelNumberOfGuideDaysHelp": "下载更多天的节目指南可以帮你进一步查看节目列表并做出提前安排,但下载过程也将耗时更久。它将基于频道数量自动选择。",
|
"LabelNumberOfGuideDaysHelp": "下载更多天的节目指南可以帮你进一步查看节目列表并做出提前安排,但下载过程也将耗时更久。它将基于频道数量自动选择。",
|
||||||
"LabelOptionalNetworkPath": "(可选的)共享的网络文件夹:",
|
"LabelOptionalNetworkPath": "共享的网络文件夹:",
|
||||||
"LabelOptionalNetworkPathHelp": "如果这个文件夹在你的网络上是共享的,提供这个网络共享地址能够允许其他设备上的 Jellyfin 应用程序直接访问媒体文件,例如 {0} 或者 {1}。",
|
"LabelOptionalNetworkPathHelp": "如果这个文件夹在你的网络上是共享的,提供这个网络共享地址能够允许其他设备上的 Jellyfin 应用程序直接访问媒体文件,例如 {0} 或者 {1}。",
|
||||||
"LabelOriginalAspectRatio": "原始长宽比:",
|
"LabelOriginalAspectRatio": "原始长宽比:",
|
||||||
"LabelOriginalTitle": "原标题:",
|
"LabelOriginalTitle": "原标题:",
|
||||||
|
@ -704,7 +704,7 @@
|
||||||
"LabelReleaseDate": "发行日期:",
|
"LabelReleaseDate": "发行日期:",
|
||||||
"LabelRemoteClientBitrateLimit": "互联网流媒体传输比特率限制(Mbps):",
|
"LabelRemoteClientBitrateLimit": "互联网流媒体传输比特率限制(Mbps):",
|
||||||
"LabelRemoteClientBitrateLimitHelp": "所有网络设备都有一个可选的每流比特率限制。这对于防止设备请求比 internet 连接所能处理的更高的比特率非常有用。这可能会导致服务器上的 CPU 负载增加, 以便将视频转码到较低的比特率。",
|
"LabelRemoteClientBitrateLimitHelp": "所有网络设备都有一个可选的每流比特率限制。这对于防止设备请求比 internet 连接所能处理的更高的比特率非常有用。这可能会导致服务器上的 CPU 负载增加, 以便将视频转码到较低的比特率。",
|
||||||
"LabelRuntimeMinutes": "播放时长(分钟):",
|
"LabelRuntimeMinutes": "播放时长:",
|
||||||
"LabelSaveLocalMetadata": "将媒体图像保存到媒体所在文件夹",
|
"LabelSaveLocalMetadata": "将媒体图像保存到媒体所在文件夹",
|
||||||
"LabelSaveLocalMetadataHelp": "直接将媒体图像保存到媒体所在文件夹以方便编辑。",
|
"LabelSaveLocalMetadataHelp": "直接将媒体图像保存到媒体所在文件夹以方便编辑。",
|
||||||
"LabelScheduledTaskLastRan": "最后运行 {0}, 花费时间 {1}.",
|
"LabelScheduledTaskLastRan": "最后运行 {0}, 花费时间 {1}.",
|
||||||
|
@ -714,7 +714,7 @@
|
||||||
"LabelSelectVersionToInstall": "选择安装版本:",
|
"LabelSelectVersionToInstall": "选择安装版本:",
|
||||||
"LabelSendNotificationToUsers": "发送通知至:",
|
"LabelSendNotificationToUsers": "发送通知至:",
|
||||||
"LabelSerialNumber": "序列号",
|
"LabelSerialNumber": "序列号",
|
||||||
"LabelSeriesRecordingPath": "电视剧录制路径 (可选的):",
|
"LabelSeriesRecordingPath": "电视剧录制路径:",
|
||||||
"LabelServerHost": "主机:",
|
"LabelServerHost": "主机:",
|
||||||
"LabelServerHostHelp": "192.168.1.100:8096 或 https://myserver.com",
|
"LabelServerHostHelp": "192.168.1.100:8096 或 https://myserver.com",
|
||||||
"LabelSimultaneousConnectionLimit": "并发流限制:",
|
"LabelSimultaneousConnectionLimit": "并发流限制:",
|
||||||
|
@ -786,7 +786,7 @@
|
||||||
"LabelYoureDone": "完成!",
|
"LabelYoureDone": "完成!",
|
||||||
"LabelZipCode": "邮编:",
|
"LabelZipCode": "邮编:",
|
||||||
"LabelffmpegPath": "FFmpeg 路径:",
|
"LabelffmpegPath": "FFmpeg 路径:",
|
||||||
"LabelffmpegPathHelp": "FFmpeg 应用程序的文件,或者包含了 FFmpeg 的文件夹的路径。",
|
"LabelffmpegPathHelp": "FFmpeg 应用文件或包含 FFmpeg 的文件夹的路径。",
|
||||||
"LanNetworksHelp": "在强制带宽限制时,认作本地网络上的 IP 地址或 IP/网络掩码条目的逗号分隔列表。如果设置此项,所有其它 IP 地址将被视为在外部网络上,并且将受到外部带宽限制。如果保留为空,则只将服务器的子网视为本地网络。",
|
"LanNetworksHelp": "在强制带宽限制时,认作本地网络上的 IP 地址或 IP/网络掩码条目的逗号分隔列表。如果设置此项,所有其它 IP 地址将被视为在外部网络上,并且将受到外部带宽限制。如果保留为空,则只将服务器的子网视为本地网络。",
|
||||||
"Large": "大",
|
"Large": "大",
|
||||||
"LatestFromLibrary": "最新的{0}",
|
"LatestFromLibrary": "最新的{0}",
|
||||||
|
@ -918,7 +918,7 @@
|
||||||
"OptionAllowLinkSharingHelp": "只有网页包含的媒体信息会被共享。媒体文件不会被公开共享。共享是有时间限制的并且会在 {0} 天后到期。",
|
"OptionAllowLinkSharingHelp": "只有网页包含的媒体信息会被共享。媒体文件不会被公开共享。共享是有时间限制的并且会在 {0} 天后到期。",
|
||||||
"OptionAllowManageLiveTv": "允许电视直播录制管理",
|
"OptionAllowManageLiveTv": "允许电视直播录制管理",
|
||||||
"OptionAllowMediaPlayback": "允许播放媒体",
|
"OptionAllowMediaPlayback": "允许播放媒体",
|
||||||
"OptionAllowMediaPlaybackTranscodingHelp": "由于不支持的媒体格式, 限制对代码转换的访问可能会导致 Jellyfin 应用程序中的播放失败。",
|
"OptionAllowMediaPlaybackTranscodingHelp": "限制对转码的访问可能会由于不支持的媒体格式导致客户端中播放失败。",
|
||||||
"OptionAllowRemoteControlOthers": "允许其他用户全程控制",
|
"OptionAllowRemoteControlOthers": "允许其他用户全程控制",
|
||||||
"OptionAllowRemoteSharedDevices": "允许远程控制共享的设备",
|
"OptionAllowRemoteSharedDevices": "允许远程控制共享的设备",
|
||||||
"OptionAllowRemoteSharedDevicesHelp": "DLNA 设备在用户对他们进行控制前都被视为是共享的。",
|
"OptionAllowRemoteSharedDevicesHelp": "DLNA 设备在用户对他们进行控制前都被视为是共享的。",
|
||||||
|
@ -931,7 +931,7 @@
|
||||||
"OptionAuto": "自动",
|
"OptionAuto": "自动",
|
||||||
"OptionAutomatic": "自动",
|
"OptionAutomatic": "自动",
|
||||||
"OptionAutomaticallyGroupSeries": "自动合并分布在不同文件夹的电视剧",
|
"OptionAutomaticallyGroupSeries": "自动合并分布在不同文件夹的电视剧",
|
||||||
"OptionAutomaticallyGroupSeriesHelp": "如果启用,分布在这个媒体库的多个文件夹中的同一部电视剧将会自动整合成一部电视剧。",
|
"OptionAutomaticallyGroupSeriesHelp": "在这个媒体库的多个文件夹中的同一部电视剧将会自动整合成一部电视剧。",
|
||||||
"OptionBlockBooks": "书籍",
|
"OptionBlockBooks": "书籍",
|
||||||
"OptionBlockChannelContent": "互联网频道内容",
|
"OptionBlockChannelContent": "互联网频道内容",
|
||||||
"OptionBlockLiveTvChannels": "电视直播频道",
|
"OptionBlockLiveTvChannels": "电视直播频道",
|
||||||
|
@ -952,7 +952,7 @@
|
||||||
"OptionDatePlayed": "播放日期",
|
"OptionDatePlayed": "播放日期",
|
||||||
"OptionDescending": "降序",
|
"OptionDescending": "降序",
|
||||||
"OptionDisableUser": "禁用此用户",
|
"OptionDisableUser": "禁用此用户",
|
||||||
"OptionDisableUserHelp": "如果禁用该用户,服务器将不允许该用户连接。现有的连接将被终止。",
|
"OptionDisableUserHelp": "服务器将不允许来自该用户的任何连接。现有的连接将立即被终止。",
|
||||||
"OptionDislikes": "不喜欢",
|
"OptionDislikes": "不喜欢",
|
||||||
"OptionDisplayFolderView": "显示一个“文件夹”类别用于按文件夹分类浏览你的媒体文件夹",
|
"OptionDisplayFolderView": "显示一个“文件夹”类别用于按文件夹分类浏览你的媒体文件夹",
|
||||||
"OptionDisplayFolderViewHelp": "在你的媒体库列表中显示文件夹。如果你有按文件夹分类进行浏览的需求,这会非常有用。",
|
"OptionDisplayFolderViewHelp": "在你的媒体库列表中显示文件夹。如果你有按文件夹分类进行浏览的需求,这会非常有用。",
|
||||||
|
@ -962,7 +962,7 @@
|
||||||
"OptionDownloadBoxImage": "包装",
|
"OptionDownloadBoxImage": "包装",
|
||||||
"OptionDownloadDiscImage": "光盘",
|
"OptionDownloadDiscImage": "光盘",
|
||||||
"OptionDownloadImagesInAdvance": "提前下载图片",
|
"OptionDownloadImagesInAdvance": "提前下载图片",
|
||||||
"OptionDownloadImagesInAdvanceHelp": "默认下,大部分图片只有在 Jellyfin 应用程序请求时下载。开启此选项将随着媒体导入时下载所有图片。这可能需要更久媒体库扫描时间。",
|
"OptionDownloadImagesInAdvanceHelp": "默认大多数图片只在客户端请求时下载。开启此选项将在新媒体导入时预先下载所有图片。这可能大大延长媒体库扫描时间。",
|
||||||
"OptionDownloadMenuImage": "菜单",
|
"OptionDownloadMenuImage": "菜单",
|
||||||
"OptionDownloadPrimaryImage": "封面图",
|
"OptionDownloadPrimaryImage": "封面图",
|
||||||
"OptionDownloadThumbImage": "缩略图",
|
"OptionDownloadThumbImage": "缩略图",
|
||||||
|
@ -994,7 +994,7 @@
|
||||||
"OptionHlsSegmentedSubtitles": "HLS分段字幕",
|
"OptionHlsSegmentedSubtitles": "HLS分段字幕",
|
||||||
"OptionHomeVideos": "照片",
|
"OptionHomeVideos": "照片",
|
||||||
"OptionIgnoreTranscodeByteRangeRequests": "忽略转码字节范围请求",
|
"OptionIgnoreTranscodeByteRangeRequests": "忽略转码字节范围请求",
|
||||||
"OptionIgnoreTranscodeByteRangeRequestsHelp": "如果启用,这些请求会被兑现,但会忽略的字节范围标头。",
|
"OptionIgnoreTranscodeByteRangeRequestsHelp": "这些请求会被兑现,但会忽略的字节范围标头。",
|
||||||
"OptionImdbRating": "IMDb 评分",
|
"OptionImdbRating": "IMDb 评分",
|
||||||
"OptionIsHD": "HD高清",
|
"OptionIsHD": "HD高清",
|
||||||
"OptionIsSD": "SD标清",
|
"OptionIsSD": "SD标清",
|
||||||
|
@ -1009,9 +1009,9 @@
|
||||||
"OptionOnInterval": "在一个期间",
|
"OptionOnInterval": "在一个期间",
|
||||||
"OptionParentalRating": "家长分级",
|
"OptionParentalRating": "家长分级",
|
||||||
"OptionPlainStorageFolders": "显示所有文件夹作为一般存储文件夹",
|
"OptionPlainStorageFolders": "显示所有文件夹作为一般存储文件夹",
|
||||||
"OptionPlainStorageFoldersHelp": "如果启用,所有文件夹在DIDL中显示为“ object.container.storageFolder ”,而不是一个更具体的类型,如“ object.container.person.musicArtist ” 。",
|
"OptionPlainStorageFoldersHelp": "所有文件夹在DIDL中显示为 \"object.container.storageFolder\" ,而不是一个更具体的类型,如 \"object.container.person.musicArtist\" 。",
|
||||||
"OptionPlainVideoItems": "显示所有视频为一般视频项目",
|
"OptionPlainVideoItems": "显示所有视频为一般视频项目",
|
||||||
"OptionPlainVideoItemsHelp": "如果启用,所有视频在DIDL中显示为“object.item.videoItem”,而不是一个更具体的类型,如“object.item.videoItem.movie ” 。",
|
"OptionPlainVideoItemsHelp": "所有视频在DIDL中显示为 \"object.item.videoItem\" ,而不是一个更具体的类型,如 \"object.item.videoItem.movie\" 。",
|
||||||
"OptionPlayCount": "播放次数",
|
"OptionPlayCount": "播放次数",
|
||||||
"OptionPlayed": "已播放",
|
"OptionPlayed": "已播放",
|
||||||
"OptionPremiereDate": "首映日期",
|
"OptionPremiereDate": "首映日期",
|
||||||
|
@ -1316,7 +1316,7 @@
|
||||||
"ErrorDeletingItem": "从 Jellyfin Server 删除项目时出错。请确认 Jellyfin Server 是否拥有对媒体目录的写权限,然后重试。",
|
"ErrorDeletingItem": "从 Jellyfin Server 删除项目时出错。请确认 Jellyfin Server 是否拥有对媒体目录的写权限,然后重试。",
|
||||||
"GroupBySeries": "按系列分组",
|
"GroupBySeries": "按系列分组",
|
||||||
"HeaderApp": "应用程序",
|
"HeaderApp": "应用程序",
|
||||||
"DirectStreamHelp1": "该媒体文件的分辨率和编码(H.264、AC3 等)与您的设备兼容,但容器格式(.mkv、.avi、.wmv 等)不受支持。因此,视频在串流至您的设备之前将会被即时封装为另一种格式。",
|
"DirectStreamHelp1": "该媒体文件的分辨率和编码(H.264、AC3 等)与您的设备兼容,但文件格式(.mkv、.avi、.wmv 等)不受支持。因此,视频在串流至您的设备之前将会被即时封装为另一种格式。",
|
||||||
"HeaderAppearsOn": "同时出现于",
|
"HeaderAppearsOn": "同时出现于",
|
||||||
"HeaderCancelSeries": "取消系列",
|
"HeaderCancelSeries": "取消系列",
|
||||||
"HeaderFavoriteEpisodes": "最爱的剧集",
|
"HeaderFavoriteEpisodes": "最爱的剧集",
|
||||||
|
@ -1361,14 +1361,14 @@
|
||||||
"OptionDownloadLogoImage": "标志",
|
"OptionDownloadLogoImage": "标志",
|
||||||
"OptionLoginAttemptsBeforeLockout": "确定在锁定之前可以进行多少次不正确的登录尝试。",
|
"OptionLoginAttemptsBeforeLockout": "确定在锁定之前可以进行多少次不正确的登录尝试。",
|
||||||
"OptionLoginAttemptsBeforeLockoutHelp": "如果值为0,则表示将允许普通用户尝试三次、管理员尝试五次的默认值。将此设置为-1将禁用此功能。",
|
"OptionLoginAttemptsBeforeLockoutHelp": "如果值为0,则表示将允许普通用户尝试三次、管理员尝试五次的默认值。将此设置为-1将禁用此功能。",
|
||||||
"PasswordResetProviderHelp": "选择一个密码重置提供者用于密码重置",
|
"PasswordResetProviderHelp": "选择一个密码重置提供者用于此用户申请重置密码",
|
||||||
"PlaceFavoriteChannelsAtBeginning": "将最喜爱的频道置顶",
|
"PlaceFavoriteChannelsAtBeginning": "将最喜爱的频道置顶",
|
||||||
"PlayNext": "播放下一个",
|
"PlayNext": "播放下一个",
|
||||||
"PlayNextEpisodeAutomatically": "自动播放下一集",
|
"PlayNextEpisodeAutomatically": "自动播放下一集",
|
||||||
"Premieres": "首映",
|
"Premieres": "首映",
|
||||||
"Raised": "提高",
|
"Raised": "提高",
|
||||||
"Recordings": "录音",
|
"Recordings": "录音",
|
||||||
"RefreshDialogHelp": "元数据根据设置和Jellyfin服务器中启用的网络服务进行刷新。",
|
"RefreshDialogHelp": "元数据根据设置和仪表盘中启用的网络服务进行刷新。",
|
||||||
"RepeatEpisodes": "重复剧集",
|
"RepeatEpisodes": "重复剧集",
|
||||||
"Schedule": "日程",
|
"Schedule": "日程",
|
||||||
"Screenshot": "屏幕截图",
|
"Screenshot": "屏幕截图",
|
||||||
|
@ -1421,7 +1421,7 @@
|
||||||
"ButtonAddImage": "添加图片",
|
"ButtonAddImage": "添加图片",
|
||||||
"LabelPlayer": "播放器:",
|
"LabelPlayer": "播放器:",
|
||||||
"LabelBaseUrl": "基础 URL:",
|
"LabelBaseUrl": "基础 URL:",
|
||||||
"LabelBaseUrlHelp": "为服务器 URL添加自定义子目录,例如:<code>http://example.com/<b><baseurl></b></code>。",
|
"LabelBaseUrlHelp": "为服务器 URL添加自定义子目录,例如:<code>http://example.com/<b><baseurl></b></code>",
|
||||||
"MusicLibraryHelp": "重播 {0}音乐命名指南{1}。",
|
"MusicLibraryHelp": "重播 {0}音乐命名指南{1}。",
|
||||||
"HeaderFavoritePeople": "最喜欢的人物",
|
"HeaderFavoritePeople": "最喜欢的人物",
|
||||||
"OptionRandom": "随机",
|
"OptionRandom": "随机",
|
||||||
|
@ -1480,7 +1480,7 @@
|
||||||
"LabelRequireHttpsHelp": "开启后服务器将自动将所有 HTTP 请求重定向到 HTTPS。如果服务器没有启用 HTTPS 则不生效。",
|
"LabelRequireHttpsHelp": "开启后服务器将自动将所有 HTTP 请求重定向到 HTTPS。如果服务器没有启用 HTTPS 则不生效。",
|
||||||
"LabelRequireHttps": "强制 HTTPS",
|
"LabelRequireHttps": "强制 HTTPS",
|
||||||
"LabelStable": "稳定版",
|
"LabelStable": "稳定版",
|
||||||
"LabelEnableHttpsHelp": "开启服务器对所配置 HTTPS 端口的监听。必须配置有效的证书才会生效。",
|
"LabelEnableHttpsHelp": "监听已配置的 HTTPS 端口。必须配置有效的证书才会生效。",
|
||||||
"LabelEnableHttps": "启用 HTTPS",
|
"LabelEnableHttps": "启用 HTTPS",
|
||||||
"LabelChromecastVersion": "Chromecast版本",
|
"LabelChromecastVersion": "Chromecast版本",
|
||||||
"HeaderDVR": "DVR",
|
"HeaderDVR": "DVR",
|
||||||
|
@ -1539,5 +1539,13 @@
|
||||||
"ClearQueue": "清空队列",
|
"ClearQueue": "清空队列",
|
||||||
"StopPlayback": "停止播放",
|
"StopPlayback": "停止播放",
|
||||||
"Writers": "作者",
|
"Writers": "作者",
|
||||||
"ViewAlbumArtist": "查看专辑艺术家"
|
"ViewAlbumArtist": "查看专辑艺术家",
|
||||||
|
"Preview": "预览",
|
||||||
|
"SubtitleVerticalPositionHelp": "文字出现的行号。正数表示由上到下,负数表示由下到上。",
|
||||||
|
"LabelSubtitleVerticalPosition": "垂直位置:",
|
||||||
|
"PreviousTrack": "上一曲",
|
||||||
|
"MessageGetInstalledPluginsError": "获取已安装插件列表时出现错误。",
|
||||||
|
"MessagePluginInstallError": "安装插件时出现错误。",
|
||||||
|
"NextTrack": "下一曲",
|
||||||
|
"LabelUnstable": "不稳定"
|
||||||
}
|
}
|
||||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -5465,10 +5465,10 @@ hex-color-regex@^1.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
|
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
|
||||||
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
|
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
|
||||||
|
|
||||||
hls.js@^0.14.7:
|
hls.js@^0.14.8:
|
||||||
version "0.14.7"
|
version "0.14.8"
|
||||||
resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-0.14.7.tgz#47fbd2662b13121ab17c07aea06b1c07828240cf"
|
resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-0.14.8.tgz#c2c6ca7005524c81eece316c2a4a199258bd0590"
|
||||||
integrity sha512-9JY0D9nwMrfQPRWc8/kEJTKK0TYfDTzIs6Xq+gdCvasRxdvQKQ2T76rdueTkS0AsFV6sQlJN0wxbnI44aRvvUA==
|
integrity sha512-4fh8k/sl1SmYXsT4Om8AY5fKa5tUUtAxup2sffrSMh5MNk4Kt4FOZxbjqTGL5VwkroY1oJ9twSciNQNFbPA/WQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
eventemitter3 "^4.0.3"
|
eventemitter3 "^4.0.3"
|
||||||
url-toolkit "^2.1.6"
|
url-toolkit "^2.1.6"
|
||||||
|
@ -11994,10 +11994,10 @@ webworkify@^1.5.0:
|
||||||
resolved "https://registry.yarnpkg.com/webworkify/-/webworkify-1.5.0.tgz#734ad87a774de6ebdd546e1d3e027da5b8f4a42c"
|
resolved "https://registry.yarnpkg.com/webworkify/-/webworkify-1.5.0.tgz#734ad87a774de6ebdd546e1d3e027da5b8f4a42c"
|
||||||
integrity sha512-AMcUeyXAhbACL8S2hqqdqOLqvJ8ylmIbNwUIqQujRSouf4+eUFaXbG6F1Rbu+srlJMmxQWsiU7mOJi0nMBfM1g==
|
integrity sha512-AMcUeyXAhbACL8S2hqqdqOLqvJ8ylmIbNwUIqQujRSouf4+eUFaXbG6F1Rbu+srlJMmxQWsiU7mOJi0nMBfM1g==
|
||||||
|
|
||||||
whatwg-fetch@^3.3.1:
|
whatwg-fetch@^3.4.0:
|
||||||
version "3.3.1"
|
version "3.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.3.1.tgz#6c1acf37dec176b0fd6bc9a74b616bec2f612935"
|
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.4.0.tgz#e11de14f4878f773fbebcde8871b2c0699af8b30"
|
||||||
integrity sha512-faXTmGDcLuEPBpJwb5LQfyxvubKiE+RlbmmweFGKjvIPFj4uHTTfdtTIkdTRhC6OSH9S9eyYbx8kZ0UEaQqYTA==
|
integrity sha512-rsum2ulz2iuZH08mJkT0Yi6JnKhwdw4oeyMjokgxd+mmqYSd9cPpOQf01TIWgjxG/U4+QR+AwKq6lSbXVxkyoQ==
|
||||||
|
|
||||||
which-module@^1.0.0:
|
which-module@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue