mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge remote-tracking branch 'origin/master' into standalone
Conflicts: package.json src/components/appRouter.js src/components/require/requiretext.js src/config.json src/scripts/clientUtils.js src/scripts/settings/webSettings.js src/scripts/site.js
This commit is contained in:
commit
5592cb7d4e
310 changed files with 7707 additions and 6701 deletions
|
@ -1,5 +1,5 @@
|
|||
import dom from 'dom';
|
||||
import focusManager from 'focusManager';
|
||||
import dom from './dom';
|
||||
import focusManager from '../components/focusManager';
|
||||
|
||||
let inputDisplayElement;
|
||||
let currentDisplayText = '';
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import backdrop from 'backdrop';
|
||||
import * as userSettings from 'userSettings';
|
||||
import libraryMenu from 'libraryMenu';
|
||||
import backdrop from '../components/backdrop/backdrop';
|
||||
import * as userSettings from './settings/userSettings';
|
||||
import libraryMenu from './libraryMenu';
|
||||
import { pageClassOn } from './clientUtils';
|
||||
|
||||
const cache = {};
|
||||
|
||||
|
|
|
@ -1,22 +1,13 @@
|
|||
import * as userSettings from 'userSettings';
|
||||
import * as webSettings from 'webSettings';
|
||||
import skinManager from 'skinManager';
|
||||
import events from 'events';
|
||||
import * as userSettings from './settings/userSettings';
|
||||
import * as webSettings from './settings/webSettings';
|
||||
import skinManager from './themeManager';
|
||||
import { Events } from 'jellyfin-apiclient';
|
||||
import ServerConnections from '../components/ServerConnections';
|
||||
|
||||
// set the default theme when loading
|
||||
// Set the default theme when loading
|
||||
skinManager.setTheme(userSettings.theme());
|
||||
|
||||
// set the saved theme once a user authenticates
|
||||
events.on(window.connectionManager, 'localusersignedin', function (e, user) {
|
||||
Events.on(ServerConnections, 'localusersignedin', function (e, user) {
|
||||
skinManager.setTheme(userSettings.theme());
|
||||
});
|
||||
|
||||
webSettings.getFonts().then(fonts => {
|
||||
for (const font of fonts) {
|
||||
const link = document.createElement('link');
|
||||
link.setAttribute('rel', 'stylesheet');
|
||||
link.href = font;
|
||||
|
||||
document.getElementsByTagName('head')[0].appendChild(link);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import events from 'events';
|
||||
import playbackManager from 'playbackManager';
|
||||
import { Events } from 'jellyfin-apiclient';
|
||||
import { playbackManager } from '../components/playback/playbackmanager';
|
||||
import ServerConnections from '../components/ServerConnections';
|
||||
|
||||
export function supported() {
|
||||
return typeof(Storage) !== 'undefined';
|
||||
|
@ -41,7 +42,8 @@ function onOpen() {
|
|||
});
|
||||
}
|
||||
|
||||
const apiClient = window.connectionManager.currentApiClient();
|
||||
const apiClient = ServerConnections.currentApiClient();
|
||||
|
||||
if (apiClient && supported()) {
|
||||
events.on(apiClient, 'websocketopen', onOpen);
|
||||
Events.on(apiClient, 'websocketopen', onOpen);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
define(['browser'], function (browser) {
|
||||
'use strict';
|
||||
|
||||
browser = browser.default || browser;
|
||||
import appSettings from './settings/appSettings';
|
||||
import * as userSettings from './settings/userSettings';
|
||||
import browser from './browser';
|
||||
/* eslint-disable indent */
|
||||
|
||||
function canPlayH264(videoTestElement) {
|
||||
return !!(videoTestElement.canPlayType && videoTestElement.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, ''));
|
||||
}
|
||||
|
||||
function canPlayH265(videoTestElement, options) {
|
||||
function canPlayHevc(videoTestElement, options) {
|
||||
if (browser.tizen || browser.xboxOne || browser.web0s || options.supportsHevc) {
|
||||
return true;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ define(['browser'], function (browser) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// hevc main level 4.0
|
||||
return !!videoTestElement.canPlayType &&
|
||||
(videoTestElement.canPlayType('video/mp4; codecs="hvc1.1.L120"').replace(/no/, '') ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="hev1.1.L120"').replace(/no/, '') ||
|
||||
|
@ -207,8 +208,7 @@ define(['browser'], function (browser) {
|
|||
// Explicitly add supported codecs to make other codecs be transcoded
|
||||
if (browser.tizenVersion >= 4) {
|
||||
videoCodecs.push('h264');
|
||||
if (canPlayH265(videoTestElement, options)) {
|
||||
videoCodecs.push('h265');
|
||||
if (canPlayHevc(videoTestElement, options)) {
|
||||
videoCodecs.push('hevc');
|
||||
}
|
||||
}
|
||||
|
@ -248,8 +248,8 @@ define(['browser'], function (browser) {
|
|||
case 'ts':
|
||||
supported = testCanPlayTs();
|
||||
videoCodecs.push('h264');
|
||||
if (canPlayH265(videoTestElement, options)) {
|
||||
videoCodecs.push('h265');
|
||||
// safari doesn't support hevc in TS-HLS
|
||||
if ((browser.tizen || browser.web0s) && canPlayHevc(videoTestElement, options)) {
|
||||
videoCodecs.push('hevc');
|
||||
}
|
||||
if (supportsVc1(videoTestElement)) {
|
||||
|
@ -294,10 +294,12 @@ define(['browser'], function (browser) {
|
|||
(browser.tizen && isTizenFhd ? 20000000 : null)));
|
||||
}
|
||||
|
||||
return function (options) {
|
||||
export default function (options) {
|
||||
options = options || {};
|
||||
|
||||
const physicalAudioChannels = options.audioChannels || (browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2);
|
||||
const isSurroundSoundSupportedBrowser = browser.safari || browser.chrome || browser.edgeChromium || browser.firefox;
|
||||
const allowedAudioChannels = parseInt(userSettings.allowedAudioChannels() || '-1');
|
||||
const physicalAudioChannels = (allowedAudioChannels > 0 ? allowedAudioChannels : null) || options.audioChannels || (isSurroundSoundSupportedBrowser || browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2);
|
||||
|
||||
const bitrateSetting = getMaxBitrate();
|
||||
|
||||
|
@ -313,12 +315,13 @@ define(['browser'], function (browser) {
|
|||
|
||||
profile.MaxStreamingBitrate = bitrateSetting;
|
||||
profile.MaxStaticBitrate = 100000000;
|
||||
profile.MusicStreamingTranscodingBitrate = Math.min(bitrateSetting, 192000);
|
||||
profile.MusicStreamingTranscodingBitrate = Math.min(bitrateSetting, 384000);
|
||||
|
||||
profile.DirectPlayProfiles = [];
|
||||
|
||||
let videoAudioCodecs = [];
|
||||
let hlsVideoAudioCodecs = [];
|
||||
let hlsInTsVideoAudioCodecs = [];
|
||||
let hlsInFmp4VideoAudioCodecs = [];
|
||||
|
||||
const supportsMp3VideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"').replace(/no/, '')
|
||||
|| videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"').replace(/no/, '')
|
||||
|
@ -338,54 +341,66 @@ define(['browser'], function (browser) {
|
|||
}
|
||||
|
||||
const canPlayAacVideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"').replace(/no/, '');
|
||||
const canPlayAc3VideoAudio = supportsAc3(videoTestElement);
|
||||
const canPlayEac3VideoAudio = supportsEac3(videoTestElement);
|
||||
const canPlayAc3VideoAudioInHls = supportsAc3InHls(videoTestElement);
|
||||
|
||||
// Only put mp3 first if mkv support is there
|
||||
// Otherwise with HLS and mp3 audio we're seeing some browsers
|
||||
// safari is lying
|
||||
if (supportsAc3(videoTestElement)) {
|
||||
if (canPlayAc3VideoAudio) {
|
||||
videoAudioCodecs.push('ac3');
|
||||
|
||||
const eAc3 = supportsEac3(videoTestElement);
|
||||
if (eAc3) {
|
||||
if (canPlayEac3VideoAudio) {
|
||||
videoAudioCodecs.push('eac3');
|
||||
}
|
||||
|
||||
// This works in edge desktop, but not mobile
|
||||
// TODO: Retest this on mobile
|
||||
if (supportsAc3InHls(videoTestElement)) {
|
||||
hlsVideoAudioCodecs.push('ac3');
|
||||
if (eAc3) {
|
||||
hlsVideoAudioCodecs.push('eac3');
|
||||
// Transcoding codec is the first in hlsVideoAudioCodecs
|
||||
// Put ac3/eac3 first only when the audio channels > 2 and need transcoding
|
||||
if (canPlayAc3VideoAudioInHls && physicalAudioChannels > 2) {
|
||||
hlsInTsVideoAudioCodecs.push('ac3');
|
||||
hlsInFmp4VideoAudioCodecs.push('ac3');
|
||||
if (canPlayEac3VideoAudio) {
|
||||
hlsInTsVideoAudioCodecs.push('eac3');
|
||||
hlsInFmp4VideoAudioCodecs.push('eac3');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (canPlayAacVideoAudio) {
|
||||
videoAudioCodecs.push('aac');
|
||||
hlsInTsVideoAudioCodecs.push('aac');
|
||||
hlsInFmp4VideoAudioCodecs.push('aac');
|
||||
}
|
||||
|
||||
if (supportsMp3VideoAudio) {
|
||||
videoAudioCodecs.push('mp3');
|
||||
|
||||
// PS4 fails to load HLS with mp3 audio
|
||||
if (!browser.ps4) {
|
||||
// mp3 encoder only supports 2 channels, so only make that preferred if we're only requesting 2 channels
|
||||
// Also apply it for chromecast because it no longer supports AAC 5.1
|
||||
if (physicalAudioChannels <= 2) {
|
||||
hlsVideoAudioCodecs.push('mp3');
|
||||
hlsInTsVideoAudioCodecs.push('mp3');
|
||||
}
|
||||
|
||||
hlsInFmp4VideoAudioCodecs.push('mp3');
|
||||
}
|
||||
|
||||
// For ac3/eac3 directstream
|
||||
if (canPlayAc3VideoAudio) {
|
||||
if (canPlayAc3VideoAudioInHls) {
|
||||
if (hlsInTsVideoAudioCodecs.indexOf('ac3') === -1) {
|
||||
hlsInTsVideoAudioCodecs.push('ac3');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (canPlayAacVideoAudio) {
|
||||
if (videoAudioCodecs.indexOf('aac') === -1) {
|
||||
videoAudioCodecs.push('aac');
|
||||
}
|
||||
if (hlsInFmp4VideoAudioCodecs.indexOf('ac3') === -1) {
|
||||
hlsInFmp4VideoAudioCodecs.push('ac3');
|
||||
}
|
||||
|
||||
hlsVideoAudioCodecs.push('aac');
|
||||
}
|
||||
if (canPlayEac3VideoAudio) {
|
||||
if (hlsInTsVideoAudioCodecs.indexOf('eac3') === -1) {
|
||||
hlsInTsVideoAudioCodecs.push('eac3');
|
||||
}
|
||||
|
||||
if (supportsMp3VideoAudio) {
|
||||
// PS4 fails to load HLS with mp3 audio
|
||||
if (!browser.ps4) {
|
||||
if (hlsVideoAudioCodecs.indexOf('mp3') === -1) {
|
||||
hlsVideoAudioCodecs.push('mp3');
|
||||
if (hlsInFmp4VideoAudioCodecs.indexOf('eac3') === -1) {
|
||||
hlsInFmp4VideoAudioCodecs.push('eac3');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -421,38 +436,54 @@ define(['browser'], function (browser) {
|
|||
|
||||
if (canPlayAudioFormat('opus')) {
|
||||
videoAudioCodecs.push('opus');
|
||||
hlsVideoAudioCodecs.push('opus');
|
||||
hlsInTsVideoAudioCodecs.push('opus');
|
||||
webmAudioCodecs.push('opus');
|
||||
}
|
||||
|
||||
if (canPlayAudioFormat('flac')) {
|
||||
videoAudioCodecs.push('flac');
|
||||
hlsInFmp4VideoAudioCodecs.push('flac');
|
||||
}
|
||||
|
||||
if (canPlayAudioFormat('alac')) {
|
||||
videoAudioCodecs.push('alac');
|
||||
hlsInFmp4VideoAudioCodecs.push('alac');
|
||||
}
|
||||
|
||||
videoAudioCodecs = videoAudioCodecs.filter(function (c) {
|
||||
return (options.disableVideoAudioCodecs || []).indexOf(c) === -1;
|
||||
});
|
||||
|
||||
hlsVideoAudioCodecs = hlsVideoAudioCodecs.filter(function (c) {
|
||||
hlsInTsVideoAudioCodecs = hlsInTsVideoAudioCodecs.filter(function (c) {
|
||||
return (options.disableHlsVideoAudioCodecs || []).indexOf(c) === -1;
|
||||
});
|
||||
|
||||
hlsInFmp4VideoAudioCodecs = hlsInFmp4VideoAudioCodecs.filter(function (c) {
|
||||
return (options.disableHlsVideoAudioCodecs || []).indexOf(c) === -1;
|
||||
});
|
||||
|
||||
const mp4VideoCodecs = [];
|
||||
const webmVideoCodecs = [];
|
||||
const hlsVideoCodecs = [];
|
||||
const hlsInTsVideoCodecs = [];
|
||||
const hlsInFmp4VideoCodecs = [];
|
||||
|
||||
if ((browser.safari || browser.tizen || browser.web0s) && canPlayHevc(videoTestElement, options)) {
|
||||
hlsInFmp4VideoCodecs.push('hevc');
|
||||
}
|
||||
|
||||
if (canPlayH264(videoTestElement)) {
|
||||
mp4VideoCodecs.push('h264');
|
||||
hlsVideoCodecs.push('h264');
|
||||
hlsInTsVideoCodecs.push('h264');
|
||||
|
||||
if (browser.safari || browser.tizen || browser.web0s) {
|
||||
hlsInFmp4VideoCodecs.push('h264');
|
||||
}
|
||||
}
|
||||
|
||||
if (canPlayH265(videoTestElement, options)) {
|
||||
mp4VideoCodecs.push('h265');
|
||||
mp4VideoCodecs.push('hevc');
|
||||
|
||||
if (browser.tizen || browser.web0s) {
|
||||
hlsVideoCodecs.push('h265');
|
||||
hlsVideoCodecs.push('hevc');
|
||||
if (canPlayHevc(videoTestElement, options)) {
|
||||
// safari is lying on HDR and 60fps videos, use fMP4 instead
|
||||
if (!browser.safari) {
|
||||
mp4VideoCodecs.push('hevc');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -524,21 +555,14 @@ define(['browser'], function (browser) {
|
|||
});
|
||||
|
||||
['opus', 'mp3', 'mp2', 'aac', 'flac', 'alac', 'webma', 'wma', 'wav', 'ogg', 'oga'].filter(canPlayAudioFormat).forEach(function (audioFormat) {
|
||||
if (audioFormat === 'mp2') {
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: audioFormat,
|
||||
Type: 'Audio'
|
||||
});
|
||||
|
||||
if (audioFormat === 'webma') {
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: 'mp2,mp3',
|
||||
Type: 'Audio',
|
||||
AudioCodec: audioFormat
|
||||
});
|
||||
} else if (audioFormat === 'mp3') {
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: audioFormat,
|
||||
Type: 'Audio',
|
||||
AudioCodec: audioFormat
|
||||
});
|
||||
} else {
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: audioFormat === 'webma' ? 'webma,webm' : audioFormat,
|
||||
Container: 'webm',
|
||||
Type: 'Audio'
|
||||
});
|
||||
}
|
||||
|
@ -547,7 +571,6 @@ define(['browser'], function (browser) {
|
|||
if (audioFormat === 'aac' || audioFormat === 'alac') {
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: 'm4a,m4b',
|
||||
AudioCodec: audioFormat,
|
||||
Type: 'Audio'
|
||||
});
|
||||
}
|
||||
|
@ -620,18 +643,34 @@ define(['browser'], function (browser) {
|
|||
});
|
||||
}
|
||||
|
||||
if (canPlayHls() && hlsVideoAudioCodecs.length && options.enableHls !== false) {
|
||||
profile.TranscodingProfiles.push({
|
||||
Container: 'ts',
|
||||
Type: 'Video',
|
||||
AudioCodec: hlsVideoAudioCodecs.join(','),
|
||||
VideoCodec: hlsVideoCodecs.join(','),
|
||||
Context: 'Streaming',
|
||||
Protocol: 'hls',
|
||||
MaxAudioChannels: physicalAudioChannels.toString(),
|
||||
MinSegments: browser.iOS || browser.osx ? '2' : '1',
|
||||
BreakOnNonKeyFrames: hlsBreakOnNonKeyFrames
|
||||
});
|
||||
if (canPlayHls() && options.enableHls !== false) {
|
||||
if (hlsInFmp4VideoCodecs.length && hlsInFmp4VideoAudioCodecs.length && userSettings.preferFmp4HlsContainer() && (browser.safari || browser.tizen || browser.web0s)) {
|
||||
profile.TranscodingProfiles.push({
|
||||
Container: 'mp4',
|
||||
Type: 'Video',
|
||||
AudioCodec: hlsInFmp4VideoAudioCodecs.join(','),
|
||||
VideoCodec: hlsInFmp4VideoCodecs.join(','),
|
||||
Context: 'Streaming',
|
||||
Protocol: 'hls',
|
||||
MaxAudioChannels: physicalAudioChannels.toString(),
|
||||
MinSegments: browser.iOS || browser.osx ? '2' : '1',
|
||||
BreakOnNonKeyFrames: hlsBreakOnNonKeyFrames
|
||||
});
|
||||
}
|
||||
|
||||
if (hlsInTsVideoCodecs.length && hlsInTsVideoAudioCodecs.length) {
|
||||
profile.TranscodingProfiles.push({
|
||||
Container: 'ts',
|
||||
Type: 'Video',
|
||||
AudioCodec: hlsInTsVideoAudioCodecs.join(','),
|
||||
VideoCodec: hlsInTsVideoCodecs.join(','),
|
||||
Context: 'Streaming',
|
||||
Protocol: 'hls',
|
||||
MaxAudioChannels: physicalAudioChannels.toString(),
|
||||
MinSegments: browser.iOS || browser.osx ? '2' : '1',
|
||||
BreakOnNonKeyFrames: hlsBreakOnNonKeyFrames
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (canPlayVp8) {
|
||||
|
@ -727,6 +766,36 @@ define(['browser'], function (browser) {
|
|||
}
|
||||
}
|
||||
|
||||
let maxHevcLevel = 120;
|
||||
let hevcProfiles = 'main';
|
||||
|
||||
// hevc main level 4.1
|
||||
if (videoTestElement.canPlayType('video/mp4; codecs="hvc1.1.4.L123"').replace(/no/, '') ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="hev1.1.4.L123"').replace(/no/, '')) {
|
||||
maxHevcLevel = 123;
|
||||
}
|
||||
|
||||
// hevc main10 level 4.1
|
||||
if (videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L123"').replace(/no/, '') ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="hev1.2.4.L123"').replace(/no/, '')) {
|
||||
maxHevcLevel = 123;
|
||||
hevcProfiles = 'main|main 10';
|
||||
}
|
||||
|
||||
// hevc main10 level 5.1
|
||||
if (videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L153"').replace(/no/, '') ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="hev1.2.4.L153"').replace(/no/, '')) {
|
||||
maxHevcLevel = 153;
|
||||
hevcProfiles = 'main|main 10';
|
||||
}
|
||||
|
||||
// hevc main10 level 6.1
|
||||
if (videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L183"').replace(/no/, '') ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="hev1.2.4.L183"').replace(/no/, '')) {
|
||||
maxHevcLevel = 183;
|
||||
hevcProfiles = 'main|main 10';
|
||||
}
|
||||
|
||||
const h264CodecProfileConditions = [
|
||||
{
|
||||
Condition: 'NotEquals',
|
||||
|
@ -748,6 +817,27 @@ define(['browser'], function (browser) {
|
|||
}
|
||||
];
|
||||
|
||||
const hevcCodecProfileConditions = [
|
||||
{
|
||||
Condition: 'NotEquals',
|
||||
Property: 'IsAnamorphic',
|
||||
Value: 'true',
|
||||
IsRequired: false
|
||||
},
|
||||
{
|
||||
Condition: 'EqualsAny',
|
||||
Property: 'VideoProfile',
|
||||
Value: hevcProfiles,
|
||||
IsRequired: false
|
||||
},
|
||||
{
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'VideoLevel',
|
||||
Value: maxHevcLevel.toString(),
|
||||
IsRequired: false
|
||||
}
|
||||
];
|
||||
|
||||
if (!browser.edgeUwp && !browser.tizen && !browser.web0s) {
|
||||
h264CodecProfileConditions.push({
|
||||
Condition: 'NotEquals',
|
||||
|
@ -755,6 +845,13 @@ define(['browser'], function (browser) {
|
|||
Value: 'true',
|
||||
IsRequired: false
|
||||
});
|
||||
|
||||
hevcCodecProfileConditions.push({
|
||||
Condition: 'NotEquals',
|
||||
Property: 'IsInterlaced',
|
||||
Value: 'true',
|
||||
IsRequired: false
|
||||
});
|
||||
}
|
||||
|
||||
if (maxVideoWidth) {
|
||||
|
@ -764,12 +861,21 @@ define(['browser'], function (browser) {
|
|||
Value: maxVideoWidth.toString(),
|
||||
IsRequired: false
|
||||
});
|
||||
|
||||
hevcCodecProfileConditions.push({
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'Width',
|
||||
Value: maxVideoWidth.toString(),
|
||||
IsRequired: false
|
||||
});
|
||||
}
|
||||
|
||||
const globalMaxVideoBitrate = (getGlobalMaxVideoBitrate() || '').toString();
|
||||
|
||||
const h264MaxVideoBitrate = globalMaxVideoBitrate;
|
||||
|
||||
const hevcMaxVideoBitrate = globalMaxVideoBitrate;
|
||||
|
||||
if (h264MaxVideoBitrate) {
|
||||
h264CodecProfileConditions.push({
|
||||
Condition: 'LessThanEqual',
|
||||
|
@ -779,6 +885,15 @@ define(['browser'], function (browser) {
|
|||
});
|
||||
}
|
||||
|
||||
if (hevcMaxVideoBitrate) {
|
||||
hevcCodecProfileConditions.push({
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'VideoBitrate',
|
||||
Value: hevcMaxVideoBitrate,
|
||||
IsRequired: true
|
||||
});
|
||||
}
|
||||
|
||||
// On iOS 12.x, for TS container max h264 level is 4.2
|
||||
if (browser.iOS && browser.iOSVersion < 13) {
|
||||
const codecProfile = {
|
||||
|
@ -806,6 +921,12 @@ define(['browser'], function (browser) {
|
|||
Conditions: h264CodecProfileConditions
|
||||
});
|
||||
|
||||
profile.CodecProfiles.push({
|
||||
Type: 'Video',
|
||||
Codec: 'hevc',
|
||||
Conditions: hevcCodecProfileConditions
|
||||
});
|
||||
|
||||
const globalVideoConditions = [];
|
||||
|
||||
if (globalMaxVideoBitrate) {
|
||||
|
@ -841,7 +962,7 @@ define(['browser'], function (browser) {
|
|||
Method: 'External'
|
||||
});
|
||||
}
|
||||
if (options.enableSsaRender) {
|
||||
if (options.enableSsaRender !== false && (!options.isRetry && appSettings.get('subtitleburnin') !== 'allcomplexformats')) {
|
||||
profile.SubtitleProfiles.push({
|
||||
Format: 'ass',
|
||||
Method: 'External'
|
||||
|
@ -860,5 +981,5 @@ define(['browser'], function (browser) {
|
|||
});
|
||||
|
||||
return profile;
|
||||
};
|
||||
});
|
||||
}
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
import * as webSettings from 'webSettings';
|
||||
import AppInfo from '../components/AppInfo';
|
||||
import ServerConnections from '../components/ServerConnections';
|
||||
import toast from '../components/toast/toast';
|
||||
import loading from '../components/loading/loading';
|
||||
import { appRouter } from '../components/appRouter';
|
||||
import baseAlert from '../components/alert';
|
||||
import baseConfirm from '../components/confirm/confirm';
|
||||
import globalize from '../scripts/globalize';
|
||||
import * as webSettings from './settings/webSettings';
|
||||
|
||||
export function getCurrentUser() {
|
||||
return window.ApiClient.getCurrentUser(false);
|
||||
|
@ -12,7 +20,7 @@ export async function serverAddress() {
|
|||
return Promise.resolve(apiClient.serverAddress());
|
||||
}
|
||||
|
||||
const current = await window.connectionManager.getAvailableServers().then(servers => {
|
||||
const current = await ServerConnections.getAvailableServers().then(servers => {
|
||||
if (servers.length !== 0) {
|
||||
return Promise.resolve(servers[0].ManualAddress);
|
||||
}
|
||||
|
@ -57,12 +65,11 @@ export function getCurrentUserId() {
|
|||
}
|
||||
|
||||
export function onServerChanged(userId, accessToken, apiClient) {
|
||||
apiClient = apiClient || window.ApiClient;
|
||||
window.ApiClient = apiClient;
|
||||
ServerConnections.setLocalApiClient(apiClient);
|
||||
}
|
||||
|
||||
export function logout() {
|
||||
window.connectionManager.logout().then(function () {
|
||||
ServerConnections.logout().then(function () {
|
||||
webSettings.getMultiServer().then(multi => {
|
||||
multi ? navigate('selectserver.html') : navigate('login.html');
|
||||
});
|
||||
|
@ -84,39 +91,21 @@ export function navigate(url, preserveQueryString) {
|
|||
url += queryString;
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
import('appRouter').then(({default: appRouter}) => {
|
||||
return appRouter.show(url).then(resolve, reject);
|
||||
});
|
||||
});
|
||||
return appRouter.show(url);
|
||||
}
|
||||
|
||||
export function processPluginConfigurationUpdateResult() {
|
||||
Promise.all([
|
||||
import('loading'),
|
||||
import('toast')
|
||||
])
|
||||
.then(([{default: loading}, {default: toast}]) => {
|
||||
loading.hide();
|
||||
toast(Globalize.translate('SettingsSaved'));
|
||||
});
|
||||
loading.hide();
|
||||
toast(globalize.translate('SettingsSaved'));
|
||||
}
|
||||
|
||||
export function processServerConfigurationUpdateResult(result) {
|
||||
Promise.all([
|
||||
import('loading'),
|
||||
import('toast')
|
||||
])
|
||||
.then(([{default: loading}, {default: toast}]) => {
|
||||
loading.hide();
|
||||
toast(Globalize.translate('SettingsSaved'));
|
||||
});
|
||||
loading.hide();
|
||||
toast(globalize.translate('SettingsSaved'));
|
||||
}
|
||||
|
||||
export function processErrorResponse(response) {
|
||||
import('loading').then(({default: loading}) => {
|
||||
loading.hide();
|
||||
});
|
||||
loading.hide();
|
||||
|
||||
let status = '' + response.status;
|
||||
|
||||
|
@ -132,29 +121,24 @@ export function processErrorResponse(response) {
|
|||
|
||||
export function alert(options) {
|
||||
if (typeof options == 'string') {
|
||||
return void import('toast').then(({default: toast}) => {
|
||||
toast({
|
||||
text: options
|
||||
});
|
||||
toast({
|
||||
text: options
|
||||
});
|
||||
}
|
||||
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert({
|
||||
title: options.title || Globalize.translate('HeaderAlert'),
|
||||
} else {
|
||||
baseAlert({
|
||||
title: options.title || globalize.translate('HeaderAlert'),
|
||||
text: options.message
|
||||
}).then(options.callback || function () {});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function capabilities(appHost) {
|
||||
const capabilities = {
|
||||
return Object.assign({
|
||||
PlayableMediaTypes: ['Audio', 'Video'],
|
||||
SupportedCommands: ['MoveUp', 'MoveDown', 'MoveLeft', 'MoveRight', 'PageUp', 'PageDown', 'PreviousLetter', 'NextLetter', 'ToggleOsd', 'ToggleContextMenu', 'Select', 'Back', 'SendKey', 'SendString', 'GoHome', 'GoToSettings', 'VolumeUp', 'VolumeDown', 'Mute', 'Unmute', 'ToggleMute', 'SetVolume', 'SetAudioStreamIndex', 'SetSubtitleStreamIndex', 'DisplayContent', 'GoToSearch', 'DisplayMessage', 'SetRepeatMode', 'SetShuffleQueue', 'ChannelUp', 'ChannelDown', 'PlayMediaSource', 'PlayTrailers'],
|
||||
SupportsPersistentIdentifier: window.appMode === 'cordova' || window.appMode === 'android',
|
||||
SupportsMediaControl: true
|
||||
};
|
||||
return Object.assign(capabilities, appHost.getPushTokenInfo());
|
||||
}, appHost.getPushTokenInfo());
|
||||
}
|
||||
|
||||
export function selectServer() {
|
||||
|
@ -166,30 +150,42 @@ export function selectServer() {
|
|||
}
|
||||
|
||||
export function hideLoadingMsg() {
|
||||
import('loading').then(({default: loading}) => {
|
||||
loading.hide();
|
||||
});
|
||||
loading.hide();
|
||||
}
|
||||
|
||||
export function showLoadingMsg() {
|
||||
import('loading').then(({default: loading}) => {
|
||||
loading.show();
|
||||
});
|
||||
loading.show();
|
||||
}
|
||||
|
||||
export function confirm(message, title, callback) {
|
||||
import('confirm').then(({default: confirm}) => {
|
||||
confirm(message, title).then(function() {
|
||||
callback(!0);
|
||||
}).catch(function() {
|
||||
callback(!1);
|
||||
});
|
||||
baseConfirm(message, title).then(function() {
|
||||
callback(true);
|
||||
}).catch(function() {
|
||||
callback(false);
|
||||
});
|
||||
}
|
||||
|
||||
// This is used in plugins and templates, so keep it defined for now.
|
||||
// TODO: Remove once plugins don't need it
|
||||
window.Dashboard = {
|
||||
export const pageClassOn = function(eventName, className, fn) {
|
||||
document.addEventListener(eventName, function (event) {
|
||||
const target = event.target;
|
||||
|
||||
if (target.classList.contains(className)) {
|
||||
fn.call(target, event);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const pageIdOn = function(eventName, id, fn) {
|
||||
document.addEventListener(eventName, function (event) {
|
||||
const target = event.target;
|
||||
|
||||
if (target.id === id) {
|
||||
fn.call(target, event);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const Dashboard = {
|
||||
alert,
|
||||
capabilities,
|
||||
confirm,
|
||||
|
@ -208,21 +204,8 @@ window.Dashboard = {
|
|||
showLoadingMsg
|
||||
};
|
||||
|
||||
export default {
|
||||
alert,
|
||||
capabilities,
|
||||
confirm,
|
||||
getPluginUrl,
|
||||
getCurrentUser,
|
||||
getCurrentUserId,
|
||||
hideLoadingMsg,
|
||||
logout,
|
||||
navigate,
|
||||
onServerChanged,
|
||||
processErrorResponse,
|
||||
processPluginConfigurationUpdateResult,
|
||||
processServerConfigurationUpdateResult,
|
||||
selectServer,
|
||||
serverAddress,
|
||||
showLoadingMsg
|
||||
};
|
||||
// This is used in plugins and templates, so keep it defined for now.
|
||||
// TODO: Remove once plugins don't need it
|
||||
window.Dashboard = Dashboard;
|
||||
|
||||
export default Dashboard;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import globalize from 'globalize';
|
||||
import globalize from './globalize';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
import confirm from 'confirm';
|
||||
import appRouter from 'appRouter';
|
||||
import globalize from 'globalize';
|
||||
|
||||
import confirm from '../components/confirm/confirm';
|
||||
import { appRouter } from '../components/appRouter';
|
||||
import globalize from './globalize';
|
||||
import ServerConnections from '../components/ServerConnections';
|
||||
import alert from '../components/alert';
|
||||
|
||||
function alertText(options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert(options).then(resolve, resolve);
|
||||
});
|
||||
});
|
||||
return alert(options);
|
||||
}
|
||||
|
||||
export function deleteItem(options) {
|
||||
const item = options.item;
|
||||
const parentId = item.SeasonId || item.SeriesId || item.ParentId;
|
||||
|
||||
const apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
const apiClient = ServerConnections.getApiClient(item.ServerId);
|
||||
|
||||
return confirm({
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ar, be, bg, ca, cs, da, de, el, enGB, enUS, es, faIR, fi, fr, frCA, he, hi, hr, hu, id, it, ja, kk, ko, lt, ms, nb,
|
||||
nl, pl, ptBR, pt, ro, ru, sk, sl, sv, tr, uk, vi, zhCN, zhTW } from 'date-fns/locale';
|
||||
import globalize from 'globalize';
|
||||
import globalize from './globalize';
|
||||
|
||||
const dateLocales = (locale) => ({
|
||||
'ar': ar,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import $ from 'jQuery';
|
||||
import globalize from 'globalize';
|
||||
import 'material-icons';
|
||||
import 'jquery';
|
||||
import globalize from './globalize';
|
||||
import 'material-design-icons-iconfont';
|
||||
import Dashboard from './clientUtils';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
@ -182,7 +183,10 @@ import 'material-icons';
|
|||
}
|
||||
|
||||
function initializeTree(page, currentUser, openItems, selectedId) {
|
||||
import('jstree').then(() => {
|
||||
Promise.all([
|
||||
import('jstree'),
|
||||
import('jstree/dist/themes/default/style.css')
|
||||
]).then(() => {
|
||||
initializeTreeInternal(page, currentUser, openItems, selectedId);
|
||||
});
|
||||
}
|
||||
|
@ -303,7 +307,7 @@ import 'material-icons';
|
|||
updateEditorNode(this, item);
|
||||
}).on('pagebeforeshow', '.metadataEditorPage', function () {
|
||||
/* eslint-disable-next-line @babel/no-unused-expressions */
|
||||
import('css!assets/css/metadataeditor.css');
|
||||
import('../assets/css/metadataeditor.css');
|
||||
}).on('pagebeforeshow', '.metadataEditorPage', function () {
|
||||
const page = this;
|
||||
Dashboard.getCurrentUser().then(function (user) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import multiDownload from 'multi-download';
|
||||
import shell from 'shell';
|
||||
import multiDownload from './multiDownload';
|
||||
import shell from './shell';
|
||||
|
||||
export function download(items) {
|
||||
if (!shell.downloadFiles(items)) {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
// # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// # THE SOFTWARE.
|
||||
|
||||
import appHost from 'apphost';
|
||||
import { appHost } from '../components/apphost';
|
||||
|
||||
const _GAMEPAD_A_BUTTON_INDEX = 0;
|
||||
const _GAMEPAD_B_BUTTON_INDEX = 1;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as userSettings from 'userSettings';
|
||||
import events from 'events';
|
||||
import * as userSettings from './settings/userSettings';
|
||||
import { Events } from 'jellyfin-apiclient';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
@ -143,7 +143,6 @@ import events from 'events';
|
|||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
const cacheParam = new Date().getTime();
|
||||
function loadTranslation(translations, lang) {
|
||||
lang = normalizeLocaleName(lang);
|
||||
let filtered = translations.filter(function (t) {
|
||||
|
@ -162,26 +161,13 @@ import events from 'events';
|
|||
return;
|
||||
}
|
||||
|
||||
let url = filtered[0].path;
|
||||
const url = filtered[0].path;
|
||||
|
||||
url += url.indexOf('?') === -1 ? '?' : '&';
|
||||
url += 'v=' + cacheParam;
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
xhr.onload = function (e) {
|
||||
if (this.status < 400) {
|
||||
resolve(JSON.parse(this.response));
|
||||
} else {
|
||||
resolve({});
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = function () {
|
||||
import(`../strings/${url}`).then((fileContent) => {
|
||||
resolve(fileContent);
|
||||
}).catch(() => {
|
||||
resolve({});
|
||||
};
|
||||
xhr.send();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -221,6 +207,8 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function translateHtml(html, module) {
|
||||
html = html.default || html;
|
||||
|
||||
if (!module) {
|
||||
module = defaultModule();
|
||||
}
|
||||
|
@ -256,7 +244,7 @@ import events from 'events';
|
|||
|
||||
updateCurrentCulture();
|
||||
|
||||
events.on(userSettings, 'change', function (e, name) {
|
||||
Events.on(userSettings, 'change', function (e, name) {
|
||||
if (name === 'language' || name === 'datetimelocale') {
|
||||
updateCurrentCulture();
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import playbackManager from 'playbackManager';
|
||||
import focusManager from 'focusManager';
|
||||
import appRouter from 'appRouter';
|
||||
import dom from 'dom';
|
||||
import appHost from 'apphost';
|
||||
import { playbackManager } from '../components/playback/playbackmanager';
|
||||
import focusManager from '../components/focusManager';
|
||||
import { appRouter } from '../components/appRouter';
|
||||
import dom from './dom';
|
||||
import { appHost } from '../components/apphost';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import listView from 'listView';
|
||||
import cardBuilder from 'cardBuilder';
|
||||
import imageLoader from 'imageLoader';
|
||||
import globalize from 'globalize';
|
||||
import 'emby-itemscontainer';
|
||||
import 'emby-button';
|
||||
import listView from '../components/listview/listview';
|
||||
import cardBuilder from '../components/cardbuilder/cardBuilder';
|
||||
import imageLoader from '../components/images/imageLoader';
|
||||
import globalize from './globalize';
|
||||
import '../elements/emby-itemscontainer/emby-itemscontainer';
|
||||
import '../elements/emby-button/emby-button';
|
||||
import ServerConnections from '../components/ServerConnections';
|
||||
|
||||
function renderItems(page, item) {
|
||||
const sections = [];
|
||||
|
@ -357,7 +358,7 @@ function getItemsFunction(options, item) {
|
|||
query.Fields += ',' + fields;
|
||||
}
|
||||
|
||||
const apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
const apiClient = ServerConnections.getApiClient(item.ServerId);
|
||||
|
||||
if (query.IncludeItemTypes === 'MusicArtist') {
|
||||
query.IncludeItemTypes = null;
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
* @module components/input/keyboardnavigation
|
||||
*/
|
||||
|
||||
import inputManager from 'inputManager';
|
||||
import layoutManager from 'layoutManager';
|
||||
import inputManager from './inputManager';
|
||||
import layoutManager from '../components/layoutManager';
|
||||
|
||||
/**
|
||||
* Key name mapping.
|
||||
|
@ -156,7 +156,7 @@ function attachGamepadScript(e) {
|
|||
console.log('Gamepad connected! Attaching gamepadtokey.js script');
|
||||
window.removeEventListener('gamepadconnected', attachGamepadScript);
|
||||
/* eslint-disable-next-line @babel/no-unused-expressions */
|
||||
import('scripts/gamepadtokey');
|
||||
import('./gamepadtokey');
|
||||
}
|
||||
|
||||
// No need to check for gamepads manually at load time, the eventhandler will be fired for that
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as userSettings from 'userSettings';
|
||||
import globalize from 'globalize';
|
||||
import * as userSettings from './settings/userSettings';
|
||||
import globalize from './globalize';
|
||||
|
||||
export function getSavedQueryKey(modifier) {
|
||||
return window.location.href.split('#')[0] + (modifier || '');
|
||||
|
@ -55,7 +55,7 @@ export function showLayoutMenu (button, currentLayout, views) {
|
|||
};
|
||||
});
|
||||
|
||||
import('actionsheet').then(({default: actionsheet}) => {
|
||||
import('../components/actionSheet/actionSheet').then(({default: actionsheet}) => {
|
||||
actionsheet.show({
|
||||
items: menuItems,
|
||||
positionTo: button,
|
||||
|
@ -120,8 +120,8 @@ export function getQueryPagingHtml (options) {
|
|||
|
||||
export function showSortMenu (options) {
|
||||
Promise.all([
|
||||
import('dialogHelper'),
|
||||
import('emby-radio')
|
||||
import('../components/dialogHelper/dialogHelper'),
|
||||
import('../elements/emby-radio/emby-radio')
|
||||
]).then(([{default: dialogHelper}]) => {
|
||||
function onSortByChange() {
|
||||
const newValue = this.value;
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
import dom from 'dom';
|
||||
import layoutManager from 'layoutManager';
|
||||
import inputManager from 'inputManager';
|
||||
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 * as 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';
|
||||
import dom from './dom';
|
||||
import layoutManager from '../components/layoutManager';
|
||||
import inputManager from './inputManager';
|
||||
import { Events } from 'jellyfin-apiclient';
|
||||
import viewManager from '../components/viewManager/viewManager';
|
||||
import { appRouter } from '../components/appRouter';
|
||||
import { appHost } from '../components/apphost';
|
||||
import { playbackManager } from '../components/playback/playbackmanager';
|
||||
import syncPlayManager from '../components/syncPlay/syncPlayManager';
|
||||
import { show as groupSelectionMenuShow } from '../components/syncPlay/groupSelectionMenu';
|
||||
import browser from './browser';
|
||||
import globalize from './globalize';
|
||||
import imageHelper from './imagehelper';
|
||||
import '../elements/emby-button/paper-icon-button-light';
|
||||
import 'material-design-icons-iconfont';
|
||||
import '../assets/css/scrollstyles.css';
|
||||
import '../assets/css/flexstyles.scss';
|
||||
import Dashboard, { pageClassOn } from './clientUtils';
|
||||
import ServerConnections from '../components/ServerConnections';
|
||||
import Headroom from 'headroom.js';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
@ -60,14 +63,14 @@ import 'flexStyles';
|
|||
|
||||
function getCurrentApiClient() {
|
||||
if (currentUser && currentUser.localUser) {
|
||||
return window.connectionManager.getApiClient(currentUser.localUser.ServerId);
|
||||
return ServerConnections.getApiClient(currentUser.localUser.ServerId);
|
||||
}
|
||||
|
||||
return window.connectionManager.currentApiClient();
|
||||
return ServerConnections.currentApiClient();
|
||||
}
|
||||
|
||||
function lazyLoadViewMenuBarImages() {
|
||||
import('imageLoader').then(({default: imageLoader}) => {
|
||||
import('../components/images/imageLoader').then((imageLoader) => {
|
||||
imageLoader.lazyChildren(skinHeader);
|
||||
});
|
||||
}
|
||||
|
@ -199,8 +202,8 @@ import 'flexStyles';
|
|||
if (layoutManager.mobile) {
|
||||
initHeadRoom(skinHeader);
|
||||
}
|
||||
events.on(playbackManager, 'playbackstart', onPlaybackStart);
|
||||
events.on(playbackManager, 'playbackstop', onPlaybackStop);
|
||||
Events.on(playbackManager, 'playbackstart', onPlaybackStart);
|
||||
Events.on(playbackManager, 'playbackstop', onPlaybackStop);
|
||||
}
|
||||
|
||||
function onPlaybackStart(e) {
|
||||
|
@ -220,14 +223,14 @@ import 'flexStyles';
|
|||
function onCastButtonClicked() {
|
||||
const btn = this;
|
||||
|
||||
import('playerSelectionMenu').then(({default: playerSelectionMenu}) => {
|
||||
import('../components/playback/playerSelectionMenu').then((playerSelectionMenu) => {
|
||||
playerSelectionMenu.show(btn);
|
||||
});
|
||||
}
|
||||
|
||||
function onSyncButtonClicked() {
|
||||
const btn = this;
|
||||
groupSelectionMenu.show(btn);
|
||||
groupSelectionMenuShow(btn);
|
||||
}
|
||||
|
||||
function onSyncPlayEnabled(event, enabled) {
|
||||
|
@ -774,7 +777,7 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
if (requiresUserRefresh) {
|
||||
window.connectionManager.user(getCurrentApiClient()).then(updateUserInHeader);
|
||||
ServerConnections.user(getCurrentApiClient()).then(updateUserInHeader);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -799,10 +802,8 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function initHeadRoom(elem) {
|
||||
import('headroom').then(({default: Headroom}) => {
|
||||
const headroom = new Headroom(elem);
|
||||
headroom.init();
|
||||
});
|
||||
const headroom = new Headroom(elem);
|
||||
headroom.init();
|
||||
}
|
||||
|
||||
function refreshLibraryDrawer(user) {
|
||||
|
@ -812,9 +813,9 @@ import 'flexStyles';
|
|||
if (user) {
|
||||
Promise.resolve(user);
|
||||
} else {
|
||||
window.connectionManager.user(getCurrentApiClient()).then(function (user) {
|
||||
refreshLibraryInfoInDrawer(user);
|
||||
updateLibraryMenu(user.localUser);
|
||||
ServerConnections.user(getCurrentApiClient()).then(function (userResult) {
|
||||
refreshLibraryInfoInDrawer(userResult);
|
||||
updateLibraryMenu(userResult.localUser);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -839,8 +840,8 @@ import 'flexStyles';
|
|||
navDrawerScrollContainer = navDrawerElement.querySelector('.scrollContainer');
|
||||
navDrawerScrollContainer.addEventListener('click', onMainDrawerClick);
|
||||
return new Promise(function (resolve, reject) {
|
||||
import('navdrawer').then(({default: navdrawer}) => {
|
||||
navDrawerInstance = new navdrawer(getNavDrawerOptions());
|
||||
import('../libraries/navdrawer/navdrawer').then(({ NavigationDrawer }) => {
|
||||
navDrawerInstance = new NavigationDrawer(getNavDrawerOptions());
|
||||
|
||||
if (!layoutManager.tv) {
|
||||
navDrawerElement.classList.remove('hide');
|
||||
|
@ -871,7 +872,7 @@ import 'flexStyles';
|
|||
let requiresUserRefresh = true;
|
||||
|
||||
function setTabs (type, selectedIndex, builder) {
|
||||
import('mainTabsManager').then((mainTabsManager) => {
|
||||
import('../components/maintabsmanager').then((mainTabsManager) => {
|
||||
if (type) {
|
||||
mainTabsManager.setTabs(viewManager.currentView(), selectedIndex, builder, function () {
|
||||
return [];
|
||||
|
@ -976,8 +977,8 @@ import 'flexStyles';
|
|||
updateLibraryNavLinks(page);
|
||||
});
|
||||
|
||||
events.on(window.connectionManager, 'localusersignedin', function (e, user) {
|
||||
const currentApiClient = window.connectionManager.getApiClient(user.ServerId);
|
||||
Events.on(ServerConnections, 'localusersignedin', function (e, user) {
|
||||
const currentApiClient = ServerConnections.getApiClient(user.ServerId);
|
||||
|
||||
currentDrawerType = null;
|
||||
currentUser = {
|
||||
|
@ -986,21 +987,21 @@ import 'flexStyles';
|
|||
|
||||
loadNavDrawer();
|
||||
|
||||
window.connectionManager.user(currentApiClient).then(function (user) {
|
||||
currentUser = user;
|
||||
updateUserInHeader(user);
|
||||
ServerConnections.user(currentApiClient).then(function (userResult) {
|
||||
currentUser = userResult;
|
||||
updateUserInHeader(userResult);
|
||||
});
|
||||
});
|
||||
|
||||
events.on(window.connectionManager, 'localusersignedout', function () {
|
||||
Events.on(ServerConnections, 'localusersignedout', function () {
|
||||
currentUser = {};
|
||||
updateUserInHeader();
|
||||
});
|
||||
|
||||
events.on(playbackManager, 'playerchange', updateCastIcon);
|
||||
Events.on(playbackManager, 'playerchange', updateCastIcon);
|
||||
|
||||
events.on(syncPlayManager, 'enabled', onSyncPlayEnabled);
|
||||
events.on(syncPlayManager, 'syncing', onSyncPlaySyncing);
|
||||
Events.on(syncPlayManager, 'enabled', onSyncPlayEnabled);
|
||||
Events.on(syncPlayManager, 'syncing', onSyncPlaySyncing);
|
||||
|
||||
loadNavDrawer();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import layoutManager from 'layoutManager';
|
||||
import datetime from 'datetime';
|
||||
import cardBuilder from 'cardBuilder';
|
||||
import layoutManager from '../components/layoutManager';
|
||||
import datetime from './datetime';
|
||||
import cardBuilder from '../components/cardbuilder/cardBuilder';
|
||||
|
||||
function enableScrollX() {
|
||||
return !layoutManager.desktop;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import inputManager from 'inputManager';
|
||||
import focusManager from 'focusManager';
|
||||
import browser from 'browser';
|
||||
import layoutManager from 'layoutManager';
|
||||
import events from 'events';
|
||||
import dom from 'dom';
|
||||
import inputManager from './inputManager';
|
||||
import focusManager from '../components/focusManager';
|
||||
import browser from '../scripts/browser';
|
||||
import layoutManager from '../components/layoutManager';
|
||||
import { Events } from 'jellyfin-apiclient';
|
||||
import dom from '../scripts/dom';
|
||||
/* eslint-disable indent */
|
||||
|
||||
const self = {};
|
||||
|
@ -40,7 +40,7 @@ import dom from 'dom';
|
|||
if (isMouseIdle) {
|
||||
isMouseIdle = false;
|
||||
removeIdleClasses();
|
||||
events.trigger(self, 'mouseactive');
|
||||
Events.trigger(self, 'mouseactive');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ import dom from 'dom';
|
|||
if (!isMouseIdle) {
|
||||
isMouseIdle = true;
|
||||
addIdleClasses();
|
||||
events.trigger(self, 'mouseidle');
|
||||
Events.trigger(self, 'mouseidle');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,7 +170,7 @@ import dom from 'dom';
|
|||
|
||||
initMouse();
|
||||
|
||||
events.on(layoutManager, 'modechange', initMouse);
|
||||
Events.on(layoutManager, 'modechange', initMouse);
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import browser from 'browser';
|
||||
import browser from '../scripts/browser';
|
||||
|
||||
function fallback(urls) {
|
||||
let i = 0;
|
||||
|
|
|
@ -1,50 +1,48 @@
|
|||
define(['listView'], function (listView) {
|
||||
'use strict';
|
||||
import listView from '../components/listview/listview';
|
||||
|
||||
function getFetchPlaylistItemsFn(itemId) {
|
||||
return function () {
|
||||
const query = {
|
||||
Fields: 'PrimaryImageAspectRatio,UserData',
|
||||
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
|
||||
UserId: ApiClient.getCurrentUserId()
|
||||
};
|
||||
return ApiClient.getJSON(ApiClient.getUrl(`Playlists/${itemId}/Items`, query));
|
||||
function getFetchPlaylistItemsFn(itemId) {
|
||||
return function () {
|
||||
const query = {
|
||||
Fields: 'PrimaryImageAspectRatio,UserData',
|
||||
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
|
||||
UserId: ApiClient.getCurrentUserId()
|
||||
};
|
||||
}
|
||||
|
||||
function getItemsHtmlFn(itemId) {
|
||||
return function (items) {
|
||||
return listView.getListViewHtml({
|
||||
items: items,
|
||||
showIndex: false,
|
||||
showRemoveFromPlaylist: true,
|
||||
playFromHere: true,
|
||||
action: 'playallfromhere',
|
||||
smallIcon: true,
|
||||
dragHandle: true,
|
||||
playlistId: itemId
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function init(page, item) {
|
||||
const elem = page.querySelector('#childrenContent .itemsContainer');
|
||||
elem.classList.add('vertical-list');
|
||||
elem.classList.remove('vertical-wrap');
|
||||
elem.enableDragReordering(true);
|
||||
elem.fetchData = getFetchPlaylistItemsFn(item.Id);
|
||||
elem.getItemsHtml = getItemsHtmlFn(item.Id);
|
||||
}
|
||||
|
||||
window.PlaylistViewer = {
|
||||
render: function (page, item) {
|
||||
if (!page.playlistInit) {
|
||||
page.playlistInit = true;
|
||||
init(page, item);
|
||||
}
|
||||
|
||||
page.querySelector('#childrenContent').classList.add('verticalSection-extrabottompadding');
|
||||
page.querySelector('#childrenContent .itemsContainer').refreshItems();
|
||||
}
|
||||
return ApiClient.getJSON(ApiClient.getUrl(`Playlists/${itemId}/Items`, query));
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getItemsHtmlFn(itemId) {
|
||||
return function (items) {
|
||||
return listView.getListViewHtml({
|
||||
items: items,
|
||||
showIndex: false,
|
||||
showRemoveFromPlaylist: true,
|
||||
playFromHere: true,
|
||||
action: 'playallfromhere',
|
||||
smallIcon: true,
|
||||
dragHandle: true,
|
||||
playlistId: itemId
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function init(page, item) {
|
||||
const elem = page.querySelector('#childrenContent .itemsContainer');
|
||||
elem.classList.add('vertical-list');
|
||||
elem.classList.remove('vertical-wrap');
|
||||
elem.enableDragReordering(true);
|
||||
elem.fetchData = getFetchPlaylistItemsFn(item.Id);
|
||||
elem.getItemsHtml = getItemsHtmlFn(item.Id);
|
||||
}
|
||||
|
||||
window.PlaylistViewer = {
|
||||
render: function (page, item) {
|
||||
if (!page.playlistInit) {
|
||||
page.playlistInit = true;
|
||||
init(page, item);
|
||||
}
|
||||
|
||||
page.querySelector('#childrenContent').classList.add('verticalSection-extrabottompadding');
|
||||
page.querySelector('#childrenContent .itemsContainer').refreshItems();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import loading from 'loading';
|
||||
import loading from '../../components/loading/loading';
|
||||
import listView from 'listView';
|
||||
import cardBuilder from 'cardBuilder';
|
||||
import libraryMenu from 'libraryMenu';
|
||||
import libraryBrowser from 'libraryBrowser';
|
||||
import imageLoader from 'imageLoader';
|
||||
import userSettings from 'userSettings';
|
||||
import 'emby-itemscontainer';
|
||||
import * as userSettings from '../scripts/settings/userSettings';
|
||||
import '../../elements/emby-itemscontainer/emby-itemscontainer';
|
||||
import Dashboard from './clientUtils';
|
||||
|
||||
export default function (view, params) {
|
||||
function getPageData(context) {
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import 'emby-button';
|
||||
import 'emby-input';
|
||||
import 'scripts/livetvcomponents';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-itemscontainer';
|
||||
import 'emby-collapse';
|
||||
import 'emby-select';
|
||||
import 'livetvcss';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-slider';
|
||||
import 'listViewStyle';
|
||||
import 'dashboardcss';
|
||||
import 'detailtablecss';
|
||||
import '../elements/emby-button/emby-button';
|
||||
import '../elements/emby-input/emby-input';
|
||||
import '../scripts/livetvcomponents';
|
||||
import '../elements/emby-button/paper-icon-button-light';
|
||||
import '../elements/emby-itemscontainer/emby-itemscontainer';
|
||||
import '../elements/emby-collapse/emby-collapse';
|
||||
import '../elements/emby-select/emby-select';
|
||||
import '../elements/emby-checkbox/emby-checkbox';
|
||||
import '../elements/emby-slider/emby-slider';
|
||||
import '../assets/css/livetv.scss';
|
||||
import '../components/listview/listview.css';
|
||||
import '../assets/css/dashboard.css';
|
||||
import '../assets/css/detailtable.scss';
|
||||
import { appRouter } from '../components/appRouter';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
@ -20,12 +21,12 @@ import 'detailtablecss';
|
|||
const path = newRoute.alias ? newRoute.alias : newRoute.path;
|
||||
console.debug('defining route: ' + path);
|
||||
newRoute.dictionary = 'core';
|
||||
Emby.Page.addRoute(path, newRoute);
|
||||
appRouter.addRoute(path, newRoute);
|
||||
}
|
||||
|
||||
defineRoute({
|
||||
alias: '/addserver.html',
|
||||
path: '/controllers/session/addServer/index.html',
|
||||
path: 'session/addServer/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
|
@ -34,7 +35,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/selectserver.html',
|
||||
path: '/controllers/session/selectServer/index.html',
|
||||
path: 'session/selectServer/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
|
@ -44,7 +45,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/login.html',
|
||||
path: '/controllers/session/login/index.html',
|
||||
path: 'session/login/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
|
@ -54,7 +55,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/forgotpassword.html',
|
||||
path: '/controllers/session/forgotPassword/index.html',
|
||||
path: 'session/forgotPassword/index.html',
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
controller: 'session/forgotPassword/index'
|
||||
|
@ -62,7 +63,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/forgotpasswordpin.html',
|
||||
path: '/controllers/session/resetPassword/index.html',
|
||||
path: 'session/resetPassword/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
|
@ -71,56 +72,56 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/mypreferencesmenu.html',
|
||||
path: '/controllers/user/menu/index.html',
|
||||
path: 'user/menu/index.html',
|
||||
autoFocus: false,
|
||||
controller: 'user/menu/index'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/myprofile.html',
|
||||
path: '/controllers/user/profile/index.html',
|
||||
path: 'user/profile/index.html',
|
||||
autoFocus: false,
|
||||
controller: 'user/profile/index'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/mypreferencesdisplay.html',
|
||||
path: '/controllers/user/display/index.html',
|
||||
path: 'user/display/index.html',
|
||||
autoFocus: false,
|
||||
controller: 'user/display/index'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/mypreferenceshome.html',
|
||||
path: '/controllers/user/home/index.html',
|
||||
path: 'user/home/index.html',
|
||||
autoFocus: false,
|
||||
controller: 'user/home/index'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/mypreferencesquickconnect.html',
|
||||
path: '/controllers/user/quickConnect/index.html',
|
||||
path: 'user/quickConnect/index.html',
|
||||
autoFocus: false,
|
||||
transition: 'fade',
|
||||
controller: 'user/quickConnect/index'
|
||||
});
|
||||
defineRoute({
|
||||
alias: '/mypreferencesplayback.html',
|
||||
path: '/controllers/user/playback/index.html',
|
||||
path: 'user/playback/index.html',
|
||||
autoFocus: false,
|
||||
controller: 'user/playback/index'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/mypreferencessubtitles.html',
|
||||
path: '/controllers/user/subtitles/index.html',
|
||||
path: 'user/subtitles/index.html',
|
||||
autoFocus: false,
|
||||
controller: 'user/subtitles/index'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/dashboard.html',
|
||||
path: '/controllers/dashboard/dashboard.html',
|
||||
path: 'dashboard/dashboard.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/dashboard'
|
||||
|
@ -128,7 +129,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/dashboardgeneral.html',
|
||||
path: '/controllers/dashboard/general.html',
|
||||
path: 'dashboard/general.html',
|
||||
controller: 'dashboard/general',
|
||||
autoFocus: false,
|
||||
roles: 'admin'
|
||||
|
@ -136,7 +137,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/networking.html',
|
||||
path: '/controllers/dashboard/networking.html',
|
||||
path: 'dashboard/networking.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/networking'
|
||||
|
@ -144,7 +145,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/devices.html',
|
||||
path: '/controllers/dashboard/devices/devices.html',
|
||||
path: 'dashboard/devices/devices.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/devices/devices'
|
||||
|
@ -152,7 +153,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/device.html',
|
||||
path: '/controllers/dashboard/devices/device.html',
|
||||
path: 'dashboard/devices/device.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/devices/device'
|
||||
|
@ -160,7 +161,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/quickConnect.html',
|
||||
path: '/controllers/dashboard/quickConnect.html',
|
||||
path: 'dashboard/quickConnect.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/quickConnect'
|
||||
|
@ -168,7 +169,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/dlnaprofile.html',
|
||||
path: '/controllers/dashboard/dlna/profile.html',
|
||||
path: 'dashboard/dlna/profile.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/dlna/profile'
|
||||
|
@ -176,7 +177,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/dlnaprofiles.html',
|
||||
path: '/controllers/dashboard/dlna/profiles.html',
|
||||
path: 'dashboard/dlna/profiles.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/dlna/profiles'
|
||||
|
@ -184,7 +185,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/dlnasettings.html',
|
||||
path: '/controllers/dashboard/dlna/settings.html',
|
||||
path: 'dashboard/dlna/settings.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/dlna/settings'
|
||||
|
@ -192,7 +193,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/addplugin.html',
|
||||
path: '/controllers/dashboard/plugins/add/index.html',
|
||||
path: 'dashboard/plugins/add/index.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/plugins/add/index'
|
||||
|
@ -200,7 +201,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/library.html',
|
||||
path: '/controllers/dashboard/library.html',
|
||||
path: 'dashboard/library.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/library'
|
||||
|
@ -208,7 +209,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/librarydisplay.html',
|
||||
path: '/controllers/dashboard/librarydisplay.html',
|
||||
path: 'dashboard/librarydisplay.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/librarydisplay'
|
||||
|
@ -216,14 +217,14 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/edititemmetadata.html',
|
||||
path: '/controllers/edititemmetadata.html',
|
||||
path: 'edititemmetadata.html',
|
||||
controller: 'edititemmetadata',
|
||||
autoFocus: false
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/encodingsettings.html',
|
||||
path: '/controllers/dashboard/encodingsettings.html',
|
||||
path: 'dashboard/encodingsettings.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/encodingsettings'
|
||||
|
@ -231,14 +232,14 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/log.html',
|
||||
path: '/controllers/dashboard/logs.html',
|
||||
path: 'dashboard/logs.html',
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/logs'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/metadataimages.html',
|
||||
path: '/controllers/dashboard/metadataimages.html',
|
||||
path: 'dashboard/metadataimages.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/metadataImages'
|
||||
|
@ -246,7 +247,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/metadatanfo.html',
|
||||
path: '/controllers/dashboard/metadatanfo.html',
|
||||
path: 'dashboard/metadatanfo.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/metadatanfo'
|
||||
|
@ -254,7 +255,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/notificationsetting.html',
|
||||
path: '/controllers/dashboard/notifications/notification/index.html',
|
||||
path: 'dashboard/notifications/notification/index.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/notifications/notification/index'
|
||||
|
@ -262,7 +263,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/notificationsettings.html',
|
||||
path: '/controllers/dashboard/notifications/notifications/index.html',
|
||||
path: 'dashboard/notifications/notifications/index.html',
|
||||
controller: 'dashboard/notifications/notifications/index',
|
||||
autoFocus: false,
|
||||
roles: 'admin'
|
||||
|
@ -270,7 +271,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/playbackconfiguration.html',
|
||||
path: '/controllers/dashboard/playback.html',
|
||||
path: 'dashboard/playback.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/playback'
|
||||
|
@ -278,7 +279,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/availableplugins.html',
|
||||
path: '/controllers/dashboard/plugins/available/index.html',
|
||||
path: 'dashboard/plugins/available/index.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/plugins/available/index'
|
||||
|
@ -286,7 +287,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/repositories.html',
|
||||
path: '/controllers/dashboard/plugins/repositories/index.html',
|
||||
path: 'dashboard/plugins/repositories/index.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/plugins/repositories/index'
|
||||
|
@ -294,7 +295,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/home.html',
|
||||
path: '/controllers/home.html',
|
||||
path: 'home.html',
|
||||
autoFocus: false,
|
||||
controller: 'home',
|
||||
type: 'home'
|
||||
|
@ -302,34 +303,34 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/search.html',
|
||||
path: '/controllers/search.html',
|
||||
path: 'search.html',
|
||||
controller: 'searchpage'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/list.html',
|
||||
path: '/controllers/list.html',
|
||||
path: 'list.html',
|
||||
autoFocus: false,
|
||||
controller: 'list'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/details',
|
||||
path: '/controllers/itemDetails/index.html',
|
||||
path: 'itemDetails/index.html',
|
||||
controller: 'itemDetails/index',
|
||||
autoFocus: false
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/livetv.html',
|
||||
path: '/controllers/livetv.html',
|
||||
path: 'livetv.html',
|
||||
controller: 'livetv/livetvsuggested',
|
||||
autoFocus: false
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/livetvguideprovider.html',
|
||||
path: '/controllers/livetvguideprovider.html',
|
||||
path: 'livetvguideprovider.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'livetvguideprovider'
|
||||
|
@ -337,14 +338,14 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/livetvsettings.html',
|
||||
path: '/controllers/livetvsettings.html',
|
||||
path: 'livetvsettings.html',
|
||||
autoFocus: false,
|
||||
controller: 'livetvsettings'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/livetvstatus.html',
|
||||
path: '/controllers/livetvstatus.html',
|
||||
path: 'livetvstatus.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'livetvstatus'
|
||||
|
@ -352,7 +353,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/livetvtuner.html',
|
||||
path: '/controllers/livetvtuner.html',
|
||||
path: 'livetvtuner.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'livetvtuner'
|
||||
|
@ -360,21 +361,21 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/movies.html',
|
||||
path: '/controllers/movies/movies.html',
|
||||
path: 'movies/movies.html',
|
||||
autoFocus: false,
|
||||
controller: 'movies/moviesrecommended'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/music.html',
|
||||
path: '/controllers/music/music.html',
|
||||
path: 'music/music.html',
|
||||
controller: 'music/musicrecommended',
|
||||
autoFocus: false
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/installedplugins.html',
|
||||
path: '/controllers/dashboard/plugins/installed/index.html',
|
||||
path: 'dashboard/plugins/installed/index.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/plugins/installed/index'
|
||||
|
@ -382,7 +383,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/scheduledtask.html',
|
||||
path: '/controllers/dashboard/scheduledtasks/scheduledtask.html',
|
||||
path: 'dashboard/scheduledtasks/scheduledtask.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/scheduledtasks/scheduledtask'
|
||||
|
@ -390,7 +391,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/scheduledtasks.html',
|
||||
path: '/controllers/dashboard/scheduledtasks/scheduledtasks.html',
|
||||
path: 'dashboard/scheduledtasks/scheduledtasks.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/scheduledtasks/scheduledtasks'
|
||||
|
@ -398,7 +399,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/serveractivity.html',
|
||||
path: '/controllers/dashboard/serveractivity.html',
|
||||
path: 'dashboard/serveractivity.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/serveractivity'
|
||||
|
@ -406,7 +407,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/apikeys.html',
|
||||
path: '/controllers/dashboard/apikeys.html',
|
||||
path: 'dashboard/apikeys.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/apikeys'
|
||||
|
@ -414,7 +415,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/streamingsettings.html',
|
||||
path: '/controllers/dashboard/streaming.html',
|
||||
path: 'dashboard/streaming.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/streaming'
|
||||
|
@ -422,14 +423,14 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/tv.html',
|
||||
path: '/controllers/shows/tvrecommended.html',
|
||||
path: 'shows/tvrecommended.html',
|
||||
autoFocus: false,
|
||||
controller: 'shows/tvrecommended'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/useredit.html',
|
||||
path: '/controllers/dashboard/users/useredit.html',
|
||||
path: 'dashboard/users/useredit.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/users/useredit'
|
||||
|
@ -437,7 +438,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/userlibraryaccess.html',
|
||||
path: '/controllers/dashboard/users/userlibraryaccess.html',
|
||||
path: 'dashboard/users/userlibraryaccess.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/users/userlibraryaccess'
|
||||
|
@ -445,7 +446,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/usernew.html',
|
||||
path: '/controllers/dashboard/users/usernew.html',
|
||||
path: 'dashboard/users/usernew.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/users/usernew'
|
||||
|
@ -453,7 +454,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/userparentalcontrol.html',
|
||||
path: '/controllers/dashboard/users/userparentalcontrol.html',
|
||||
path: 'dashboard/users/userparentalcontrol.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/users/userparentalcontrol'
|
||||
|
@ -461,14 +462,14 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/userpassword.html',
|
||||
path: '/controllers/dashboard/users/userpassword.html',
|
||||
path: 'dashboard/users/userpassword.html',
|
||||
autoFocus: false,
|
||||
controller: 'dashboard/users/userpasswordpage'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
alias: '/userprofiles.html',
|
||||
path: '/controllers/dashboard/users/userprofiles.html',
|
||||
path: 'dashboard/users/userprofiles.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/users/userprofilespage'
|
||||
|
@ -476,7 +477,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/wizardremoteaccess.html',
|
||||
path: '/controllers/wizard/remote/index.html',
|
||||
path: 'wizard/remote/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
controller: 'wizard/remote/index'
|
||||
|
@ -484,7 +485,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/wizardfinish.html',
|
||||
path: '/controllers/wizard/finish/index.html',
|
||||
path: 'wizard/finish/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
controller: 'wizard/finish/index'
|
||||
|
@ -492,7 +493,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/wizardlibrary.html',
|
||||
path: '/controllers/wizard/library.html',
|
||||
path: 'wizard/library.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
controller: 'dashboard/library'
|
||||
|
@ -500,7 +501,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/wizardsettings.html',
|
||||
path: '/controllers/wizard/settings/index.html',
|
||||
path: 'wizard/settings/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
controller: 'wizard/settings/index'
|
||||
|
@ -508,7 +509,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/wizardstart.html',
|
||||
path: '/controllers/wizard/start/index.html',
|
||||
path: 'wizard/start/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
controller: 'wizard/start/index'
|
||||
|
@ -516,7 +517,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/wizarduser.html',
|
||||
path: '/controllers/wizard/user/index.html',
|
||||
path: 'wizard/user/index.html',
|
||||
controller: 'wizard/user/index',
|
||||
autoFocus: false,
|
||||
anonymous: true
|
||||
|
@ -524,7 +525,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/video',
|
||||
path: '/controllers/playback/video/index.html',
|
||||
path: 'playback/video/index.html',
|
||||
controller: 'playback/video/index',
|
||||
autoFocus: false,
|
||||
type: 'video-osd',
|
||||
|
@ -535,7 +536,7 @@ import 'detailtablecss';
|
|||
|
||||
defineRoute({
|
||||
alias: '/queue',
|
||||
path: '/controllers/playback/queue/index.html',
|
||||
path: 'playback/queue/index.html',
|
||||
controller: 'playback/queue/index',
|
||||
autoFocus: false,
|
||||
fullscreen: true,
|
||||
|
@ -548,17 +549,18 @@ import 'detailtablecss';
|
|||
autoFocus: false,
|
||||
enableCache: false,
|
||||
enableContentQueryString: true,
|
||||
roles: 'admin'
|
||||
roles: 'admin',
|
||||
serverRequest: true
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
path: '/',
|
||||
path: '',
|
||||
isDefaultRoute: true,
|
||||
autoFocus: false
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
path: '/index.html',
|
||||
path: 'index.html',
|
||||
autoFocus: false,
|
||||
isDefaultRoute: true
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import focusManager from 'focusManager';
|
||||
import dom from 'dom';
|
||||
import 'scrollStyles';
|
||||
import focusManager from '../components/focusManager';
|
||||
import dom from './dom';
|
||||
import '../assets/css/scrollstyles.css';
|
||||
|
||||
function getBoundingClientRect(elem) {
|
||||
// Support: BlackBerry 5, iOS 3 (original iPhone)
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import playbackManager from 'playbackManager';
|
||||
import syncPlayManager from 'syncPlayManager';
|
||||
import events from 'events';
|
||||
import inputManager from 'inputManager';
|
||||
import focusManager from 'focusManager';
|
||||
import appRouter from 'appRouter';
|
||||
import { playbackManager } from '../components/playback/playbackmanager';
|
||||
import syncPlayManager from '../components/syncPlay/syncPlayManager';
|
||||
import { Events } from 'jellyfin-apiclient';
|
||||
import inputManager from '../scripts/inputManager';
|
||||
import focusManager from '../components/focusManager';
|
||||
import { appRouter } from '../components/appRouter';
|
||||
import ServerConnections from '../components/ServerConnections';
|
||||
import toast from '../components/toast/toast';
|
||||
import alert from '../components/alert';
|
||||
|
||||
const serverNotifications = {};
|
||||
|
||||
|
@ -14,13 +17,9 @@ function notifyApp() {
|
|||
function displayMessage(cmd) {
|
||||
const args = cmd.Arguments;
|
||||
if (args.TimeoutMs) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast({ title: args.Header, text: args.Text });
|
||||
});
|
||||
toast({ title: args.Header, text: args.Text });
|
||||
} else {
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert({ title: args.Header, text: args.Text });
|
||||
});
|
||||
alert({ title: args.Header, text: args.Text });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,7 +190,7 @@ function onMessageReceived(e, msg) {
|
|||
} else if (msg.MessageType === 'UserDataChanged') {
|
||||
if (msg.Data.UserId === apiClient.getCurrentUserId()) {
|
||||
for (let i = 0, length = msg.Data.UserDataList.length; i < length; i++) {
|
||||
events.trigger(serverNotifications, 'UserDataChanged', [apiClient, msg.Data.UserDataList[i]]);
|
||||
Events.trigger(serverNotifications, 'UserDataChanged', [apiClient, msg.Data.UserDataList[i]]);
|
||||
}
|
||||
}
|
||||
} else if (msg.MessageType === 'SyncPlayCommand') {
|
||||
|
@ -199,16 +198,16 @@ function onMessageReceived(e, msg) {
|
|||
} else if (msg.MessageType === 'SyncPlayGroupUpdate') {
|
||||
syncPlayManager.processGroupUpdate(msg.Data, apiClient);
|
||||
} else {
|
||||
events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]);
|
||||
Events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]);
|
||||
}
|
||||
}
|
||||
function bindEvents(apiClient) {
|
||||
events.off(apiClient, 'message', onMessageReceived);
|
||||
events.on(apiClient, 'message', onMessageReceived);
|
||||
Events.off(apiClient, 'message', onMessageReceived);
|
||||
Events.on(apiClient, 'message', onMessageReceived);
|
||||
}
|
||||
|
||||
window.connectionManager.getApiClients().forEach(bindEvents);
|
||||
events.on(window.connectionManager, 'apiclientcreated', function (e, newApiClient) {
|
||||
ServerConnections.getApiClients().forEach(bindEvents);
|
||||
Events.on(ServerConnections, 'apiclientcreated', function (e, newApiClient) {
|
||||
bindEvents(newApiClient);
|
||||
});
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
/* eslint-disable indent */
|
||||
import { AppStorage, Events } from 'jellyfin-apiclient';
|
||||
|
||||
import appStorage from 'appStorage';
|
||||
import events from 'events';
|
||||
|
||||
function getKey(name, userId) {
|
||||
class AppSettings {
|
||||
#getKey(name, userId) {
|
||||
if (userId) {
|
||||
name = userId + '-' + name;
|
||||
}
|
||||
|
@ -11,7 +10,7 @@ import events from 'events';
|
|||
return name;
|
||||
}
|
||||
|
||||
export function enableAutoLogin(val) {
|
||||
enableAutoLogin(val) {
|
||||
if (val !== undefined) {
|
||||
this.set('enableAutoLogin', val.toString());
|
||||
}
|
||||
|
@ -19,7 +18,7 @@ import events from 'events';
|
|||
return this.get('enableAutoLogin') !== 'false';
|
||||
}
|
||||
|
||||
export function enableSystemExternalPlayers(val) {
|
||||
enableSystemExternalPlayers(val) {
|
||||
if (val !== undefined) {
|
||||
this.set('enableSystemExternalPlayers', val.toString());
|
||||
}
|
||||
|
@ -27,7 +26,7 @@ import events from 'events';
|
|||
return this.get('enableSystemExternalPlayers') === 'true';
|
||||
}
|
||||
|
||||
export function enableAutomaticBitrateDetection(isInNetwork, mediaType, val) {
|
||||
enableAutomaticBitrateDetection(isInNetwork, mediaType, val) {
|
||||
const key = 'enableautobitratebitrate-' + mediaType + '-' + isInNetwork;
|
||||
if (val !== undefined) {
|
||||
if (isInNetwork && mediaType === 'Audio') {
|
||||
|
@ -44,7 +43,7 @@ import events from 'events';
|
|||
}
|
||||
}
|
||||
|
||||
export function maxStreamingBitrate(isInNetwork, mediaType, val) {
|
||||
maxStreamingBitrate(isInNetwork, mediaType, val) {
|
||||
const key = 'maxbitrate-' + mediaType + '-' + isInNetwork;
|
||||
if (val !== undefined) {
|
||||
if (isInNetwork && mediaType === 'Audio') {
|
||||
|
@ -62,7 +61,7 @@ import events from 'events';
|
|||
}
|
||||
}
|
||||
|
||||
export function maxStaticMusicBitrate(val) {
|
||||
maxStaticMusicBitrate(val) {
|
||||
if (val !== undefined) {
|
||||
this.set('maxStaticMusicBitrate', val);
|
||||
}
|
||||
|
@ -71,7 +70,7 @@ import events from 'events';
|
|||
return parseInt(this.get('maxStaticMusicBitrate') || defaultValue.toString()) || defaultValue;
|
||||
}
|
||||
|
||||
export function maxChromecastBitrate(val) {
|
||||
maxChromecastBitrate(val) {
|
||||
if (val !== undefined) {
|
||||
this.set('chromecastBitrate1', val);
|
||||
}
|
||||
|
@ -80,28 +79,20 @@ import events from 'events';
|
|||
return val ? parseInt(val) : null;
|
||||
}
|
||||
|
||||
export function set(name, value, userId) {
|
||||
set(name, value, userId) {
|
||||
const currentValue = this.get(name, userId);
|
||||
appStorage.setItem(getKey(name, userId), value);
|
||||
AppStorage.setItem(this.#getKey(name, userId), value);
|
||||
|
||||
if (currentValue !== value) {
|
||||
events.trigger(this, 'change', [name]);
|
||||
Events.trigger(this, 'change', [name]);
|
||||
}
|
||||
}
|
||||
|
||||
export function get(name, userId) {
|
||||
return appStorage.getItem(getKey(name, userId));
|
||||
get(name, userId) {
|
||||
return AppStorage.getItem(this.#getKey(name, userId));
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
enableAutoLogin: enableAutoLogin,
|
||||
enableSystemExternalPlayers: enableSystemExternalPlayers,
|
||||
enableAutomaticBitrateDetection: enableAutomaticBitrateDetection,
|
||||
maxStreamingBitrate: maxStreamingBitrate,
|
||||
maxStaticMusicBitrate: maxStaticMusicBitrate,
|
||||
maxChromecastBitrate: maxChromecastBitrate,
|
||||
set: set,
|
||||
get: get
|
||||
};
|
||||
export default new AppSettings();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import appSettings from 'appSettings';
|
||||
import events from 'events';
|
||||
import appSettings from './appSettings';
|
||||
import { Events } from 'jellyfin-apiclient';
|
||||
|
||||
function onSaveTimeout() {
|
||||
const self = this;
|
||||
|
@ -77,7 +77,7 @@ export class UserSettings {
|
|||
}
|
||||
|
||||
if (currentValue !== value) {
|
||||
events.trigger(this, 'change', [name]);
|
||||
Events.trigger(this, 'change', [name]);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -114,6 +114,33 @@ export class UserSettings {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set 'Allowed Audio Channels'.
|
||||
* @param {string|undefined} val - 'Allowed Audio Channels'.
|
||||
* @return {string} 'Allowed Audio Channels'.
|
||||
*/
|
||||
allowedAudioChannels(val) {
|
||||
if (val !== undefined) {
|
||||
return this.set('allowedAudioChannels', val, false);
|
||||
}
|
||||
|
||||
return this.get('allowedAudioChannels', false) || '-1';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set 'Perfer fMP4-HLS Container' state.
|
||||
* @param {boolean|undefined} val - Flag to enable 'Perfer fMP4-HLS Container' or undefined.
|
||||
* @return {boolean} 'Prefer fMP4-HLS Container' state.
|
||||
*/
|
||||
preferFmp4HlsContainer(val) {
|
||||
if (val !== undefined) {
|
||||
return this.set('preferFmp4HlsContainer', val.toString(), false);
|
||||
}
|
||||
|
||||
val = this.get('preferFmp4HlsContainer', false);
|
||||
return val === 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set 'Cinema Mode' state.
|
||||
* @param {boolean|undefined} val - Flag to enable 'Cinema Mode' or undefined.
|
||||
|
@ -457,6 +484,8 @@ export const importFrom = currentSettings.importFrom.bind(currentSettings);
|
|||
export const set = currentSettings.set.bind(currentSettings);
|
||||
export const get = currentSettings.get.bind(currentSettings);
|
||||
export const serverConfig = currentSettings.serverConfig.bind(currentSettings);
|
||||
export const allowedAudioChannels = currentSettings.allowedAudioChannels.bind(currentSettings);
|
||||
export const preferFmp4HlsContainer = currentSettings.preferFmp4HlsContainer.bind(currentSettings);
|
||||
export const enableCinemaMode = currentSettings.enableCinemaMode.bind(currentSettings);
|
||||
export const enableNextVideoInfoOverlay = currentSettings.enableNextVideoInfoOverlay.bind(currentSettings);
|
||||
export const enableThemeSongs = currentSettings.enableThemeSongs.bind(currentSettings);
|
||||
|
|
|
@ -94,15 +94,41 @@ export function getServers() {
|
|||
});
|
||||
}
|
||||
|
||||
const baseDefaultTheme = {
|
||||
'name': 'Dark',
|
||||
'id': 'dark',
|
||||
'default': true
|
||||
};
|
||||
|
||||
let internalDefaultTheme = baseDefaultTheme;
|
||||
|
||||
const checkDefaultTheme = (themes) => {
|
||||
if (themes) {
|
||||
const defaultTheme = themes.find((theme) => theme.default);
|
||||
|
||||
if (defaultTheme) {
|
||||
internalDefaultTheme = defaultTheme;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
internalDefaultTheme = baseDefaultTheme;
|
||||
};
|
||||
|
||||
export function getThemes() {
|
||||
return getConfig().then(config => {
|
||||
return config.themes;
|
||||
const themes = Array.isArray(config.themes) ? config.themes : [];
|
||||
checkDefaultTheme(themes);
|
||||
return themes;
|
||||
}).catch(error => {
|
||||
console.log('cannot get web config:', error);
|
||||
checkDefaultTheme();
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
export const getDefaultTheme = () => internalDefaultTheme;
|
||||
|
||||
export function getPlugins() {
|
||||
return getConfig().then(config => {
|
||||
return config.plugins;
|
||||
|
@ -111,12 +137,3 @@ export function getPlugins() {
|
|||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
export function getFonts() {
|
||||
return getConfig().then(config => {
|
||||
return config.fonts;
|
||||
}).catch(error => {
|
||||
console.log('cannot get web config:', error);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,38 @@
|
|||
window.getWindowLocationSearch = function(win) {
|
||||
'use strict';
|
||||
import 'core-js/stable';
|
||||
import 'regenerator-runtime/runtime';
|
||||
import 'jquery';
|
||||
import 'fast-text-encoding';
|
||||
import 'intersection-observer';
|
||||
import 'classlist.js';
|
||||
import 'whatwg-fetch';
|
||||
import 'resize-observer-polyfill';
|
||||
import '../assets/css/site.scss';
|
||||
import AppInfo from '../components/AppInfo';
|
||||
import { Events } from 'jellyfin-apiclient';
|
||||
import ServerConnections from '../components/ServerConnections';
|
||||
import globalize from './globalize';
|
||||
import browser from './browser';
|
||||
import keyboardNavigation from './keyboardNavigation';
|
||||
import './mouseManager';
|
||||
import autoFocuser from '../components/autoFocuser';
|
||||
import { appHost } from '../components/apphost';
|
||||
import { getPlugins } from './settings/webSettings';
|
||||
import { pluginManager } from '../components/pluginManager';
|
||||
import packageManager from '../components/packageManager';
|
||||
import { appRouter } from '../components/appRouter';
|
||||
import '../elements/emby-button/emby-button';
|
||||
import './autoThemes';
|
||||
import './libraryMenu';
|
||||
import './routes';
|
||||
import '../components/themeMediaPlayer';
|
||||
import './autoBackdrops';
|
||||
import { pageClassOn, serverAddress } from './clientUtils';
|
||||
import '../libraries/screensavermanager';
|
||||
import './serverNotifications';
|
||||
import '../components/playback/playerSelectionMenu';
|
||||
|
||||
// TODO: Move this elsewhere
|
||||
window.getWindowLocationSearch = function(win) {
|
||||
let search = (win || window).location.search;
|
||||
|
||||
if (!search) {
|
||||
|
@ -14,9 +46,8 @@ window.getWindowLocationSearch = function(win) {
|
|||
return search || '';
|
||||
};
|
||||
|
||||
// TODO: Move this elsewhere
|
||||
window.getParameterByName = function(name, url) {
|
||||
'use strict';
|
||||
|
||||
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||
const regexS = '[\\?&]' + name + '=([^&#]*)';
|
||||
const regex = new RegExp(regexS, 'i');
|
||||
|
@ -29,653 +60,188 @@ window.getParameterByName = function(name, url) {
|
|||
return decodeURIComponent(results[1].replace(/\+/g, ' '));
|
||||
};
|
||||
|
||||
window.pageClassOn = function(eventName, className, fn) {
|
||||
'use strict';
|
||||
Object.freeze(AppInfo);
|
||||
|
||||
document.addEventListener(eventName, function (event) {
|
||||
const target = event.target;
|
||||
|
||||
if (target.classList.contains(className)) {
|
||||
fn.call(target, event);
|
||||
}
|
||||
function loadCoreDictionary() {
|
||||
const languages = ['ar', 'be-by', 'bg-bg', 'ca', 'cs', 'da', 'de', 'el', 'en-gb', 'en-us', 'es', 'es-ar', 'es-mx', 'fa', 'fi', 'fr', 'fr-ca', 'gsw', 'he', 'hi-in', 'hr', 'hu', 'id', 'it', 'ja', 'kk', 'ko', 'lt-lt', 'ms', 'nb', 'nl', 'pl', 'pt-br', 'pt-pt', 'ro', 'ru', 'sk', 'sl-si', 'sv', 'tr', 'uk', 'vi', 'zh-cn', 'zh-hk', 'zh-tw'];
|
||||
const translations = languages.map(function (language) {
|
||||
return {
|
||||
lang: language,
|
||||
path: language + '.json'
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
window.pageIdOn = function(eventName, id, fn) {
|
||||
'use strict';
|
||||
|
||||
document.addEventListener(eventName, function (event) {
|
||||
const target = event.target;
|
||||
|
||||
if (target.id === id) {
|
||||
fn.call(target, event);
|
||||
}
|
||||
globalize.defaultModule('core');
|
||||
return globalize.loadStrings({
|
||||
name: 'core',
|
||||
translations: translations
|
||||
});
|
||||
};
|
||||
|
||||
const AppInfo = {};
|
||||
|
||||
function initClient() {
|
||||
function bindConnectionManagerEvents(connectionManager, events, userSettings) {
|
||||
window.Events = events;
|
||||
|
||||
window.connectionManager.currentApiClient = function () {
|
||||
if (!localApiClient) {
|
||||
const server = window.connectionManager.getLastUsedServer();
|
||||
|
||||
if (server && server.Id) {
|
||||
localApiClient = window.connectionManager.getApiClient(server.Id);
|
||||
}
|
||||
}
|
||||
|
||||
return localApiClient;
|
||||
};
|
||||
|
||||
window.connectionManager.onLocalUserSignedIn = function (user) {
|
||||
localApiClient = window.connectionManager.getApiClient(user.ServerId);
|
||||
window.ApiClient = localApiClient;
|
||||
return userSettings.setUserInfo(user.Id, localApiClient);
|
||||
};
|
||||
|
||||
events.on(connectionManager, 'localusersignedout', function () {
|
||||
userSettings.setUserInfo(null, null);
|
||||
});
|
||||
}
|
||||
|
||||
function createConnectionManager() {
|
||||
return require(['connectionManagerFactory', 'apphost', 'credentialprovider', 'events', 'userSettings', 'apiclient', 'clientUtils'], function (ConnectionManager, appHost, credentialProvider, events, userSettings, apiClientFactory, clientUtils) {
|
||||
appHost = appHost.default || appHost;
|
||||
|
||||
const credentialProviderInstance = new credentialProvider();
|
||||
const promises = [appHost.init()];
|
||||
|
||||
return Promise.all(promises).then(responses => {
|
||||
const capabilities = Dashboard.capabilities(appHost);
|
||||
|
||||
window.connectionManager = new ConnectionManager(credentialProviderInstance, appHost.appName(), appHost.appVersion(), appHost.deviceName(), appHost.deviceId(), capabilities);
|
||||
|
||||
bindConnectionManagerEvents(window.connectionManager, events, userSettings);
|
||||
clientUtils.serverAddress().then(server => {
|
||||
if (!server) {
|
||||
Dashboard.navigate('selectserver.html');
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('creating apiclient singleton');
|
||||
const apiClient = new apiClientFactory(server, appHost.appName(), appHost.appVersion(), appHost.deviceName(), appHost.deviceId());
|
||||
|
||||
apiClient.enableAutomaticNetworking = false;
|
||||
apiClient.manualAddressOnly = true;
|
||||
|
||||
window.connectionManager.addApiClient(apiClient);
|
||||
window.ApiClient = apiClient;
|
||||
console.debug('loaded apiclient singleton');
|
||||
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function returnFirstDependency(obj) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
function returnDefault(obj) {
|
||||
if (obj.default === null) {
|
||||
throw new Error('Object has no default!');
|
||||
}
|
||||
return obj.default;
|
||||
}
|
||||
|
||||
function getBowerPath() {
|
||||
return 'libraries';
|
||||
}
|
||||
|
||||
function getComponentsPath() {
|
||||
return 'components';
|
||||
}
|
||||
|
||||
function getElementsPath() {
|
||||
return 'elements';
|
||||
}
|
||||
|
||||
function getScriptsPath() {
|
||||
return 'scripts';
|
||||
}
|
||||
|
||||
function getPlaybackManager(playbackManager) {
|
||||
window.addEventListener('beforeunload', function () {
|
||||
try {
|
||||
playbackManager.default.onAppClose();
|
||||
} catch (err) {
|
||||
console.error('error in onAppClose: ' + err);
|
||||
}
|
||||
});
|
||||
return playbackManager;
|
||||
}
|
||||
|
||||
function getLayoutManager(layoutManager, appHost) {
|
||||
layoutManager = layoutManager.default || layoutManager;
|
||||
appHost = appHost.default || appHost;
|
||||
if (appHost.getDefaultLayout) {
|
||||
layoutManager.defaultLayout = appHost.getDefaultLayout();
|
||||
}
|
||||
|
||||
layoutManager.init();
|
||||
return layoutManager;
|
||||
}
|
||||
|
||||
function createSharedAppFooter({default: appFooter}) {
|
||||
return new appFooter({});
|
||||
}
|
||||
|
||||
function onRequireJsError(requireType, requireModules) {
|
||||
console.error('RequireJS error: ' + (requireType || 'unknown') + '. Failed modules: ' + (requireModules || []).join(','));
|
||||
}
|
||||
|
||||
function defineResizeObserver() {
|
||||
if (window.ResizeObserver) {
|
||||
define('ResizeObserver', [], function () {
|
||||
return window.ResizeObserver;
|
||||
});
|
||||
} else {
|
||||
define('ResizeObserver', ['resize-observer-polyfill'], returnFirstDependency);
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
define('livetvcss', ['css!assets/css/livetv.css'], returnFirstDependency);
|
||||
define('detailtablecss', ['css!assets/css/detailtable.css'], returnFirstDependency);
|
||||
|
||||
require(['clientUtils']);
|
||||
|
||||
const promises = [];
|
||||
if (!window.fetch) {
|
||||
promises.push(require(['fetch']));
|
||||
}
|
||||
|
||||
Promise.all(promises).then(function () {
|
||||
createConnectionManager().then(function () {
|
||||
console.debug('initAfterDependencies promises resolved');
|
||||
|
||||
require(['globalize', 'browser'], function (globalize, {default: browser}) {
|
||||
window.Globalize = globalize;
|
||||
loadCoreDictionary(globalize).then(function () {
|
||||
onGlobalizeInit(browser, globalize);
|
||||
});
|
||||
});
|
||||
require(['keyboardnavigation'], function(keyboardnavigation) {
|
||||
keyboardnavigation.enable();
|
||||
});
|
||||
require(['mouseManager']);
|
||||
require(['focusPreventScroll']);
|
||||
require(['vendorStyles']);
|
||||
require(['autoFocuser'], function(autoFocuser) {
|
||||
autoFocuser.enable();
|
||||
});
|
||||
require(['globalize', 'events'], function (globalize, events) {
|
||||
events.on(window.connectionManager, 'localusersignedin', globalize.updateCurrentCulture);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function loadCoreDictionary(globalize) {
|
||||
const languages = ['ar', 'be-by', 'bg-bg', 'ca', 'cs', 'da', 'de', 'el', 'en-gb', 'en-us', 'es', 'es-ar', 'es-mx', 'fa', 'fi', 'fr', 'fr-ca', 'gsw', 'he', 'hi-in', 'hr', 'hu', 'id', 'it', 'ja', 'kk', 'ko', 'lt-lt', 'ms', 'nb', 'nl', 'pl', 'pt-br', 'pt-pt', 'ro', 'ru', 'sk', 'sl-si', 'sv', 'tr', 'uk', 'vi', 'zh-cn', 'zh-hk', 'zh-tw'];
|
||||
const translations = languages.map(function (language) {
|
||||
return {
|
||||
lang: language,
|
||||
path: 'strings/' + language + '.json'
|
||||
};
|
||||
});
|
||||
globalize.defaultModule('core');
|
||||
return globalize.loadStrings({
|
||||
name: 'core',
|
||||
translations: translations
|
||||
});
|
||||
}
|
||||
|
||||
function onGlobalizeInit(browser, globalize) {
|
||||
if (window.appMode === 'android') {
|
||||
if (window.location.href.toString().toLowerCase().indexOf('start=backgroundsync') !== -1) {
|
||||
return onAppReady(browser);
|
||||
}
|
||||
}
|
||||
|
||||
document.title = globalize.translateHtml(document.title, 'core');
|
||||
|
||||
if (browser.tv && !browser.android) {
|
||||
console.debug('using system fonts with explicit sizes');
|
||||
require(['systemFontsSizedCss']);
|
||||
} else {
|
||||
console.debug('using default fonts');
|
||||
require(['systemFontsCss']);
|
||||
}
|
||||
|
||||
require(['apphost', 'css!assets/css/librarybrowser'], function (appHost) {
|
||||
appHost = appHost.default || appHost;
|
||||
|
||||
loadPlugins(appHost, browser).then(function () {
|
||||
onAppReady(browser);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function loadPlugins(appHost, browser, shell) {
|
||||
console.groupCollapsed('loading installed plugins');
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(['webSettings'], function (webSettings) {
|
||||
webSettings.getPlugins().then(function (list) {
|
||||
// these two plugins are dependent on features
|
||||
if (!appHost.supports('remotecontrol')) {
|
||||
list.splice(list.indexOf('sessionPlayer'), 1);
|
||||
|
||||
if (!browser.chrome && !browser.opera) {
|
||||
list.splice(list.indexOf('chromecastPlayer', 1));
|
||||
}
|
||||
}
|
||||
|
||||
// add any native plugins
|
||||
if (window.NativeShell) {
|
||||
list = list.concat(window.NativeShell.getPlugins());
|
||||
}
|
||||
|
||||
Promise.all(list.map(loadPlugin))
|
||||
.then(function () {
|
||||
console.debug('finished loading plugins');
|
||||
})
|
||||
.catch(() => reject)
|
||||
.finally(() => {
|
||||
console.groupEnd('loading installed plugins');
|
||||
require(['packageManager'], function (packageManager) {
|
||||
packageManager.default.init().then(resolve, reject);
|
||||
});
|
||||
})
|
||||
;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function loadPlugin(url) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(['pluginManager'], function (pluginManager) {
|
||||
pluginManager.default.loadPlugin(url).then(resolve, reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onAppReady(browser) {
|
||||
console.debug('begin onAppReady');
|
||||
|
||||
// ensure that appHost is loaded in this point
|
||||
require(['apphost', 'appRouter'], function (appHost, appRouter) {
|
||||
appRouter = appRouter.default || appRouter;
|
||||
appHost = appHost.default || appHost;
|
||||
|
||||
window.Emby = {};
|
||||
|
||||
console.debug('onAppReady: loading dependencies');
|
||||
if (browser.iOS) {
|
||||
require(['css!assets/css/ios.css']);
|
||||
}
|
||||
|
||||
window.Emby.Page = appRouter;
|
||||
|
||||
require(['emby-button', 'scripts/autoThemes', 'libraryMenu', 'scripts/routes'], function () {
|
||||
Emby.Page.start({
|
||||
click: false,
|
||||
hashbang: true
|
||||
});
|
||||
|
||||
require(['components/themeMediaPlayer', 'scripts/autoBackdrops']);
|
||||
|
||||
if (!browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
require(['components/nowPlayingBar/nowPlayingBar']);
|
||||
}
|
||||
|
||||
if (appHost.supports('remotecontrol')) {
|
||||
require(['playerSelectionMenu', 'components/playback/remotecontrolautoplay']);
|
||||
}
|
||||
|
||||
require(['libraries/screensavermanager']);
|
||||
|
||||
if (!appHost.supports('physicalvolumecontrol') || browser.touch) {
|
||||
require(['components/playback/volumeosd']);
|
||||
}
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (navigator.mediaSession || window.NativeShell) {
|
||||
require(['mediaSession']);
|
||||
}
|
||||
require(['serverNotifications']);
|
||||
require(['date-fns', 'date-fns/locale']);
|
||||
|
||||
if (!browser.tv && !browser.xboxOne) {
|
||||
require(['components/playback/playbackorientation']);
|
||||
registerServiceWorker();
|
||||
|
||||
if (window.Notification) {
|
||||
require(['components/notifications/notifications']);
|
||||
}
|
||||
}
|
||||
|
||||
require(['playerSelectionMenu']);
|
||||
|
||||
const apiClient = window.connectionManager && window.connectionManager.currentApiClient();
|
||||
if (apiClient) {
|
||||
fetch(apiClient.getUrl('Branding/Css'))
|
||||
.then(function(response) {
|
||||
if (!response.ok) {
|
||||
throw new Error(response.status + ' ' + response.statusText);
|
||||
}
|
||||
return response.text();
|
||||
})
|
||||
.then(function(css) {
|
||||
let style = document.querySelector('#cssBranding');
|
||||
if (!style) {
|
||||
// Inject the branding css as a dom element in body so it will take
|
||||
// precedence over other stylesheets
|
||||
style = document.createElement('style');
|
||||
style.id = 'cssBranding';
|
||||
document.body.appendChild(style);
|
||||
}
|
||||
style.textContent = css;
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.warn('Error applying custom css', err);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function registerServiceWorker() {
|
||||
/* eslint-disable compat/compat */
|
||||
if (navigator.serviceWorker && window.appMode !== 'cordova' && window.appMode !== 'android') {
|
||||
try {
|
||||
navigator.serviceWorker.register('serviceworker.js');
|
||||
} catch (err) {
|
||||
console.error('error registering serviceWorker: ' + err);
|
||||
}
|
||||
} else {
|
||||
console.warn('serviceWorker unsupported');
|
||||
}
|
||||
/* eslint-enable compat/compat */
|
||||
}
|
||||
|
||||
function onWebComponentsReady() {
|
||||
const componentsPath = getComponentsPath();
|
||||
const scriptsPath = getScriptsPath();
|
||||
|
||||
define('filesystem', [scriptsPath + '/filesystem'], returnFirstDependency);
|
||||
|
||||
define('lazyLoader', [componentsPath + '/lazyLoader/lazyLoaderIntersectionObserver'], returnFirstDependency);
|
||||
define('shell', [scriptsPath + '/shell'], returnFirstDependency);
|
||||
|
||||
define('alert', [componentsPath + '/alert'], returnFirstDependency);
|
||||
|
||||
defineResizeObserver();
|
||||
|
||||
define('dialog', [componentsPath + '/dialog/dialog'], returnFirstDependency);
|
||||
|
||||
define('confirm', [componentsPath + '/confirm/confirm'], returnFirstDependency);
|
||||
|
||||
define('prompt', [componentsPath + '/prompt/prompt'], returnFirstDependency);
|
||||
|
||||
define('loading', [componentsPath + '/loading/loading'], returnFirstDependency);
|
||||
define('multi-download', [scriptsPath + '/multiDownload'], returnFirstDependency);
|
||||
define('fileDownloader', [scriptsPath + '/fileDownloader'], returnFirstDependency);
|
||||
|
||||
define('castSenderApiLoader', [componentsPath + '/castSenderApi'], returnFirstDependency);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
let promise;
|
||||
let localApiClient;
|
||||
|
||||
function initRequireJs() {
|
||||
const urlArgs = 'v=' + (window.dashboardVersion || new Date().getDate());
|
||||
|
||||
const bowerPath = getBowerPath();
|
||||
const componentsPath = getComponentsPath();
|
||||
const elementsPath = getElementsPath();
|
||||
const scriptsPath = getScriptsPath();
|
||||
|
||||
const paths = {
|
||||
browserdeviceprofile: 'scripts/browserDeviceProfile',
|
||||
browser: 'scripts/browser',
|
||||
libraryBrowser: 'scripts/libraryBrowser',
|
||||
inputManager: 'scripts/inputManager',
|
||||
datetime: 'scripts/datetime',
|
||||
globalize: 'scripts/globalize',
|
||||
dfnshelper: 'scripts/dfnshelper',
|
||||
libraryMenu: 'scripts/libraryMenu',
|
||||
playlisteditor: componentsPath + '/playlisteditor/playlisteditor',
|
||||
medialibrarycreator: componentsPath + '/mediaLibraryCreator/mediaLibraryCreator',
|
||||
medialibraryeditor: componentsPath + '/mediaLibraryEditor/mediaLibraryEditor',
|
||||
imageoptionseditor: componentsPath + '/imageOptionsEditor/imageOptionsEditor',
|
||||
apphost: componentsPath + '/apphost',
|
||||
visibleinviewport: bowerPath + '/visibleinviewport',
|
||||
qualityoptions: componentsPath + '/qualityOptions',
|
||||
focusManager: componentsPath + '/focusManager',
|
||||
itemHelper: componentsPath + '/itemHelper',
|
||||
itemShortcuts: componentsPath + '/shortcuts',
|
||||
playQueueManager: componentsPath + '/playback/playqueuemanager',
|
||||
nowPlayingHelper: componentsPath + '/playback/nowplayinghelper',
|
||||
pluginManager: componentsPath + '/pluginManager',
|
||||
packageManager: componentsPath + '/packageManager',
|
||||
screensaverManager: componentsPath + '/screensavermanager',
|
||||
clientUtils: scriptsPath + '/clientUtils',
|
||||
appRouter: 'components/appRouter'
|
||||
};
|
||||
|
||||
requirejs.onError = onRequireJsError;
|
||||
requirejs.config({
|
||||
waitSeconds: 0,
|
||||
map: {
|
||||
'*': {
|
||||
css: 'components/require/requirecss',
|
||||
text: 'components/require/requiretext'
|
||||
}
|
||||
},
|
||||
bundles: {
|
||||
bundle: [
|
||||
'fetch',
|
||||
'flvjs',
|
||||
'jstree',
|
||||
'epubjs',
|
||||
'pdfjs',
|
||||
'jQuery',
|
||||
'hlsjs',
|
||||
'howler',
|
||||
'native-promise-only',
|
||||
'resize-observer-polyfill',
|
||||
'swiper',
|
||||
'queryString',
|
||||
'sortable',
|
||||
'webcomponents',
|
||||
'material-icons',
|
||||
'date-fns',
|
||||
'page',
|
||||
'polyfill',
|
||||
'fast-text-encoding',
|
||||
'intersection-observer',
|
||||
'classlist-polyfill',
|
||||
'screenfull',
|
||||
'headroom',
|
||||
'apiclient',
|
||||
'events',
|
||||
'credentialprovider',
|
||||
'connectionManagerFactory',
|
||||
'appStorage',
|
||||
'comicReader'
|
||||
]
|
||||
},
|
||||
urlArgs: urlArgs,
|
||||
paths: paths,
|
||||
onError: onRequireJsError
|
||||
});
|
||||
|
||||
promise = require(['fetch'])
|
||||
.then(() => require(['jQuery', 'polyfill', 'fast-text-encoding', 'intersection-observer', 'classlist-polyfill', 'css!assets/css/site'], (jQuery) => {
|
||||
// Expose jQuery globally
|
||||
window.$ = jQuery;
|
||||
window.jQuery = jQuery;
|
||||
}));
|
||||
|
||||
// define styles
|
||||
// TODO determine which of these files can be moved to the components themselves
|
||||
define('systemFontsCss', ['css!assets/css/fonts'], returnFirstDependency);
|
||||
define('systemFontsSizedCss', ['css!assets/css/fonts.sized'], returnFirstDependency);
|
||||
define('scrollStyles', ['css!assets/css/scrollstyles'], returnFirstDependency);
|
||||
define('dashboardcss', ['css!assets/css/dashboard'], returnFirstDependency);
|
||||
define('programStyles', ['css!' + componentsPath + '/guide/programs'], returnFirstDependency);
|
||||
define('listViewStyle', ['css!' + componentsPath + '/listview/listview'], returnFirstDependency);
|
||||
define('formDialogStyle', ['css!' + componentsPath + '/formdialog'], returnFirstDependency);
|
||||
define('clearButtonStyle', ['css!assets/css/clearbutton'], returnFirstDependency);
|
||||
define('cardStyle', ['css!' + componentsPath + '/cardbuilder/card'], returnFirstDependency);
|
||||
define('flexStyles', ['css!assets/css/flexstyles'], returnFirstDependency);
|
||||
|
||||
// there are several objects that need to be instantiated
|
||||
// TODO find a better way to do this
|
||||
define('appFooter', [componentsPath + '/appFooter/appFooter'], returnFirstDependency);
|
||||
define('appFooter-shared', ['appFooter'], createSharedAppFooter);
|
||||
|
||||
// TODO remove these libraries
|
||||
// all of these have been modified so we need to fix that first
|
||||
define('scroller', [bowerPath + '/scroller'], returnFirstDependency);
|
||||
define('navdrawer', [bowerPath + '/navdrawer/navdrawer'], returnFirstDependency);
|
||||
|
||||
define('emby-button', [elementsPath + '/emby-button/emby-button'], returnFirstDependency);
|
||||
define('paper-icon-button-light', [elementsPath + '/emby-button/paper-icon-button-light'], returnFirstDependency);
|
||||
define('emby-checkbox', [elementsPath + '/emby-checkbox/emby-checkbox'], returnFirstDependency);
|
||||
define('emby-collapse', [elementsPath + '/emby-collapse/emby-collapse'], returnFirstDependency);
|
||||
define('emby-input', [elementsPath + '/emby-input/emby-input'], returnFirstDependency);
|
||||
define('emby-progressring', [elementsPath + '/emby-progressring/emby-progressring'], returnFirstDependency);
|
||||
define('emby-radio', [elementsPath + '/emby-radio/emby-radio'], returnFirstDependency);
|
||||
define('emby-select', [elementsPath + '/emby-select/emby-select'], returnFirstDependency);
|
||||
define('emby-slider', [elementsPath + '/emby-slider/emby-slider'], returnFirstDependency);
|
||||
define('emby-textarea', [elementsPath + '/emby-textarea/emby-textarea'], returnFirstDependency);
|
||||
define('emby-toggle', [elementsPath + '/emby-toggle/emby-toggle'], returnFirstDependency);
|
||||
define('emby-scroller', [elementsPath + '/emby-scroller/emby-scroller'], returnFirstDependency);
|
||||
define('emby-tabs', [elementsPath + '/emby-tabs/emby-tabs'], returnFirstDependency);
|
||||
define('emby-scrollbuttons', [elementsPath + '/emby-scrollbuttons/emby-scrollbuttons'], returnFirstDependency);
|
||||
define('emby-itemrefreshindicator', [elementsPath + '/emby-itemrefreshindicator/emby-itemrefreshindicator'], returnFirstDependency);
|
||||
define('emby-itemscontainer', [elementsPath + '/emby-itemscontainer/emby-itemscontainer'], returnFirstDependency);
|
||||
define('emby-playstatebutton', [elementsPath + '/emby-playstatebutton/emby-playstatebutton'], returnFirstDependency);
|
||||
define('emby-ratingbutton', [elementsPath + '/emby-ratingbutton/emby-ratingbutton'], returnFirstDependency);
|
||||
define('emby-progressbar', [elementsPath + '/emby-progressbar/emby-progressbar'], returnFirstDependency);
|
||||
define('emby-programcell', [elementsPath + '/emby-programcell/emby-programcell'], returnFirstDependency);
|
||||
|
||||
define('webSettings', [scriptsPath + '/settings/webSettings'], returnFirstDependency);
|
||||
define('appSettings', [scriptsPath + '/settings/appSettings'], returnFirstDependency);
|
||||
define('userSettings', [scriptsPath + '/settings/userSettings'], returnFirstDependency);
|
||||
define('autocast', [scriptsPath + '/autocast'], returnFirstDependency);
|
||||
|
||||
define('mediaSession', [componentsPath + '/playback/mediasession'], returnFirstDependency);
|
||||
define('actionsheet', [componentsPath + '/actionSheet/actionSheet'], returnFirstDependency);
|
||||
define('tunerPicker', [componentsPath + '/tunerPicker'], returnFirstDependency);
|
||||
define('mainTabsManager', [componentsPath + '/maintabsmanager'], returnFirstDependency);
|
||||
define('imageLoader', [componentsPath + '/images/imageLoader'], returnFirstDependency);
|
||||
define('directorybrowser', [componentsPath + '/directorybrowser/directorybrowser'], returnFirstDependency);
|
||||
define('metadataEditor', [componentsPath + '/metadataEditor/metadataEditor'], returnFirstDependency);
|
||||
define('personEditor', [componentsPath + '/metadataEditor/personEditor'], returnFirstDependency);
|
||||
define('playerSelectionMenu', [componentsPath + '/playback/playerSelectionMenu'], returnFirstDependency);
|
||||
define('playerSettingsMenu', [componentsPath + '/playback/playersettingsmenu'], returnFirstDependency);
|
||||
define('playMethodHelper', [componentsPath + '/playback/playmethodhelper'], returnFirstDependency);
|
||||
define('brightnessOsd', [componentsPath + '/playback/brightnessosd'], returnFirstDependency);
|
||||
define('alphaNumericShortcuts', [scriptsPath + '/alphanumericshortcuts'], returnFirstDependency);
|
||||
define('multiSelect', [componentsPath + '/multiSelect/multiSelect'], returnFirstDependency);
|
||||
define('alphaPicker', [componentsPath + '/alphaPicker/alphaPicker'], returnFirstDependency);
|
||||
define('tabbedView', [componentsPath + '/tabbedview/tabbedview'], returnFirstDependency);
|
||||
define('collectionEditor', [componentsPath + '/collectionEditor/collectionEditor'], returnFirstDependency);
|
||||
define('playlistEditor', [componentsPath + '/playlisteditor/playlisteditor'], returnFirstDependency);
|
||||
define('recordingCreator', [componentsPath + '/recordingcreator/recordingcreator'], returnFirstDependency);
|
||||
define('recordingEditor', [componentsPath + '/recordingcreator/recordingeditor'], returnFirstDependency);
|
||||
define('seriesRecordingEditor', [componentsPath + '/recordingcreator/seriesrecordingeditor'], returnFirstDependency);
|
||||
define('recordingFields', [componentsPath + '/recordingcreator/recordingfields'], returnFirstDependency);
|
||||
define('recordingButton', [componentsPath + '/recordingcreator/recordingbutton'], returnFirstDependency);
|
||||
define('recordingHelper', [componentsPath + '/recordingcreator/recordinghelper'], returnFirstDependency);
|
||||
define('subtitleEditor', [componentsPath + '/subtitleeditor/subtitleeditor'], returnFirstDependency);
|
||||
define('subtitleSync', [componentsPath + '/subtitlesync/subtitlesync'], returnFirstDependency);
|
||||
define('itemIdentifier', [componentsPath + '/itemidentifier/itemidentifier'], returnFirstDependency);
|
||||
define('itemMediaInfo', [componentsPath + '/itemMediaInfo/itemMediaInfo'], returnFirstDependency);
|
||||
define('mediaInfo', [componentsPath + '/mediainfo/mediainfo'], returnFirstDependency);
|
||||
define('itemContextMenu', [componentsPath + '/itemContextMenu'], returnFirstDependency);
|
||||
define('imageEditor', [componentsPath + '/imageeditor/imageeditor'], returnFirstDependency);
|
||||
define('imageDownloader', [componentsPath + '/imageDownloader/imageDownloader'], returnFirstDependency);
|
||||
define('dom', [scriptsPath + '/dom'], returnFirstDependency);
|
||||
define('playerStats', [componentsPath + '/playerstats/playerstats'], returnFirstDependency);
|
||||
define('searchFields', [componentsPath + '/search/searchfields'], returnFirstDependency);
|
||||
define('searchResults', [componentsPath + '/search/searchresults'], returnFirstDependency);
|
||||
define('upNextDialog', [componentsPath + '/upnextdialog/upnextdialog'], returnFirstDependency);
|
||||
define('subtitleAppearanceHelper', [componentsPath + '/subtitlesettings/subtitleappearancehelper'], returnFirstDependency);
|
||||
define('subtitleSettings', [componentsPath + '/subtitlesettings/subtitlesettings'], returnFirstDependency);
|
||||
define('settingsHelper', [componentsPath + '/settingshelper'], returnFirstDependency);
|
||||
define('displaySettings', [componentsPath + '/displaySettings/displaySettings'], returnFirstDependency);
|
||||
define('playbackSettings', [componentsPath + '/playbackSettings/playbackSettings'], returnFirstDependency);
|
||||
define('homescreenSettings', [componentsPath + '/homeScreenSettings/homeScreenSettings'], returnFirstDependency);
|
||||
define('quickConnectSettings', [componentsPath + '/quickConnectSettings/quickConnectSettings'], returnFirstDependency);
|
||||
define('playbackManager', [componentsPath + '/playback/playbackmanager'], getPlaybackManager);
|
||||
define('timeSyncManager', [componentsPath + '/syncPlay/timeSyncManager'], returnDefault);
|
||||
define('groupSelectionMenu', [componentsPath + '/syncPlay/groupSelectionMenu'], returnFirstDependency);
|
||||
define('syncPlayManager', [componentsPath + '/syncPlay/syncPlayManager'], returnDefault);
|
||||
define('playbackPermissionManager', [componentsPath + '/syncPlay/playbackPermissionManager'], returnDefault);
|
||||
define('layoutManager', [componentsPath + '/layoutManager', 'apphost'], getLayoutManager);
|
||||
define('homeSections', [componentsPath + '/homesections/homesections'], returnFirstDependency);
|
||||
define('playMenu', [componentsPath + '/playmenu'], returnFirstDependency);
|
||||
define('refreshDialog', [componentsPath + '/refreshdialog/refreshdialog'], returnFirstDependency);
|
||||
define('backdrop', [componentsPath + '/backdrop/backdrop'], returnFirstDependency);
|
||||
define('fetchHelper', [componentsPath + '/fetchhelper'], returnFirstDependency);
|
||||
define('cardBuilder', [componentsPath + '/cardbuilder/cardBuilder'], returnFirstDependency);
|
||||
define('peoplecardbuilder', [componentsPath + '/cardbuilder/peoplecardbuilder'], returnFirstDependency);
|
||||
define('chaptercardbuilder', [componentsPath + '/cardbuilder/chaptercardbuilder'], returnFirstDependency);
|
||||
define('deleteHelper', [scriptsPath + '/deleteHelper'], returnFirstDependency);
|
||||
define('tvguide', [componentsPath + '/guide/guide'], returnFirstDependency);
|
||||
define('guide-settings-dialog', [componentsPath + '/guide/guide-settings'], returnFirstDependency);
|
||||
define('viewManager', [componentsPath + '/viewManager/viewManager'], function (viewManager) {
|
||||
window.ViewManager = viewManager.default;
|
||||
viewManager.default.dispatchPageEvents(true);
|
||||
return viewManager;
|
||||
});
|
||||
define('slideshow', [componentsPath + '/slideshow/slideshow'], returnFirstDependency);
|
||||
define('focusPreventScroll', ['legacy/focusPreventScroll'], returnFirstDependency);
|
||||
define('vendorStyles', ['legacy/vendorStyles'], returnFirstDependency);
|
||||
define('userdataButtons', [componentsPath + '/userdatabuttons/userdatabuttons'], returnFirstDependency);
|
||||
define('listView', [componentsPath + '/listview/listview'], returnFirstDependency);
|
||||
define('indicators', [componentsPath + '/indicators/indicators'], returnFirstDependency);
|
||||
define('viewSettings', [componentsPath + '/viewSettings/viewSettings'], returnFirstDependency);
|
||||
define('filterMenu', [componentsPath + '/filtermenu/filtermenu'], returnFirstDependency);
|
||||
define('sortMenu', [componentsPath + '/sortmenu/sortmenu'], returnFirstDependency);
|
||||
define('sanitizefilename', [componentsPath + '/sanitizeFilename'], returnFirstDependency);
|
||||
define('toast', [componentsPath + '/toast/toast'], returnFirstDependency);
|
||||
define('scrollHelper', [scriptsPath + '/scrollHelper'], returnFirstDependency);
|
||||
define('touchHelper', [scriptsPath + '/touchHelper'], returnFirstDependency);
|
||||
define('imageUploader', [componentsPath + '/imageUploader/imageUploader'], returnFirstDependency);
|
||||
define('htmlMediaHelper', [componentsPath + '/htmlMediaHelper'], returnFirstDependency);
|
||||
define('viewContainer', [componentsPath + '/viewContainer'], returnFirstDependency);
|
||||
define('dialogHelper', [componentsPath + '/dialogHelper/dialogHelper'], returnFirstDependency);
|
||||
define('serverNotifications', [scriptsPath + '/serverNotifications'], returnFirstDependency);
|
||||
define('skinManager', [scriptsPath + '/themeManager'], returnFirstDependency);
|
||||
define('keyboardnavigation', [scriptsPath + '/keyboardNavigation'], returnFirstDependency);
|
||||
define('mouseManager', [scriptsPath + '/mouseManager'], returnFirstDependency);
|
||||
define('scrollManager', [componentsPath + '/scrollManager'], returnFirstDependency);
|
||||
define('autoFocuser', [componentsPath + '/autoFocuser'], returnFirstDependency);
|
||||
define('apiClientResolver', [], function () {
|
||||
return function () {
|
||||
return window.ApiClient;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
initRequireJs();
|
||||
promise.then(onWebComponentsReady);
|
||||
}
|
||||
|
||||
initClient();
|
||||
function init() {
|
||||
serverAddress().then(server => {
|
||||
if (!server) {
|
||||
Dashboard.navigate('selectserver.html');
|
||||
return;
|
||||
}
|
||||
|
||||
ServerConnections.initApiClient(server);
|
||||
}).then(() => {
|
||||
console.debug('initAfterDependencies promises resolved');
|
||||
|
||||
loadCoreDictionary().then(function () {
|
||||
onGlobalizeInit();
|
||||
});
|
||||
|
||||
keyboardNavigation.enable();
|
||||
autoFocuser.enable();
|
||||
|
||||
Events.on(ServerConnections, 'localusersignedin', globalize.updateCurrentCulture);
|
||||
});
|
||||
}
|
||||
|
||||
function onGlobalizeInit() {
|
||||
if (window.appMode === 'android') {
|
||||
if (window.location.href.toString().toLowerCase().indexOf('start=backgroundsync') !== -1) {
|
||||
return onAppReady();
|
||||
}
|
||||
}
|
||||
|
||||
document.title = globalize.translateHtml(document.title, 'core');
|
||||
|
||||
if (browser.tv && !browser.android) {
|
||||
console.debug('using system fonts with explicit sizes');
|
||||
import('../assets/css/fonts.sized.scss');
|
||||
} else {
|
||||
console.debug('using default fonts');
|
||||
import('../assets/css/fonts.scss');
|
||||
}
|
||||
|
||||
import('../assets/css/librarybrowser.css');
|
||||
|
||||
loadPlugins().then(function () {
|
||||
onAppReady();
|
||||
});
|
||||
}
|
||||
|
||||
function loadPlugins() {
|
||||
console.groupCollapsed('loading installed plugins');
|
||||
console.dir(pluginManager);
|
||||
return getPlugins().then(function (list) {
|
||||
// these two plugins are dependent on features
|
||||
if (!appHost.supports('remotecontrol')) {
|
||||
list.splice(list.indexOf('sessionPlayer'), 1);
|
||||
|
||||
if (!browser.chrome && !browser.opera) {
|
||||
list.splice(list.indexOf('chromecastPlayer', 1));
|
||||
}
|
||||
}
|
||||
|
||||
// add any native plugins
|
||||
if (window.NativeShell) {
|
||||
list = list.concat(window.NativeShell.getPlugins());
|
||||
}
|
||||
|
||||
Promise.all(list.map((plugin) => {
|
||||
return pluginManager.loadPlugin(import(/* webpackChunkName: "[request]" */ `../plugins/${plugin}`));
|
||||
}))
|
||||
.then(function () {
|
||||
console.debug('finished loading plugins');
|
||||
})
|
||||
.catch(() => console.debug('failed loading plugins'))
|
||||
.finally(() => {
|
||||
console.groupEnd('loading installed plugins');
|
||||
packageManager.init();
|
||||
})
|
||||
;
|
||||
});
|
||||
}
|
||||
|
||||
function onAppReady() {
|
||||
console.debug('begin onAppReady');
|
||||
|
||||
console.debug('onAppReady: loading dependencies');
|
||||
|
||||
if (browser.iOS) {
|
||||
import('../assets/css/ios.scss');
|
||||
}
|
||||
|
||||
appRouter.start({
|
||||
click: false,
|
||||
hashbang: true
|
||||
});
|
||||
|
||||
if (!browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
import('../components/nowPlayingBar/nowPlayingBar');
|
||||
}
|
||||
|
||||
if (appHost.supports('remotecontrol')) {
|
||||
import('../components/playback/playerSelectionMenu');
|
||||
import('../components/playback/remotecontrolautoplay');
|
||||
}
|
||||
|
||||
if (!appHost.supports('physicalvolumecontrol') || browser.touch) {
|
||||
import('../components/playback/volumeosd');
|
||||
}
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (navigator.mediaSession || window.NativeShell) {
|
||||
import('../components/playback/mediasession');
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.xboxOne) {
|
||||
import('../components/playback/playbackorientation');
|
||||
registerServiceWorker();
|
||||
|
||||
if (window.Notification) {
|
||||
import('../components/notifications/notifications');
|
||||
}
|
||||
}
|
||||
|
||||
const apiClient = ServerConnections.currentApiClient();
|
||||
if (apiClient) {
|
||||
fetch(apiClient.getUrl('Branding/Css'))
|
||||
.then(function(response) {
|
||||
if (!response.ok) {
|
||||
throw new Error(response.status + ' ' + response.statusText);
|
||||
}
|
||||
return response.text();
|
||||
})
|
||||
.then(function(css) {
|
||||
let style = document.querySelector('#cssBranding');
|
||||
if (!style) {
|
||||
// Inject the branding css as a dom element in body so it will take
|
||||
// precedence over other stylesheets
|
||||
style = document.createElement('style');
|
||||
style.id = 'cssBranding';
|
||||
document.body.appendChild(style);
|
||||
}
|
||||
style.textContent = css;
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.warn('Error applying custom css', err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function registerServiceWorker() {
|
||||
/* eslint-disable compat/compat */
|
||||
if (navigator.serviceWorker && window.appMode !== 'cordova' && window.appMode !== 'android') {
|
||||
try {
|
||||
navigator.serviceWorker.register('/serviceworker.js').then(() =>
|
||||
console.log('serviceWorker registered')
|
||||
).catch(error =>
|
||||
console.log('error registering serviceWorker: ' + error)
|
||||
);
|
||||
} catch (err) {
|
||||
console.error('error registering serviceWorker: ' + err);
|
||||
}
|
||||
} else {
|
||||
console.warn('serviceWorker unsupported');
|
||||
}
|
||||
/* eslint-enable compat/compat */
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
pageClassOn('viewshow', 'standalonePage', function () {
|
||||
document.querySelector('.skinHeader').classList.add('noHeaderRight');
|
||||
|
|
3
src/scripts/standalone.js
Normal file
3
src/scripts/standalone.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
window.appMode = 'standalone';
|
||||
|
||||
import('./site');
|
|
@ -1,12 +1,13 @@
|
|||
|
||||
import events from 'events';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import globalize from 'globalize';
|
||||
import 'emby-button';
|
||||
import { Events } from 'jellyfin-apiclient';
|
||||
import serverNotifications from '../scripts/serverNotifications';
|
||||
import globalize from '../scripts/globalize';
|
||||
import '../elements/emby-button/emby-button';
|
||||
import ServerConnections from '../components/ServerConnections';
|
||||
|
||||
export default function (options) {
|
||||
function pollTasks() {
|
||||
window.connectionManager.getApiClient(serverId).getScheduledTasks({
|
||||
ServerConnections.getApiClient(serverId).getScheduledTasks({
|
||||
IsEnabled: true
|
||||
}).then(updateTasks);
|
||||
}
|
||||
|
@ -63,7 +64,7 @@ export default function (options) {
|
|||
}
|
||||
|
||||
function onScheduledTaskMessageConfirmed(id) {
|
||||
window.connectionManager.getApiClient(serverId).startScheduledTask(id).then(pollTasks);
|
||||
ServerConnections.getApiClient(serverId).startScheduledTask(id).then(pollTasks);
|
||||
}
|
||||
|
||||
function onButtonClick() {
|
||||
|
@ -81,13 +82,13 @@ export default function (options) {
|
|||
const serverId = ApiClient.serverId();
|
||||
|
||||
function onPollIntervalFired() {
|
||||
if (!window.connectionManager.getApiClient(serverId).isMessageChannelOpen()) {
|
||||
if (!ServerConnections.getApiClient(serverId).isMessageChannelOpen()) {
|
||||
pollTasks();
|
||||
}
|
||||
}
|
||||
|
||||
function startInterval() {
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
const apiClient = ServerConnections.getApiClient(serverId);
|
||||
|
||||
if (pollInterval) {
|
||||
clearInterval(pollInterval);
|
||||
|
@ -97,7 +98,7 @@ export default function (options) {
|
|||
}
|
||||
|
||||
function stopInterval() {
|
||||
window.connectionManager.getApiClient(serverId).sendMessage('ScheduledTasksInfoStop');
|
||||
ServerConnections.getApiClient(serverId).sendMessage('ScheduledTasksInfoStop');
|
||||
|
||||
if (pollInterval) {
|
||||
clearInterval(pollInterval);
|
||||
|
@ -110,12 +111,12 @@ export default function (options) {
|
|||
|
||||
if (options.mode == 'off') {
|
||||
button.removeEventListener('click', onButtonClick);
|
||||
events.off(serverNotifications, 'ScheduledTasksInfo', onScheduledTasksUpdate);
|
||||
Events.off(serverNotifications, 'ScheduledTasksInfo', onScheduledTasksUpdate);
|
||||
stopInterval();
|
||||
} else {
|
||||
button.addEventListener('click', onButtonClick);
|
||||
pollTasks();
|
||||
startInterval();
|
||||
events.on(serverNotifications, 'ScheduledTasksInfo', onScheduledTasksUpdate);
|
||||
Events.on(serverNotifications, 'ScheduledTasksInfo', onScheduledTasksUpdate);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import * as webSettings from 'webSettings';
|
||||
import { getDefaultTheme, getThemes as getConfiguredThemes } from './settings/webSettings';
|
||||
|
||||
let themeStyleElement = document.querySelector('#cssTheme');
|
||||
let currentThemeId;
|
||||
|
@ -12,14 +12,22 @@ function unloadTheme() {
|
|||
}
|
||||
|
||||
function getThemes() {
|
||||
return webSettings.getThemes();
|
||||
return getConfiguredThemes();
|
||||
}
|
||||
|
||||
function getThemeStylesheetInfo(id) {
|
||||
return getThemes().then(themes => {
|
||||
const theme = themes.find(theme => {
|
||||
return id ? theme.id === id : theme.default;
|
||||
});
|
||||
let theme;
|
||||
|
||||
if (id) {
|
||||
theme = themes.find(currentTheme => {
|
||||
return currentTheme.id === id;
|
||||
});
|
||||
}
|
||||
|
||||
if (!theme) {
|
||||
theme = getDefaultTheme();
|
||||
}
|
||||
|
||||
return {
|
||||
stylesheetPath: 'themes/' + theme.id + '/theme.css',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import dom from 'dom';
|
||||
import events from 'events';
|
||||
import dom from '../scripts/dom';
|
||||
import { Events } from 'jellyfin-apiclient';
|
||||
|
||||
function getTouches(e) {
|
||||
return e.changedTouches || e.targetTouches || e.touches;
|
||||
|
@ -73,13 +73,13 @@ class TouchHelper {
|
|||
lastDeltaY = deltaY;
|
||||
|
||||
if (deltaX > swipeXThreshold && Math.abs(deltaY) < swipeXMaxY) {
|
||||
events.trigger(self, 'swiperight', [touchTarget]);
|
||||
Events.trigger(self, 'swiperight', [touchTarget]);
|
||||
} else if (deltaX < (0 - swipeXThreshold) && Math.abs(deltaY) < swipeXMaxY) {
|
||||
events.trigger(self, 'swipeleft', [touchTarget]);
|
||||
Events.trigger(self, 'swipeleft', [touchTarget]);
|
||||
} else if ((deltaY < (0 - swipeYThreshold) || thresholdYMet) && Math.abs(deltaX) < swipeXMaxY) {
|
||||
thresholdYMet = true;
|
||||
|
||||
events.trigger(self, 'swipeup', [touchTarget, {
|
||||
Events.trigger(self, 'swipeup', [touchTarget, {
|
||||
deltaY: deltaY,
|
||||
deltaX: deltaX,
|
||||
clientX: clientX,
|
||||
|
@ -90,7 +90,7 @@ class TouchHelper {
|
|||
} else if ((deltaY > swipeYThreshold || thresholdYMet) && Math.abs(deltaX) < swipeXMaxY) {
|
||||
thresholdYMet = true;
|
||||
|
||||
events.trigger(self, 'swipedown', [touchTarget, {
|
||||
Events.trigger(self, 'swipedown', [touchTarget, {
|
||||
deltaY: deltaY,
|
||||
deltaX: deltaX,
|
||||
clientX: clientX,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue