mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge pull request #3 from LogicalPhallacy/master
update to current master
This commit is contained in:
commit
78ca7e48d1
413 changed files with 1701 additions and 22902 deletions
9
.drone.yml
Normal file
9
.drone.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
kind: pipeline
|
||||
name: eslint
|
||||
|
||||
steps:
|
||||
- name: run
|
||||
image: nextcloudci/eslint:eslint-1
|
||||
commands:
|
||||
- ./run-eslint.sh
|
3
.eslintrc.yml
Normal file
3
.eslintrc.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
env:
|
||||
browser: true
|
||||
amd: true
|
18
run-eslint.sh
Executable file
18
run-eslint.sh
Executable file
|
@ -0,0 +1,18 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
# used this pull request for reference
|
||||
# https://github.com/nextcloud/spreed/pull/48
|
||||
ESLINT=$(which eslint || true)
|
||||
if [ -z "$ESLINT" ]
|
||||
then
|
||||
echo "could not find eslint in $PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo checking scripts with $ESLINT
|
||||
find -name "*.js" -print0 | xargs -0 $ESLINT
|
||||
|
||||
# use this line to test changes locally
|
||||
#find src -name "*.js" -exec sh -c 'npx eslint $1' -- {} \;
|
|
@ -1,6 +1,11 @@
|
|||
define(["apiclientcore", "localassetmanager"], function(ApiClient, localassetmanager) {
|
||||
//TODO: (vitorsemeano) modify this lines for webpack
|
||||
define(["bower_components/apiclient/apiclientcore", "localassetmanager"], function(ApiClient, localassetmanager) {
|
||||
"use strict";
|
||||
|
||||
if ("cordova" !== window.appMode && "android" !== window.appMode) {
|
||||
return ApiClient;
|
||||
}
|
||||
|
||||
function isLocalId(str) {
|
||||
return startsWith(str, localPrefix)
|
||||
}
|
53
src/bower_components/apiclient/appStorage.js
vendored
Normal file
53
src/bower_components/apiclient/appStorage.js
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function onCachePutFail(e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
function updateCache(instance) {
|
||||
if (instance.cache) {
|
||||
instance.cache.put("data", new Response(JSON.stringify(instance.localData))).catch(onCachePutFail);
|
||||
}
|
||||
}
|
||||
|
||||
function onCacheOpened(result) {
|
||||
this.cache = result;
|
||||
this.localData = {};
|
||||
}
|
||||
|
||||
function MyStore() {
|
||||
|
||||
this.setItem = function(name, value) {
|
||||
localStorage.setItem(name, value);
|
||||
|
||||
if (this.localData && this.localData[name] !== value) {
|
||||
this.localData[name] = value;
|
||||
updateCache(this);
|
||||
}
|
||||
};
|
||||
|
||||
this.getItem = function(name) {
|
||||
return localStorage.getItem(name);
|
||||
};
|
||||
|
||||
this.removeItem = function(name) {
|
||||
localStorage.removeItem(name);
|
||||
|
||||
if (this.localData) {
|
||||
delete this.localData[name];
|
||||
updateCache(this);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
if (self.caches) {
|
||||
self.caches.open("embydata").then(onCacheOpened.bind(this));
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Error opening cache: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
return new MyStore;
|
||||
});
|
|
@ -269,12 +269,15 @@ define(["events", "apiclient", "appStorage"], function(events, apiClientFactory,
|
|||
});
|
||||
resolve(servers)
|
||||
};
|
||||
require(["serverdiscovery"], function(serverDiscovery) {
|
||||
serverDiscovery.findServers(1e3).then(onFinish, function() {
|
||||
|
||||
if (window.NativeShell && typeof window.NativeShell.findServers === 'function') {
|
||||
window.NativeShell.findServers(1e3).then(onFinish, function() {
|
||||
onFinish([])
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
} else {
|
||||
resolve([]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function convertEndpointAddressToManualAddress(info) {
|
3
src/bower_components/apiclient/package.json
vendored
Normal file
3
src/bower_components/apiclient/package.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"main": "apiclient.js"
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function MyStore() {}
|
||||
|
||||
function updateCache(instance) {
|
||||
instance.cache.put("data", new Response(JSON.stringify(instance.localData)))
|
||||
}
|
||||
return MyStore.prototype.init = function() {
|
||||
var instance = this;
|
||||
return caches.open("embydata").then(function(result) {
|
||||
instance.cache = result, instance.localData = {}
|
||||
})
|
||||
}, MyStore.prototype.setItem = function(name, value) {
|
||||
if (this.localData) {
|
||||
this.localData[name] !== value && (this.localData[name] = value, updateCache(this))
|
||||
}
|
||||
}, MyStore.prototype.getItem = function(name) {
|
||||
if (this.localData) return this.localData[name]
|
||||
}, MyStore.prototype.removeItem = function(name) {
|
||||
this.localData && (this.localData[name] = null, delete this.localData[name], updateCache(this))
|
||||
}, new MyStore
|
||||
});
|
|
@ -1,37 +0,0 @@
|
|||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function onCachePutFail(e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
function updateCache(instance) {
|
||||
var cache = instance.cache;
|
||||
cache && cache.put("data", new Response(JSON.stringify(instance.localData))).catch(onCachePutFail)
|
||||
}
|
||||
|
||||
function onCacheOpened(result) {
|
||||
this.cache = result, this.localData = {}
|
||||
}
|
||||
|
||||
function MyStore() {
|
||||
try {
|
||||
self.caches && caches.open("embydata").then(onCacheOpened.bind(this))
|
||||
} catch (err) {
|
||||
console.log("Error opening cache: " + err)
|
||||
}
|
||||
}
|
||||
return MyStore.prototype.setItem = function(name, value) {
|
||||
localStorage.setItem(name, value);
|
||||
var localData = this.localData;
|
||||
if (localData) {
|
||||
localData[name] !== value && (localData[name] = value, updateCache(this))
|
||||
}
|
||||
}, MyStore.prototype.getItem = function(name) {
|
||||
return localStorage.getItem(name)
|
||||
}, MyStore.prototype.removeItem = function(name) {
|
||||
localStorage.removeItem(name);
|
||||
var localData = this.localData;
|
||||
localData && (localData[name] = null, delete localData[name], updateCache(this))
|
||||
}, new MyStore
|
||||
});
|
|
@ -1,14 +0,0 @@
|
|||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function MyStore() {
|
||||
this.localData = {}
|
||||
}
|
||||
return MyStore.prototype.setItem = function(name, value) {
|
||||
this.localData[name] = value
|
||||
}, MyStore.prototype.getItem = function(name) {
|
||||
return this.localData[name]
|
||||
}, MyStore.prototype.removeItem = function(name) {
|
||||
this.localData[name] = null
|
||||
}, new MyStore
|
||||
});
|
|
@ -1,8 +0,0 @@
|
|||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function FileUpload() {}
|
||||
return FileUpload.prototype.upload = function(file, url) {
|
||||
return Promise.reject()
|
||||
}, FileUpload
|
||||
});
|
|
@ -1,8 +0,0 @@
|
|||
define([], function() {
|
||||
"use strict";
|
||||
return {
|
||||
findServers: function(timeoutMs) {
|
||||
return Promise.resolve([])
|
||||
}
|
||||
}
|
||||
});
|
15
src/bower_components/emby-apiclient/wakeonlan.js
vendored
15
src/bower_components/emby-apiclient/wakeonlan.js
vendored
|
@ -1,15 +0,0 @@
|
|||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function send(info) {
|
||||
return Promise.reject()
|
||||
}
|
||||
|
||||
function isSupported() {
|
||||
return !1
|
||||
}
|
||||
return {
|
||||
send: send,
|
||||
isSupported: isSupported
|
||||
}
|
||||
});
|
|
@ -1,34 +0,0 @@
|
|||
define(['dialog', 'globalize'], function (dialog, globalize) {
|
||||
'use strict';
|
||||
|
||||
return function (text, title) {
|
||||
|
||||
var options;
|
||||
if (typeof text === 'string') {
|
||||
options = {
|
||||
title: title,
|
||||
text: text
|
||||
};
|
||||
} else {
|
||||
options = text;
|
||||
}
|
||||
|
||||
var items = [];
|
||||
|
||||
items.push({
|
||||
name: globalize.translate('ButtonGotIt'),
|
||||
id: 'ok',
|
||||
type: 'submit'
|
||||
});
|
||||
|
||||
options.buttons = items;
|
||||
|
||||
return dialog(options).then(function (result) {
|
||||
if (result === 'ok') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
};
|
||||
});
|
|
@ -1,23 +0,0 @@
|
|||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
function replaceAll(str, find, replace) {
|
||||
|
||||
return str.split(find).join(replace);
|
||||
}
|
||||
|
||||
return function (options) {
|
||||
|
||||
if (typeof options === 'string') {
|
||||
options = {
|
||||
text: options
|
||||
};
|
||||
}
|
||||
|
||||
var text = replaceAll(options.text || '', '<br/>', '\n');
|
||||
|
||||
alert(text);
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
});
|
|
@ -1,12 +0,0 @@
|
|||
define(['multi-download'], function (multiDownload) {
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
download: function (items) {
|
||||
|
||||
multiDownload(items.map(function (item) {
|
||||
return item.url;
|
||||
}));
|
||||
}
|
||||
};
|
||||
});
|
|
@ -1,12 +0,0 @@
|
|||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
fileExists: function (path) {
|
||||
return Promise.reject();
|
||||
},
|
||||
directoryExists: function (path) {
|
||||
return Promise.reject();
|
||||
}
|
||||
};
|
||||
});
|
|
@ -1,80 +0,0 @@
|
|||
define(['playbackManager', 'itemHelper'], function (playbackManager, itemHelper) {
|
||||
"use strict";
|
||||
|
||||
function getRequirePromise(deps) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(deps, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function validatePlayback(options) {
|
||||
|
||||
var feature = 'playback';
|
||||
if (options.item && (options.item.Type === 'TvChannel' || options.item.Type === 'Recording')) {
|
||||
feature = 'livetv';
|
||||
}
|
||||
|
||||
if (feature === 'playback') {
|
||||
var player = playbackManager.getCurrentPlayer();
|
||||
if (player && !player.isLocalPlayer) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
return getRequirePromise(["registrationServices"]).then(function (registrationServices) {
|
||||
|
||||
return registrationServices.validateFeature(feature, options).then(function (result) {
|
||||
|
||||
if (result && result.enableTimeLimit) {
|
||||
startAutoStopTimer();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var autoStopTimeout;
|
||||
function startAutoStopTimer() {
|
||||
stopAutoStopTimer();
|
||||
autoStopTimeout = setTimeout(onAutoStopTimeout, 63000);
|
||||
}
|
||||
|
||||
function onAutoStopTimeout() {
|
||||
stopAutoStopTimer();
|
||||
playbackManager.stop();
|
||||
}
|
||||
|
||||
function stopAutoStopTimer() {
|
||||
|
||||
var timeout = autoStopTimeout;
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
autoStopTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
function PlaybackValidation() {
|
||||
|
||||
this.name = 'Playback validation';
|
||||
this.type = 'preplayintercept';
|
||||
this.id = 'playbackvalidation';
|
||||
this.order = -1;
|
||||
}
|
||||
|
||||
PlaybackValidation.prototype.intercept = function (options) {
|
||||
|
||||
// Don't care about video backdrops, or theme music or any kind of non-fullscreen playback
|
||||
if (!options.fullscreen) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (options.item && itemHelper.isLocalItem(options.item)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return validatePlayback(options);
|
||||
};
|
||||
|
||||
return PlaybackValidation;
|
||||
});
|
|
@ -1,25 +0,0 @@
|
|||
if (!Array.prototype.filter) {
|
||||
Array.prototype.filter = function (fun /*, thisp*/) {
|
||||
"use strict";
|
||||
|
||||
if (this == null)
|
||||
throw new TypeError();
|
||||
|
||||
var t = Object(this);
|
||||
var len = t.length >>> 0;
|
||||
if (typeof fun != "function")
|
||||
throw new TypeError();
|
||||
|
||||
var res = [];
|
||||
var thisp = arguments[1];
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (i in t) {
|
||||
var val = t[i]; // in case fun mutates this
|
||||
if (fun.call(thisp, val, i, t))
|
||||
res.push(val);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
if (!Function.prototype.bind) {
|
||||
Function.prototype.bind = function (oThis) {
|
||||
if (typeof this !== 'function') {
|
||||
// closest thing possible to the ECMAScript 5
|
||||
// internal IsCallable function
|
||||
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
||||
}
|
||||
|
||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
||||
fToBind = this,
|
||||
fNOP = function () { },
|
||||
fBound = function () {
|
||||
return fToBind.apply(this instanceof fNOP
|
||||
? this
|
||||
: oThis,
|
||||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
||||
};
|
||||
|
||||
if (this.prototype) {
|
||||
// Function.prototype doesn't have a prototype property
|
||||
fNOP.prototype = this.prototype;
|
||||
}
|
||||
fBound.prototype = new fNOP();
|
||||
|
||||
return fBound;
|
||||
};
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
if (typeof Object.assign != 'function') {
|
||||
(function () {
|
||||
Object.assign = function (target) {
|
||||
'use strict';
|
||||
if (target === undefined || target === null) {
|
||||
throw new TypeError('Cannot convert undefined or null to object');
|
||||
}
|
||||
|
||||
var output = Object(target);
|
||||
for (var index = 1; index < arguments.length; index++) {
|
||||
var source = arguments[index];
|
||||
if (source !== undefined && source !== null) {
|
||||
for (var nextKey in source) {
|
||||
if (source.hasOwnProperty(nextKey)) {
|
||||
output[nextKey] = source[nextKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
};
|
||||
})();
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
|
||||
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
|
||||
|
||||
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
|
||||
|
||||
// MIT license
|
||||
|
||||
(function () {
|
||||
var lastTime = 0;
|
||||
var vendors = ['ms', 'moz', 'webkit', 'o'];
|
||||
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
||||
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
|
||||
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame']
|
||||
|| window[vendors[x] + 'CancelRequestAnimationFrame'];
|
||||
}
|
||||
|
||||
if (!window.requestAnimationFrame)
|
||||
window.requestAnimationFrame = function (callback, element) {
|
||||
var currTime = new Date().getTime();
|
||||
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
|
||||
var id = window.setTimeout(function () { callback(currTime + timeToCall); },
|
||||
timeToCall);
|
||||
lastTime = currTime + timeToCall;
|
||||
return id;
|
||||
};
|
||||
|
||||
if (!window.cancelAnimationFrame)
|
||||
window.cancelAnimationFrame = function (id) {
|
||||
clearTimeout(id);
|
||||
};
|
||||
}());
|
|
@ -1,16 +0,0 @@
|
|||
define(['appSettings', 'loading', 'apphost', 'events', 'shell', 'globalize', 'dialogHelper', 'connectionManager', 'layoutManager', 'emby-button', 'emby-linkbutton'], function (appSettings, loading, appHost, events, shell, globalize, dialogHelper, connectionManager, layoutManager) {
|
||||
'use strict';
|
||||
|
||||
function validateFeature(feature, options) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function showPremiereInfo() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return {
|
||||
validateFeature: validateFeature,
|
||||
showPremiereInfo: showPremiereInfo
|
||||
};
|
||||
});
|
|
@ -1,6 +0,0 @@
|
|||
self.addEventListener('sync', function (event) {
|
||||
'use strict';
|
||||
|
||||
if (event.tag === 'emby-sync') {
|
||||
}
|
||||
});
|
21
src/bower_components/emby-webcomponents/shell.js
vendored
21
src/bower_components/emby-webcomponents/shell.js
vendored
|
@ -1,21 +0,0 @@
|
|||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
openUrl: function (url) {
|
||||
window.open(url, '_blank');
|
||||
},
|
||||
canExec: false,
|
||||
exec: function (options) {
|
||||
// options.path
|
||||
// options.arguments
|
||||
return Promise.reject();
|
||||
},
|
||||
enableFullscreen: function () {
|
||||
// do nothing since this is for native apps
|
||||
},
|
||||
disableFullscreen: function () {
|
||||
// do nothing since this is for native apps
|
||||
}
|
||||
};
|
||||
});
|
|
@ -1,355 +0,0 @@
|
|||
define(['apphost', 'userSettings', 'browser', 'events', 'pluginManager', 'backdrop', 'globalize', 'require', 'appSettings'], function (appHost, userSettings, browser, events, pluginManager, backdrop, globalize, require, appSettings) {
|
||||
'use strict';
|
||||
|
||||
var currentSkin;
|
||||
|
||||
function getCurrentSkin() {
|
||||
return currentSkin;
|
||||
}
|
||||
|
||||
function getRequirePromise(deps) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(deps, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function loadSkin(id) {
|
||||
|
||||
var newSkin = pluginManager.plugins().filter(function (p) {
|
||||
return p.id === id;
|
||||
})[0];
|
||||
|
||||
if (!newSkin) {
|
||||
newSkin = pluginManager.plugins().filter(function (p) {
|
||||
return p.id === 'defaultskin';
|
||||
})[0];
|
||||
}
|
||||
|
||||
var unloadPromise;
|
||||
|
||||
if (currentSkin) {
|
||||
|
||||
if (currentSkin.id === newSkin.id) {
|
||||
// Nothing to do, it's already the active skin
|
||||
return Promise.resolve(currentSkin);
|
||||
}
|
||||
unloadPromise = unloadSkin(currentSkin);
|
||||
} else {
|
||||
unloadPromise = Promise.resolve();
|
||||
}
|
||||
|
||||
return unloadPromise.then(function () {
|
||||
var deps = newSkin.getDependencies();
|
||||
|
||||
console.log('Loading skin dependencies');
|
||||
|
||||
return getRequirePromise(deps).then(function () {
|
||||
|
||||
console.log('Skin dependencies loaded');
|
||||
|
||||
var strings = newSkin.getTranslations ? newSkin.getTranslations() : [];
|
||||
|
||||
return globalize.loadStrings({
|
||||
|
||||
name: newSkin.id,
|
||||
strings: strings
|
||||
|
||||
}).then(function () {
|
||||
|
||||
globalize.defaultModule(newSkin.id);
|
||||
return loadSkinHeader(newSkin);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function unloadSkin(skin) {
|
||||
|
||||
unloadTheme();
|
||||
backdrop.clear();
|
||||
|
||||
console.log('Unloading skin: ' + skin.name);
|
||||
|
||||
// TODO: unload css
|
||||
|
||||
return skin.unload().then(function () {
|
||||
document.dispatchEvent(new CustomEvent("skinunload", {
|
||||
detail: {
|
||||
name: skin.name
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function loadSkinHeader(skin) {
|
||||
|
||||
return getSkinHeader(skin).then(function (headerHtml) {
|
||||
|
||||
document.querySelector('.skinHeader').innerHTML = headerHtml;
|
||||
|
||||
currentSkin = skin;
|
||||
skin.load();
|
||||
|
||||
return skin;
|
||||
});
|
||||
}
|
||||
|
||||
var cacheParam = new Date().getTime();
|
||||
|
||||
function getSkinHeader(skin) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
if (!skin.getHeaderTemplate) {
|
||||
resolve('');
|
||||
return;
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
var url = skin.getHeaderTemplate();
|
||||
url += url.indexOf('?') === -1 ? '?' : '&';
|
||||
url += 'v=' + cacheParam;
|
||||
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
xhr.onload = function (e) {
|
||||
if (this.status < 400) {
|
||||
resolve(this.response);
|
||||
} else {
|
||||
resolve('');
|
||||
}
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
function loadUserSkin(options) {
|
||||
|
||||
var skin = userSettings.get('skin', false) || 'defaultskin';
|
||||
|
||||
loadSkin(skin).then(function (skin) {
|
||||
|
||||
options = options || {};
|
||||
if (options.start) {
|
||||
Emby.Page.invokeShortcut(options.start);
|
||||
} else {
|
||||
Emby.Page.goHome();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
events.on(userSettings, 'change', function (e, name) {
|
||||
if (name === 'skin' || name === 'language') {
|
||||
loadUserSkin();
|
||||
}
|
||||
});
|
||||
|
||||
var themeStyleElement;
|
||||
var currentThemeId;
|
||||
function unloadTheme() {
|
||||
var elem = themeStyleElement;
|
||||
if (elem) {
|
||||
|
||||
elem.parentNode.removeChild(elem);
|
||||
themeStyleElement = null;
|
||||
currentThemeId = null;
|
||||
}
|
||||
}
|
||||
|
||||
function getThemes() {
|
||||
|
||||
if (currentSkin.getThemes) {
|
||||
return currentSkin.getThemes();
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
var skinManager = {
|
||||
getCurrentSkin: getCurrentSkin,
|
||||
loadSkin: loadSkin,
|
||||
loadUserSkin: loadUserSkin,
|
||||
getThemes: getThemes
|
||||
};
|
||||
|
||||
function onRegistrationSuccess() {
|
||||
appSettings.set('appthemesregistered', 'true');
|
||||
}
|
||||
|
||||
function onRegistrationFailure() {
|
||||
appSettings.set('appthemesregistered', 'false');
|
||||
}
|
||||
|
||||
function isRegistered() {
|
||||
|
||||
getRequirePromise(['registrationServices']).then(function (registrationServices) {
|
||||
registrationServices.validateFeature('themes', {
|
||||
|
||||
showDialog: false
|
||||
|
||||
}).then(onRegistrationSuccess, onRegistrationFailure);
|
||||
});
|
||||
|
||||
return appSettings.get('appthemesregistered') !== 'false';
|
||||
}
|
||||
|
||||
function getThemeStylesheetInfo(id, requiresRegistration, isDefaultProperty) {
|
||||
|
||||
var themes = skinManager.getThemes();
|
||||
var defaultTheme;
|
||||
var selectedTheme;
|
||||
|
||||
for (var i = 0, length = themes.length; i < length; i++) {
|
||||
|
||||
var theme = themes[i];
|
||||
if (theme[isDefaultProperty]) {
|
||||
defaultTheme = theme;
|
||||
}
|
||||
if (id === theme.id) {
|
||||
selectedTheme = theme;
|
||||
}
|
||||
}
|
||||
|
||||
selectedTheme = selectedTheme || defaultTheme;
|
||||
|
||||
if (selectedTheme.id !== defaultTheme.id && requiresRegistration && !isRegistered()) {
|
||||
selectedTheme = defaultTheme;
|
||||
}
|
||||
|
||||
var embyWebComponentsBowerPath = 'bower_components/emby-webcomponents';
|
||||
|
||||
return {
|
||||
stylesheetPath: require.toUrl(embyWebComponentsBowerPath + '/themes/' + selectedTheme.id + '/theme.css'),
|
||||
themeId: selectedTheme.id
|
||||
};
|
||||
}
|
||||
|
||||
var themeResources = {};
|
||||
var lastSound = 0;
|
||||
var currentSound;
|
||||
|
||||
function loadThemeResources(id) {
|
||||
|
||||
lastSound = 0;
|
||||
|
||||
if (currentSound) {
|
||||
currentSound.stop();
|
||||
currentSound = null;
|
||||
}
|
||||
|
||||
backdrop.clear();
|
||||
}
|
||||
|
||||
function onThemeLoaded() {
|
||||
document.documentElement.classList.remove('preload');
|
||||
|
||||
|
||||
try {
|
||||
var color = getComputedStyle(document.querySelector('.skinHeader')).getPropertyValue("background-color");
|
||||
|
||||
if (color) {
|
||||
appHost.setThemeColor(color);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log('Error setting theme color: ' + err);
|
||||
}
|
||||
}
|
||||
|
||||
skinManager.setTheme = function (id, context) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var requiresRegistration = true;
|
||||
|
||||
if (currentThemeId && currentThemeId === id) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
var isDefaultProperty = context === 'serverdashboard' ? 'isDefaultServerDashboard' : 'isDefault';
|
||||
var info = getThemeStylesheetInfo(id, requiresRegistration, isDefaultProperty);
|
||||
|
||||
if (currentThemeId && currentThemeId === info.themeId) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
var linkUrl = info.stylesheetPath;
|
||||
|
||||
unloadTheme();
|
||||
|
||||
var link = document.createElement('link');
|
||||
|
||||
link.setAttribute('rel', 'stylesheet');
|
||||
link.setAttribute('type', 'text/css');
|
||||
link.onload = function () {
|
||||
|
||||
onThemeLoaded();
|
||||
resolve();
|
||||
};
|
||||
|
||||
link.setAttribute('href', linkUrl);
|
||||
document.head.appendChild(link);
|
||||
themeStyleElement = link;
|
||||
currentThemeId = info.themeId;
|
||||
loadThemeResources(info.themeId);
|
||||
|
||||
onViewBeforeShow({});
|
||||
});
|
||||
};
|
||||
|
||||
function onViewBeforeShow(e) {
|
||||
|
||||
if (e.detail && e.detail.type === 'video-osd') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (themeResources.backdrop) {
|
||||
|
||||
backdrop.setBackdrop(themeResources.backdrop);
|
||||
}
|
||||
|
||||
if (!browser.mobile && userSettings.enableThemeSongs()) {
|
||||
if (lastSound === 0) {
|
||||
|
||||
if (themeResources.themeSong) {
|
||||
playSound(themeResources.themeSong);
|
||||
}
|
||||
|
||||
} else if ((new Date().getTime() - lastSound) > 30000) {
|
||||
if (themeResources.effect) {
|
||||
playSound(themeResources.effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('viewshow', onViewBeforeShow);
|
||||
|
||||
function playSound(path, volume) {
|
||||
|
||||
lastSound = new Date().getTime();
|
||||
|
||||
require(['howler'], function (howler) {
|
||||
|
||||
try {
|
||||
var sound = new Howl({
|
||||
src: [path],
|
||||
volume: volume || 0.1
|
||||
});
|
||||
|
||||
sound.play();
|
||||
currentSound = sound;
|
||||
}
|
||||
catch (err) {
|
||||
console.log('Error playing sound: ' + err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return skinManager;
|
||||
});
|
|
@ -1,188 +0,0 @@
|
|||
define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby-button'], function (connectionManager, serverNotifications, events, globalize, EmbyButtonPrototype) {
|
||||
'use strict';
|
||||
|
||||
function onClick(e) {
|
||||
|
||||
var button = this;
|
||||
var id = button.getAttribute('data-id');
|
||||
var serverId = button.getAttribute('data-serverid');
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
|
||||
if (!button.classList.contains('downloadbutton-on')) {
|
||||
|
||||
require(['syncDialog'], function (syncDialog) {
|
||||
syncDialog.showMenu({
|
||||
|
||||
items: [id],
|
||||
mode: 'download',
|
||||
serverId: serverId
|
||||
|
||||
}).then(function () {
|
||||
|
||||
button.dispatchEvent(new CustomEvent('download', {
|
||||
cancelable: false
|
||||
}));
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
require(['confirm'], function (confirm) {
|
||||
|
||||
confirm({
|
||||
|
||||
text: globalize.translate('ConfirmRemoveDownload'),
|
||||
confirmText: globalize.translate('RemoveDownload'),
|
||||
cancelText: globalize.translate('KeepDownload'),
|
||||
primary: 'cancel'
|
||||
|
||||
}).then(function () {
|
||||
apiClient.cancelSyncItems([id]);
|
||||
|
||||
button.dispatchEvent(new CustomEvent('download-cancel', {
|
||||
cancelable: false
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function updateSyncStatus(button, syncPercent) {
|
||||
|
||||
var icon = button.iconElement;
|
||||
if (!icon) {
|
||||
button.iconElement = button.querySelector('i');
|
||||
icon = button.iconElement;
|
||||
}
|
||||
|
||||
if (syncPercent != null) {
|
||||
button.classList.add('downloadbutton-on');
|
||||
|
||||
if (icon) {
|
||||
icon.classList.add('downloadbutton-icon-on');
|
||||
}
|
||||
|
||||
} else {
|
||||
button.classList.remove('downloadbutton-on');
|
||||
|
||||
if (icon) {
|
||||
icon.classList.remove('downloadbutton-icon-on');
|
||||
}
|
||||
}
|
||||
|
||||
if ((syncPercent || 0) >= 100) {
|
||||
button.classList.add('downloadbutton-complete');
|
||||
|
||||
if (icon) {
|
||||
icon.classList.add('downloadbutton-icon-complete');
|
||||
}
|
||||
} else {
|
||||
button.classList.remove('downloadbutton-complete');
|
||||
|
||||
if (icon) {
|
||||
icon.classList.remove('downloadbutton-icon-complete');
|
||||
}
|
||||
}
|
||||
|
||||
var text;
|
||||
if ((syncPercent || 0) >= 100) {
|
||||
text = globalize.translate('Downloaded');
|
||||
} else if (syncPercent != null) {
|
||||
text = globalize.translate('Downloading');
|
||||
} else {
|
||||
text = globalize.translate('Download');
|
||||
}
|
||||
|
||||
var textElement = button.querySelector('.emby-downloadbutton-downloadtext');
|
||||
if (textElement) {
|
||||
textElement.innerHTML = text;
|
||||
}
|
||||
|
||||
button.title = text;
|
||||
}
|
||||
|
||||
function clearEvents(button) {
|
||||
|
||||
button.removeEventListener('click', onClick);
|
||||
}
|
||||
|
||||
function bindEvents(button) {
|
||||
|
||||
clearEvents(button);
|
||||
|
||||
button.addEventListener('click', onClick);
|
||||
}
|
||||
|
||||
var EmbyDownloadButtonPrototype = Object.create(EmbyButtonPrototype);
|
||||
|
||||
EmbyDownloadButtonPrototype.createdCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyButtonPrototype.createdCallback) {
|
||||
EmbyButtonPrototype.createdCallback.call(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyDownloadButtonPrototype.attachedCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyButtonPrototype.attachedCallback) {
|
||||
EmbyButtonPrototype.attachedCallback.call(this);
|
||||
}
|
||||
|
||||
var itemId = this.getAttribute('data-id');
|
||||
var serverId = this.getAttribute('data-serverid');
|
||||
if (itemId && serverId) {
|
||||
|
||||
bindEvents(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyDownloadButtonPrototype.detachedCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyButtonPrototype.detachedCallback) {
|
||||
EmbyButtonPrototype.detachedCallback.call(this);
|
||||
}
|
||||
|
||||
clearEvents(this);
|
||||
|
||||
this.iconElement = null;
|
||||
};
|
||||
|
||||
function fetchAndUpdate(button, item) {
|
||||
|
||||
connectionManager.getApiClient(item.ServerId).getSyncStatus(item.Id).then(function (result) {
|
||||
|
||||
updateSyncStatus(button, result.Progress);
|
||||
|
||||
}, function () {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
EmbyDownloadButtonPrototype.setItem = function (item) {
|
||||
|
||||
if (item) {
|
||||
|
||||
this.setAttribute('data-id', item.Id);
|
||||
this.setAttribute('data-serverid', item.ServerId);
|
||||
|
||||
fetchAndUpdate(this, item);
|
||||
|
||||
bindEvents(this);
|
||||
|
||||
} else {
|
||||
|
||||
this.removeAttribute('data-id');
|
||||
this.removeAttribute('data-serverid');
|
||||
clearEvents(this);
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-downloadbutton', {
|
||||
prototype: EmbyDownloadButtonPrototype,
|
||||
extends: 'button'
|
||||
});
|
||||
});
|
736
src/bower_components/emby-webcomponents/sync/sync.js
vendored
736
src/bower_components/emby-webcomponents/sync/sync.js
vendored
|
@ -1,736 +0,0 @@
|
|||
define(['apphost', 'globalize', 'connectionManager', 'layoutManager', 'focusManager', 'scrollHelper', 'appSettings', 'registrationServices', 'dialogHelper', 'paper-icon-button-light', 'formDialogStyle'], function (appHost, globalize, connectionManager, layoutManager, focusManager, scrollHelper, appSettings, registrationServices, dialogHelper) {
|
||||
'use strict';
|
||||
|
||||
var currentDialogOptions;
|
||||
|
||||
function submitJob(dlg, apiClient, userId, syncOptions, form) {
|
||||
|
||||
if (!userId) {
|
||||
throw new Error('userId cannot be null');
|
||||
}
|
||||
|
||||
if (!syncOptions) {
|
||||
throw new Error('syncOptions cannot be null');
|
||||
}
|
||||
|
||||
if (!form) {
|
||||
throw new Error('form cannot be null');
|
||||
}
|
||||
|
||||
var selectSyncTarget = form.querySelector('#selectSyncTarget');
|
||||
var target = selectSyncTarget ? selectSyncTarget.value : null;
|
||||
|
||||
if (!target) {
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
toast(globalize.translate('PleaseSelectDeviceToSyncTo'));
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
var options = {
|
||||
|
||||
userId: userId,
|
||||
TargetId: target,
|
||||
|
||||
ParentId: syncOptions.ParentId,
|
||||
Category: syncOptions.Category
|
||||
};
|
||||
|
||||
setJobValues(options, form);
|
||||
|
||||
if (syncOptions.items && syncOptions.items.length) {
|
||||
options.ItemIds = (syncOptions.items || []).map(function (i) {
|
||||
return i.Id || i;
|
||||
}).join(',');
|
||||
}
|
||||
|
||||
apiClient.ajax({
|
||||
|
||||
type: "POST",
|
||||
url: apiClient.getUrl("Sync/Jobs"),
|
||||
data: JSON.stringify(options),
|
||||
contentType: "application/json",
|
||||
dataType: 'json'
|
||||
|
||||
}).then(function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
require(['toast'], function (toast) {
|
||||
|
||||
showSubmissionToast(target, apiClient);
|
||||
|
||||
if (syncOptions.mode === 'download') {
|
||||
syncNow();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function showSubmissionToast(targetId, apiClient) {
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
|
||||
var msg = targetId === apiClient.deviceId() ?
|
||||
globalize.translate('DownloadingDots') :
|
||||
globalize.translate('SyncingDots');
|
||||
|
||||
toast(msg);
|
||||
});
|
||||
}
|
||||
|
||||
function syncNow() {
|
||||
require(['localsync'], function (localSync) {
|
||||
localSync.sync();
|
||||
});
|
||||
}
|
||||
|
||||
function submitQuickSyncJob(apiClient, userId, targetId, syncOptions) {
|
||||
|
||||
if (!userId) {
|
||||
throw new Error('userId cannot be null');
|
||||
}
|
||||
|
||||
if (!syncOptions) {
|
||||
throw new Error('syncOptions cannot be null');
|
||||
}
|
||||
|
||||
if (!targetId) {
|
||||
throw new Error('targetId cannot be null');
|
||||
}
|
||||
|
||||
var options = {
|
||||
|
||||
userId: userId,
|
||||
TargetId: targetId,
|
||||
|
||||
ParentId: syncOptions.ParentId,
|
||||
Category: syncOptions.Category,
|
||||
Quality: syncOptions.Quality,
|
||||
Bitrate: syncOptions.Bitrate
|
||||
};
|
||||
|
||||
if (syncOptions.items && syncOptions.items.length) {
|
||||
options.ItemIds = (syncOptions.items || []).map(function (i) {
|
||||
return i.Id || i;
|
||||
}).join(',');
|
||||
}
|
||||
|
||||
return apiClient.ajax({
|
||||
|
||||
type: "POST",
|
||||
url: apiClient.getUrl("Sync/Jobs"),
|
||||
data: JSON.stringify(options),
|
||||
contentType: "application/json",
|
||||
dataType: 'json'
|
||||
|
||||
}).then(function () {
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
|
||||
showSubmissionToast(targetId, apiClient);
|
||||
|
||||
if (syncOptions.mode === 'download') {
|
||||
syncNow();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setJobValues(job, form) {
|
||||
|
||||
var txtBitrate = form.querySelector('#txtBitrate');
|
||||
var bitrate = txtBitrate ? txtBitrate.value : null;
|
||||
|
||||
if (bitrate) {
|
||||
bitrate = parseFloat(bitrate) * 1000000;
|
||||
}
|
||||
job.Bitrate = bitrate;
|
||||
|
||||
var selectQuality = form.querySelector('#selectQuality');
|
||||
if (selectQuality) {
|
||||
job.Quality = selectQuality.value;
|
||||
|
||||
appSettings.set('sync-lastquality', job.Quality || '');
|
||||
}
|
||||
|
||||
var selectProfile = form.querySelector('#selectProfile');
|
||||
if (selectProfile) {
|
||||
job.Profile = selectProfile.value;
|
||||
}
|
||||
|
||||
var txtItemLimit = form.querySelector('#txtItemLimit');
|
||||
if (txtItemLimit) {
|
||||
job.ItemLimit = txtItemLimit.value || null;
|
||||
}
|
||||
|
||||
var chkSyncNewContent = form.querySelector('#chkSyncNewContent');
|
||||
if (chkSyncNewContent) {
|
||||
job.SyncNewContent = chkSyncNewContent.checked;
|
||||
}
|
||||
|
||||
var chkUnwatchedOnly = form.querySelector('#chkUnwatchedOnly');
|
||||
if (chkUnwatchedOnly) {
|
||||
job.UnwatchedOnly = chkUnwatchedOnly.checked;
|
||||
}
|
||||
}
|
||||
|
||||
function renderForm(options) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['emby-checkbox', 'emby-input', 'emby-select'], function () {
|
||||
|
||||
renderFormInternal(options, connectionManager.deviceId(), resolve);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderFormInternal(options, defaultTargetId, resolve) {
|
||||
|
||||
var elem = options.elem;
|
||||
var dialogOptions = options.dialogOptions;
|
||||
|
||||
var targets = dialogOptions.Targets;
|
||||
|
||||
var html = '';
|
||||
|
||||
var mode = options.mode;
|
||||
var targetContainerClass = mode === 'download' ? ' hide' : '';
|
||||
|
||||
var syncTargetLabel = mode === 'convert' ? globalize.translate('LabelConvertTo') : globalize.translate('LabelSyncTo');
|
||||
|
||||
if (options.readOnlySyncTarget) {
|
||||
html += '<div class="inputContainer' + targetContainerClass + '">';
|
||||
html += '<input is="emby-input" type="text" id="selectSyncTarget" readonly label="' + syncTargetLabel + '"/>';
|
||||
html += '</div>';
|
||||
} else {
|
||||
html += '<div class="selectContainer' + targetContainerClass + '">';
|
||||
html += '<select is="emby-select" id="selectSyncTarget" required="required" label="' + syncTargetLabel + '">';
|
||||
|
||||
html += targets.map(function (t) {
|
||||
|
||||
var isSelected = defaultTargetId === t.Id;
|
||||
var selectedHtml = isSelected ? ' selected="selected"' : '';
|
||||
return '<option' + selectedHtml + ' value="' + t.Id + '">' + t.Name + '</option>';
|
||||
|
||||
}).join('');
|
||||
html += '</select>';
|
||||
if (!targets.length) {
|
||||
html += '<div class="fieldDescription">' + globalize.translate('LabelSyncNoTargetsHelp') + '</div>';
|
||||
}
|
||||
|
||||
if (appHost.supports('externallinks')) {
|
||||
html += '<div class="fieldDescription"><a is="emby-linkbutton" class="button-link lnkLearnMore" href="https://github.com/MediaBrowser/Wiki/wiki/Sync" target="_blank">' + globalize.translate('LearnMore') + '</a></div>';
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '<div class="fldProfile selectContainer hide">';
|
||||
html += '<select is="emby-select" id="selectProfile" label="' + globalize.translate('LabelProfile') + '">';
|
||||
html += '</select>';
|
||||
html += '<div class="fieldDescription profileDescription"></div>';
|
||||
html += '</div>';
|
||||
|
||||
html += '<div class="fldQuality selectContainer hide">';
|
||||
html += '<select is="emby-select" id="selectQuality" required="required" label="' + globalize.translate('LabelQuality') + '">';
|
||||
html += '</select>';
|
||||
html += '<div class="fieldDescription qualityDescription"></div>';
|
||||
html += '</div>';
|
||||
|
||||
html += '<div class="fldBitrate inputContainer hide">';
|
||||
html += '<input is="emby-input" type="number" step=".1" min=".1" id="txtBitrate" label="' + globalize.translate('LabelBitrateMbps') + '"/>';
|
||||
html += '</div>';
|
||||
|
||||
if (dialogOptions.Options.indexOf('UnwatchedOnly') !== -1) {
|
||||
html += '<div class="checkboxContainer checkboxContainer-withDescription">';
|
||||
html += '<label>';
|
||||
html += '<input is="emby-checkbox" type="checkbox" id="chkUnwatchedOnly"/>';
|
||||
|
||||
if (mode === 'convert') {
|
||||
html += '<span>' + globalize.translate('ConvertUnwatchedVideosOnly') + '</span>';
|
||||
} else {
|
||||
html += '<span>' + globalize.translate('SyncUnwatchedVideosOnly') + '</span>';
|
||||
}
|
||||
|
||||
html += '</label>';
|
||||
|
||||
if (mode === 'convert') {
|
||||
html += '<div class="fieldDescription checkboxFieldDescription">' + globalize.translate('ConvertUnwatchedVideosOnlyHelp') + '</div>';
|
||||
} else {
|
||||
html += '<div class="fieldDescription checkboxFieldDescription">' + globalize.translate('SyncUnwatchedVideosOnlyHelp') + '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
if (dialogOptions.Options.indexOf('SyncNewContent') !== -1) {
|
||||
html += '<div class="checkboxContainer checkboxContainer-withDescription">';
|
||||
html += '<label>';
|
||||
html += '<input is="emby-checkbox" type="checkbox" id="chkSyncNewContent"/>';
|
||||
|
||||
if (mode === 'convert') {
|
||||
html += '<span>' + globalize.translate('AutomaticallyConvertNewContent') + '</span>';
|
||||
} else {
|
||||
html += '<span>' + globalize.translate('AutomaticallySyncNewContent') + '</span>';
|
||||
}
|
||||
|
||||
html += '</label>';
|
||||
|
||||
if (mode === 'convert') {
|
||||
html += '<div class="fieldDescription checkboxFieldDescription">' + globalize.translate('AutomaticallyConvertNewContentHelp') + '</div>';
|
||||
} else {
|
||||
html += '<div class="fieldDescription checkboxFieldDescription">' + globalize.translate('AutomaticallySyncNewContentHelp') + '</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
if (dialogOptions.Options.indexOf('ItemLimit') !== -1) {
|
||||
html += '<div class="inputContainer">';
|
||||
html += '<input is="emby-input" type="number" step="1" min="1" id="txtItemLimit" label="' + globalize.translate('LabelItemLimit') + '"/>';
|
||||
|
||||
if (mode === 'convert') {
|
||||
html += '<div class="fieldDescription">' + globalize.translate('ConvertItemLimitHelp') + '</div>';
|
||||
} else {
|
||||
html += '<div class="fieldDescription">' + globalize.translate('DownloadItemLimitHelp') + '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
//html += '</div>';
|
||||
//html += '</div>';
|
||||
|
||||
elem.innerHTML = html;
|
||||
|
||||
var selectSyncTarget = elem.querySelector('#selectSyncTarget');
|
||||
if (selectSyncTarget) {
|
||||
selectSyncTarget.addEventListener('change', function () {
|
||||
loadQualityOptions(elem, this.value, options.dialogOptionsFn).then(resolve);
|
||||
});
|
||||
selectSyncTarget.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
}
|
||||
|
||||
var selectProfile = elem.querySelector('#selectProfile');
|
||||
if (selectProfile) {
|
||||
selectProfile.addEventListener('change', function () {
|
||||
onProfileChange(elem, this.value);
|
||||
});
|
||||
|
||||
if (dialogOptions.ProfileOptions.length) {
|
||||
selectProfile.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
var selectQuality = elem.querySelector('#selectQuality');
|
||||
if (selectQuality) {
|
||||
selectQuality.addEventListener('change', function () {
|
||||
onQualityChange(elem, this.value);
|
||||
});
|
||||
selectQuality.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
}
|
||||
|
||||
// This isn't ideal, but allow time for the change handlers above to run
|
||||
setTimeout(function () {
|
||||
focusManager.autoFocus(elem);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function showWifiMessage() {
|
||||
|
||||
require(['dialog', 'appRouter'], function (dialog, appRouter) {
|
||||
|
||||
var options = {
|
||||
|
||||
title: globalize.translate('HeaderWaitingForWifi'),
|
||||
text: globalize.translate('WifiRequiredToDownload')
|
||||
};
|
||||
|
||||
var items = [];
|
||||
|
||||
items.push({
|
||||
name: options.confirmText || globalize.translate('ButtonOk'),
|
||||
id: 'ok',
|
||||
type: 'submit'
|
||||
});
|
||||
|
||||
items.push({
|
||||
name: options.cancelText || globalize.translate('HeaderDownloadSettings'),
|
||||
id: 'downloadsettings',
|
||||
type: 'cancel'
|
||||
});
|
||||
|
||||
options.buttons = items;
|
||||
|
||||
dialog(options).then(function (result) {
|
||||
|
||||
if (result === 'ok') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (result === 'downloadsettings') {
|
||||
appRouter.show(appRouter.getRouteUrl('downloadsettings'));
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function validateNetwork() {
|
||||
|
||||
var network = navigator.connection ? navigator.connection.type : null;
|
||||
|
||||
switch (network) {
|
||||
|
||||
case 'cellular':
|
||||
case 'bluetooth':
|
||||
showWifiMessage();
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function showSyncMenu(options) {
|
||||
|
||||
if (options.mode === 'download' && appSettings.syncOnlyOnWifi() && !validateNetwork()) {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
return registrationServices.validateFeature('sync').then(function () {
|
||||
return showSyncMenuInternal(options);
|
||||
});
|
||||
}
|
||||
|
||||
function enableAutoSync(options) {
|
||||
|
||||
if (options.mode !== 'download') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var firstItem = (options.items || [])[0] || {};
|
||||
|
||||
if (firstItem.Type === 'Audio') {
|
||||
return true;
|
||||
}
|
||||
if (firstItem.Type === 'MusicAlbum') {
|
||||
return true;
|
||||
}
|
||||
if (firstItem.Type === 'MusicArtist') {
|
||||
return true;
|
||||
}
|
||||
if (firstItem.Type === 'MusicGenre') {
|
||||
return true;
|
||||
}
|
||||
if (firstItem.Type === 'Playlist' && firstItem.MediaType === 'Audio') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function showSyncMenuInternal(options) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(options.serverId);
|
||||
var userId = apiClient.getCurrentUserId();
|
||||
|
||||
if (enableAutoSync(options)) {
|
||||
|
||||
return submitQuickSyncJob(apiClient, userId, apiClient.deviceId(), {
|
||||
items: options.items,
|
||||
Quality: 'custom',
|
||||
Bitrate: appSettings.maxStaticMusicBitrate()
|
||||
});
|
||||
}
|
||||
|
||||
var dialogOptionsFn = getTargetDialogOptionsFn(apiClient, {
|
||||
UserId: userId,
|
||||
ItemIds: (options.items || []).map(function (i) {
|
||||
return i.Id || i;
|
||||
}).join(','),
|
||||
|
||||
ParentId: options.ParentId,
|
||||
Category: options.Category,
|
||||
IncludeProviders: options.mode === 'convert' ? 'ConvertSyncProvider' : null,
|
||||
ExcludeProviders: options.mode === 'convert' ? null : 'ConvertSyncProvider'
|
||||
});
|
||||
|
||||
return dialogOptionsFn().then(function (dialogOptions) {
|
||||
|
||||
currentDialogOptions = dialogOptions;
|
||||
|
||||
var dlgElementOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false,
|
||||
autoFocus: false
|
||||
};
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dlgElementOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dlgElementOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dlgElementOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var html = '';
|
||||
html += '<div class="formDialogHeader">';
|
||||
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon"></i></button>';
|
||||
html += '<h3 class="formDialogHeaderTitle">';
|
||||
|
||||
var syncButtonLabel = options.mode === 'download' ?
|
||||
globalize.translate('Download') :
|
||||
(options.mode === 'convert' ? globalize.translate('Convert') : globalize.translate('Sync'));
|
||||
|
||||
html += syncButtonLabel;
|
||||
html += '</h3>';
|
||||
|
||||
if (appHost.supports('externallinks')) {
|
||||
html += '<a is="emby-linkbutton" href="https://github.com/MediaBrowser/Wiki/wiki/Sync" target="_blank" class="button-link lnkHelp" style="margin-top:0;display:inline-block;vertical-align:middle;margin-left:auto;"><i class="md-icon">info</i><span>' + globalize.translate('Help') + '</span></a>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">';
|
||||
html += '<div class="dialogContentInner dialog-content-centered">';
|
||||
|
||||
html += '<form class="formSubmitSyncRequest" style="margin: auto;">';
|
||||
|
||||
html += '<div class="formFields"></div>';
|
||||
|
||||
html += '<div class="formDialogFooter">';
|
||||
|
||||
html += '<button is="emby-button" type="submit" class="raised button-submit block formDialogFooterItem"><span>' + syncButtonLabel + '</span></button>';
|
||||
html += '</div>';
|
||||
|
||||
html += '</form>';
|
||||
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
var submitted = false;
|
||||
|
||||
dlg.querySelector('form').addEventListener('submit', function (e) {
|
||||
|
||||
submitted = submitJob(dlg, apiClient, userId, options, this);
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
var promise = dialogHelper.open(dlg);
|
||||
|
||||
renderForm({
|
||||
elem: dlg.querySelector('.formFields'),
|
||||
dialogOptions: dialogOptions,
|
||||
dialogOptionsFn: dialogOptionsFn,
|
||||
mode: options.mode
|
||||
});
|
||||
|
||||
return promise.then(function () {
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
if (submitted) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getTargetDialogOptionsFn(apiClient, query) {
|
||||
|
||||
return function (targetId) {
|
||||
|
||||
query.TargetId = targetId;
|
||||
return apiClient.getJSON(apiClient.getUrl('Sync/Options', query));
|
||||
};
|
||||
}
|
||||
|
||||
function setQualityFieldVisible(form, visible) {
|
||||
|
||||
var fldQuality = form.querySelector('.fldQuality');
|
||||
var selectQuality = form.querySelector('#selectQuality');
|
||||
|
||||
if (visible) {
|
||||
if (fldQuality) {
|
||||
fldQuality.classList.remove('hide');
|
||||
}
|
||||
if (selectQuality) {
|
||||
//selectQuality.setAttribute('required', 'required');
|
||||
|
||||
// This is a hack due to what appears to be a edge bug but it shoudln't matter as the list always has selectable items
|
||||
selectQuality.removeAttribute('required');
|
||||
}
|
||||
} else {
|
||||
if (fldQuality) {
|
||||
fldQuality.classList.add('hide');
|
||||
}
|
||||
if (selectQuality) {
|
||||
selectQuality.removeAttribute('required');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onProfileChange(form, profileId) {
|
||||
|
||||
var options = currentDialogOptions || {};
|
||||
|
||||
var profileOptions = options.ProfileOptions || [];
|
||||
|
||||
if (!profileOptions.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var option = profileOptions.filter(function (o) {
|
||||
return o.Id === profileId;
|
||||
})[0];
|
||||
|
||||
var qualityOptions = options.QualityOptions || [];
|
||||
|
||||
if (option) {
|
||||
form.querySelector('.profileDescription').innerHTML = option.Description || '';
|
||||
setQualityFieldVisible(form, qualityOptions.length > 0 && option.EnableQualityOptions && options.Options.indexOf('Quality') !== -1);
|
||||
} else {
|
||||
form.querySelector('.profileDescription').innerHTML = '';
|
||||
setQualityFieldVisible(form, qualityOptions.length > 0 && options.Options.indexOf('Quality') !== -1);
|
||||
}
|
||||
}
|
||||
|
||||
function onQualityChange(form, qualityId) {
|
||||
|
||||
var options = currentDialogOptions || {};
|
||||
var option = (options.QualityOptions || []).filter(function (o) {
|
||||
return o.Id === qualityId;
|
||||
})[0];
|
||||
|
||||
var qualityDescription = form.querySelector('.qualityDescription');
|
||||
|
||||
if (option) {
|
||||
qualityDescription.innerHTML = option.Description || '';
|
||||
} else {
|
||||
qualityDescription.innerHTML = '';
|
||||
}
|
||||
|
||||
var fldBitrate = form.querySelector('.fldBitrate');
|
||||
var txtBitrate = form.querySelector('#txtBitrate');
|
||||
|
||||
if (qualityId === 'custom') {
|
||||
|
||||
if (fldBitrate) {
|
||||
fldBitrate.classList.remove('hide');
|
||||
}
|
||||
if (txtBitrate) {
|
||||
txtBitrate.setAttribute('required', 'required');
|
||||
}
|
||||
} else {
|
||||
if (fldBitrate) {
|
||||
fldBitrate.classList.add('hide');
|
||||
}
|
||||
if (txtBitrate) {
|
||||
txtBitrate.removeAttribute('required');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderTargetDialogOptions(form, options) {
|
||||
|
||||
currentDialogOptions = options;
|
||||
|
||||
var fldProfile = form.querySelector('.fldProfile');
|
||||
var selectProfile = form.querySelector('#selectProfile');
|
||||
|
||||
if (options.ProfileOptions.length && options.Options.indexOf('Profile') !== -1) {
|
||||
if (fldProfile) {
|
||||
fldProfile.classList.remove('hide');
|
||||
}
|
||||
if (selectProfile) {
|
||||
selectProfile.setAttribute('required', 'required');
|
||||
}
|
||||
} else {
|
||||
if (fldProfile) {
|
||||
fldProfile.classList.add('hide');
|
||||
}
|
||||
if (selectProfile) {
|
||||
selectProfile.removeAttribute('required');
|
||||
}
|
||||
}
|
||||
|
||||
setQualityFieldVisible(form, options.QualityOptions.length > 0);
|
||||
|
||||
if (selectProfile) {
|
||||
selectProfile.innerHTML = options.ProfileOptions.map(function (o) {
|
||||
|
||||
var selectedAttribute = o.IsDefault ? ' selected="selected"' : '';
|
||||
return '<option value="' + o.Id + '"' + selectedAttribute + '>' + o.Name + '</option>';
|
||||
|
||||
}).join('');
|
||||
|
||||
selectProfile.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
}
|
||||
|
||||
var selectQuality = form.querySelector('#selectQuality');
|
||||
if (selectQuality) {
|
||||
selectQuality.innerHTML = options.QualityOptions.map(function (o) {
|
||||
|
||||
var selectedAttribute = o.IsDefault ? ' selected="selected"' : '';
|
||||
return '<option value="' + o.Id + '"' + selectedAttribute + '>' + o.Name + '</option>';
|
||||
|
||||
}).join('');
|
||||
|
||||
var lastQuality = appSettings.get('sync-lastquality');
|
||||
if (lastQuality && options.QualityOptions.filter(function (i) {
|
||||
|
||||
return i.Id === lastQuality;
|
||||
|
||||
}).length) {
|
||||
selectQuality.value = lastQuality;
|
||||
}
|
||||
|
||||
selectQuality.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function loadQualityOptions(form, targetId, dialogOptionsFn) {
|
||||
|
||||
return dialogOptionsFn(targetId).then(function (options) {
|
||||
|
||||
return renderTargetDialogOptions(form, options);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
showMenu: showSyncMenu,
|
||||
renderForm: renderForm,
|
||||
setJobValues: setJobValues
|
||||
};
|
||||
});
|
3
src/components/actionsheet/package.json
Normal file
3
src/components/actionsheet/package.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"main": "actionsheet.js"
|
||||
}
|
40
src/components/alert.js
Normal file
40
src/components/alert.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize) {
|
||||
'use strict';
|
||||
|
||||
return function (text, title) {
|
||||
|
||||
var options;
|
||||
if (typeof text === 'string') {
|
||||
options = {
|
||||
title: title,
|
||||
text: text
|
||||
};
|
||||
} else {
|
||||
options = text;
|
||||
}
|
||||
|
||||
if (browser.tv && window.alert) {
|
||||
alert(replaceAll(options.text || '', '<br/>', '\n'));
|
||||
} else {
|
||||
var items = [];
|
||||
|
||||
items.push({
|
||||
name: globalize.translate('ButtonGotIt'),
|
||||
id: 'ok',
|
||||
type: 'submit'
|
||||
});
|
||||
|
||||
options.buttons = items;
|
||||
|
||||
return dialog(options).then(function (result) {
|
||||
if (result === 'ok') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
});
|
|
@ -234,6 +234,19 @@ define(['connectionManager', 'playbackManager', 'events', 'inputManager', 'focus
|
|||
events.on(apiClient, "message", onMessageReceived);
|
||||
}
|
||||
|
||||
function enableNativeGamepadKeyMapping() {
|
||||
if (window.navigator && "string" == typeof window.navigator.gamepadInputEmulation) {
|
||||
window.navigator.gamepadInputEmulation = "keyboard";
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function isGamepadSupported() {
|
||||
return "ongamepadconnected" in window || navigator.getGamepads || navigator.webkitGetGamepads;
|
||||
}
|
||||
|
||||
connectionManager.getApiClients().forEach(bindEvents);
|
||||
|
||||
events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) {
|
||||
|
@ -241,5 +254,11 @@ define(['connectionManager', 'playbackManager', 'events', 'inputManager', 'focus
|
|||
bindEvents(newApiClient);
|
||||
});
|
||||
|
||||
if (!enableNativeGamepadKeyMapping() && isGamepadSupported()) {
|
||||
require(["components/apiInput/gamepadtokey"]);
|
||||
}
|
||||
|
||||
require(["components/apiInput/mouseManager"]);
|
||||
|
||||
return serverNotifications;
|
||||
});
|
3
src/components/apiInput/package.json
Normal file
3
src/components/apiInput/package.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"main": "apiInput.js"
|
||||
}
|
|
@ -14,31 +14,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||
},
|
||||
showSettings: function () {
|
||||
show('/settings/settings.html');
|
||||
},
|
||||
showSearch: function () {
|
||||
skinManager.getCurrentSkin().search();
|
||||
},
|
||||
showGenre: function (options) {
|
||||
skinManager.getCurrentSkin().showGenre(options);
|
||||
},
|
||||
showGuide: function () {
|
||||
skinManager.getCurrentSkin().showGuide({
|
||||
serverId: connectionManager.currentApiClient().serverId()
|
||||
});
|
||||
},
|
||||
showLiveTV: function () {
|
||||
skinManager.getCurrentSkin().showLiveTV({
|
||||
serverId: connectionManager.currentApiClient().serverId()
|
||||
});
|
||||
},
|
||||
showRecordedTV: function () {
|
||||
skinManager.getCurrentSkin().showRecordedTV();
|
||||
},
|
||||
showFavorites: function () {
|
||||
skinManager.getCurrentSkin().showFavorites();
|
||||
},
|
||||
showNowPlaying: function () {
|
||||
skinManager.getCurrentSkin().showNowPlaying();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -125,13 +100,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||
sendRouteToViewManager(ctx, next, route, controllerFactory);
|
||||
};
|
||||
|
||||
require(route.dependencies || [], function () {
|
||||
if (route.controller) {
|
||||
require([route.controller], onInitComplete);
|
||||
require([`controllers/${route.controller}`], onInitComplete);
|
||||
} else {
|
||||
onInitComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cancelCurrentLoadRequest() {
|
||||
|
@ -363,8 +336,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||
|
||||
firstConnectionResult = result;
|
||||
|
||||
loading.hide();
|
||||
|
||||
options = options || {};
|
||||
|
||||
page({
|
||||
|
@ -372,6 +343,8 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||
hashbang: options.hashbang !== false,
|
||||
enableHistory: enableHistory()
|
||||
});
|
||||
}).finally(function () {
|
||||
loading.hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -438,11 +411,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||
|
||||
console.log('appRouter - user is authenticated');
|
||||
|
||||
if (ctx.isBack && (route.isDefaultRoute || route.startup) && !isCurrentRouteStartup) {
|
||||
handleBackToDefault();
|
||||
return;
|
||||
}
|
||||
else if (route.isDefaultRoute) {
|
||||
if (route.isDefaultRoute) {
|
||||
console.log('appRouter - loading skin home page');
|
||||
loadUserSkinWithOptions(ctx);
|
||||
return;
|
||||
|
@ -501,30 +470,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||
var isHandlingBackToDefault;
|
||||
var isDummyBackToHome;
|
||||
|
||||
function handleBackToDefault() {
|
||||
|
||||
if (!appHost.supports('exitmenu') && appHost.supports('exit')) {
|
||||
appHost.exit();
|
||||
return;
|
||||
}
|
||||
|
||||
isDummyBackToHome = true;
|
||||
skinManager.loadUserSkin();
|
||||
|
||||
if (isHandlingBackToDefault) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This must result in a call to either
|
||||
// skinManager.loadUserSkin();
|
||||
// Logout
|
||||
// Or exit app
|
||||
skinManager.getCurrentSkin().showBackMenu().then(function () {
|
||||
|
||||
isHandlingBackToDefault = false;
|
||||
});
|
||||
}
|
||||
|
||||
function loadContent(ctx, route, html, request) {
|
||||
|
||||
html = globalize.translateDocument(html, route.dictionary);
|
||||
|
@ -670,30 +615,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||
return currentRouteInfo ? currentRouteInfo.route : null;
|
||||
}
|
||||
|
||||
function goHome() {
|
||||
|
||||
var skin = skinManager.getCurrentSkin();
|
||||
|
||||
if (skin.getHomeRoute) {
|
||||
var homePath = skin.getHomeRoute();
|
||||
return show(pluginManager.mapRoute(skin, homePath));
|
||||
} else {
|
||||
var homeRoute = skin.getRoutes().filter(function (r) {
|
||||
return r.type === 'home';
|
||||
})[0];
|
||||
|
||||
return show(pluginManager.mapRoute(skin, homeRoute));
|
||||
}
|
||||
}
|
||||
|
||||
function getRouteUrl(item, options) {
|
||||
if (item === 'settings') {
|
||||
return 'settings/settings.html';
|
||||
}
|
||||
|
||||
return skinManager.getCurrentSkin().getRouteUrl(item, options);
|
||||
}
|
||||
|
||||
function showItem(item, serverId, options) {
|
||||
|
||||
if (typeof (item) === 'string') {
|
||||
|
@ -714,20 +635,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||
}
|
||||
}
|
||||
|
||||
function setTitle(title) {
|
||||
skinManager.getCurrentSkin().setTitle(title);
|
||||
}
|
||||
|
||||
function showVideoOsd() {
|
||||
var skin = skinManager.getCurrentSkin();
|
||||
|
||||
var homeRoute = skin.getRoutes().filter(function (r) {
|
||||
return r.type === 'video-osd';
|
||||
})[0];
|
||||
|
||||
return show(pluginManager.mapRoute(skin, homeRoute));
|
||||
}
|
||||
|
||||
var allRoutes = [];
|
||||
|
||||
function addRoute(path, newRoute) {
|
||||
|
@ -834,15 +741,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||
appRouter.canGoBack = canGoBack;
|
||||
appRouter.current = current;
|
||||
appRouter.beginConnectionWizard = beginConnectionWizard;
|
||||
appRouter.goHome = goHome;
|
||||
appRouter.showItem = showItem;
|
||||
appRouter.setTitle = setTitle;
|
||||
appRouter.setTransparency = setTransparency;
|
||||
appRouter.getRoutes = getRoutes;
|
||||
appRouter.getRouteUrl = getRouteUrl;
|
||||
appRouter.pushState = pushState;
|
||||
appRouter.enableNativeHistory = enableNativeHistory;
|
||||
appRouter.showVideoOsd = showVideoOsd;
|
||||
appRouter.handleAnchorClick = page.handleAnchorClick;
|
||||
appRouter.TransparencyLevel = {
|
||||
None: 0,
|
|
@ -1,109 +1,191 @@
|
|||
define(["appSettings", "browser", "events", "htmlMediaHelper"], function(appSettings, browser, events, htmlMediaHelper) {
|
||||
define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSettings, browser, events, htmlMediaHelper) {
|
||||
"use strict";
|
||||
|
||||
function getBaseProfileOptions(item) {
|
||||
var disableHlsVideoAudioCodecs = [];
|
||||
return item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType) && ((browser.edge || browser.msie) && disableHlsVideoAudioCodecs.push("mp3"), disableHlsVideoAudioCodecs.push("ac3"), disableHlsVideoAudioCodecs.push("eac3"), disableHlsVideoAudioCodecs.push("opus")), {
|
||||
enableMkvProgressive: !1,
|
||||
disableHlsVideoAudioCodecs: disableHlsVideoAudioCodecs
|
||||
|
||||
if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) {
|
||||
if (browser.edge || browser.msie) {
|
||||
disableHlsVideoAudioCodecs.push("mp3");
|
||||
}
|
||||
|
||||
disableHlsVideoAudioCodecs.push("ac3");
|
||||
disableHlsVideoAudioCodecs.push("eac3");
|
||||
disableHlsVideoAudioCodecs.push("opus");
|
||||
}
|
||||
|
||||
return {
|
||||
enableMkvProgressive: false,
|
||||
disableHlsVideoAudioCodecs: disableHlsVideoAudioCodecs
|
||||
};
|
||||
}
|
||||
|
||||
function getDeviceProfileForWindowsUwp(item) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
require(["browserdeviceprofile", "environments/windows-uwp/mediacaps"], function(profileBuilder, uwpMediaCaps) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(["browserdeviceprofile", "environments/windows-uwp/mediacaps"], function (profileBuilder, uwpMediaCaps) {
|
||||
var profileOptions = getBaseProfileOptions(item);
|
||||
profileOptions.supportsDts = uwpMediaCaps.supportsDTS(), profileOptions.supportsTrueHd = uwpMediaCaps.supportsDolby(), profileOptions.audioChannels = uwpMediaCaps.getAudioChannels(), resolve(profileBuilder(profileOptions))
|
||||
})
|
||||
})
|
||||
profileOptions.supportsDts = uwpMediaCaps.supportsDTS();
|
||||
profileOptions.supportsTrueHd = uwpMediaCaps.supportsDolby();
|
||||
profileOptions.audioChannels = uwpMediaCaps.getAudioChannels();
|
||||
resolve(profileBuilder(profileOptions));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getDeviceProfile(item, options) {
|
||||
return options = options || {}, self.Windows ? getDeviceProfileForWindowsUwp(item) : new Promise(function(resolve, reject) {
|
||||
require(["browserdeviceprofile"], function(profileBuilder) {
|
||||
var profile = profileBuilder(getBaseProfileOptions(item));
|
||||
item && !options.isRetry && "allcomplexformats" !== appSettings.get("subtitleburnin") && (browser.orsay || browser.tizen || (profile.SubtitleProfiles.push({
|
||||
options = options || {};
|
||||
|
||||
if (self.Windows) {
|
||||
return getDeviceProfileForWindowsUwp(item);
|
||||
}
|
||||
|
||||
return new Promise(function (resolve) {
|
||||
require(["browserdeviceprofile"], function (profileBuilder) {
|
||||
var profile;
|
||||
|
||||
if (window.NativeShell) {
|
||||
profile = window.NativeShell.AppHost.getDeviceProfile(profileBuilder);
|
||||
} else {
|
||||
profile = profileBuilder(getBaseProfileOptions(item));
|
||||
|
||||
if (item && !options.isRetry && "allcomplexformats" !== appSettings.get("subtitleburnin")) {
|
||||
if (!browser.orsay && !browser.tizen) {
|
||||
profile.SubtitleProfiles.push({
|
||||
Format: "ass",
|
||||
Method: "External"
|
||||
}), profile.SubtitleProfiles.push({
|
||||
});
|
||||
profile.SubtitleProfiles.push({
|
||||
Format: "ssa",
|
||||
Method: "External"
|
||||
}))), resolve(profile)
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolve(profile);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1")
|
||||
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
|
||||
}
|
||||
|
||||
function replaceAll(originalString, strReplace, strWith) {
|
||||
var strReplace2 = escapeRegExp(strReplace),
|
||||
reg = new RegExp(strReplace2, "ig");
|
||||
return originalString.replace(reg, strWith)
|
||||
var strReplace2 = escapeRegExp(strReplace);
|
||||
var reg = new RegExp(strReplace2, "ig");
|
||||
return originalString.replace(reg, strWith);
|
||||
}
|
||||
|
||||
function generateDeviceId() {
|
||||
var keys = [];
|
||||
if (keys.push(navigator.userAgent), keys.push((new Date).getTime()), self.btoa) {
|
||||
|
||||
if (keys.push(navigator.userAgent), keys.push(new Date().getTime()), self.btoa) {
|
||||
var result = replaceAll(btoa(keys.join("|")), "=", "1");
|
||||
return Promise.resolve(result)
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
return Promise.resolve((new Date).getTime())
|
||||
|
||||
return Promise.resolve(new Date().getTime());
|
||||
}
|
||||
|
||||
function getDeviceId() {
|
||||
var key = "_deviceId2",
|
||||
deviceId = appSettings.get(key);
|
||||
return deviceId ? Promise.resolve(deviceId) : generateDeviceId().then(function(deviceId) {
|
||||
return appSettings.set(key, deviceId), deviceId
|
||||
})
|
||||
var key = "_deviceId2";
|
||||
var deviceId = appSettings.get(key);
|
||||
|
||||
if (deviceId) {
|
||||
return Promise.resolve(deviceId);
|
||||
}
|
||||
|
||||
return generateDeviceId().then(function (deviceId) {
|
||||
appSettings.set(key, deviceId);
|
||||
return deviceId;
|
||||
});
|
||||
}
|
||||
|
||||
function getDeviceName() {
|
||||
var deviceName;
|
||||
return deviceName = browser.tizen ? "Samsung Smart TV" : browser.web0s ? "LG Smart TV" : browser.operaTv ? "Opera TV" : browser.xboxOne ? "Xbox One" : browser.ps4 ? "Sony PS4" : browser.chrome ? "Chrome" : browser.edge ? "Edge" : browser.firefox ? "Firefox" : browser.msie ? "Internet Explorer" : browser.opera ? "Opera" : "Web Browser", browser.ipad ? deviceName += " Ipad" : browser.iphone ? deviceName += " Iphone" : browser.android && (deviceName += " Android"), deviceName
|
||||
deviceName = browser.tizen ? "Samsung Smart TV" : browser.web0s ? "LG Smart TV" : browser.operaTv ? "Opera TV" : browser.xboxOne ? "Xbox One" : browser.ps4 ? "Sony PS4" : browser.chrome ? "Chrome" : browser.edge ? "Edge" : browser.firefox ? "Firefox" : browser.msie ? "Internet Explorer" : browser.opera ? "Opera" : "Web Browser";
|
||||
|
||||
if (browser.ipad) {
|
||||
deviceName += " Ipad";
|
||||
} else {
|
||||
if (browser.iphone) {
|
||||
deviceName += " Iphone";
|
||||
} else {
|
||||
if (browser.android) {
|
||||
deviceName += " Android";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
function supportsVoiceInput() {
|
||||
return !browser.tv && (window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.oSpeechRecognition || window.msSpeechRecognition)
|
||||
if (!browser.tv) {
|
||||
return window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.oSpeechRecognition || window.msSpeechRecognition;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function supportsFullscreen() {
|
||||
if (browser.tv) return !1;
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var element = document.documentElement;
|
||||
return !!(element.requestFullscreen || element.mozRequestFullScreen || element.webkitRequestFullscreen || element.msRequestFullscreen) || !!document.createElement("video").webkitEnterFullscreen
|
||||
return (element.requestFullscreen || element.mozRequestFullScreen || element.webkitRequestFullscreen || element.msRequestFullscreen) || document.createElement("video").webkitEnterFullscreen;
|
||||
}
|
||||
|
||||
function getSyncProfile() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
require(["browserdeviceprofile", "appSettings"], function(profileBuilder, appSettings) {
|
||||
var profile = profileBuilder();
|
||||
profile.MaxStaticMusicBitrate = appSettings.maxStaticMusicBitrate(), resolve(profile)
|
||||
})
|
||||
})
|
||||
return new Promise(function (resolve) {
|
||||
require(["browserdeviceprofile", "appSettings"], function (profileBuilder, appSettings) {
|
||||
var profile;
|
||||
|
||||
if (window.NativeShell) {
|
||||
profile = window.NativeShell.AppHost.getSyncProfile(profileBuilder, appSettings);
|
||||
} else {
|
||||
profile = profileBuilder();
|
||||
profile.MaxStaticMusicBitrate = appSettings.maxStaticMusicBitrate();
|
||||
}
|
||||
|
||||
resolve(profile);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getDefaultLayout() {
|
||||
return "desktop"
|
||||
return "desktop";
|
||||
}
|
||||
|
||||
function supportsHtmlMediaAutoplay() {
|
||||
if (browser.edgeUwp || browser.tizen || browser.web0s || browser.orsay || browser.operaTv || browser.ps4 || browser.xboxOne) return !0;
|
||||
if (browser.mobile) return !1;
|
||||
if (browser.edgeUwp || browser.tizen || browser.web0s || browser.orsay || browser.operaTv || browser.ps4 || browser.xboxOne) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.mobile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var savedResult = appSettings.get(htmlMediaAutoplayAppStorageKey);
|
||||
return "true" === savedResult || "false" !== savedResult && null
|
||||
return "true" === savedResult || "false" !== savedResult && null;
|
||||
}
|
||||
|
||||
function cueSupported() {
|
||||
try {
|
||||
var video = document.createElement("video"),
|
||||
style = document.createElement("style");
|
||||
style.textContent = "video::cue {background: inherit}", document.body.appendChild(style), document.body.appendChild(video);
|
||||
var video = document.createElement("video");
|
||||
var style = document.createElement("style");
|
||||
style.textContent = "video::cue {background: inherit}";
|
||||
document.body.appendChild(style);
|
||||
document.body.appendChild(video);
|
||||
var cue = window.getComputedStyle(video, "::cue").background;
|
||||
return document.body.removeChild(style), document.body.removeChild(video), !!cue.length
|
||||
document.body.removeChild(style);
|
||||
document.body.removeChild(video);
|
||||
return !!cue.length;
|
||||
} catch (err) {
|
||||
return console.log("Error detecting cue support:" + err), !1
|
||||
console.log("Error detecting cue support:" + err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,41 +205,104 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function(appSett
|
|||
}
|
||||
|
||||
var htmlMediaAutoplayAppStorageKey = "supportshtmlmediaautoplay0";
|
||||
var supportedFeatures = function() {
|
||||
|
||||
var supportedFeatures = function () {
|
||||
var features = [];
|
||||
navigator.share && features.push("sharing");
|
||||
browser.edgeUwp || browser.tv || browser.xboxOne || browser.ps4 || features.push("filedownload");
|
||||
browser.operaTv || browser.tizen || browser.orsay || browser.web0s
|
||||
? features.push("exit")
|
||||
: (features.push("exitmenu"), features.push("plugins"));
|
||||
browser.operaTv || browser.tizen || browser.orsay || browser.web0s || browser.ps4 || (features.push("externallinks"), features.push("externalpremium"));
|
||||
browser.operaTv || features.push("externallinkdisplay");
|
||||
supportsVoiceInput() && features.push("voiceinput");
|
||||
!browser.tv && !browser.xboxOne && browser.ps4, supportsHtmlMediaAutoplay() && (features.push("htmlaudioautoplay"), features.push("htmlvideoautoplay"));
|
||||
browser.edgeUwp && features.push("sync");
|
||||
supportsFullscreen() && features.push("fullscreenchange");
|
||||
(browser.chrome || browser.edge && !browser.slow) && (browser.noAnimation || browser.edgeUwp || browser.xboxOne || features.push("imageanalysis"));
|
||||
(browser.tv || browser.xboxOne || browser.ps4 || browser.mobile) && features.push("physicalvolumecontrol");
|
||||
browser.tv || browser.xboxOne || browser.ps4 || features.push("remotecontrol");
|
||||
browser.operaTv || browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp || features.push("remotevideo");
|
||||
|
||||
if (navigator.share) {
|
||||
features.push("sharing");
|
||||
}
|
||||
|
||||
if (!browser.edgeUwp && !browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
features.push("filedownload");
|
||||
}
|
||||
|
||||
if (browser.operaTv || browser.tizen || browser.orsay || browser.web0s) {
|
||||
features.push("exit");
|
||||
} else {
|
||||
features.push("exitmenu");
|
||||
features.push("plugins");
|
||||
}
|
||||
|
||||
if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.ps4) {
|
||||
features.push("externallinks");
|
||||
features.push("externalpremium");
|
||||
}
|
||||
|
||||
if (!browser.operaTv) {
|
||||
features.push("externallinkdisplay");
|
||||
}
|
||||
|
||||
if (supportsVoiceInput()) {
|
||||
features.push("voiceinput");
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.xboxOne) {
|
||||
browser.ps4;
|
||||
}
|
||||
|
||||
if (supportsHtmlMediaAutoplay()) {
|
||||
features.push("htmlaudioautoplay");
|
||||
features.push("htmlvideoautoplay");
|
||||
}
|
||||
|
||||
if (browser.edgeUwp) {
|
||||
features.push("sync");
|
||||
}
|
||||
|
||||
if (supportsFullscreen()) {
|
||||
features.push("fullscreenchange");
|
||||
}
|
||||
|
||||
if (browser.chrome || browser.edge && !browser.slow) {
|
||||
if (!browser.noAnimation && !browser.edgeUwp && !browser.xboxOne) {
|
||||
features.push("imageanalysis");
|
||||
}
|
||||
}
|
||||
|
||||
if (browser.tv || browser.xboxOne || browser.ps4 || browser.mobile) {
|
||||
features.push("physicalvolumecontrol");
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
features.push("remotecontrol");
|
||||
}
|
||||
|
||||
if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.edgeUwp) {
|
||||
features.push("remotevideo");
|
||||
}
|
||||
|
||||
features.push("displaylanguage");
|
||||
features.push("otherapppromotions");
|
||||
features.push("targetblank");
|
||||
// allows users to connect to more than one server
|
||||
features.push("targetblank"); // allows users to connect to more than one server
|
||||
//features.push("multiserver");
|
||||
browser.orsay || browser.tizen || browser.msie || !(browser.firefox || browser.ps4 || browser.edge || cueSupported()) || features.push("subtitleappearancesettings");
|
||||
browser.orsay || browser.tizen || features.push("subtitleburnsettings");
|
||||
browser.tv || browser.ps4 || browser.xboxOne || features.push("fileinput");
|
||||
browser.chrome && features.push("chromecast");
|
||||
|
||||
if (!browser.orsay && !browser.tizen && !browser.msie && (browser.firefox || browser.ps4 || browser.edge || cueSupported())) {
|
||||
features.push("subtitleappearancesettings");
|
||||
}
|
||||
|
||||
if (!browser.orsay && !browser.tizen) {
|
||||
features.push("subtitleburnsettings");
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.ps4 && !browser.xboxOne) {
|
||||
features.push("fileinput");
|
||||
}
|
||||
|
||||
if (browser.chrome) {
|
||||
features.push("chromecast");
|
||||
}
|
||||
|
||||
return features;
|
||||
}();
|
||||
|
||||
if (supportedFeatures.indexOf("htmlvideoautoplay") === -1 && supportsHtmlMediaAutoplay() !== false) {
|
||||
require(["autoPlayDetect"], function(autoPlayDetect) {
|
||||
autoPlayDetect.supportsHtmlMediaAutoplay().then(function() {
|
||||
require(["autoPlayDetect"], function (autoPlayDetect) {
|
||||
autoPlayDetect.supportsHtmlMediaAutoplay().then(function () {
|
||||
appSettings.set(htmlMediaAutoplayAppStorageKey, "true");
|
||||
supportedFeatures.push("htmlvideoautoplay");
|
||||
supportedFeatures.push("htmlaudioautoplay");
|
||||
}, function() {
|
||||
}, function () {
|
||||
appSettings.set(htmlMediaAutoplayAppStorageKey, "false");
|
||||
});
|
||||
});
|
||||
|
@ -169,73 +314,171 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function(appSett
|
|||
var visibilityState;
|
||||
var appVersion = window.dashboardVersion || "3.0";
|
||||
var appHost = {
|
||||
getWindowState: function() {
|
||||
return document.windowState || "Normal"
|
||||
getWindowState: function () {
|
||||
return document.windowState || "Normal";
|
||||
},
|
||||
setWindowState: function(state) {
|
||||
alert("setWindowState is not supported and should not be called")
|
||||
setWindowState: function (state) {
|
||||
alert("setWindowState is not supported and should not be called");
|
||||
},
|
||||
exit: function() {
|
||||
if (browser.tizen) try {
|
||||
tizen.application.getCurrentApplication().exit()
|
||||
exit: function () {
|
||||
if (window.NativeShell) {
|
||||
window.NativeShell.AppHost.exit();
|
||||
} else if (browser.tizen) {
|
||||
try {
|
||||
tizen.application.getCurrentApplication().exit();
|
||||
} catch (err) {
|
||||
console.log("error closing application: " + err)
|
||||
} else window.close()
|
||||
console.log("error closing application: " + err);
|
||||
}
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
},
|
||||
supports: function(command) {
|
||||
return -1 !== supportedFeatures.indexOf(command.toLowerCase())
|
||||
supports: function (command) {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.supports(command);
|
||||
}
|
||||
|
||||
return -1 !== supportedFeatures.indexOf(command.toLowerCase());
|
||||
},
|
||||
preferVisualCards: browser.android || browser.chrome,
|
||||
moreIcon: browser.android ? "dots-vert" : "dots-horiz",
|
||||
getSyncProfile: getSyncProfile,
|
||||
getDefaultLayout: getDefaultLayout,
|
||||
getDefaultLayout: function () {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.getDefaultLayout();
|
||||
}
|
||||
|
||||
return getDefaultLayout()
|
||||
},
|
||||
getDeviceProfile: getDeviceProfile,
|
||||
init: function() {
|
||||
return deviceName = getDeviceName(), getDeviceId().then(function(resolvedDeviceId) {
|
||||
deviceId = resolvedDeviceId
|
||||
})
|
||||
init: function () {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.init();
|
||||
}
|
||||
|
||||
deviceName = getDeviceName();
|
||||
return getDeviceId().then(function (resolvedDeviceId) {
|
||||
deviceId = resolvedDeviceId;
|
||||
});
|
||||
},
|
||||
deviceName: function() {
|
||||
return deviceName
|
||||
deviceName: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.deviceName() : deviceName;
|
||||
},
|
||||
deviceId: function() {
|
||||
return deviceId
|
||||
deviceId: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.deviceId() : deviceId;
|
||||
},
|
||||
appName: function() {
|
||||
return "Jellyfin Web"
|
||||
appName: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.appName() : "Jellyfin Web";
|
||||
},
|
||||
appVersion: function() {
|
||||
return appVersion
|
||||
appVersion: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.appVersion() : appVersion;
|
||||
},
|
||||
getPushTokenInfo: function() {
|
||||
return {}
|
||||
getPushTokenInfo: function () {
|
||||
return {};
|
||||
},
|
||||
setThemeColor: function(color) {
|
||||
setThemeColor: function (color) {
|
||||
var metaThemeColor = document.querySelector("meta[name=theme-color]");
|
||||
metaThemeColor && metaThemeColor.setAttribute("content", color)
|
||||
|
||||
if (metaThemeColor) {
|
||||
metaThemeColor.setAttribute("content", color);
|
||||
}
|
||||
},
|
||||
setUserScalable: function(scalable) {
|
||||
setUserScalable: function (scalable) {
|
||||
if (!browser.tv) {
|
||||
var att = scalable ? "width=device-width, initial-scale=1, minimum-scale=1, user-scalable=yes" : "width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no";
|
||||
document.querySelector("meta[name=viewport]").setAttribute("content", att)
|
||||
document.querySelector("meta[name=viewport]").setAttribute("content", att);
|
||||
}
|
||||
},
|
||||
deviceIconUrl: function() {
|
||||
return browser.edgeUwp, browser.edgeUwp ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/windowsrt.png" : browser.opera || browser.operaTv ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/opera.png" : browser.orsay || browser.tizen ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/samsungtv.png" : browser.web0s ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/lgtv.png" : browser.ps4 ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/ps4.png" : browser.chromecast ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/chromecast.png" : browser.chrome ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/chrome.png" : browser.edge ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/edge.png" : browser.firefox ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/firefox.png" : browser.msie ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/internetexplorer.png" : browser.safari ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/safari.png" : "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/html5.png"
|
||||
deviceIconUrl: function () {
|
||||
browser.edgeUwp;
|
||||
|
||||
if (browser.edgeUwp) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/windowsrt.png";
|
||||
}
|
||||
|
||||
if (browser.opera || browser.operaTv) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/opera.png";
|
||||
}
|
||||
|
||||
if (browser.orsay || browser.tizen) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/samsungtv.png";
|
||||
}
|
||||
|
||||
if (browser.web0s) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/lgtv.png";
|
||||
}
|
||||
|
||||
if (browser.ps4) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/ps4.png";
|
||||
}
|
||||
|
||||
if (browser.chromecast) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/chromecast.png";
|
||||
}
|
||||
|
||||
if (browser.chrome) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/chrome.png";
|
||||
}
|
||||
|
||||
if (browser.edge) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/edge.png";
|
||||
}
|
||||
|
||||
if (browser.firefox) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/firefox.png";
|
||||
}
|
||||
|
||||
if (browser.msie) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/internetexplorer.png";
|
||||
}
|
||||
|
||||
if (browser.safari) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/safari.png";
|
||||
}
|
||||
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/html5.png";
|
||||
}
|
||||
};
|
||||
|
||||
var doc = self.document;
|
||||
doc && (void 0 !== doc.visibilityState ? (visibilityChange = "visibilitychange", visibilityState = "hidden") : void 0 !== doc.mozHidden ? (visibilityChange = "mozvisibilitychange", visibilityState = "mozVisibilityState") : void 0 !== doc.msHidden ? (visibilityChange = "msvisibilitychange", visibilityState = "msVisibilityState") : void 0 !== doc.webkitHidden && (visibilityChange = "webkitvisibilitychange", visibilityState = "webkitVisibilityState"));
|
||||
var isHidden = false;
|
||||
|
||||
if (doc) {
|
||||
doc.addEventListener(visibilityChange, function() {
|
||||
document[visibilityState] ? onAppHidden() : onAppVisible()
|
||||
if (void 0 !== doc.visibilityState) {
|
||||
visibilityChange = "visibilitychange";
|
||||
visibilityState = "hidden";
|
||||
} else {
|
||||
if (void 0 !== doc.mozHidden) {
|
||||
visibilityChange = "mozvisibilitychange";
|
||||
visibilityState = "mozVisibilityState";
|
||||
} else {
|
||||
if (void 0 !== doc.msHidden) {
|
||||
visibilityChange = "msvisibilitychange";
|
||||
visibilityState = "msVisibilityState";
|
||||
} else {
|
||||
if (void 0 !== doc.webkitHidden) {
|
||||
visibilityChange = "webkitvisibilitychange";
|
||||
visibilityState = "webkitVisibilityState";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var isHidden = false;
|
||||
|
||||
if (doc) {
|
||||
doc.addEventListener(visibilityChange, function () {
|
||||
if (document[visibilityState]) {
|
||||
onAppHidden();
|
||||
} else {
|
||||
onAppVisible();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (self.addEventListener) {
|
||||
self.addEventListener("focus", onAppVisible);
|
||||
self.addEventListener("blur", onAppHidden);
|
||||
}
|
||||
|
||||
return appHost;
|
||||
});
|
||||
|
|
3
src/components/backdrop/package.json
Normal file
3
src/components/backdrop/package.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"main": "backdrop.js"
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
define(["itemHelper", "libraryMenu", "apphost"], function(itemHelper, libraryMenu, appHost) {
|
||||
"use strict";
|
||||
|
||||
function initSyncButtons(view) {
|
||||
var apiClient = window.ApiClient;
|
||||
apiClient && apiClient.getCurrentUserId() && apiClient.getCurrentUser().then(function(user) {
|
||||
for (var item = {
|
||||
SupportsSync: !0
|
||||
}, categorySyncButtons = view.querySelectorAll(".categorySyncButton"), i = 0, length = categorySyncButtons.length; i < length; i++) categorySyncButtons[i].addEventListener("click", onCategorySyncButtonClick), itemHelper.canSync(user, item) ? categorySyncButtons[i].classList.remove("hide") : categorySyncButtons[i].classList.add("hide")
|
||||
})
|
||||
}
|
||||
|
||||
function onCategorySyncButtonClick(e) {
|
||||
var button = this,
|
||||
category = button.getAttribute("data-category"),
|
||||
parentId = libraryMenu.getTopParentId();
|
||||
require(["syncDialog"], function(syncDialog) {
|
||||
syncDialog.showMenu({
|
||||
ParentId: parentId,
|
||||
Category: category,
|
||||
serverId: ApiClient.serverId(),
|
||||
mode: appHost.supports("sync") ? "download" : "sync"
|
||||
})
|
||||
})
|
||||
}
|
||||
return {
|
||||
init: function(view) {
|
||||
initSyncButtons(view)
|
||||
}
|
||||
}
|
||||
});
|
3
src/components/dialog/package.json
Normal file
3
src/components/dialog/package.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"main": "dialog.js"
|
||||
}
|
3
src/components/dialoghelper/package.json
Normal file
3
src/components/dialoghelper/package.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"main": "dialogHelper.js"
|
||||
}
|
|
@ -4,25 +4,11 @@ define(['browser', 'dom', 'layoutManager', 'shell', 'appRouter', 'apphost', 'css
|
|||
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype);
|
||||
var EmbyLinkButtonPrototype = Object.create(HTMLAnchorElement.prototype);
|
||||
|
||||
function openPremiumInfo() {
|
||||
|
||||
require(['registrationServices'], function (registrationServices) {
|
||||
registrationServices.showPremiereInfo();
|
||||
});
|
||||
}
|
||||
|
||||
function onAnchorClick(e) {
|
||||
|
||||
var href = this.getAttribute('href') || '';
|
||||
|
||||
if (href !== '#') {
|
||||
|
||||
if (this.getAttribute('target')) {
|
||||
if (href.indexOf('emby.media/premiere') !== -1 && !appHost.supports('externalpremium')) {
|
||||
e.preventDefault();
|
||||
openPremiumInfo();
|
||||
}
|
||||
else if (!appHost.supports('targetblank')) {
|
||||
if (!appHost.supports('targetblank')) {
|
||||
e.preventDefault();
|
||||
shell.openUrl(href);
|
||||
}
|
3
src/components/emby-input/package.json
Normal file
3
src/components/emby-input/package.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"main": "emby-input.js"
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue