diff --git a/package.json b/package.json index 1191639a6..c8edcf091 100644 --- a/package.json +++ b/package.json @@ -160,7 +160,11 @@ "src/components/refreshdialog/refreshdialog.js", "src/components/sanatizefilename.js", "src/components/scrollManager.js", + "src/components/slideshow/slideshow.js", + "src/components/sortmenu/sortmenu.js", "src/plugins/htmlVideoPlayer/plugin.js", + "src/plugins/logoScreensaver/plugin.js", + "src/plugins/playAccessValidation/plugin.js", "src/components/search/searchfields.js", "src/components/search/searchresults.js", "src/components/settingshelper.js", @@ -203,13 +207,16 @@ "src/controllers/music/musicplaylists.js", "src/controllers/music/musicrecommended.js", "src/controllers/music/songs.js", - "src/controllers/dashboard/mediaLibrary.js", + "src/controllers/dashboard/library.js", "src/controllers/dashboard/metadataImages.js", "src/controllers/dashboard/metadatanfo.js", "src/controllers/dashboard/networking.js", "src/controllers/dashboard/notifications/notification.js", "src/controllers/dashboard/notifications/notifications.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/scheduledtasks/scheduledtask.js", "src/controllers/dashboard/scheduledtasks/scheduledtasks.js", diff --git a/src/components/slideshow/slideshow.js b/src/components/slideshow/slideshow.js index 29b2452cb..82f541a11 100644 --- a/src/components/slideshow/slideshow.js +++ b/src/components/slideshow/slideshow.js @@ -2,668 +2,672 @@ * Image viewer component * @module components/slideshow/slideshow */ -define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'focusManager', 'browser', 'apphost', 'dom', 'css!./style', 'material-icons', 'paper-icon-button-light'], function (dialogHelper, inputManager, connectionManager, layoutManager, focusManager, browser, appHost, dom) { - 'use strict'; +import dialogHelper from 'dialogHelper'; +import inputManager from 'inputManager'; +import connectionManager from 'connectionManager'; +import layoutManager from 'layoutManager'; +import focusManager from 'focusManager'; +import browser from 'browser'; +import appHost from 'apphost'; +import dom from 'dom'; +import 'css!./style'; +import 'material-icons'; +import 'paper-icon-button-light'; - browser = browser.default || browser; - layoutManager = layoutManager.default || layoutManager; - focusManager = focusManager.default || focusManager; +/** + * Name of transition event. + */ +const transitionEndEventName = dom.whichTransitionEvent(); - /** - * Name of transition event. - */ - const transitionEndEventName = dom.whichTransitionEvent(); +/** + * Flag to use fake image to fix blurry zoomed image. + * At least WebKit doesn't restore quality for zoomed images. + */ +const useFakeZoomImage = browser.safari; - /** - * Flag to use fake image to fix blurry zoomed image. - * At least WebKit doesn't restore quality for zoomed images. - */ - const useFakeZoomImage = browser.safari; +/** + * Retrieves an item's image URL from the API. + * @param {object|string} item - Item used to generate the image URL. + * @param {object} options - Options of the image. + * @param {object} apiClient - API client instance used to retrieve the image. + * @returns {null|string} URL of the item's image. + */ +function getImageUrl(item, options, apiClient) { + options = options || {}; + options.type = options.type || 'Primary'; - /** - * Retrieves an item's image URL from the API. - * @param {object|string} item - Item used to generate the image URL. - * @param {object} options - Options of the image. - * @param {object} apiClient - API client instance used to retrieve the image. - * @returns {null|string} URL of the item's image. - */ - function getImageUrl(item, options, apiClient) { - options = options || {}; - options.type = options.type || 'Primary'; + if (typeof (item) === 'string') { + return apiClient.getScaledImageUrl(item, options); + } - if (typeof (item) === 'string') { - return apiClient.getScaledImageUrl(item, options); + if (item.ImageTags && item.ImageTags[options.type]) { + options.tag = item.ImageTags[options.type]; + return apiClient.getScaledImageUrl(item.Id, options); + } + + if (options.type === 'Primary') { + if (item.AlbumId && item.AlbumPrimaryImageTag) { + options.tag = item.AlbumPrimaryImageTag; + return apiClient.getScaledImageUrl(item.AlbumId, options); } + } - if (item.ImageTags && item.ImageTags[options.type]) { - options.tag = item.ImageTags[options.type]; - return apiClient.getScaledImageUrl(item.Id, options); + return null; +} + +/** + * Retrieves a backdrop's image URL from the API. + * @param {object} item - Item used to generate the image URL. + * @param {object} options - Options of the image. + * @param {object} apiClient - API client instance used to retrieve the image. + * @returns {null|string} URL of the item's backdrop. + */ +function getBackdropImageUrl(item, options, apiClient) { + options = options || {}; + options.type = options.type || 'Backdrop'; + + // If not resizing, get the original image + if (!options.maxWidth && !options.width && !options.maxHeight && !options.height) { + options.quality = 100; + } + + if (item.BackdropImageTags && item.BackdropImageTags.length) { + options.tag = item.BackdropImageTags[0]; + return apiClient.getScaledImageUrl(item.Id, options); + } + + return null; +} + +/** + * Dispatches a request for an item's image to its respective handler. + * @param {object} item - Item used to generate the image URL. + * @returns {string} URL of the item's image. + */ +function getImgUrl(item, user) { + const apiClient = connectionManager.getApiClient(item.ServerId); + const imageOptions = {}; + + if (item.BackdropImageTags && item.BackdropImageTags.length) { + return getBackdropImageUrl(item, imageOptions, apiClient); + } else { + if (item.MediaType === 'Photo' && user && user.Policy.EnableContentDownloading) { + return apiClient.getItemDownloadUrl(item.Id); } + imageOptions.type = 'Primary'; + return getImageUrl(item, imageOptions, apiClient); + } +} - if (options.type === 'Primary') { - if (item.AlbumId && item.AlbumPrimaryImageTag) { - options.tag = item.AlbumPrimaryImageTag; - return apiClient.getScaledImageUrl(item.AlbumId, options); +/** + * Generates a button using the specified icon, classes and properties. + * @param {string} icon - Name of the material icon on the button + * @param {string} cssClass - CSS classes to assign to the button + * @param {boolean} canFocus - Flag to set the tabindex attribute on the button to -1. + * @param {boolean} autoFocus - Flag to set the autofocus attribute on the button. + * @returns {string} The HTML markup of the button. + */ +function getIcon(icon, cssClass, canFocus, autoFocus) { + const tabIndex = canFocus ? '' : ' tabindex="-1"'; + autoFocus = autoFocus ? ' autofocus' : ''; + return ''; +} + +/** + * Sets the viewport meta tag to enable or disable scaling by the user. + * @param {boolean} scalable - Flag to set the scalability of the viewport. + */ +function setUserScalable(scalable) { + try { + appHost.setUserScalable(scalable); + } catch (err) { + console.error('error in appHost.setUserScalable: ' + err); + } +} + +export default function (options) { + const self = this; + /** Initialized instance of Swiper. */ + let swiperInstance; + /** Initialized instance of the dialog containing the Swiper instance. */ + let dialog; + /** Options of the slideshow components */ + let currentOptions; + /** ID of the timeout used to hide the OSD. */ + let hideTimeout; + /** Last coordinates of the mouse pointer. */ + let lastMouseMoveData; + + /** + * Creates the HTML markup for the dialog and the OSD. + * @param {Object} options - Options used to create the dialog and slideshow. + */ + function createElements(options) { + currentOptions = options; + + dialog = dialogHelper.createDialog({ + exitAnimationDuration: options.interactive ? 400 : 800, + size: 'fullscreen', + autoFocus: false, + scrollY: false, + exitAnimation: 'fadeout', + removeOnClose: true + }); + + dialog.classList.add('slideshowDialog'); + + let html = ''; + + html += '
'; + + if (options.interactive && !layoutManager.tv) { + const actionButtonsOnTop = layoutManager.mobile; + + html += getIcon('keyboard_arrow_left', 'btnSlideshowPrevious slideshowButton hide-mouse-idle-tv', false); + html += getIcon('keyboard_arrow_right', 'btnSlideshowNext slideshowButton hide-mouse-idle-tv', false); + + html += ''; - html += globalize.translate('MessageBrowsePluginCatalog'); - html += '
'; - html += ''; + html += globalize.translate('MessageBrowsePluginCatalog'); + html += '
'; + html += '
';
}
- }
- 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 = '
';
- }
-
- stopInterval();
- interval = setInterval(animate, 3000);
- });
- };
-
- self.hide = function () {
stopInterval();
-
- 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();
- }
- }
- };
+ interval = setInterval(animate, 3000);
+ });
};
-});
+
+ 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();
+ }
+ }
+ };
+}
diff --git a/src/plugins/playAccessValidation/plugin.js b/src/plugins/playAccessValidation/plugin.js
index 5148d2b82..a9fbeda9a 100644
--- a/src/plugins/playAccessValidation/plugin.js
+++ b/src/plugins/playAccessValidation/plugin.js
@@ -1,33 +1,26 @@
-define(['connectionManager', 'globalize'], function (connectionManager, globalize) {
- 'use strict';
+import connectionManager from 'connectionManager';
+import globalize from 'globalize';
- function getRequirePromise(deps) {
- return new Promise(function (resolve, reject) {
- require(deps, resolve);
- });
- }
+function showErrorMessage() {
+ return import('alert').then(({default: alert}) => {
+ return alert(globalize.translate('MessagePlayAccessRestricted'));
+ });
+}
- function showErrorMessage() {
- return getRequirePromise(['alert']).then(function (alert) {
- return alert(globalize.translate('MessagePlayAccessRestricted')).then(function () {
- return Promise.reject();
- });
- });
- }
-
- function PlayAccessValidation() {
+class PlayAccessValidation {
+ constructor() {
this.name = 'Playback validation';
this.type = 'preplayintercept';
this.id = 'playaccessvalidation';
this.order = -2;
}
- PlayAccessValidation.prototype.intercept = function (options) {
- var item = options.item;
+ intercept(options) {
+ const item = options.item;
if (!item) {
return Promise.resolve();
}
- var serverId = item.ServerId;
+ const serverId = item.ServerId;
if (!serverId) {
return Promise.resolve();
}
@@ -44,7 +37,7 @@ define(['connectionManager', 'globalize'], function (connectionManager, globaliz
return showErrorMessage();
});
- };
+ }
+}
- return PlayAccessValidation;
-});
+export default PlayAccessValidation;
diff --git a/src/scripts/routes.js b/src/scripts/routes.js
index 4094a2552..4bb3eb25d 100644
--- a/src/scripts/routes.js
+++ b/src/scripts/routes.js
@@ -112,54 +112,69 @@ import 'detailtablecss';
});
defineRoute({
- path: '/dashboard.html',
+ alias: '/dashboard.html',
+ path: '/controllers/dashboard/dashboard.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/dashboard'
});
defineRoute({
- path: '/dashboardgeneral.html',
+ alias: '/dashboardgeneral.html',
+ path: '/controllers/dashboard/general.html',
controller: 'dashboard/general',
autoFocus: false,
roles: 'admin'
});
defineRoute({
- path: '/networking.html',
+ alias: '/networking.html',
+ path: '/controllers/dashboard/networking.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/networking'
});
defineRoute({
- path: '/devices.html',
+ alias: '/devices.html',
+ path: '/controllers/dashboard/devices/devices.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/devices/devices'
});
defineRoute({
- path: '/device.html',
+ alias: '/device.html',
+ path: '/controllers/dashboard/devices/device.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/devices/device'
});
defineRoute({
- path: '/dlnaprofile.html',
+ alias: '/dlnaprofile.html',
+ path: '/controllers/dashboard/dlna/profile.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/dlna/profile'
});
defineRoute({
- path: '/dlnaprofiles.html',
+ alias: '/dlnaprofiles.html',
+ path: '/controllers/dashboard/dlna/profiles.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/dlna/profiles'
});
+ defineRoute({
+ alias: '/dlnasettings.html',
+ path: '/controllers/dashboard/dlna/settings.html',
+ autoFocus: false,
+ roles: 'admin',
+ controller: 'dashboard/dlna/settings'
+ });
+
defineRoute({
alias: '/addplugin.html',
path: '/controllers/dashboard/plugins/add/index.html',
@@ -169,54 +184,54 @@ import 'detailtablecss';
});
defineRoute({
- path: '/library.html',
+ alias: '/library.html',
+ path: '/controllers/dashboard/library.html',
autoFocus: false,
roles: 'admin',
- controller: 'dashboard/mediaLibrary'
+ controller: 'dashboard/library'
});
defineRoute({
- path: '/librarydisplay.html',
+ alias: '/librarydisplay.html',
+ path: '/controllers/dashboard/librarydisplay.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/librarydisplay'
});
defineRoute({
- path: '/dlnasettings.html',
- autoFocus: false,
- roles: 'admin',
- controller: 'dashboard/dlna/settings'
- });
-
- defineRoute({
- path: '/edititemmetadata.html',
+ alias: '/edititemmetadata.html',
+ path: '/controllers/edititemmetadata.html',
controller: 'edititemmetadata',
autoFocus: false
});
defineRoute({
- path: '/encodingsettings.html',
+ alias: '/encodingsettings.html',
+ path: '/controllers/dashboard/encodingsettings.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/encodingsettings'
});
defineRoute({
- path: '/log.html',
+ alias: '/log.html',
+ path: '/controllers/dashboard/logs.html',
roles: 'admin',
controller: 'dashboard/logs'
});
defineRoute({
- path: '/metadataimages.html',
+ alias: '/metadataimages.html',
+ path: '/controllers/dashboard/metadataimages.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/metadataImages'
});
defineRoute({
- path: '/metadatanfo.html',
+ alias: '/metadatanfo.html',
+ path: '/controllers/dashboard/metadatanfo.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/metadatanfo'
@@ -239,7 +254,8 @@ import 'detailtablecss';
});
defineRoute({
- path: '/playbackconfiguration.html',
+ alias: '/playbackconfiguration.html',
+ path: '/controllers/dashboard/playback.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/playback'
@@ -262,19 +278,22 @@ import 'detailtablecss';
});
defineRoute({
- path: '/home.html',
+ alias: '/home.html',
+ path: '/controllers/home.html',
autoFocus: false,
controller: 'home',
type: 'home'
});
defineRoute({
- path: '/search.html',
+ alias: '/search.html',
+ path: '/controllers/search.html',
controller: 'searchpage'
});
defineRoute({
- path: '/list.html',
+ alias: '/list.html',
+ path: '/controllers/list.html',
autoFocus: false,
controller: 'list'
});
@@ -287,46 +306,53 @@ import 'detailtablecss';
});
defineRoute({
- path: '/livetv.html',
+ alias: '/livetv.html',
+ path: '/controllers/livetv.html',
controller: 'livetv/livetvsuggested',
autoFocus: false
});
defineRoute({
- path: '/livetvguideprovider.html',
+ alias: '/livetvguideprovider.html',
+ path: '/controllers/livetvguideprovider.html',
autoFocus: false,
roles: 'admin',
controller: 'livetvguideprovider'
});
defineRoute({
- path: '/livetvsettings.html',
+ alias: '/livetvsettings.html',
+ path: '/controllers/livetvsettings.html',
autoFocus: false,
controller: 'livetvsettings'
});
defineRoute({
- path: '/livetvstatus.html',
+ alias: '/livetvstatus.html',
+ path: '/controllers/livetvstatus.html',
autoFocus: false,
roles: 'admin',
controller: 'livetvstatus'
});
defineRoute({
- path: '/livetvtuner.html',
+ alias: '/livetvtuner.html',
+ path: '/controllers/livetvtuner.html',
autoFocus: false,
roles: 'admin',
controller: 'livetvtuner'
});
defineRoute({
- path: '/movies.html',
+ alias: '/movies.html',
+ path: '/controllers/movies/movies.html',
autoFocus: false,
controller: 'movies/moviesrecommended'
});
defineRoute({
- path: '/music.html',
+ alias: '/music.html',
+ path: '/controllers/music/music.html',
controller: 'music/musicrecommended',
autoFocus: false
});
@@ -340,82 +366,94 @@ import 'detailtablecss';
});
defineRoute({
- path: '/scheduledtask.html',
+ alias: '/scheduledtask.html',
+ path: '/controllers/dashboard/scheduledtasks/scheduledtask.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/scheduledtasks/scheduledtask'
});
defineRoute({
- path: '/scheduledtasks.html',
+ alias: '/scheduledtasks.html',
+ path: '/controllers/dashboard/scheduledtasks/scheduledtasks.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/scheduledtasks/scheduledtasks'
});
defineRoute({
- path: '/serveractivity.html',
+ alias: '/serveractivity.html',
+ path: '/controllers/dashboard/serveractivity.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/serveractivity'
});
defineRoute({
- path: '/apikeys.html',
+ alias: '/apikeys.html',
+ path: '/controllers/dashboard/apikeys.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/apikeys'
});
defineRoute({
- path: '/streamingsettings.html',
+ alias: '/streamingsettings.html',
+ path: '/controllers/dashboard/streaming.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/streaming'
});
defineRoute({
- path: '/tv.html',
+ alias: '/tv.html',
+ path: '/controllers/shows/tvrecommended.html',
autoFocus: false,
controller: 'shows/tvrecommended'
});
defineRoute({
- path: '/useredit.html',
+ alias: '/useredit.html',
+ path: '/controllers/dashboard/users/useredit.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/users/useredit'
});
defineRoute({
- path: '/userlibraryaccess.html',
+ alias: '/userlibraryaccess.html',
+ path: '/controllers/dashboard/users/userlibraryaccess.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/users/userlibraryaccess'
});
defineRoute({
- path: '/usernew.html',
+ alias: '/usernew.html',
+ path: '/controllers/dashboard/users/usernew.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/users/usernew'
});
defineRoute({
- path: '/userparentalcontrol.html',
+ alias: '/userparentalcontrol.html',
+ path: '/controllers/dashboard/users/userparentalcontrol.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/users/userparentalcontrol'
});
defineRoute({
- path: '/userpassword.html',
+ alias: '/userpassword.html',
+ path: '/controllers/dashboard/users/userpassword.html',
autoFocus: false,
controller: 'dashboard/users/userpasswordpage'
});
defineRoute({
- path: '/userprofiles.html',
+ alias: '/userprofiles.html',
+ path: '/controllers/dashboard/users/userprofiles.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/users/userprofilespage'
@@ -438,10 +476,11 @@ import 'detailtablecss';
});
defineRoute({
- path: '/wizardlibrary.html',
+ alias: '/wizardlibrary.html',
+ path: '/controllers/wizard/library.html',
autoFocus: false,
anonymous: true,
- controller: 'dashboard/mediaLibrary'
+ controller: 'dashboard/library'
});
defineRoute({
diff --git a/src/strings/de.json b/src/strings/de.json
index 0aa4d2172..b167c3170 100644
--- a/src/strings/de.json
+++ b/src/strings/de.json
@@ -1545,5 +1545,7 @@
"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:"
+ "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."
}
diff --git a/src/strings/en-us.json b/src/strings/en-us.json
index 4dffc4961..638be2efa 100644
--- a/src/strings/en-us.json
+++ b/src/strings/en-us.json
@@ -1282,6 +1282,8 @@
"PleaseRestartServerName": "Please restart Jellyfin Server - {0}.",
"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.",
+ "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",
"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.",