diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000000..d1a67db6e8 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,9 @@ +--- +kind: pipeline +name: eslint + +steps: +- name: run + image: nextcloudci/eslint:eslint-1 + commands: + - ./run-eslint.sh diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 0000000000..943b958ecd --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,3 @@ +env: + browser: true + amd: true diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..137a689e8b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,35 @@ +--- +name: Bug report +about: Create a bug report +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** + + +**To Reproduce** + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** + + +**Logs** + + +**Screenshots** + + +**System (please complete the following information):** + - OS: [e.g. Docker, Debian, Windows] + - Browser: [e.g. Firefox, Chrome, Safari] + - Jellyfin Version: [e.g. 10.0.1] + +**Additional context** + diff --git a/.github/ISSUE_TEMPLATE/enhancement-request.md b/.github/ISSUE_TEMPLATE/enhancement-request.md new file mode 100644 index 0000000000..a655b60f53 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement-request.md @@ -0,0 +1,20 @@ +--- +name: Enhancement request +about: Suggest an modification to an existing feature +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** + + +**Describe the solution you'd like** + + +**Describe alternatives you've considered** + + +**Additional context** + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..3cbc8cbb91 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,14 @@ +--- +name: Feature request +about: Suggest a new feature +title: '' +labels: feature +assignees: '' + +--- + +**Describe the feature you'd like** + + +**Additional context** + diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..967be0fb73 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,11 @@ + + +**Changes** + + +**Issues** + diff --git a/.gitignore b/.gitignore index ac62bd07a1..ce35528e1f 100644 --- a/.gitignore +++ b/.gitignore @@ -71,9 +71,6 @@ coverage # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) .grunt -# Bower dependency directory (https://bower.io/) -bower_components - # node-waf configuration .lock-wscript @@ -573,3 +570,6 @@ ASALocalRun/ healthchecksdb # End of https://www.gitignore.io/api/node,rider,macos,linux,windows,visualstudio,visualstudiocode + +# dist for webpack output +dist \ No newline at end of file diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 9a343ddd15..1fe5f517ab 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -19,7 +19,8 @@ - [nkmerrill](https://github.com/nkmerrill) - [TtheCreator](https://github.com/Tthecreator) - [RazeLighter777](https://github.com/RazeLighter777) - - [anthonylavado](https://github.com/anthonylavado) + - [LogicalPhallacy](https://github.com/LogicalPhallacy) + - [thornbill](https://github.com/thornbill) # Emby Contributors diff --git a/package.json b/package.json new file mode 100644 index 0000000000..1816b6ea91 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "jellyfin-web", + "version": "0.0.0", + "description": "Web interface for Jellyfin", + "repository": "https://github.com/jellyfin/jellyfin-web", + "license": "GPL-2", + "devDependencies": { + "webpack": "^4.29.5", + "webpack-cli": "^3.2.3" + } +} diff --git a/run-eslint.sh b/run-eslint.sh new file mode 100755 index 0000000000..46b74c1a7e --- /dev/null +++ b/run-eslint.sh @@ -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' -- {} \; diff --git a/src/addplugin.html b/src/addplugin.html index efdfbcc3d3..5d5d5799d3 100644 --- a/src/addplugin.html +++ b/src/addplugin.html @@ -1,4 +1,4 @@ -
+
@@ -8,7 +8,7 @@

diff --git a/src/addserver.html b/src/addserver.html index f87e889502..a17bbcf729 100644 --- a/src/addserver.html +++ b/src/addserver.html @@ -3,7 +3,7 @@

${HeaderConnectToServer}

- +
${LabelServerHostHelp}

@@ -19,4 +19,4 @@
-
\ No newline at end of file +
diff --git a/src/appservices.html b/src/appservices.html deleted file mode 100644 index 43f37a0980..0000000000 --- a/src/appservices.html +++ /dev/null @@ -1,21 +0,0 @@ -
- -
-
- -
- -
-

${HeaderInstalledServices}

- ${Help} -
- -
-
-
-

${HeaderAvailableServices}

-
-
-
-
-
\ No newline at end of file diff --git a/src/availableplugins.html b/src/availableplugins.html new file mode 100644 index 0000000000..ea1147fbfd --- /dev/null +++ b/src/availableplugins.html @@ -0,0 +1,8 @@ +
+
+
+
${MessageNoAvailablePlugins}
+
+
+
+
\ No newline at end of file diff --git a/src/bower_components/emby-apiclient/apiclientex.js b/src/bower_components/apiclient/apiclient.js similarity index 98% rename from src/bower_components/emby-apiclient/apiclientex.js rename to src/bower_components/apiclient/apiclient.js index b6a0c1bb14..98aaed75e3 100644 --- a/src/bower_components/emby-apiclient/apiclientex.js +++ b/src/bower_components/apiclient/apiclient.js @@ -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) } diff --git a/src/bower_components/emby-apiclient/apiclient.js b/src/bower_components/apiclient/apiclientcore.js similarity index 100% rename from src/bower_components/emby-apiclient/apiclient.js rename to src/bower_components/apiclient/apiclientcore.js diff --git a/src/bower_components/apiclient/appStorage.js b/src/bower_components/apiclient/appStorage.js new file mode 100644 index 0000000000..6083bb4953 --- /dev/null +++ b/src/bower_components/apiclient/appStorage.js @@ -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; +}); \ No newline at end of file diff --git a/src/bower_components/emby-apiclient/connectionmanager.js b/src/bower_components/apiclient/connectionmanager.js similarity index 99% rename from src/bower_components/emby-apiclient/connectionmanager.js rename to src/bower_components/apiclient/connectionmanager.js index 39824d31f7..93e9673a46 100644 --- a/src/bower_components/emby-apiclient/connectionmanager.js +++ b/src/bower_components/apiclient/connectionmanager.js @@ -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) { diff --git a/src/bower_components/emby-apiclient/credentials.js b/src/bower_components/apiclient/credentials.js similarity index 100% rename from src/bower_components/emby-apiclient/credentials.js rename to src/bower_components/apiclient/credentials.js diff --git a/src/bower_components/emby-apiclient/events.js b/src/bower_components/apiclient/events.js similarity index 100% rename from src/bower_components/emby-apiclient/events.js rename to src/bower_components/apiclient/events.js diff --git a/src/bower_components/emby-apiclient/localassetmanager.js b/src/bower_components/apiclient/localassetmanager.js similarity index 100% rename from src/bower_components/emby-apiclient/localassetmanager.js rename to src/bower_components/apiclient/localassetmanager.js diff --git a/src/bower_components/apiclient/package.json b/src/bower_components/apiclient/package.json new file mode 100644 index 0000000000..0069cfc6bf --- /dev/null +++ b/src/bower_components/apiclient/package.json @@ -0,0 +1,3 @@ +{ + "main": "apiclient.js" +} \ No newline at end of file diff --git a/src/bower_components/emby-apiclient/sync/filerepository.js b/src/bower_components/apiclient/sync/filerepository.js similarity index 100% rename from src/bower_components/emby-apiclient/sync/filerepository.js rename to src/bower_components/apiclient/sync/filerepository.js diff --git a/src/bower_components/emby-apiclient/sync/itemrepository.js b/src/bower_components/apiclient/sync/itemrepository.js similarity index 100% rename from src/bower_components/emby-apiclient/sync/itemrepository.js rename to src/bower_components/apiclient/sync/itemrepository.js diff --git a/src/bower_components/emby-apiclient/sync/localsync.js b/src/bower_components/apiclient/sync/localsync.js similarity index 100% rename from src/bower_components/emby-apiclient/sync/localsync.js rename to src/bower_components/apiclient/sync/localsync.js diff --git a/src/bower_components/emby-apiclient/sync/mediasync.js b/src/bower_components/apiclient/sync/mediasync.js similarity index 100% rename from src/bower_components/emby-apiclient/sync/mediasync.js rename to src/bower_components/apiclient/sync/mediasync.js diff --git a/src/bower_components/emby-apiclient/sync/multiserversync.js b/src/bower_components/apiclient/sync/multiserversync.js similarity index 100% rename from src/bower_components/emby-apiclient/sync/multiserversync.js rename to src/bower_components/apiclient/sync/multiserversync.js diff --git a/src/bower_components/emby-apiclient/sync/serversync.js b/src/bower_components/apiclient/sync/serversync.js similarity index 100% rename from src/bower_components/emby-apiclient/sync/serversync.js rename to src/bower_components/apiclient/sync/serversync.js diff --git a/src/bower_components/emby-apiclient/sync/transfermanager.js b/src/bower_components/apiclient/sync/transfermanager.js similarity index 100% rename from src/bower_components/emby-apiclient/sync/transfermanager.js rename to src/bower_components/apiclient/sync/transfermanager.js diff --git a/src/bower_components/emby-apiclient/sync/useractionrepository.js b/src/bower_components/apiclient/sync/useractionrepository.js similarity index 100% rename from src/bower_components/emby-apiclient/sync/useractionrepository.js rename to src/bower_components/apiclient/sync/useractionrepository.js diff --git a/src/bower_components/emby-apiclient/appstorage-cache.js b/src/bower_components/emby-apiclient/appstorage-cache.js deleted file mode 100644 index 1f584f2a2b..0000000000 --- a/src/bower_components/emby-apiclient/appstorage-cache.js +++ /dev/null @@ -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 -}); \ No newline at end of file diff --git a/src/bower_components/emby-apiclient/appstorage-localstorage.js b/src/bower_components/emby-apiclient/appstorage-localstorage.js deleted file mode 100644 index 4baa82618e..0000000000 --- a/src/bower_components/emby-apiclient/appstorage-localstorage.js +++ /dev/null @@ -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 -}); \ No newline at end of file diff --git a/src/bower_components/emby-apiclient/appstorage-memory.js b/src/bower_components/emby-apiclient/appstorage-memory.js deleted file mode 100644 index 75aab19923..0000000000 --- a/src/bower_components/emby-apiclient/appstorage-memory.js +++ /dev/null @@ -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 -}); \ No newline at end of file diff --git a/src/bower_components/emby-apiclient/fileupload.js b/src/bower_components/emby-apiclient/fileupload.js deleted file mode 100644 index 91f77395e6..0000000000 --- a/src/bower_components/emby-apiclient/fileupload.js +++ /dev/null @@ -1,8 +0,0 @@ -define([], function() { - "use strict"; - - function FileUpload() {} - return FileUpload.prototype.upload = function(file, url) { - return Promise.reject() - }, FileUpload -}); \ No newline at end of file diff --git a/src/bower_components/emby-apiclient/serverdiscovery.js b/src/bower_components/emby-apiclient/serverdiscovery.js deleted file mode 100644 index 4f18505ecc..0000000000 --- a/src/bower_components/emby-apiclient/serverdiscovery.js +++ /dev/null @@ -1,8 +0,0 @@ -define([], function() { - "use strict"; - return { - findServers: function(timeoutMs) { - return Promise.resolve([]) - } - } -}); \ No newline at end of file diff --git a/src/bower_components/emby-apiclient/wakeonlan.js b/src/bower_components/emby-apiclient/wakeonlan.js deleted file mode 100644 index 58c01e61a5..0000000000 --- a/src/bower_components/emby-apiclient/wakeonlan.js +++ /dev/null @@ -1,15 +0,0 @@ -define([], function() { - "use strict"; - - function send(info) { - return Promise.reject() - } - - function isSupported() { - return !1 - } - return { - send: send, - isSupported: isSupported - } -}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/alert/alert.js b/src/bower_components/emby-webcomponents/alert/alert.js deleted file mode 100644 index ce434bac8a..0000000000 --- a/src/bower_components/emby-webcomponents/alert/alert.js +++ /dev/null @@ -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(); - }); - }; -}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/alert/nativealert.js b/src/bower_components/emby-webcomponents/alert/nativealert.js deleted file mode 100644 index f565e802c7..0000000000 --- a/src/bower_components/emby-webcomponents/alert/nativealert.js +++ /dev/null @@ -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 || '', '
', '\n'); - - alert(text); - - return Promise.resolve(); - }; -}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/filedownloader.js b/src/bower_components/emby-webcomponents/filedownloader.js deleted file mode 100644 index c8e3011be2..0000000000 --- a/src/bower_components/emby-webcomponents/filedownloader.js +++ /dev/null @@ -1,12 +0,0 @@ -define(['multi-download'], function (multiDownload) { - 'use strict'; - - return { - download: function (items) { - - multiDownload(items.map(function (item) { - return item.url; - })); - } - }; -}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/filesystem.js b/src/bower_components/emby-webcomponents/filesystem.js deleted file mode 100644 index 4489d2921f..0000000000 --- a/src/bower_components/emby-webcomponents/filesystem.js +++ /dev/null @@ -1,12 +0,0 @@ -define([], function () { - 'use strict'; - - return { - fileExists: function (path) { - return Promise.reject(); - }, - directoryExists: function (path) { - return Promise.reject(); - } - }; -}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/fullscreen/fullscreen-dc.js b/src/bower_components/emby-webcomponents/fullscreen/fullscreen-dc.js deleted file mode 100644 index bc12a6a76d..0000000000 --- a/src/bower_components/emby-webcomponents/fullscreen/fullscreen-dc.js +++ /dev/null @@ -1,26 +0,0 @@ -define(['dom', 'fullscreenManager'], function (dom, fullscreenManager) { - 'use strict'; - - function isTargetValid(target) { - - if (dom.parentWithTag(target, ['BUTTON', 'INPUT', 'TEXTAREA'])) { - return false; - } - - return true; - } - - dom.addEventListener(window, 'dblclick', function (e) { - - if (isTargetValid(e.target)) { - if (fullscreenManager.isFullScreen()) { - fullscreenManager.exitFullscreen(); - } else { - fullscreenManager.requestFullscreen(); - } - } - - }, { - passive: true - }); -}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/notifications/badge.png b/src/bower_components/emby-webcomponents/notifications/badge.png deleted file mode 100644 index 372343f5c9..0000000000 Binary files a/src/bower_components/emby-webcomponents/notifications/badge.png and /dev/null differ diff --git a/src/bower_components/emby-webcomponents/notifications/notificationicon.png b/src/bower_components/emby-webcomponents/notifications/notificationicon.png deleted file mode 100644 index 372343f5c9..0000000000 Binary files a/src/bower_components/emby-webcomponents/notifications/notificationicon.png and /dev/null differ diff --git a/src/bower_components/emby-webcomponents/playback/playbackvalidation.js b/src/bower_components/emby-webcomponents/playback/playbackvalidation.js deleted file mode 100644 index c36d5c1b5a..0000000000 --- a/src/bower_components/emby-webcomponents/playback/playbackvalidation.js +++ /dev/null @@ -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; -}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/polyfills/array.js b/src/bower_components/emby-webcomponents/polyfills/array.js deleted file mode 100644 index 5caea62e3b..0000000000 --- a/src/bower_components/emby-webcomponents/polyfills/array.js +++ /dev/null @@ -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; - }; -} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/polyfills/bind.js b/src/bower_components/emby-webcomponents/polyfills/bind.js deleted file mode 100644 index 82495aa103..0000000000 --- a/src/bower_components/emby-webcomponents/polyfills/bind.js +++ /dev/null @@ -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; - }; -} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/polyfills/objectassign.js b/src/bower_components/emby-webcomponents/polyfills/objectassign.js deleted file mode 100644 index 2ea96b188d..0000000000 --- a/src/bower_components/emby-webcomponents/polyfills/objectassign.js +++ /dev/null @@ -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; - }; - })(); -} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/polyfills/raf.js b/src/bower_components/emby-webcomponents/polyfills/raf.js deleted file mode 100644 index 2c7c433329..0000000000 --- a/src/bower_components/emby-webcomponents/polyfills/raf.js +++ /dev/null @@ -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); - }; -}()); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/registrationservices/registrationservices.js b/src/bower_components/emby-webcomponents/registrationservices/registrationservices.js deleted file mode 100644 index f5b4094213..0000000000 --- a/src/bower_components/emby-webcomponents/registrationservices/registrationservices.js +++ /dev/null @@ -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 - }; -}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/serviceworker/sync.js b/src/bower_components/emby-webcomponents/serviceworker/sync.js deleted file mode 100644 index 3dcff8f363..0000000000 --- a/src/bower_components/emby-webcomponents/serviceworker/sync.js +++ /dev/null @@ -1,6 +0,0 @@ -self.addEventListener('sync', function (event) { - 'use strict'; - - if (event.tag === 'emby-sync') { - } -}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/shell.js b/src/bower_components/emby-webcomponents/shell.js deleted file mode 100644 index 0083404e19..0000000000 --- a/src/bower_components/emby-webcomponents/shell.js +++ /dev/null @@ -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 - } - }; -}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/skinmanager.js b/src/bower_components/emby-webcomponents/skinmanager.js deleted file mode 100644 index 48820512cf..0000000000 --- a/src/bower_components/emby-webcomponents/skinmanager.js +++ /dev/null @@ -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; -}); diff --git a/src/bower_components/emby-webcomponents/sync/emby-downloadbutton.js b/src/bower_components/emby-webcomponents/sync/emby-downloadbutton.js deleted file mode 100644 index 74a9f6b3bb..0000000000 --- a/src/bower_components/emby-webcomponents/sync/emby-downloadbutton.js +++ /dev/null @@ -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' - }); -}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/sync/sync.js b/src/bower_components/emby-webcomponents/sync/sync.js deleted file mode 100644 index e7c51e3dc5..0000000000 --- a/src/bower_components/emby-webcomponents/sync/sync.js +++ /dev/null @@ -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 += '
'; - html += ''; - html += '
'; - } else { - html += '
'; - html += ''; - if (!targets.length) { - html += '
' + globalize.translate('LabelSyncNoTargetsHelp') + '
'; - } - - if (appHost.supports('externallinks')) { - html += ''; - } - html += '
'; - } - - html += '
'; - html += ''; - html += '
'; - html += '
'; - - html += '
'; - html += ''; - html += '
'; - html += '
'; - - html += '
'; - html += ''; - html += '
'; - - if (dialogOptions.Options.indexOf('UnwatchedOnly') !== -1) { - html += '
'; - html += ''; - - if (mode === 'convert') { - html += '
' + globalize.translate('ConvertUnwatchedVideosOnlyHelp') + '
'; - } else { - html += '
' + globalize.translate('SyncUnwatchedVideosOnlyHelp') + '
'; - } - - html += '
'; - } - - if (dialogOptions.Options.indexOf('SyncNewContent') !== -1) { - html += '
'; - html += ''; - - if (mode === 'convert') { - html += '
' + globalize.translate('AutomaticallyConvertNewContentHelp') + '
'; - } else { - html += '
' + globalize.translate('AutomaticallySyncNewContentHelp') + '
'; - } - html += '
'; - } - - if (dialogOptions.Options.indexOf('ItemLimit') !== -1) { - html += '
'; - html += ''; - - if (mode === 'convert') { - html += '
' + globalize.translate('ConvertItemLimitHelp') + '
'; - } else { - html += '
' + globalize.translate('DownloadItemLimitHelp') + '
'; - } - - html += '
'; - } - - //html += '
'; - //html += '
'; - - 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 += '
'; - html += ''; - html += '

'; - - var syncButtonLabel = options.mode === 'download' ? - globalize.translate('Download') : - (options.mode === 'convert' ? globalize.translate('Convert') : globalize.translate('Sync')); - - html += syncButtonLabel; - html += '

'; - - if (appHost.supports('externallinks')) { - html += 'info' + globalize.translate('Help') + ''; - } - - html += '
'; - - html += '
'; - html += '
'; - - html += '
'; - - html += '
'; - - html += '
'; - - html += ''; - html += '
'; - - html += '
'; - - html += '
'; - html += '
'; - - 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 ''; - - }).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 ''; - - }).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 - }; -}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/themes/logodark.png b/src/bower_components/emby-webcomponents/themes/logodark.png deleted file mode 100644 index 3511abc23b..0000000000 Binary files a/src/bower_components/emby-webcomponents/themes/logodark.png and /dev/null differ diff --git a/src/bower_components/emby-webcomponents/themes/logowhite.png b/src/bower_components/emby-webcomponents/themes/logowhite.png deleted file mode 100644 index 58f94fa989..0000000000 Binary files a/src/bower_components/emby-webcomponents/themes/logowhite.png and /dev/null differ diff --git a/src/bower_components/emby-webcomponents/viewmanager/viewcontainer-lite.js b/src/bower_components/emby-webcomponents/viewmanager/viewcontainer-lite.js deleted file mode 100644 index 57c8fe926c..0000000000 --- a/src/bower_components/emby-webcomponents/viewmanager/viewcontainer-lite.js +++ /dev/null @@ -1,313 +0,0 @@ -define(['browser', 'dom', 'layoutManager', 'css!./viewcontainer-lite'], function (browser, dom, layoutManager) { - 'use strict'; - - var mainAnimatedPages = document.querySelector('.mainAnimatedPages'); - var allPages = []; - var currentUrls = []; - var pageContainerCount = 3; - var selectedPageIndex = -1; - - function enableAnimation() { - - // too slow - if (browser.tv) { - return false; - } - - return browser.supportsCssAnimation(); - } - - function findLastView(parent, className) { - - var nodes = parent.childNodes; - for (var i = nodes.length - 1; i >= 0; i--) { - var node = nodes[i]; - var classList = node.classList; - if (classList && classList.contains(className)) { - return node; - } - } - } - - function findViewBefore(elem, className) { - - var node = elem.previousSibling; - while (node) { - var classList = node.classList; - if (classList && classList.contains(className)) { - return node; - } - - node = node.previousSibling; - } - } - - function loadView(options) { - - if (options.cancel) { - return; - } - - cancelActiveAnimations(); - - var selected = selectedPageIndex; - var previousAnimatable = selected === -1 ? null : allPages[selected]; - var pageIndex = selected + 1; - - if (pageIndex >= pageContainerCount) { - pageIndex = 0; - } - - var viewHtml = options.view; - - var properties = []; - if (options.fullscreen) { - properties.push('fullscreen'); - } - - var currentPage = allPages[pageIndex]; - - var view; - - if (currentPage) { - triggerDestroy(currentPage); - currentPage.insertAdjacentHTML('beforebegin', viewHtml); - view = findViewBefore(currentPage, 'view'); - - mainAnimatedPages.removeChild(currentPage); - - } else { - mainAnimatedPages.insertAdjacentHTML('beforeend', viewHtml); - - view = findLastView(mainAnimatedPages, 'view'); - } - - view.classList.add('mainAnimatedPage'); - - if (properties.length) { - view.setAttribute('data-properties', properties.join(',')); - } - - if (options.type) { - view.setAttribute('data-type', options.type); - } - - allPages[pageIndex] = view; - - if (onBeforeChange) { - onBeforeChange(view, false, options); - } - - beforeAnimate(allPages, pageIndex, selected); - - // animate here - return animate(view, previousAnimatable, options.transition, options.isBack).then(function () { - - selectedPageIndex = pageIndex; - currentUrls[pageIndex] = options.url; - if (!options.cancel && previousAnimatable) { - afterAnimate(allPages, pageIndex); - } - - return view; - }); - } - - function beforeAnimate(allPages, newPageIndex, oldPageIndex) { - for (var i = 0, length = allPages.length; i < length; i++) { - if (newPageIndex === i || oldPageIndex === i) { - //allPages[i].classList.remove('hide'); - } else { - allPages[i].classList.add('hide'); - } - } - } - - function afterAnimate(allPages, newPageIndex) { - for (var i = 0, length = allPages.length; i < length; i++) { - if (newPageIndex === i) { - //allPages[i].classList.remove('hide'); - } else { - allPages[i].classList.add('hide'); - } - } - } - - function animate(newAnimatedPage, oldAnimatedPage, transition, isBack) { - - if (enableAnimation() && oldAnimatedPage) { - if (transition === 'slide') { - return slide(newAnimatedPage, oldAnimatedPage, transition, isBack); - } else if (transition === 'fade') { - return fade(newAnimatedPage, oldAnimatedPage, transition, isBack); - } else { - clearAnimation(newAnimatedPage); - if (oldAnimatedPage) { - clearAnimation(oldAnimatedPage); - } - } - } - - return Promise.resolve(); - } - - function clearAnimation(elem) { - setAnimation(elem, 'none'); - } - - function slide(newAnimatedPage, oldAnimatedPage, transition, isBack) { - - return new Promise(function (resolve, reject) { - - var duration = layoutManager.tv ? 450 : 160; - - var animations = []; - - if (oldAnimatedPage) { - if (isBack) { - setAnimation(oldAnimatedPage, 'view-slideright-r ' + duration + 'ms ease-out normal both'); - } else { - setAnimation(oldAnimatedPage, 'view-slideleft-r ' + duration + 'ms ease-out normal both'); - } - animations.push(oldAnimatedPage); - } - - if (isBack) { - setAnimation(newAnimatedPage, 'view-slideright ' + duration + 'ms ease-out normal both'); - } else { - setAnimation(newAnimatedPage, 'view-slideleft ' + duration + 'ms ease-out normal both'); - } - animations.push(newAnimatedPage); - - currentAnimations = animations; - - var onAnimationComplete = function () { - dom.removeEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, { - once: true - }); - resolve(); - }; - - dom.addEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, { - once: true - }); - }); - } - - function fade(newAnimatedPage, oldAnimatedPage, transition, isBack) { - - return new Promise(function (resolve, reject) { - - var duration = layoutManager.tv ? 450 : 270; - var animations = []; - - newAnimatedPage.style.opacity = 0; - setAnimation(newAnimatedPage, 'view-fadein ' + duration + 'ms ease-in normal both'); - animations.push(newAnimatedPage); - - if (oldAnimatedPage) { - setAnimation(oldAnimatedPage, 'view-fadeout ' + duration + 'ms ease-out normal both'); - animations.push(oldAnimatedPage); - } - - currentAnimations = animations; - - var onAnimationComplete = function () { - dom.removeEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, { - once: true - }); - resolve(); - }; - - dom.addEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, { - once: true - }); - }); - } - - function setAnimation(elem, value) { - - requestAnimationFrame(function () { - elem.style.animation = value; - }); - } - - var currentAnimations = []; - function cancelActiveAnimations() { - - var animations = currentAnimations; - for (var i = 0, length = animations.length; i < length; i++) { - animations[i].style.animation = 'none'; - } - } - - var onBeforeChange; - function setOnBeforeChange(fn) { - onBeforeChange = fn; - } - - function tryRestoreView(options) { - - var url = options.url; - var index = currentUrls.indexOf(url); - - if (index !== -1) { - - var animatable = allPages[index]; - var view = animatable; - - if (view) { - - if (options.cancel) { - return; - } - - cancelActiveAnimations(); - - var selected = selectedPageIndex; - var previousAnimatable = selected === -1 ? null : allPages[selected]; - - if (onBeforeChange) { - onBeforeChange(view, true, options); - } - - beforeAnimate(allPages, index, selected); - - animatable.classList.remove('hide'); - - return animate(animatable, previousAnimatable, options.transition, options.isBack).then(function () { - - selectedPageIndex = index; - if (!options.cancel && previousAnimatable) { - afterAnimate(allPages, index); - } - return view; - }); - } - } - - return Promise.reject(); - } - - function triggerDestroy(view) { - - view.dispatchEvent(new CustomEvent('viewdestroy', { - cancelable: false - })); - } - - function reset() { - - allPages = []; - currentUrls = []; - mainAnimatedPages.innerHTML = ''; - selectedPageIndex = -1; - } - - return { - loadView: loadView, - tryRestoreView: tryRestoreView, - reset: reset, - setOnBeforeChange: setOnBeforeChange - }; -}); \ No newline at end of file diff --git a/src/bower_components/fetch/fetch.js b/src/bower_components/fetch/fetch.js deleted file mode 100644 index cd40b3ed2d..0000000000 --- a/src/bower_components/fetch/fetch.js +++ /dev/null @@ -1,263 +0,0 @@ -! function(self) { - "use strict"; - - function normalizeName(name) { - if ("string" != typeof name && (name = String(name)), /[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) throw new TypeError("Invalid character in header field name"); - return name.toLowerCase() - } - - function normalizeValue(value) { - return "string" != typeof value && (value = String(value)), value - } - - function iteratorFor(items) { - var iterator = { - next: function() { - var value = items.shift(); - return { - done: void 0 === value, - value: value - } - } - }; - return support.iterable && (iterator[Symbol.iterator] = function() { - return iterator - }), iterator - } - - function Headers(headers) { - this.map = {}, headers instanceof Headers ? headers.forEach(function(value, name) { - this.append(name, value) - }, this) : headers && Object.getOwnPropertyNames(headers).forEach(function(name) { - this.append(name, headers[name]) - }, this) - } - - function consumed(body) { - if (body.bodyUsed) return Promise.reject(new TypeError("Already read")); - body.bodyUsed = !0 - } - - function fileReaderReady(reader) { - return new Promise(function(resolve, reject) { - reader.onload = function() { - resolve(reader.result) - }, reader.onerror = function() { - reject(reader.error) - } - }) - } - - function readBlobAsArrayBuffer(blob) { - var reader = new FileReader, - promise = fileReaderReady(reader); - return reader.readAsArrayBuffer(blob), promise - } - - function readBlobAsText(blob) { - var reader = new FileReader, - promise = fileReaderReady(reader); - return reader.readAsText(blob), promise - } - - function readArrayBufferAsText(buf) { - for (var view = new Uint8Array(buf), chars = new Array(view.length), i = 0; i < view.length; i++) chars[i] = String.fromCharCode(view[i]); - return chars.join("") - } - - function bufferClone(buf) { - if (buf.slice) return buf.slice(0); - var view = new Uint8Array(buf.byteLength); - return view.set(new Uint8Array(buf)), view.buffer - } - - function Body() { - return this.bodyUsed = !1, this._initBody = function(body) { - if (this._bodyInit = body, body) - if ("string" == typeof body) this._bodyText = body; - else if (support.blob && Blob.prototype.isPrototypeOf(body)) this._bodyBlob = body; - else if (support.formData && FormData.prototype.isPrototypeOf(body)) this._bodyFormData = body; - else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) this._bodyText = body.toString(); - else if (support.arrayBuffer && support.blob && isDataView(body)) this._bodyArrayBuffer = bufferClone(body.buffer), this._bodyInit = new Blob([this._bodyArrayBuffer]); - else { - if (!support.arrayBuffer || !ArrayBuffer.prototype.isPrototypeOf(body) && !isArrayBufferView(body)) throw new Error("unsupported BodyInit type"); - this._bodyArrayBuffer = bufferClone(body) - } else this._bodyText = ""; - this.headers.get("content-type") || ("string" == typeof body ? this.headers.set("content-type", "text/plain;charset=UTF-8") : this._bodyBlob && this._bodyBlob.type ? this.headers.set("content-type", this._bodyBlob.type) : support.searchParams && URLSearchParams.prototype.isPrototypeOf(body) && this.headers.set("content-type", "application/x-www-form-urlencoded;charset=UTF-8")) - }, support.blob && (this.blob = function() { - var rejected = consumed(this); - if (rejected) return rejected; - if (this._bodyBlob) return Promise.resolve(this._bodyBlob); - if (this._bodyArrayBuffer) return Promise.resolve(new Blob([this._bodyArrayBuffer])); - if (this._bodyFormData) throw new Error("could not read FormData body as blob"); - return Promise.resolve(new Blob([this._bodyText])) - }, this.arrayBuffer = function() { - return this._bodyArrayBuffer ? consumed(this) || Promise.resolve(this._bodyArrayBuffer) : this.blob().then(readBlobAsArrayBuffer) - }), this.text = function() { - var rejected = consumed(this); - if (rejected) return rejected; - if (this._bodyBlob) return readBlobAsText(this._bodyBlob); - if (this._bodyArrayBuffer) return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer)); - if (this._bodyFormData) throw new Error("could not read FormData body as text"); - return Promise.resolve(this._bodyText) - }, support.formData && (this.formData = function() { - return this.text().then(decode) - }), this.json = function() { - return this.text().then(JSON.parse) - }, this - } - - function normalizeMethod(method) { - var upcased = method.toUpperCase(); - return methods.indexOf(upcased) > -1 ? upcased : method - } - - function Request(input, options) { - options = options || {}; - var body = options.body; - if ("string" == typeof input) this.url = input; - else { - if (input.bodyUsed) throw new TypeError("Already read"); - this.url = input.url, this.credentials = input.credentials, options.headers || (this.headers = new Headers(input.headers)), this.method = input.method, this.mode = input.mode, body || null == input._bodyInit || (body = input._bodyInit, input.bodyUsed = !0) - } - if (this.credentials = options.credentials || this.credentials || "omit", !options.headers && this.headers || (this.headers = new Headers(options.headers)), this.method = normalizeMethod(options.method || this.method || "GET"), this.mode = options.mode || this.mode || null, this.referrer = null, ("GET" === this.method || "HEAD" === this.method) && body) throw new TypeError("Body not allowed for GET or HEAD requests"); - this._initBody(body) - } - - function decode(body) { - var form = new FormData; - return body.trim().split("&").forEach(function(bytes) { - if (bytes) { - var split = bytes.split("="), - name = split.shift().replace(/\+/g, " "), - value = split.join("=").replace(/\+/g, " "); - form.append(decodeURIComponent(name), decodeURIComponent(value)) - } - }), form - } - - function parseHeaders(rawHeaders) { - var headers = new Headers; - return rawHeaders.split("\r\n").forEach(function(line) { - var parts = line.split(":"), - key = parts.shift().trim(); - if (key) { - var value = parts.join(":").trim(); - headers.append(key, value) - } - }), headers - } - - function Response(bodyInit, options) { - options || (options = {}), this.type = "default", this.status = "status" in options ? options.status : 200, this.ok = this.status >= 200 && this.status < 300, this.statusText = "statusText" in options ? options.statusText : "OK", this.headers = new Headers(options.headers), this.url = options.url || "", this._initBody(bodyInit) - } - if (!self.fetch) { - var support = { - searchParams: "URLSearchParams" in self, - iterable: "Symbol" in self && "iterator" in Symbol, - blob: "FileReader" in self && "Blob" in self && function() { - try { - return new Blob, !0 - } catch (e) { - return !1 - } - }(), - formData: "FormData" in self, - arrayBuffer: "ArrayBuffer" in self - }; - if (support.arrayBuffer) var viewClasses = ["[object Int8Array]", "[object Uint8Array]", "[object Uint8ClampedArray]", "[object Int16Array]", "[object Uint16Array]", "[object Int32Array]", "[object Uint32Array]", "[object Float32Array]", "[object Float64Array]"], - isDataView = function(obj) { - return obj && DataView.prototype.isPrototypeOf(obj) - }, - isArrayBufferView = ArrayBuffer.isView || function(obj) { - return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1 - }; - Headers.prototype.append = function(name, value) { - name = normalizeName(name), value = normalizeValue(value); - var list = this.map[name]; - list || (list = [], this.map[name] = list), list.push(value) - }, Headers.prototype.delete = function(name) { - delete this.map[normalizeName(name)] - }, Headers.prototype.get = function(name) { - var values = this.map[normalizeName(name)]; - return values ? values[0] : null - }, Headers.prototype.getAll = function(name) { - return this.map[normalizeName(name)] || [] - }, Headers.prototype.has = function(name) { - return this.map.hasOwnProperty(normalizeName(name)) - }, Headers.prototype.set = function(name, value) { - this.map[normalizeName(name)] = [normalizeValue(value)] - }, Headers.prototype.forEach = function(callback, thisArg) { - Object.getOwnPropertyNames(this.map).forEach(function(name) { - this.map[name].forEach(function(value) { - callback.call(thisArg, value, name, this) - }, this) - }, this) - }, Headers.prototype.keys = function() { - var items = []; - return this.forEach(function(value, name) { - items.push(name) - }), iteratorFor(items) - }, Headers.prototype.values = function() { - var items = []; - return this.forEach(function(value) { - items.push(value) - }), iteratorFor(items) - }, Headers.prototype.entries = function() { - var items = []; - return this.forEach(function(value, name) { - items.push([name, value]) - }), iteratorFor(items) - }, support.iterable && (Headers.prototype[Symbol.iterator] = Headers.prototype.entries); - var methods = ["DELETE", "GET", "HEAD", "OPTIONS", "POST", "PUT"]; - Request.prototype.clone = function() { - return new Request(this, { - body: this._bodyInit - }) - }, Body.call(Request.prototype), Body.call(Response.prototype), Response.prototype.clone = function() { - return new Response(this._bodyInit, { - status: this.status, - statusText: this.statusText, - headers: new Headers(this.headers), - url: this.url - }) - }, Response.error = function() { - var response = new Response(null, { - status: 0, - statusText: "" - }); - return response.type = "error", response - }; - var redirectStatuses = [301, 302, 303, 307, 308]; - Response.redirect = function(url, status) { - if (-1 === redirectStatuses.indexOf(status)) throw new RangeError("Invalid status code"); - return new Response(null, { - status: status, - headers: { - location: url - } - }) - }, self.Headers = Headers, self.Request = Request, self.Response = Response, self.fetch = function(input, init) { - return new Promise(function(resolve, reject) { - var request = new Request(input, init), - xhr = new XMLHttpRequest; - xhr.onload = function() { - var options = { - status: xhr.status, - statusText: xhr.statusText, - headers: parseHeaders(xhr.getAllResponseHeaders() || "") - }; - options.url = "responseURL" in xhr ? xhr.responseURL : options.headers.get("X-Request-URL"); - var body = "response" in xhr ? xhr.response : xhr.responseText; - resolve(new Response(body, options)) - }, xhr.onerror = function() { - reject(new TypeError("Network request failed")) - }, xhr.ontimeout = function() { - reject(new TypeError("Network request failed")) - }, xhr.open(request.method, request.url, !0), "include" === request.credentials && (xhr.withCredentials = !0), "responseType" in xhr && support.blob && (xhr.responseType = "blob"), request.headers.forEach(function(value, name) { - xhr.setRequestHeader(name, value) - }), xhr.send(void 0 === request._bodyInit ? null : request._bodyInit) - }) - }, self.fetch.polyfill = !0 - } -}("undefined" != typeof self ? self : this); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/actionsheet/actionsheet.css b/src/components/actionsheet/actionsheet.css similarity index 100% rename from src/bower_components/emby-webcomponents/actionsheet/actionsheet.css rename to src/components/actionsheet/actionsheet.css diff --git a/src/bower_components/emby-webcomponents/actionsheet/actionsheet.js b/src/components/actionsheet/actionsheet.js similarity index 100% rename from src/bower_components/emby-webcomponents/actionsheet/actionsheet.js rename to src/components/actionsheet/actionsheet.js diff --git a/src/components/actionsheet/package.json b/src/components/actionsheet/package.json new file mode 100644 index 0000000000..622f1e075d --- /dev/null +++ b/src/components/actionsheet/package.json @@ -0,0 +1,3 @@ +{ + "main": "actionsheet.js" +} \ No newline at end of file diff --git a/src/components/alert.js b/src/components/alert.js new file mode 100644 index 0000000000..0e8c16501f --- /dev/null +++ b/src/components/alert.js @@ -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 || '', '
', '\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(); + }; +}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/alphanumericshortcuts/alphanumericshortcuts.js b/src/components/alphanumericshortcuts/alphanumericshortcuts.js similarity index 100% rename from src/bower_components/emby-webcomponents/alphanumericshortcuts/alphanumericshortcuts.js rename to src/components/alphanumericshortcuts/alphanumericshortcuts.js diff --git a/src/bower_components/emby-webcomponents/alphapicker/alphapicker.js b/src/components/alphapicker/alphapicker.js similarity index 100% rename from src/bower_components/emby-webcomponents/alphapicker/alphapicker.js rename to src/components/alphapicker/alphapicker.js diff --git a/src/bower_components/emby-webcomponents/alphapicker/style.css b/src/components/alphapicker/style.css similarity index 100% rename from src/bower_components/emby-webcomponents/alphapicker/style.css rename to src/components/alphapicker/style.css diff --git a/src/bower_components/emby-webcomponents/router.js b/src/components/appRouter.js similarity index 86% rename from src/bower_components/emby-webcomponents/router.js rename to src/components/appRouter.js index e2ae62e75b..f9761d4d61 100644 --- a/src/bower_components/emby-webcomponents/router.js +++ b/src/components/appRouter.js @@ -1,4 +1,4 @@ -define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinManager', 'pluginManager', 'backdrop', 'browser', 'pageJs', 'appSettings', 'apphost', 'connectionManager'], function (loading, globalize, events, viewManager, layoutManager, skinManager, pluginManager, backdrop, browser, page, appSettings, appHost, connectionManager) { +define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinManager', 'pluginManager', 'backdrop', 'browser', 'page', 'appSettings', 'apphost', 'connectionManager'], function (loading, globalize, events, viewManager, layoutManager, skinManager, pluginManager, backdrop, browser, page, appSettings, appHost, connectionManager) { 'use strict'; var appRouter = { @@ -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); - } else { - onInitComplete(); - } - }); + if (route.controller) { + 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, diff --git a/src/bower_components/emby-webcomponents/appfooter/appfooter.css b/src/components/appfooter/appfooter.css similarity index 100% rename from src/bower_components/emby-webcomponents/appfooter/appfooter.css rename to src/components/appfooter/appfooter.css diff --git a/src/bower_components/emby-webcomponents/appfooter/appfooter.js b/src/components/appfooter/appfooter.js similarity index 100% rename from src/bower_components/emby-webcomponents/appfooter/appfooter.js rename to src/components/appfooter/appfooter.js diff --git a/src/components/apphost.js b/src/components/apphost.js index 8de18f166f..4106cac285 100644 --- a/src/components/apphost.js +++ b/src/components/apphost.js @@ -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({ - Format: "ass", - Method: "External" - }), profile.SubtitleProfiles.push({ - Format: "ssa", - Method: "External" - }))), resolve(profile) - }) - }) + 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({ + Format: "ssa", + Method: "External" + }); + } + } + } + + 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,40 +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"); - 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"); + features.push("targetblank"); // allows users to connect to more than one server + //features.push("multiserver"); + + 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"); }); }); @@ -168,73 +314,169 @@ 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() - } catch (err) { - console.log("error closing application: " + err) - } else window.close() + 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(); + } }, - 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) - }, - 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) + + if (metaThemeColor) { + metaThemeColor.setAttribute("content", color); } }, - 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" + 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); + } + }, + deviceIconUrl: function () { + 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; }); diff --git a/src/bower_components/emby-webcomponents/appsettings.js b/src/components/appsettings.js similarity index 100% rename from src/bower_components/emby-webcomponents/appsettings.js rename to src/components/appsettings.js diff --git a/src/bower_components/emby-webcomponents/backdrop/backdrop.js b/src/components/backdrop/backdrop.js similarity index 100% rename from src/bower_components/emby-webcomponents/backdrop/backdrop.js rename to src/components/backdrop/backdrop.js diff --git a/src/components/backdrop/package.json b/src/components/backdrop/package.json new file mode 100644 index 0000000000..5f04e53a9e --- /dev/null +++ b/src/components/backdrop/package.json @@ -0,0 +1,3 @@ +{ + "main": "backdrop.js" +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/backdrop/style.css b/src/components/backdrop/style.css similarity index 100% rename from src/bower_components/emby-webcomponents/backdrop/style.css rename to src/components/backdrop/style.css diff --git a/src/bower_components/emby-webcomponents/browser.js b/src/components/browser.js similarity index 100% rename from src/bower_components/emby-webcomponents/browser.js rename to src/components/browser.js diff --git a/src/bower_components/emby-webcomponents/browserdeviceprofile.js b/src/components/browserdeviceprofile.js similarity index 99% rename from src/bower_components/emby-webcomponents/browserdeviceprofile.js rename to src/components/browserdeviceprofile.js index 7b37a0cdb1..ad5237fde8 100644 --- a/src/bower_components/emby-webcomponents/browserdeviceprofile.js +++ b/src/components/browserdeviceprofile.js @@ -751,7 +751,7 @@ define(['browser'], function (browser) { Condition: 'Equals', Property: 'IsSecondaryAudio', Value: 'false', - IsRequired: 'false' + IsRequired: false }); } @@ -780,7 +780,7 @@ define(['browser'], function (browser) { Condition: 'Equals', Property: 'IsSecondaryAudio', Value: 'false', - IsRequired: 'false' + IsRequired: false } ] }); @@ -913,4 +913,4 @@ define(['browser'], function (browser) { return profile; }; -}); \ No newline at end of file +}); diff --git a/src/bower_components/emby-webcomponents/cardbuilder/card.css b/src/components/cardbuilder/card.css similarity index 100% rename from src/bower_components/emby-webcomponents/cardbuilder/card.css rename to src/components/cardbuilder/card.css diff --git a/src/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js b/src/components/cardbuilder/cardbuilder.js similarity index 100% rename from src/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js rename to src/components/cardbuilder/cardbuilder.js diff --git a/src/bower_components/emby-webcomponents/cardbuilder/chaptercardbuilder.js b/src/components/cardbuilder/chaptercardbuilder.js similarity index 100% rename from src/bower_components/emby-webcomponents/cardbuilder/chaptercardbuilder.js rename to src/components/cardbuilder/chaptercardbuilder.js diff --git a/src/bower_components/emby-webcomponents/cardbuilder/peoplecardbuilder.js b/src/components/cardbuilder/peoplecardbuilder.js similarity index 100% rename from src/bower_components/emby-webcomponents/cardbuilder/peoplecardbuilder.js rename to src/components/cardbuilder/peoplecardbuilder.js diff --git a/src/bower_components/emby-webcomponents/cardbuilder/roundcard.css b/src/components/cardbuilder/roundcard.css similarity index 100% rename from src/bower_components/emby-webcomponents/cardbuilder/roundcard.css rename to src/components/cardbuilder/roundcard.css diff --git a/src/components/categorysyncbuttons.js b/src/components/categorysyncbuttons.js deleted file mode 100644 index 5a6075b196..0000000000 --- a/src/components/categorysyncbuttons.js +++ /dev/null @@ -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) - } - } -}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/chromecast/chromecasthelpers.js b/src/components/chromecast/chromecasthelpers.js similarity index 95% rename from src/bower_components/emby-webcomponents/chromecast/chromecasthelpers.js rename to src/components/chromecast/chromecasthelpers.js index c86233207d..0beba824c0 100644 --- a/src/bower_components/emby-webcomponents/chromecast/chromecasthelpers.js +++ b/src/components/chromecast/chromecasthelpers.js @@ -187,8 +187,13 @@ define(['events'], function (events) { return apiClient.getEndpointInfo().then(function (endpoint) { if (endpoint.IsInNetwork) { return apiClient.getPublicSystemInfo().then(function (info) { - addToCache(serverAddress, info.LocalAddress); - return info.LocalAddress; + var localAddress = info.LocalAddress + if (!localAddress) { + console.log("No valid local address returned, defaulting to external one") + localAddress = serverAddress; + } + addToCache(serverAddress, localAddress); + return localAddress; }); } else { addToCache(serverAddress, serverAddress); diff --git a/src/bower_components/emby-webcomponents/chromecast/chromecastplayer.js b/src/components/chromecast/chromecastplayer.js similarity index 95% rename from src/bower_components/emby-webcomponents/chromecast/chromecastplayer.js rename to src/components/chromecast/chromecastplayer.js index d276bb4de2..9b382aeecf 100644 --- a/src/bower_components/emby-webcomponents/chromecast/chromecastplayer.js +++ b/src/components/chromecast/chromecastplayer.js @@ -220,7 +220,9 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' this.session = null; this.deviceState = DEVICE_STATE.IDLE; this.castPlayerState = PLAYER_STATE.IDLE; - + document.removeEventListener("volumeupbutton", onVolumeUpKeyDown, false); + document.removeEventListener("volumedownbutton", onVolumeDownKeyDown, false); + //console.log('sessionUpdateListener: setting currentMediaSession to null'); this.currentMediaSession = null; @@ -258,6 +260,9 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' this.session.addMediaListener(this.sessionMediaListener.bind(this)); this.session.addUpdateListener(this.sessionUpdateListener.bind(this)); + document.addEventListener("volumeupbutton", onVolumeUpKeyDown, false); + document.addEventListener("volumedownbutton", onVolumeDownKeyDown, false); + events.trigger(this, 'connect'); this.sendMessage({ @@ -266,6 +271,14 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' }); }; + function onVolumeUpKeyDown() { + playbackManager.volumeUp(); + } + + function onVolumeDownKeyDown() { + playbackManager.volumeDown(); + } + /** * session update listener */ @@ -305,6 +318,8 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' //console.log(message); this.deviceState = DEVICE_STATE.IDLE; this.castPlayerState = PLAYER_STATE.IDLE; + document.removeEventListener("volumeupbutton", onVolumeUpKeyDown, false); + document.removeEventListener("volumedownbutton", onVolumeDownKeyDown, false); //console.log('onStopAppSuccess: setting currentMediaSession to null'); this.currentMediaSession = null; @@ -574,8 +589,15 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' events.trigger(instance, "playbackstop", [state]); + var state = instance.lastPlayerData.PlayState || {}; + var volume = state.VolumeLevel || 0.5; + var mute = state.IsMuted || false; + // Reset this so the next query doesn't make it appear like content is playing. instance.lastPlayerData = {}; + instance.lastPlayerData.PlayState = {}; + instance.lastPlayerData.PlayState.VolumeLevel = volume; + instance.lastPlayerData.PlayState.IsMuted = mute; }); events.on(instance._castPlayer, "playbackprogress", function (e, data) { @@ -780,11 +802,16 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' }; ChromecastPlayer.prototype.volumeDown = function () { + var vol = this._castPlayer.session.receiver.volume.level; + if (vol == null) + { + vol = 0.5; + } + vol -= 0.05; + vol = Math.max(vol, 0); + + this._castPlayer.session.setReceiverVolumeLevel(vol); - this._castPlayer.sendMessage({ - options: {}, - command: 'VolumeDown' - }); }; ChromecastPlayer.prototype.endSession = function () { @@ -799,24 +826,24 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' }; ChromecastPlayer.prototype.volumeUp = function () { + var vol = this._castPlayer.session.receiver.volume.level; + if (vol == null) + { + vol = 0.5; + } + vol += 0.05; + vol = Math.min(vol, 1); - this._castPlayer.sendMessage({ - options: {}, - command: 'VolumeUp' - }); + this._castPlayer.session.setReceiverVolumeLevel(vol); }; ChromecastPlayer.prototype.setVolume = function (vol) { vol = Math.min(vol, 100); vol = Math.max(vol, 0); - - this._castPlayer.sendMessage({ - options: { - volume: vol - }, - command: 'SetVolume' - }); + vol = vol / 100; + + this._castPlayer.session.setReceiverVolumeLevel(vol); }; ChromecastPlayer.prototype.unpause = function () { diff --git a/src/bower_components/emby-webcomponents/clearbutton.css b/src/components/clearbutton.css similarity index 100% rename from src/bower_components/emby-webcomponents/clearbutton.css rename to src/components/clearbutton.css diff --git a/src/bower_components/emby-webcomponents/collectioneditor/collectioneditor.js b/src/components/collectioneditor/collectioneditor.js similarity index 98% rename from src/bower_components/emby-webcomponents/collectioneditor/collectioneditor.js rename to src/components/collectioneditor/collectioneditor.js index 4473c661e7..5c1bd5c6f8 100644 --- a/src/bower_components/emby-webcomponents/collectioneditor/collectioneditor.js +++ b/src/components/collectioneditor/collectioneditor.js @@ -1,4 +1,4 @@ -define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'emby-linkbutton', 'flexStyles'], function (dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize) { +define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize) { 'use strict'; var currentServerId; diff --git a/src/bower_components/emby-webcomponents/confirm/confirm.js b/src/components/confirm/confirm.js similarity index 100% rename from src/bower_components/emby-webcomponents/confirm/confirm.js rename to src/components/confirm/confirm.js diff --git a/src/bower_components/emby-webcomponents/confirm/nativeconfirm.js b/src/components/confirm/nativeconfirm.js similarity index 100% rename from src/bower_components/emby-webcomponents/confirm/nativeconfirm.js rename to src/components/confirm/nativeconfirm.js diff --git a/src/bower_components/emby-webcomponents/datetime.js b/src/components/datetime.js similarity index 100% rename from src/bower_components/emby-webcomponents/datetime.js rename to src/components/datetime.js diff --git a/src/bower_components/emby-webcomponents/deletehelper.js b/src/components/deletehelper.js similarity index 100% rename from src/bower_components/emby-webcomponents/deletehelper.js rename to src/components/deletehelper.js diff --git a/src/bower_components/emby-webcomponents/dialog/dialog.js b/src/components/dialog/dialog.js similarity index 100% rename from src/bower_components/emby-webcomponents/dialog/dialog.js rename to src/components/dialog/dialog.js diff --git a/src/bower_components/emby-webcomponents/dialog/dialog.template.html b/src/components/dialog/dialog.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/dialog/dialog.template.html rename to src/components/dialog/dialog.template.html diff --git a/src/components/dialog/package.json b/src/components/dialog/package.json new file mode 100644 index 0000000000..d13dd844ba --- /dev/null +++ b/src/components/dialog/package.json @@ -0,0 +1,3 @@ +{ + "main": "dialog.js" +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/dialoghelper/dialoghelper.js b/src/components/dialogHelper/dialogHelper.js similarity index 100% rename from src/bower_components/emby-webcomponents/dialoghelper/dialoghelper.js rename to src/components/dialogHelper/dialogHelper.js diff --git a/src/bower_components/emby-webcomponents/dialoghelper/dialoghelper.css b/src/components/dialogHelper/dialoghelper.css similarity index 100% rename from src/bower_components/emby-webcomponents/dialoghelper/dialoghelper.css rename to src/components/dialogHelper/dialoghelper.css diff --git a/src/components/dialogHelper/package.json b/src/components/dialogHelper/package.json new file mode 100644 index 0000000000..71863d045f --- /dev/null +++ b/src/components/dialogHelper/package.json @@ -0,0 +1,3 @@ +{ + "main": "dialogHelper.js" +} \ No newline at end of file diff --git a/src/components/directorybrowser/directorybrowser.js b/src/components/directorybrowser/directorybrowser.js index 7eb91fffa0..e4ceecc0ca 100644 --- a/src/components/directorybrowser/directorybrowser.js +++ b/src/components/directorybrowser/directorybrowser.js @@ -1,4 +1,4 @@ -define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'emby-button', 'paper-icon-button-light', 'css!./directorybrowser', 'formDialogStyle', 'emby-linkbutton'], function(loading, dialogHelper, dom) { +define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-icon-button-light', 'css!./directorybrowser', 'formDialogStyle', 'emby-button'], function(loading, dialogHelper, dom) { 'use strict'; function getSystemInfo() { @@ -18,18 +18,18 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'emby-b if (path && typeof path !== 'string') { throw new Error("invalid path"); } - + loading.show(); - + var promises = []; if ("Network" === path) { promises.push(ApiClient.getNetworkDevices()) } else { - if (path) { + if (path) { promises.push(ApiClient.getDirectoryContents(path, fileOptions)); promises.push(ApiClient.getParentPath(path)); - } else { + } else { promises.push(ApiClient.getDrives()); } } @@ -42,7 +42,7 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'emby-b page.querySelector(".results").scrollTop = 0; page.querySelector("#txtDirectoryPickerPath").value = path || ""; - + if (path) { html += getItem("lnkPath lnkDirectory", "", parentPath, "..."); } @@ -51,7 +51,7 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'emby-b var cssClass = "File" === folder.Type ? "lnkPath lnkFile" : "lnkPath lnkDirectory"; html += getItem(cssClass, folder.Type, folder.Path, folder.Name); } - + if (!path) { html += getItem("lnkPath lnkDirectory", "", "Network", Globalize.translate("ButtonNetwork")); } @@ -128,7 +128,7 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'emby-b html += ''; } html += ""; - if (!readOnlyAttribute) { + if (!readOnlyAttribute) { html += '
'; } if (options.enableNetworkSharePath) { @@ -222,11 +222,7 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'emby-b var networkSharePath = this.querySelector("#txtNetworkPath"); networkSharePath = networkSharePath ? networkSharePath.value : null; var path = this.querySelector("#txtDirectoryPickerPath").value; - validatePath(path, options.validateWriteable, ApiClient).then( - function() { - options.callback(path, networkSharePath); - } - ); + validatePath(path, options.validateWriteable, ApiClient).then(options.callback(path, networkSharePath)); } e.preventDefault(); e.stopPropagation(); diff --git a/src/bower_components/emby-webcomponents/displaysettings/displaysettings.js b/src/components/displaysettings/displaysettings.js similarity index 97% rename from src/bower_components/emby-webcomponents/displaysettings/displaysettings.js rename to src/components/displaysettings/displaysettings.js index 9d39ff00fd..680c6b634b 100644 --- a/src/bower_components/emby-webcomponents/displaysettings/displaysettings.js +++ b/src/components/displaysettings/displaysettings.js @@ -1,4 +1,4 @@ -define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', 'apphost', 'focusManager', 'datetime', 'globalize', 'loading', 'connectionManager', 'skinManager', 'dom', 'events', 'emby-select', 'emby-checkbox', 'emby-linkbutton'], function (require, browser, layoutManager, appSettings, pluginManager, appHost, focusManager, datetime, globalize, loading, connectionManager, skinManager, dom, events) { +define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', 'apphost', 'focusManager', 'datetime', 'globalize', 'loading', 'connectionManager', 'skinManager', 'dom', 'events', 'emby-select', 'emby-checkbox', 'emby-button'], function (require, browser, layoutManager, appSettings, pluginManager, appHost, focusManager, datetime, globalize, loading, connectionManager, skinManager, dom, events) { "use strict"; function fillThemes(select, isDashboard) { @@ -225,32 +225,25 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', ' userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked); if (user.Id === apiClient.getCurrentUserId()) { - skinManager.setTheme(userSettingsInstance.theme()); } layoutManager.setLayout(context.querySelector('.selectLayout').value); - return apiClient.updateUserConfiguration(user.Id, user.Configuration); } function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) { - loading.show(); apiClient.getUser(userId).then(function (user) { - saveUser(context, user, userSettings, apiClient).then(function () { - loading.hide(); if (enableSaveConfirmation) { require(['toast'], function (toast) { toast(globalize.translate('SettingsSaved')); }); } - events.trigger(instance, 'saved'); - }, function () { loading.hide(); }); @@ -258,14 +251,12 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', ' } function onSubmit(e) { - var self = this; var apiClient = connectionManager.getApiClient(self.options.serverId); var userId = self.options.userId; var userSettings = self.options.userSettings; userSettings.setUserInfo(userId, apiClient).then(function () { - var enableSaveConfirmation = self.options.enableSaveConfirmation; save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation); }); @@ -278,30 +269,22 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', ' } function embed(options, self) { - require(['text!./displaysettings.template.html'], function (template) { - options.element.innerHTML = globalize.translateDocument(template, 'core'); - options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self)); - if (options.enableSaveButton) { options.element.querySelector('.btnSave').classList.remove('hide'); } - self.loadData(options.autoFocus); }); } function DisplaySettings(options) { - this.options = options; - embed(options, this); } DisplaySettings.prototype.loadData = function (autoFocus) { - var self = this; var context = self.options.element; @@ -312,13 +295,9 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', ' var userSettings = self.options.userSettings; return apiClient.getUser(userId).then(function (user) { - return userSettings.setUserInfo(userId, apiClient).then(function () { - self.dataLoaded = true; - loadForm(context, user, userSettings, apiClient); - if (autoFocus) { focusManager.autoFocus(context); } @@ -331,7 +310,6 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', ' }; DisplaySettings.prototype.destroy = function () { - this.options = null; }; diff --git a/src/bower_components/emby-webcomponents/displaysettings/displaysettings.template.html b/src/components/displaysettings/displaysettings.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/displaysettings/displaysettings.template.html rename to src/components/displaysettings/displaysettings.template.html diff --git a/src/bower_components/emby-webcomponents/dom.js b/src/components/dom.js similarity index 100% rename from src/bower_components/emby-webcomponents/dom.js rename to src/components/dom.js diff --git a/src/bower_components/emby-webcomponents/emby-button/emby-button.css b/src/components/emby-button/emby-button.css similarity index 100% rename from src/bower_components/emby-webcomponents/emby-button/emby-button.css rename to src/components/emby-button/emby-button.css diff --git a/src/bower_components/emby-webcomponents/emby-button/emby-button.js b/src/components/emby-button/emby-button.js similarity index 84% rename from src/bower_components/emby-webcomponents/emby-button/emby-button.js rename to src/components/emby-button/emby-button.js index 99a6aea925..d80b224d03 100644 --- a/src/bower_components/emby-webcomponents/emby-button/emby-button.js +++ b/src/components/emby-button/emby-button.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); } diff --git a/src/bower_components/emby-webcomponents/emby-button/paper-icon-button-light.js b/src/components/emby-button/paper-icon-button-light.js similarity index 100% rename from src/bower_components/emby-webcomponents/emby-button/paper-icon-button-light.js rename to src/components/emby-button/paper-icon-button-light.js diff --git a/src/bower_components/emby-webcomponents/emby-checkbox/emby-checkbox.css b/src/components/emby-checkbox/emby-checkbox.css similarity index 100% rename from src/bower_components/emby-webcomponents/emby-checkbox/emby-checkbox.css rename to src/components/emby-checkbox/emby-checkbox.css diff --git a/src/bower_components/emby-webcomponents/emby-checkbox/emby-checkbox.js b/src/components/emby-checkbox/emby-checkbox.js similarity index 100% rename from src/bower_components/emby-webcomponents/emby-checkbox/emby-checkbox.js rename to src/components/emby-checkbox/emby-checkbox.js diff --git a/src/bower_components/emby-webcomponents/emby-collapse/emby-collapse.css b/src/components/emby-collapse/emby-collapse.css similarity index 100% rename from src/bower_components/emby-webcomponents/emby-collapse/emby-collapse.css rename to src/components/emby-collapse/emby-collapse.css diff --git a/src/bower_components/emby-webcomponents/emby-collapse/emby-collapse.js b/src/components/emby-collapse/emby-collapse.js similarity index 100% rename from src/bower_components/emby-webcomponents/emby-collapse/emby-collapse.js rename to src/components/emby-collapse/emby-collapse.js diff --git a/src/bower_components/emby-webcomponents/emby-input/emby-input.css b/src/components/emby-input/emby-input.css similarity index 100% rename from src/bower_components/emby-webcomponents/emby-input/emby-input.css rename to src/components/emby-input/emby-input.css diff --git a/src/bower_components/emby-webcomponents/emby-input/emby-input.js b/src/components/emby-input/emby-input.js similarity index 100% rename from src/bower_components/emby-webcomponents/emby-input/emby-input.js rename to src/components/emby-input/emby-input.js diff --git a/src/components/emby-input/package.json b/src/components/emby-input/package.json new file mode 100644 index 0000000000..07be9f7b45 --- /dev/null +++ b/src/components/emby-input/package.json @@ -0,0 +1,3 @@ +{ + "main": "emby-input.js" +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-itemrefreshindicator/emby-itemrefreshindicator.js b/src/components/emby-itemrefreshindicator/emby-itemrefreshindicator.js similarity index 100% rename from src/bower_components/emby-webcomponents/emby-itemrefreshindicator/emby-itemrefreshindicator.js rename to src/components/emby-itemrefreshindicator/emby-itemrefreshindicator.js diff --git a/src/bower_components/emby-webcomponents/emby-itemscontainer/emby-itemscontainer.js b/src/components/emby-itemscontainer/emby-itemscontainer.js similarity index 100% rename from src/bower_components/emby-webcomponents/emby-itemscontainer/emby-itemscontainer.js rename to src/components/emby-itemscontainer/emby-itemscontainer.js diff --git a/src/bower_components/emby-webcomponents/emby-progressring/emby-progressring.css b/src/components/emby-progressring/emby-progressring.css similarity index 100% rename from src/bower_components/emby-webcomponents/emby-progressring/emby-progressring.css rename to src/components/emby-progressring/emby-progressring.css diff --git a/src/bower_components/emby-webcomponents/emby-progressring/emby-progressring.js b/src/components/emby-progressring/emby-progressring.js similarity index 100% rename from src/bower_components/emby-webcomponents/emby-progressring/emby-progressring.js rename to src/components/emby-progressring/emby-progressring.js diff --git a/src/bower_components/emby-webcomponents/emby-progressring/emby-progressring.template.html b/src/components/emby-progressring/emby-progressring.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/emby-progressring/emby-progressring.template.html rename to src/components/emby-progressring/emby-progressring.template.html diff --git a/src/bower_components/emby-webcomponents/emby-radio/emby-radio.css b/src/components/emby-radio/emby-radio.css similarity index 100% rename from src/bower_components/emby-webcomponents/emby-radio/emby-radio.css rename to src/components/emby-radio/emby-radio.css diff --git a/src/bower_components/emby-webcomponents/emby-radio/emby-radio.js b/src/components/emby-radio/emby-radio.js similarity index 100% rename from src/bower_components/emby-webcomponents/emby-radio/emby-radio.js rename to src/components/emby-radio/emby-radio.js diff --git a/src/components/emby-radio/package.json b/src/components/emby-radio/package.json new file mode 100644 index 0000000000..2c1b97bd32 --- /dev/null +++ b/src/components/emby-radio/package.json @@ -0,0 +1,3 @@ +{ + "main": "emby-radio.js" +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-scrollbuttons/emby-scrollbuttons.css b/src/components/emby-scrollbuttons/emby-scrollbuttons.css similarity index 97% rename from src/bower_components/emby-webcomponents/emby-scrollbuttons/emby-scrollbuttons.css rename to src/components/emby-scrollbuttons/emby-scrollbuttons.css index 5e404e780d..04b2ce68c6 100644 --- a/src/bower_components/emby-webcomponents/emby-scrollbuttons/emby-scrollbuttons.css +++ b/src/components/emby-scrollbuttons/emby-scrollbuttons.css @@ -4,8 +4,8 @@ .scrollbuttoncontainer { position: absolute; - top: 0; - bottom: 0; + top: 10%; + bottom: 35%; align-items: center; justify-content: center; z-index: 1; diff --git a/src/bower_components/emby-webcomponents/emby-scrollbuttons/emby-scrollbuttons.js b/src/components/emby-scrollbuttons/emby-scrollbuttons.js similarity index 100% rename from src/bower_components/emby-webcomponents/emby-scrollbuttons/emby-scrollbuttons.js rename to src/components/emby-scrollbuttons/emby-scrollbuttons.js diff --git a/src/bower_components/emby-webcomponents/emby-scroller/emby-scroller.js b/src/components/emby-scroller/emby-scroller.js similarity index 99% rename from src/bower_components/emby-webcomponents/emby-scroller/emby-scroller.js rename to src/components/emby-scroller/emby-scroller.js index d3718cedf3..7ef39eea0a 100644 --- a/src/bower_components/emby-webcomponents/emby-scroller/emby-scroller.js +++ b/src/components/emby-scroller/emby-scroller.js @@ -108,8 +108,7 @@ define(['scroller', 'dom', 'layoutManager', 'inputManager', 'focusManager', 'bro var headroom = new Headroom([], { scroller: elem }); - // initialise - headroom.init(); + headroom.add(document.querySelector('.skinHeader')); elem.headroom = headroom; }); diff --git a/src/bower_components/emby-webcomponents/emby-select/emby-select.css b/src/components/emby-select/emby-select.css similarity index 100% rename from src/bower_components/emby-webcomponents/emby-select/emby-select.css rename to src/components/emby-select/emby-select.css diff --git a/src/bower_components/emby-webcomponents/emby-select/emby-select.js b/src/components/emby-select/emby-select.js similarity index 100% rename from src/bower_components/emby-webcomponents/emby-select/emby-select.js rename to src/components/emby-select/emby-select.js diff --git a/src/bower_components/emby-webcomponents/emby-slider/emby-slider.css b/src/components/emby-slider/emby-slider.css similarity index 100% rename from src/bower_components/emby-webcomponents/emby-slider/emby-slider.css rename to src/components/emby-slider/emby-slider.css diff --git a/src/bower_components/emby-webcomponents/emby-slider/emby-slider.js b/src/components/emby-slider/emby-slider.js similarity index 100% rename from src/bower_components/emby-webcomponents/emby-slider/emby-slider.js rename to src/components/emby-slider/emby-slider.js diff --git a/src/bower_components/emby-webcomponents/emby-tabs/emby-tabs.css b/src/components/emby-tabs/emby-tabs.css similarity index 100% rename from src/bower_components/emby-webcomponents/emby-tabs/emby-tabs.css rename to src/components/emby-tabs/emby-tabs.css diff --git a/src/bower_components/emby-webcomponents/emby-tabs/emby-tabs.js b/src/components/emby-tabs/emby-tabs.js similarity index 100% rename from src/bower_components/emby-webcomponents/emby-tabs/emby-tabs.js rename to src/components/emby-tabs/emby-tabs.js diff --git a/src/components/emby-tabs/package.json b/src/components/emby-tabs/package.json new file mode 100644 index 0000000000..0813d041c7 --- /dev/null +++ b/src/components/emby-tabs/package.json @@ -0,0 +1,3 @@ +{ + "main": "emby-tabs.js" +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/emby-textarea/emby-textarea.css b/src/components/emby-textarea/emby-textarea.css similarity index 100% rename from src/bower_components/emby-webcomponents/emby-textarea/emby-textarea.css rename to src/components/emby-textarea/emby-textarea.css diff --git a/src/bower_components/emby-webcomponents/emby-textarea/emby-textarea.js b/src/components/emby-textarea/emby-textarea.js similarity index 100% rename from src/bower_components/emby-webcomponents/emby-textarea/emby-textarea.js rename to src/components/emby-textarea/emby-textarea.js diff --git a/src/bower_components/emby-webcomponents/emby-toggle/emby-toggle.css b/src/components/emby-toggle/emby-toggle.css similarity index 100% rename from src/bower_components/emby-webcomponents/emby-toggle/emby-toggle.css rename to src/components/emby-toggle/emby-toggle.css diff --git a/src/bower_components/emby-webcomponents/emby-toggle/emby-toggle.js b/src/components/emby-toggle/emby-toggle.js similarity index 100% rename from src/bower_components/emby-webcomponents/emby-toggle/emby-toggle.js rename to src/components/emby-toggle/emby-toggle.js diff --git a/src/bower_components/emby-webcomponents/fetchhelper.js b/src/components/fetchhelper.js similarity index 100% rename from src/bower_components/emby-webcomponents/fetchhelper.js rename to src/components/fetchhelper.js diff --git a/src/components/filedownloader.js b/src/components/filedownloader.js new file mode 100644 index 0000000000..c5810b460e --- /dev/null +++ b/src/components/filedownloader.js @@ -0,0 +1,18 @@ +define(['multi-download'], function (multiDownload) { + 'use strict'; + + return { + download: function (items) { + + if (window.NativeShell) { + items.map(function (item) { + window.NativeShell.downloadFile(item.url); + }); + } else { + multiDownload(items.map(function (item) { + return item.url; + })); + } + } + }; +}); \ No newline at end of file diff --git a/src/components/filesystem.js b/src/components/filesystem.js new file mode 100644 index 0000000000..3ab759b28a --- /dev/null +++ b/src/components/filesystem.js @@ -0,0 +1,18 @@ +define([], function () { + 'use strict'; + + return { + fileExists: function (path) { + if (window.NativeShell && window.NativeShell.FileSystem) { + return window.NativeShell.FileSystem.fileExists(path); + } + return Promise.reject(); + }, + directoryExists: function (path) { + if (window.NativeShell && window.NativeShell.FileSystem) { + return window.NativeShell.FileSystem.directoryExists(path); + } + return Promise.reject(); + } + }; +}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/filtermenu/filtermenu.js b/src/components/filtermenu/filtermenu.js similarity index 97% rename from src/bower_components/emby-webcomponents/filtermenu/filtermenu.js rename to src/components/filtermenu/filtermenu.js index 42bd101129..89457aa4e6 100644 --- a/src/bower_components/emby-webcomponents/filtermenu/filtermenu.js +++ b/src/components/filtermenu/filtermenu.js @@ -1,4 +1,4 @@ -define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost', 'inputManager', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'userSettings', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'emby-linkbutton', 'flexStyles'], function (require, dom, focusManager, dialogHelper, loading, appHost, inputManager, layoutManager, connectionManager, appRouter, globalize, userSettings) { +define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost', 'inputManager', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'userSettings', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (require, dom, focusManager, dialogHelper, loading, appHost, inputManager, layoutManager, connectionManager, appRouter, globalize, userSettings) { 'use strict'; function onSubmit(e) { diff --git a/src/bower_components/emby-webcomponents/filtermenu/filtermenu.template.html b/src/components/filtermenu/filtermenu.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/filtermenu/filtermenu.template.html rename to src/components/filtermenu/filtermenu.template.html diff --git a/src/bower_components/emby-webcomponents/flexstyles.css b/src/components/flexstyles.css similarity index 100% rename from src/bower_components/emby-webcomponents/flexstyles.css rename to src/components/flexstyles.css diff --git a/src/bower_components/emby-webcomponents/focusmanager.js b/src/components/focusmanager.js similarity index 100% rename from src/bower_components/emby-webcomponents/focusmanager.js rename to src/components/focusmanager.js diff --git a/src/bower_components/emby-webcomponents/formdialog.css b/src/components/formdialog.css similarity index 100% rename from src/bower_components/emby-webcomponents/formdialog.css rename to src/components/formdialog.css diff --git a/src/bower_components/emby-webcomponents/fullscreen/fullscreenmanager.js b/src/components/fullscreenManager.js similarity index 62% rename from src/bower_components/emby-webcomponents/fullscreen/fullscreenmanager.js rename to src/components/fullscreenManager.js index d39d8fd3b6..079267a6c4 100644 --- a/src/bower_components/emby-webcomponents/fullscreen/fullscreenmanager.js +++ b/src/components/fullscreenManager.js @@ -1,4 +1,4 @@ -define(['events', 'dom'], function (events, dom) { +define(['events', 'dom', 'apphost', 'browser'], function (events, dom, appHost, browser) { 'use strict'; function fullscreenManager() { @@ -29,11 +29,14 @@ define(['events', 'dom'], function (events, dom) { } if (element.webkitEnterFullscreen) { element.webkitEnterFullscreen(); - } + } }; fullscreenManager.prototype.exitFullscreen = function () { + if (!this.isFullScreen()) { + return; + } if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.mozCancelFullScreen) { @@ -47,9 +50,15 @@ define(['events', 'dom'], function (events, dom) { } }; + // TODO: use screenfull.js fullscreenManager.prototype.isFullScreen = function () { - - return document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement ? true : false; + return document.fullscreen || + document.mozFullScreen || + document.webkitIsFullScreen || + document.msFullscreenElement || /* IE/Edge syntax */ + document.fullscreenElement || /* Standard syntax */ + document.webkitFullscreenElement || /* Chrome, Safari and Opera syntax */ + document.mozFullScreenElement; /* Firefox syntax */ }; var manager = new fullscreenManager(); @@ -70,5 +79,25 @@ define(['events', 'dom'], function (events, dom) { passive: true }); + if (appHost.supports("fullscreenchange") && (browser.edgeUwp || -1 !== navigator.userAgent.toLowerCase().indexOf("electron"))) { + function isTargetValid(target) { + return !dom.parentWithTag(target, ['BUTTON', 'INPUT', 'TEXTAREA']); + } + + dom.addEventListener(window, 'dblclick', function (e) { + + if (isTargetValid(e.target)) { + if (manager.isFullScreen()) { + manager.exitFullscreen(); + } else { + manager.requestFullscreen(); + } + } + + }, { + passive: true + }); + } + return manager; -}); \ No newline at end of file +}); diff --git a/src/bower_components/emby-webcomponents/globalize.js b/src/components/globalize.js similarity index 100% rename from src/bower_components/emby-webcomponents/globalize.js rename to src/components/globalize.js diff --git a/src/bower_components/emby-webcomponents/guide/guide-settings.js b/src/components/guide/guide-settings.js similarity index 100% rename from src/bower_components/emby-webcomponents/guide/guide-settings.js rename to src/components/guide/guide-settings.js diff --git a/src/bower_components/emby-webcomponents/guide/guide-settings.template.html b/src/components/guide/guide-settings.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/guide/guide-settings.template.html rename to src/components/guide/guide-settings.template.html diff --git a/src/bower_components/emby-webcomponents/guide/guide.css b/src/components/guide/guide.css similarity index 100% rename from src/bower_components/emby-webcomponents/guide/guide.css rename to src/components/guide/guide.css diff --git a/src/bower_components/emby-webcomponents/guide/guide.js b/src/components/guide/guide.js similarity index 100% rename from src/bower_components/emby-webcomponents/guide/guide.js rename to src/components/guide/guide.js diff --git a/src/bower_components/emby-webcomponents/guide/programs.css b/src/components/guide/programs.css similarity index 100% rename from src/bower_components/emby-webcomponents/guide/programs.css rename to src/components/guide/programs.css diff --git a/src/bower_components/emby-webcomponents/guide/tvguide.template.html b/src/components/guide/tvguide.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/guide/tvguide.template.html rename to src/components/guide/tvguide.template.html diff --git a/src/bower_components/emby-webcomponents/headroom/headroom.css b/src/components/headroom/headroom.css similarity index 100% rename from src/bower_components/emby-webcomponents/headroom/headroom.css rename to src/components/headroom/headroom.css diff --git a/src/bower_components/emby-webcomponents/headroom/headroom.js b/src/components/headroom/headroom.js similarity index 87% rename from src/bower_components/emby-webcomponents/headroom/headroom.js rename to src/components/headroom/headroom.js index 9cb1cac04d..a3cc5b0435 100644 --- a/src/bower_components/emby-webcomponents/headroom/headroom.js +++ b/src/components/headroom/headroom.js @@ -75,47 +75,25 @@ define(['dom', 'layoutManager', 'browser', 'css!./headroom'], function (dom, lay this.pinnedClass = options.pinnedClass; this.state = 'clear'; - } - function onScroll() { + this.options = { + offset: 0, + scroller: window, + initialClass: 'headroom', + unPinnedClass: 'headroom--unpinned', + pinnedClass: 'headroom--pinned' + }; - if (this.paused) { - return; - } - - requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this))); - } - - Headroom.prototype = { - constructor: Headroom, - - /** - * Initialises the widget - */ - init: function () { - - if (browser.supportsCssAnimation()) { - for (var i = 0, length = this.elems.length; i < length; i++) { - this.elems[i].classList.add(this.initialClass); - this.elems[i].addEventListener('clearheadroom', onHeadroomClearedExternally.bind(this)); - } - - this.attachEvent(); - } - - return this; - }, - - add: function (elem) { + this.add = function (elem) { if (browser.supportsCssAnimation()) { elem.classList.add(this.initialClass); elem.addEventListener('clearheadroom', onHeadroomClearedExternally.bind(this)); this.elems.push(elem); } - }, + }; - remove: function (elem) { + this.remove = function (elem) { elem.classList.remove(this.unPinnedClass); elem.classList.remove(this.initialClass); @@ -125,20 +103,20 @@ define(['dom', 'layoutManager', 'browser', 'css!./headroom'], function (dom, lay if (i !== -1) { this.elems.splice(i, 1); } - }, + }; - pause: function () { + this.pause = function () { this.paused = true; - }, + }; - resume: function () { + this.resume = function () { this.paused = false; - }, + }; /** * Unattaches events and removes any classes that were added */ - destroy: function () { + this.destroy = function () { this.initialised = false; @@ -157,13 +135,13 @@ define(['dom', 'layoutManager', 'browser', 'css!./headroom'], function (dom, lay capture: false, passive: true }); - }, + }; /** * Attaches the scroll event * @private */ - attachEvent: function () { + this.attachEvent = function () { if (!this.initialised) { this.lastKnownScrollY = this.getScrollY(); this.initialised = true; @@ -177,12 +155,12 @@ define(['dom', 'layoutManager', 'browser', 'css!./headroom'], function (dom, lay this.update(); } - }, + }; /** * Unpins the header if it's currently pinned */ - clear: function () { + this.clear = function () { if (this.state === 'clear') { return; @@ -199,12 +177,12 @@ define(['dom', 'layoutManager', 'browser', 'css!./headroom'], function (dom, lay classList.remove(unpinnedClass); //classList.remove(pinnedClass); } - }, + }; /** * Unpins the header if it's currently pinned */ - pin: function () { + this.pin = function () { if (this.state === 'pin') { return; @@ -221,12 +199,12 @@ define(['dom', 'layoutManager', 'browser', 'css!./headroom'], function (dom, lay classList.remove(unpinnedClass); classList.add(pinnedClass); } - }, + }; /** * Unpins the header if it's currently pinned */ - unpin: function () { + this.unpin = function () { if (this.state === 'unpin') { return; @@ -243,14 +221,14 @@ define(['dom', 'layoutManager', 'browser', 'css!./headroom'], function (dom, lay classList.add(unpinnedClass); //classList.remove(pinnedClass); } - }, + }; /** * Gets the Y scroll position * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY * @return {Number} pixels the page has scrolled along the Y-axis */ - getScrollY: function () { + this.getScrollY = function () { var scroller = this.scroller; @@ -269,36 +247,36 @@ define(['dom', 'layoutManager', 'browser', 'css!./headroom'], function (dom, lay } return (document.documentElement || document.body).scrollTop; - }, + }; /** * determine if it is appropriate to unpin * @param {int} currentScrollY the current y scroll position * @return {bool} true if should unpin, false otherwise */ - shouldUnpin: function (currentScrollY) { + this.shouldUnpin = function (currentScrollY) { var scrollingDown = currentScrollY > this.lastKnownScrollY, pastOffset = currentScrollY >= this.offset; return scrollingDown && pastOffset; - }, + }; /** * determine if it is appropriate to pin * @param {int} currentScrollY the current y scroll position * @return {bool} true if should pin, false otherwise */ - shouldPin: function (currentScrollY) { + this.shouldPin = function (currentScrollY) { var scrollingUp = currentScrollY < this.lastKnownScrollY, pastOffset = currentScrollY <= this.offset; return scrollingUp || pastOffset; - }, + }; /** * Handles updating the state of the widget */ - update: function () { + this.update = function () { if (this.paused) { return; @@ -330,8 +308,28 @@ define(['dom', 'layoutManager', 'browser', 'css!./headroom'], function (dom, lay } this.lastKnownScrollY = currentScrollY; + }; + + + if (browser.supportsCssAnimation()) { + for (var i = 0, length = this.elems.length; i < length; i++) { + this.elems[i].classList.add(this.initialClass); + this.elems[i].addEventListener('clearheadroom', onHeadroomClearedExternally.bind(this)); + } + + this.attachEvent(); } - }; + } + + function onScroll() { + + if (this.paused) { + return; + } + + requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this))); + } + /** * Default options * @type {Object} @@ -345,5 +343,4 @@ define(['dom', 'layoutManager', 'browser', 'css!./headroom'], function (dom, lay }; return Headroom; - }); \ No newline at end of file diff --git a/src/components/headroom/package.json b/src/components/headroom/package.json new file mode 100644 index 0000000000..9c6c42c82a --- /dev/null +++ b/src/components/headroom/package.json @@ -0,0 +1,3 @@ +{ + "main": "headroom.js" +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/homescreensettings/homescreensettings.js b/src/components/homescreensettings/homescreensettings.js similarity index 100% rename from src/bower_components/emby-webcomponents/homescreensettings/homescreensettings.js rename to src/components/homescreensettings/homescreensettings.js diff --git a/src/bower_components/emby-webcomponents/homescreensettings/homescreensettings.template.html b/src/components/homescreensettings/homescreensettings.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/homescreensettings/homescreensettings.template.html rename to src/components/homescreensettings/homescreensettings.template.html diff --git a/src/bower_components/emby-webcomponents/homescreensettings/homescreensettingsdialog.js b/src/components/homescreensettings/homescreensettingsdialog.js similarity index 100% rename from src/bower_components/emby-webcomponents/homescreensettings/homescreensettingsdialog.js rename to src/components/homescreensettings/homescreensettingsdialog.js diff --git a/src/bower_components/emby-webcomponents/homescreensettings/homescreensettingsdialog.template.html b/src/components/homescreensettings/homescreensettingsdialog.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/homescreensettings/homescreensettingsdialog.template.html rename to src/components/homescreensettings/homescreensettingsdialog.template.html diff --git a/src/bower_components/emby-webcomponents/homesections/homesections.css b/src/components/homesections/homesections.css similarity index 100% rename from src/bower_components/emby-webcomponents/homesections/homesections.css rename to src/components/homesections/homesections.css diff --git a/src/bower_components/emby-webcomponents/homesections/homesections.js b/src/components/homesections/homesections.js similarity index 93% rename from src/bower_components/emby-webcomponents/homesections/homesections.js rename to src/components/homesections/homesections.js index 82f6041c3e..0c30a015cc 100644 --- a/src/bower_components/emby-webcomponents/homesections/homesections.js +++ b/src/components/homesections/homesections.js @@ -1,4 +1,4 @@ -define(['connectionManager', 'cardBuilder', 'registrationServices', 'appSettings', 'dom', 'apphost', 'layoutManager', 'imageLoader', 'globalize', 'itemShortcuts', 'itemHelper', 'appRouter', 'emby-button', 'paper-icon-button-light', 'emby-itemscontainer', 'emby-scroller', 'emby-linkbutton', 'css!./homesections'], function (connectionManager, cardBuilder, registrationServices, appSettings, dom, appHost, layoutManager, imageLoader, globalize, itemShortcuts, itemHelper, appRouter) { +define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'layoutManager', 'imageLoader', 'globalize', 'itemShortcuts', 'itemHelper', 'appRouter', 'paper-icon-button-light', 'emby-itemscontainer', 'emby-scroller', 'emby-button', 'css!./homesections'], function (connectionManager, cardBuilder, appSettings, dom, appHost, layoutManager, imageLoader, globalize, itemShortcuts, itemHelper, appRouter) { 'use strict'; function getDefaultSection(index) { @@ -662,34 +662,10 @@ define(['connectionManager', 'cardBuilder', 'registrationServices', 'appSettings itemsContainer.parentContainer = elem; } - function bindUnlockClick(elem) { - - var btnUnlock = elem.querySelector('.btnUnlock'); - if (btnUnlock) { - btnUnlock.addEventListener('click', function (e) { - - registrationServices.validateFeature('livetv', { - - viewOnly: true - - }).then(function () { - - dom.parentWithClass(elem, 'homeSectionsContainer').dispatchEvent(new CustomEvent('settingschange', { - cancelable: false - })); - }); - }); - } - } - function getOnNowFetchFn(serverId) { - return function () { - var apiClient = connectionManager.getApiClient(serverId); - return apiClient.getLiveTvRecommendedPrograms({ - userId: apiClient.getCurrentUserId(), IsAiring: true, limit: 24, @@ -697,15 +673,12 @@ define(['connectionManager', 'cardBuilder', 'registrationServices', 'appSettings EnableImageTypes: "Primary,Thumb,Backdrop", EnableTotalRecordCount: false, Fields: "ChannelInfo,PrimaryImageAspectRatio" - }); }; } function getOnNowItemsHtml(items) { - var cardLayout = false; - return cardBuilder.getCardsHtml({ items: items, preferThumb: 'auto', @@ -728,27 +701,12 @@ define(['connectionManager', 'cardBuilder', 'registrationServices', 'appSettings } function loadOnNow(elem, apiClient, user) { - if (!user.Policy.EnableLiveTvAccess) { return Promise.resolve(); } - var promises = []; - - promises.push(registrationServices.validateFeature('livetv', - { - viewOnly: true, - showDialog: false - }).then(function () { - return true; - }, function () { - return false; - })); - var userId = user.Id; - - promises.push(apiClient.getLiveTvRecommendedPrograms({ - + apiClient.getLiveTvRecommendedPrograms({ userId: apiClient.getCurrentUserId(), IsAiring: true, limit: 1, @@ -756,17 +714,9 @@ define(['connectionManager', 'cardBuilder', 'registrationServices', 'appSettings EnableImageTypes: "Primary,Thumb,Backdrop", EnableTotalRecordCount: false, Fields: "ChannelInfo,PrimaryImageAspectRatio" - - })); - - return Promise.all(promises).then(function (responses) { - - var registered = responses[0]; - var result = responses[1]; + }).then(function (result) { var html = ''; - - if (result.Items.length && registered) { - + if (result.Items.length) { elem.classList.remove('padded-left'); elem.classList.remove('padded-right'); elem.classList.remove('padded-bottom'); @@ -774,51 +724,38 @@ define(['connectionManager', 'cardBuilder', 'registrationServices', 'appSettings html += '
'; html += '
'; - html += '

' + globalize.translate('LiveTV') + '

'; - html += '
'; if (enableScrollX()) { html += '
'; html += '
'; - } - else { + } else { html += ''; - if (enableScrollX()) { html += '
'; } - html += '
'; html += '
'; @@ -826,12 +763,9 @@ define(['connectionManager', 'cardBuilder', 'registrationServices', 'appSettings html += '
'; if (!layoutManager.tv) { - html += ''; html += '

'; html += globalize.translate('HeaderOnNow'); @@ -863,22 +797,7 @@ define(['connectionManager', 'cardBuilder', 'registrationServices', 'appSettings itemsContainer.parentContainer = elem; itemsContainer.fetchData = getOnNowFetchFn(apiClient.serverId()); itemsContainer.getItemsHtml = getOnNowItemsHtml; - - } else if (result.Items.length && !registered) { - - elem.classList.add('padded-left'); - elem.classList.add('padded-right'); - elem.classList.add('padded-bottom'); - - html += '

' + globalize.translate('LiveTvRequiresUnlock') + '

'; - html += ''; - - elem.innerHTML = html; } - - bindUnlockClick(elem); }); } diff --git a/src/bower_components/emby-webcomponents/htmlvideoplayer/htmlmediahelper.js b/src/components/htmlMediaHelper.js similarity index 100% rename from src/bower_components/emby-webcomponents/htmlvideoplayer/htmlmediahelper.js rename to src/components/htmlMediaHelper.js diff --git a/src/bower_components/emby-webcomponents/htmlaudioplayer/plugin.js b/src/components/htmlaudioplayer/plugin.js similarity index 100% rename from src/bower_components/emby-webcomponents/htmlaudioplayer/plugin.js rename to src/components/htmlaudioplayer/plugin.js diff --git a/src/bower_components/emby-webcomponents/htmlvideoplayer/plugin.js b/src/components/htmlvideoplayer/plugin.js similarity index 99% rename from src/bower_components/emby-webcomponents/htmlvideoplayer/plugin.js rename to src/components/htmlvideoplayer/plugin.js index 19b075b622..d25b49163b 100644 --- a/src/bower_components/emby-webcomponents/htmlvideoplayer/plugin.js +++ b/src/components/htmlvideoplayer/plugin.js @@ -1,4 +1,4 @@ -define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackManager', 'appRouter', 'appSettings', 'connectionManager', 'htmlMediaHelper', 'itemHelper'], function (browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager, htmlMediaHelper, itemHelper) { +define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackManager', 'appRouter', 'appSettings', 'connectionManager', 'htmlMediaHelper', 'itemHelper', 'fullscreenManager'], function (browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager, htmlMediaHelper, itemHelper, fullscreenManager) { "use strict"; var mediaManager; @@ -692,6 +692,8 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa dlg.parentNode.removeChild(dlg); } + + fullscreenManager.exitFullscreen(); }; function onEnded() { diff --git a/src/bower_components/emby-webcomponents/htmlvideoplayer/style.css b/src/components/htmlvideoplayer/style.css similarity index 100% rename from src/bower_components/emby-webcomponents/htmlvideoplayer/style.css rename to src/components/htmlvideoplayer/style.css diff --git a/src/bower_components/emby-webcomponents/imagedownloader/imagedownloader.js b/src/components/imagedownloader/imagedownloader.js similarity index 98% rename from src/bower_components/emby-webcomponents/imagedownloader/imagedownloader.js rename to src/components/imagedownloader/imagedownloader.js index f24acbb655..729bce3382 100644 --- a/src/bower_components/emby-webcomponents/imagedownloader/imagedownloader.js +++ b/src/components/imagedownloader/imagedownloader.js @@ -1,4 +1,4 @@ -define(['loading', 'apphost', 'dialogHelper', 'connectionManager', 'imageLoader', 'browser', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'emby-checkbox', 'emby-button', 'paper-icon-button-light', 'emby-linkbutton', 'formDialogStyle', 'cardStyle'], function (loading, appHost, dialogHelper, connectionManager, imageLoader, browser, layoutManager, scrollHelper, globalize, require) { +define(['loading', 'apphost', 'dialogHelper', 'connectionManager', 'imageLoader', 'browser', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'emby-checkbox', 'paper-icon-button-light', 'emby-button', 'formDialogStyle', 'cardStyle'], function (loading, appHost, dialogHelper, connectionManager, imageLoader, browser, layoutManager, scrollHelper, globalize, require) { 'use strict'; var currentItemId; @@ -364,7 +364,7 @@ define(['loading', 'apphost', 'dialogHelper', 'connectionManager', 'imageLoader' scrollHelper.centerFocus.on(dlg, false); } - // Has to be assigned a z-index after the call to .open() + // Has to be assigned a z-index after the call to .open() dlg.addEventListener('close', onDialogClosed); dialogHelper.open(dlg); diff --git a/src/bower_components/emby-webcomponents/imagedownloader/imagedownloader.template.html b/src/components/imagedownloader/imagedownloader.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/imagedownloader/imagedownloader.template.html rename to src/components/imagedownloader/imagedownloader.template.html diff --git a/src/bower_components/emby-webcomponents/imageeditor/imageeditor.css b/src/components/imageeditor/imageeditor.css similarity index 100% rename from src/bower_components/emby-webcomponents/imageeditor/imageeditor.css rename to src/components/imageeditor/imageeditor.css diff --git a/src/bower_components/emby-webcomponents/imageeditor/imageeditor.js b/src/components/imageeditor/imageeditor.js similarity index 100% rename from src/bower_components/emby-webcomponents/imageeditor/imageeditor.js rename to src/components/imageeditor/imageeditor.js diff --git a/src/bower_components/emby-webcomponents/imageeditor/imageeditor.template.html b/src/components/imageeditor/imageeditor.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/imageeditor/imageeditor.template.html rename to src/components/imageeditor/imageeditor.template.html diff --git a/src/bower_components/emby-webcomponents/images/basicimagefetcher.js b/src/components/images/imageFetcher.js similarity index 100% rename from src/bower_components/emby-webcomponents/images/basicimagefetcher.js rename to src/components/images/imageFetcher.js diff --git a/src/bower_components/emby-webcomponents/images/imagehelper.js b/src/components/images/imageLoader.js similarity index 100% rename from src/bower_components/emby-webcomponents/images/imagehelper.js rename to src/components/images/imageLoader.js diff --git a/src/bower_components/emby-webcomponents/images/style.css b/src/components/images/style.css similarity index 100% rename from src/bower_components/emby-webcomponents/images/style.css rename to src/components/images/style.css diff --git a/src/bower_components/emby-webcomponents/imageuploader/imageuploader.js b/src/components/imageuploader/imageuploader.js similarity index 100% rename from src/bower_components/emby-webcomponents/imageuploader/imageuploader.js rename to src/components/imageuploader/imageuploader.js diff --git a/src/bower_components/emby-webcomponents/imageuploader/imageuploader.template.html b/src/components/imageuploader/imageuploader.template.html similarity index 99% rename from src/bower_components/emby-webcomponents/imageuploader/imageuploader.template.html rename to src/components/imageuploader/imageuploader.template.html index f01dd90433..90d9cf0def 100644 --- a/src/bower_components/emby-webcomponents/imageuploader/imageuploader.template.html +++ b/src/components/imageuploader/imageuploader.template.html @@ -50,7 +50,3 @@
- - - - diff --git a/src/bower_components/emby-webcomponents/imageuploader/style.css b/src/components/imageuploader/style.css similarity index 100% rename from src/bower_components/emby-webcomponents/imageuploader/style.css rename to src/components/imageuploader/style.css diff --git a/src/bower_components/emby-webcomponents/indicators/indicators.css b/src/components/indicators/indicators.css similarity index 100% rename from src/bower_components/emby-webcomponents/indicators/indicators.css rename to src/components/indicators/indicators.css diff --git a/src/bower_components/emby-webcomponents/indicators/indicators.js b/src/components/indicators/indicators.js similarity index 100% rename from src/bower_components/emby-webcomponents/indicators/indicators.js rename to src/components/indicators/indicators.js diff --git a/src/bower_components/emby-webcomponents/inputmanager.js b/src/components/inputmanager.js similarity index 100% rename from src/bower_components/emby-webcomponents/inputmanager.js rename to src/components/inputmanager.js diff --git a/src/bower_components/emby-webcomponents/itemcontextmenu.js b/src/components/itemcontextmenu.js similarity index 87% rename from src/bower_components/emby-webcomponents/itemcontextmenu.js rename to src/components/itemcontextmenu.js index 270345d3b7..6bc81f62b2 100644 --- a/src/bower_components/emby-webcomponents/itemcontextmenu.js +++ b/src/components/itemcontextmenu.js @@ -118,13 +118,6 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter', }); } - if (itemHelper.canConvert(item, user, connectionManager.getApiClient(item))) { - commands.push({ - name: globalize.translate('Convert'), - id: 'convert' - }); - } - if (item.CanDelete && options.deleteItem !== false) { if (item.Type === 'Playlist' || item.Type === 'BoxSet') { @@ -147,15 +140,6 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter', }); } - if (appHost.supports('sync') && options.syncLocal !== false) { - if (itemHelper.canSync(user, item)) { - commands.push({ - name: globalize.translate('Download'), - id: 'synclocal' - }); - } - } - var canEdit = itemHelper.canEdit(user, item); if (canEdit) { @@ -328,17 +312,13 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter', { require(['fileDownloader'], function (fileDownloader) { var downloadHref = apiClient.getItemDownloadUrl(itemId); - - fileDownloader.download([ - { - url: downloadHref, - itemId: itemId, - serverId: serverId - }]); - + fileDownloader.download([{ + url: downloadHref, + itemId: itemId, + serverId: serverId + }]); getResolveFunction(getResolveFunction(resolve, id), id)(); }); - break; } case 'editsubtitles': @@ -433,102 +413,48 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter', break; } case 'share': - { navigator.share({ title: item.Name, text: item.Overview, url: "https://github.com/jellyfin/jellyfin" }); break; - } case 'album': - { - appRouter.showItem(item.AlbumId, item.ServerId); - getResolveFunction(resolve, id)(); - break; - } + appRouter.showItem(item.AlbumId, item.ServerId); + getResolveFunction(resolve, id)(); + break; case 'artist': - { - appRouter.showItem(item.ArtistItems[0].Id, item.ServerId); - getResolveFunction(resolve, id)(); + appRouter.showItem(item.ArtistItems[0].Id, item.ServerId); + getResolveFunction(resolve, id)(); break; - } case 'playallfromhere': - { - getResolveFunction(resolve, id)(); + getResolveFunction(resolve, id)(); break; - } case 'queueallfromhere': { getResolveFunction(resolve, id)(); break; } - case 'convert': - { - require(['syncDialog'], function (syncDialog) { - syncDialog.showMenu({ - items: [item], - serverId: serverId, - mode: 'convert' - }); - }); - getResolveFunction(resolve, id)(); - break; - } - case 'sync': - { - require(['syncDialog'], function (syncDialog) { - syncDialog.showMenu({ - items: [item], - serverId: serverId, - mode: 'sync' - }); - }); - getResolveFunction(resolve, id)(); - break; - } - case 'synclocal': - { - require(['syncDialog'], function (syncDialog) { - syncDialog.showMenu({ - items: [item], - serverId: serverId, - mode: 'download' - }); - }); - getResolveFunction(resolve, id)(); - break; - } case 'removefromplaylist': - apiClient.ajax({ - url: apiClient.getUrl('Playlists/' + options.playlistId + '/Items', { EntryIds: [item.PlaylistItemId].join(',') }), - type: 'DELETE' - }).then(function () { - getResolveFunction(resolve, id, true)(); }); - break; case 'removefromcollection': - apiClient.ajax({ type: "DELETE", url: apiClient.getUrl("Collections/" + options.collectionId + "/Items", { Ids: [item.Id].join(',') }) - }).then(function () { - getResolveFunction(resolve, id, true)(); }); - break; case 'canceltimer': deleteTimer(apiClient, item, resolve, id); diff --git a/src/bower_components/emby-webcomponents/itemhelper.js b/src/components/itemhelper.js similarity index 100% rename from src/bower_components/emby-webcomponents/itemhelper.js rename to src/components/itemhelper.js diff --git a/src/bower_components/emby-webcomponents/itemidentifier/itemidentifier.js b/src/components/itemidentifier/itemidentifier.js similarity index 100% rename from src/bower_components/emby-webcomponents/itemidentifier/itemidentifier.js rename to src/components/itemidentifier/itemidentifier.js diff --git a/src/bower_components/emby-webcomponents/itemidentifier/itemidentifier.template.html b/src/components/itemidentifier/itemidentifier.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/itemidentifier/itemidentifier.template.html rename to src/components/itemidentifier/itemidentifier.template.html diff --git a/src/bower_components/emby-webcomponents/itemsrefresher.js b/src/components/itemsrefresher.js similarity index 100% rename from src/bower_components/emby-webcomponents/itemsrefresher.js rename to src/components/itemsrefresher.js diff --git a/src/bower_components/emby-webcomponents/layoutmanager.js b/src/components/layoutmanager.js similarity index 100% rename from src/bower_components/emby-webcomponents/layoutmanager.js rename to src/components/layoutmanager.js diff --git a/src/bower_components/emby-webcomponents/lazyloader/lazyedgehack.css b/src/components/lazyloader/lazyedgehack.css similarity index 100% rename from src/bower_components/emby-webcomponents/lazyloader/lazyedgehack.css rename to src/components/lazyloader/lazyedgehack.css diff --git a/src/bower_components/emby-webcomponents/lazyloader/lazyloader-intersectionobserver.js b/src/components/lazyloader/lazyloader-intersectionobserver.js similarity index 100% rename from src/bower_components/emby-webcomponents/lazyloader/lazyloader-intersectionobserver.js rename to src/components/lazyloader/lazyloader-intersectionobserver.js diff --git a/src/bower_components/emby-webcomponents/lazyloader/lazyloader-scroll.js b/src/components/lazyloader/lazyloader-scroll.js similarity index 100% rename from src/bower_components/emby-webcomponents/lazyloader/lazyloader-scroll.js rename to src/components/lazyloader/lazyloader-scroll.js diff --git a/src/bower_components/emby-webcomponents/listview/listview.css b/src/components/listview/listview.css similarity index 99% rename from src/bower_components/emby-webcomponents/listview/listview.css rename to src/components/listview/listview.css index 4b4e88f842..312bf14a16 100644 --- a/src/bower_components/emby-webcomponents/listview/listview.css +++ b/src/components/listview/listview.css @@ -100,7 +100,7 @@ min-width: 2.78em; min-height: 2.78em; background-repeat: no-repeat; - background-size: contain; + background-size: cover; flex-shrink: 0; background-position: center center; position: relative; diff --git a/src/bower_components/emby-webcomponents/listview/listview.js b/src/components/listview/listview.js similarity index 100% rename from src/bower_components/emby-webcomponents/listview/listview.js rename to src/components/listview/listview.js diff --git a/src/bower_components/emby-webcomponents/loading/loader2.gif b/src/components/loading/loader2.gif similarity index 100% rename from src/bower_components/emby-webcomponents/loading/loader2.gif rename to src/components/loading/loader2.gif diff --git a/src/bower_components/emby-webcomponents/loading/loading-lite.css b/src/components/loading/loading.css similarity index 100% rename from src/bower_components/emby-webcomponents/loading/loading-lite.css rename to src/components/loading/loading.css diff --git a/src/bower_components/emby-webcomponents/loading/loading-lite.js b/src/components/loading/loading.js similarity index 93% rename from src/bower_components/emby-webcomponents/loading/loading-lite.js rename to src/components/loading/loading.js index 00aff8f0f8..ad9aea950a 100644 --- a/src/bower_components/emby-webcomponents/loading/loading-lite.js +++ b/src/components/loading/loading.js @@ -1,6 +1,10 @@ -define(['css!./loading-lite'], function () { +define(['components/loading/loadingLegacy', 'browser', 'css!./loading'], function (loadingLegacy, browser) { 'use strict'; + if (browser.tizen || browser.operaTv || browser.chromecast || browser.orsay || browser.web0s || browser.ps4) { + return loadingLegacy; + } + var loadingElem; var layer1; var layer2; diff --git a/src/bower_components/emby-webcomponents/loading/loading-legacy.css b/src/components/loading/loadingLegacy.css similarity index 100% rename from src/bower_components/emby-webcomponents/loading/loading-legacy.css rename to src/components/loading/loadingLegacy.css diff --git a/src/bower_components/emby-webcomponents/loading/loading-legacy.js b/src/components/loading/loadingLegacy.js similarity index 90% rename from src/bower_components/emby-webcomponents/loading/loading-legacy.js rename to src/components/loading/loadingLegacy.js index bb8d8a99ab..c5ffd8dc6b 100644 --- a/src/bower_components/emby-webcomponents/loading/loading-legacy.js +++ b/src/components/loading/loadingLegacy.js @@ -1,4 +1,4 @@ -define(['require', 'css!./loading-legacy'], function (require) { +define(['require', 'css!./loadingLegacy'], function (require) { 'use strict'; var loadingElem; diff --git a/src/components/loading/package.json b/src/components/loading/package.json new file mode 100644 index 0000000000..79fd41b0f8 --- /dev/null +++ b/src/components/loading/package.json @@ -0,0 +1,3 @@ +{ + "main": "loading.js" +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/loadingdialog/loadingdialog.js b/src/components/loadingdialog/loadingdialog.js similarity index 100% rename from src/bower_components/emby-webcomponents/loadingdialog/loadingdialog.js rename to src/components/loadingdialog/loadingdialog.js diff --git a/src/bower_components/emby-webcomponents/maintabsmanager.js b/src/components/maintabsmanager.js similarity index 98% rename from src/bower_components/emby-webcomponents/maintabsmanager.js rename to src/components/maintabsmanager.js index b8da631df9..64e25b4870 100644 --- a/src/bower_components/emby-webcomponents/maintabsmanager.js +++ b/src/components/maintabsmanager.js @@ -1,4 +1,4 @@ -define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button', 'emby-linkbutton'], function (dom, browser, events) { +define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom, browser, events) { 'use strict'; var tabOwnerView; diff --git a/src/bower_components/emby-webcomponents/mediainfo/fresh.png b/src/components/mediainfo/fresh.png similarity index 100% rename from src/bower_components/emby-webcomponents/mediainfo/fresh.png rename to src/components/mediainfo/fresh.png diff --git a/src/bower_components/emby-webcomponents/mediainfo/mediainfo.css b/src/components/mediainfo/mediainfo.css similarity index 100% rename from src/bower_components/emby-webcomponents/mediainfo/mediainfo.css rename to src/components/mediainfo/mediainfo.css diff --git a/src/bower_components/emby-webcomponents/mediainfo/mediainfo.js b/src/components/mediainfo/mediainfo.js similarity index 99% rename from src/bower_components/emby-webcomponents/mediainfo/mediainfo.js rename to src/components/mediainfo/mediainfo.js index 3f92425034..441adac3dd 100644 --- a/src/bower_components/emby-webcomponents/mediainfo/mediainfo.js +++ b/src/components/mediainfo/mediainfo.js @@ -1,4 +1,4 @@ -define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'material-icons', 'css!./mediainfo.css', 'programStyles', 'emby-linkbutton'], function (datetime, globalize, appRouter, itemHelper, indicators) { +define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'material-icons', 'css!./mediainfo.css', 'programStyles', 'emby-button'], function (datetime, globalize, appRouter, itemHelper, indicators) { 'use strict'; function getTimerIndicator(item) { diff --git a/src/bower_components/emby-webcomponents/mediainfo/rotten.png b/src/components/mediainfo/rotten.png similarity index 100% rename from src/bower_components/emby-webcomponents/mediainfo/rotten.png rename to src/components/mediainfo/rotten.png diff --git a/src/components/medialibrarycreator/medialibrarycreator.js b/src/components/medialibrarycreator/medialibrarycreator.js index af51d2ef54..d02f0940cb 100644 --- a/src/components/medialibrarycreator/medialibrarycreator.js +++ b/src/components/medialibrarycreator/medialibrarycreator.js @@ -1,4 +1,4 @@ -define(["loading", "dialogHelper", "dom", "jQuery", "components/libraryoptionseditor/libraryoptionseditor", "emby-toggle", "emby-input", "emby-select", "paper-icon-button-light", "listViewStyle", "formDialogStyle", "emby-linkbutton", "flexStyles"], function(loading, dialogHelper, dom, $, libraryoptionseditor) { +define(["loading", "dialogHelper", "dom", "jQuery", "components/libraryoptionseditor/libraryoptionseditor", "emby-toggle", "emby-input", "emby-select", "paper-icon-button-light", "listViewStyle", "formDialogStyle", "emby-button", "flexStyles"], function(loading, dialogHelper, dom, $, libraryoptionseditor) { "use strict"; function onSubmit(e) { diff --git a/src/bower_components/emby-webcomponents/metadataeditor/metadataeditor.js b/src/components/metadataeditor/metadataeditor.js similarity index 100% rename from src/bower_components/emby-webcomponents/metadataeditor/metadataeditor.js rename to src/components/metadataeditor/metadataeditor.js diff --git a/src/bower_components/emby-webcomponents/metadataeditor/metadataeditor.template.html b/src/components/metadataeditor/metadataeditor.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/metadataeditor/metadataeditor.template.html rename to src/components/metadataeditor/metadataeditor.template.html diff --git a/src/bower_components/emby-webcomponents/metadataeditor/personeditor.js b/src/components/metadataeditor/personeditor.js similarity index 100% rename from src/bower_components/emby-webcomponents/metadataeditor/personeditor.js rename to src/components/metadataeditor/personeditor.js diff --git a/src/bower_components/emby-webcomponents/metadataeditor/personeditor.template.html b/src/components/metadataeditor/personeditor.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/metadataeditor/personeditor.template.html rename to src/components/metadataeditor/personeditor.template.html diff --git a/src/bower_components/emby-webcomponents/multidownload.js b/src/components/multidownload.js similarity index 100% rename from src/bower_components/emby-webcomponents/multidownload.js rename to src/components/multidownload.js diff --git a/src/bower_components/emby-webcomponents/multiselect/multiselect.css b/src/components/multiselect/multiselect.css similarity index 100% rename from src/bower_components/emby-webcomponents/multiselect/multiselect.css rename to src/components/multiselect/multiselect.css diff --git a/src/bower_components/emby-webcomponents/multiselect/multiselect.js b/src/components/multiselect/multiselect.js similarity index 90% rename from src/bower_components/emby-webcomponents/multiselect/multiselect.js rename to src/components/multiselect/multiselect.js index 32e3ab9f82..d06bb63ce1 100644 --- a/src/bower_components/emby-webcomponents/multiselect/multiselect.js +++ b/src/components/multiselect/multiselect.js @@ -218,13 +218,6 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo }); } - if (user.Policy.EnableContentDownloading && appHost.supports('sync')) { - menuItems.push({ - name: globalize.translate('Download'), - id: 'synclocal' - }); - } - menuItems.push({ name: globalize.translate('GroupVersions'), id: 'groupvideos', @@ -246,28 +239,19 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo id: 'refresh' }); - if (user.Policy.EnableContentDownloading) { - menuItems.push({ - name: globalize.translate('Sync'), - id: 'sync' - }); - } + require(['actionsheet'], function (actionsheet) { - actionsheet.show({ items: menuItems, positionTo: e.target, callback: function (id) { - var items = selectedItems.slice(0); var serverId = apiClient.serverInfo().Id; switch (id) { - case 'addtocollection': require(['collectionEditor'], function (collectionEditor) { - new collectionEditor().show({ items: items, serverId: serverId @@ -318,35 +302,6 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo hideSelections(); dispatchNeedsRefresh(); break; - case 'sync': - require(['syncDialog'], function (syncDialog) { - syncDialog.showMenu({ - items: items.map(function (i) { - return { - Id: i - }; - }), - serverId: serverId - }); - }); - hideSelections(); - dispatchNeedsRefresh(); - break; - case 'synclocal': - require(['syncDialog'], function (syncDialog) { - syncDialog.showMenu({ - items: items.map(function (i) { - return { - Id: i - }; - }), - isLocalSync: true, - serverId: serverId - }); - }); - hideSelections(); - dispatchNeedsRefresh(); - break; default: break; } diff --git a/src/components/navdrawer/package.json b/src/components/navdrawer/package.json new file mode 100644 index 0000000000..d02800957b --- /dev/null +++ b/src/components/navdrawer/package.json @@ -0,0 +1,3 @@ +{ + "main": "navdrawer.js" +} \ No newline at end of file diff --git a/src/components/notifications/badge.png b/src/components/notifications/badge.png new file mode 100644 index 0000000000..656b516456 Binary files /dev/null and b/src/components/notifications/badge.png differ diff --git a/src/components/notifications/notificationicon.png b/src/components/notifications/notificationicon.png new file mode 100644 index 0000000000..656b516456 Binary files /dev/null and b/src/components/notifications/notificationicon.png differ diff --git a/src/bower_components/emby-webcomponents/notifications/notifications.js b/src/components/notifications/notifications.js similarity index 100% rename from src/bower_components/emby-webcomponents/notifications/notifications.js rename to src/components/notifications/notifications.js diff --git a/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.css b/src/components/nowplayingbar/nowplayingbar.css similarity index 80% rename from src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.css rename to src/components/nowplayingbar/nowplayingbar.css index 1392541e16..80f078d880 100644 --- a/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.css +++ b/src/components/nowplayingbar/nowplayingbar.css @@ -119,38 +119,66 @@ height: 1.2em !important; } -@media all and (max-width: 87.5em) { - .nowPlayingBarUserDataButtons { +@media all and (max-width: 70em) { + + .nowPlayingBarRight .nowPlayingBarUserDataButtons { display: none; } } -@media all and (max-width: 68.75em) { - - .nowPlayingBarVolumeSliderContainer, .nowPlayingBar .muteButton, .nowPlayingBar .unmuteButton { +@media all and (max-width: 66em) { + .toggleRepeatButton { display: none !important; } } -@media all and (max-width: 50em) { + +@media all and (max-width: 62em) { + + .nowPlayingBarCenter .nowPlayingBarCurrentTime { + display: none !important; + } + +} + +@media all and (max-width: 56em) { .nowPlayingBarCenter { display: none !important; } - .toggleRepeatButton { - display: none; - } } -@media all and (min-width: 50em) { + +@media all and (min-width: 56em) { .nowPlayingBarRight .playPauseButton { display: none; } - .nowPlayingBarInfoContainer { - max-width: 40%; - } +} + +@media all and (max-width: 40em) { + + .nowPlayingBarInfoContainer .nowPlayingImage { + display: none; + } + +} + +@media all and (max-width: 36em) { + + .nowPlayingBarRight .nowPlayingBarVolumeSliderContainer { + display: none !important; + } + +} + +@media all and (max-width: 24em) { + + .nowPlayingBar .muteButton, .nowPlayingBar .unmuteButton { + display: none; + } + } diff --git a/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.js b/src/components/nowplayingbar/nowplayingbar.js similarity index 98% rename from src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.js rename to src/components/nowplayingbar/nowplayingbar.js index 331b178b39..01c920a501 100644 --- a/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.js +++ b/src/components/nowplayingbar/nowplayingbar.js @@ -56,7 +56,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', html += ''; - html += '
'; + html += '
'; html += ''; html += '
'; @@ -191,9 +191,9 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', currentPlayer.setVolume(this.value); } } - volumeSlider.addEventListener('change', setVolume.bind(this)); - volumeSlider.addEventListener('mousemove', setVolume.bind(this)); - volumeSlider.addEventListener('touchmove', setVolume.bind(this)); + volumeSlider.addEventListener('change', setVolume); + volumeSlider.addEventListener('mousemove', setVolume); + volumeSlider.addEventListener('touchmove', setVolume); positionSlider = elem.querySelector('.nowPlayingBarPositionSlider'); diff --git a/src/bower_components/emby-webcomponents/packagemanager.js b/src/components/packagemanager.js similarity index 100% rename from src/bower_components/emby-webcomponents/packagemanager.js rename to src/components/packagemanager.js diff --git a/src/bower_components/emby-webcomponents/photoplayer/plugin.js b/src/components/photoplayer/plugin.js similarity index 100% rename from src/bower_components/emby-webcomponents/photoplayer/plugin.js rename to src/components/photoplayer/plugin.js diff --git a/src/bower_components/emby-webcomponents/playback/autoplaydetect.js b/src/components/playback/autoplaydetect.js similarity index 100% rename from src/bower_components/emby-webcomponents/playback/autoplaydetect.js rename to src/components/playback/autoplaydetect.js diff --git a/src/bower_components/emby-webcomponents/playback/brightnessosd.js b/src/components/playback/brightnessosd.js similarity index 100% rename from src/bower_components/emby-webcomponents/playback/brightnessosd.js rename to src/components/playback/brightnessosd.js diff --git a/src/bower_components/emby-webcomponents/playback/experimentalwarnings.js b/src/components/playback/experimentalwarnings.js similarity index 100% rename from src/bower_components/emby-webcomponents/playback/experimentalwarnings.js rename to src/components/playback/experimentalwarnings.js diff --git a/src/bower_components/emby-webcomponents/playback/iconosd.css b/src/components/playback/iconosd.css similarity index 100% rename from src/bower_components/emby-webcomponents/playback/iconosd.css rename to src/components/playback/iconosd.css diff --git a/src/bower_components/emby-webcomponents/playback/mediasession.js b/src/components/playback/mediasession.js similarity index 60% rename from src/bower_components/emby-webcomponents/playback/mediasession.js rename to src/components/playback/mediasession.js index 8e2f7d0c01..b92e581b25 100644 --- a/src/bower_components/emby-webcomponents/playback/mediasession.js +++ b/src/components/playback/mediasession.js @@ -1,6 +1,11 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], function (playbackManager, nowPlayingHelper, events, connectionManager) { "use strict"; + // no support for mediaSession + if (!navigator.mediaSession && !window.NativeShell) { + return; + } + // Reports media playback to the device for lock screen control var currentPlayer; @@ -64,15 +69,16 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f return null; } - function pushImageUrl(item, height, list) { - - var imageOptions = { - height: height - }; - + function pushImageUrl(item, imageOptions, list) { var url = seriesImageUrl(item, imageOptions) || imageUrl(item, imageOptions); + if (url) { - list.push({ src: url, sizes: height + 'x' + height }); + var height = imageOptions.height || imageOptions.maxHeight; + + list.push({ + src: url, + sizes: height + 'x' + height + }); } } @@ -80,12 +86,12 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f var list = []; - pushImageUrl(item, 96, list); - pushImageUrl(item, 128, list); - pushImageUrl(item, 192, list); - pushImageUrl(item, 256, list); - pushImageUrl(item, 384, list); - pushImageUrl(item, 512, list); + pushImageUrl(item, {height: 96}, list); + pushImageUrl(item, {height: 128}, list); + pushImageUrl(item, {height: 192}, list); + pushImageUrl(item, {height: 256}, list); + pushImageUrl(item, {height: 384}, list); + pushImageUrl(item, {height: 512}, list); return list; } @@ -99,6 +105,18 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f return; } + if (eventName == 'init') { // transform "init" event into "timeupdate" to restraint update rate + eventName = 'timeupdate'; + } + + var isVideo = item.MediaType === 'Video'; + var isLocalPlayer = player.isLocalPlayer || false; + + // Local players do their own notifications + if (isLocalPlayer && isVideo) { + return; + } + var playState = state.PlayState || {}; var parts = nowPlayingHelper.getNowPlayingNames(item); @@ -106,8 +124,6 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f var artist = parts.length === 1 ? '' : parts[0].text; var title = parts[parts.length - 1].text; - var isVideo = item.MediaType === 'Video'; - // Switch these two around for video if (isVideo && parts.length > 1) { var temp = artist; @@ -131,18 +147,54 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f var isPaused = playState.IsPaused || false; var canSeek = playState.CanSeek || false; - navigator.mediaSession.metadata = new MediaMetadata({ - title: title, - artist: artist, - album: album, - artwork: getImageUrls(item), - albumArtist: albumArtist, - currentTime: currentTime, - duration: duration, - paused: isPaused, - itemId: itemId, - mediaType: item.MediaType - }); + var now = new Date().getTime(); + + // Don't go crazy reporting position changes + if (eventName == 'timeupdate' && (now - lastUpdateTime) < 5000) { + // Only report if this item hasn't been reported yet, or if there's an actual playback change. + // Don't report on simple time updates + return; + } + + lastUpdateTime = now; + + if (navigator.mediaSession){ + navigator.mediaSession.metadata = new MediaMetadata({ + title: title, + artist: artist, + album: album, + artwork: getImageUrls(item), + albumArtist: albumArtist, + currentTime: currentTime, + duration: duration, + paused: isPaused, + itemId: itemId, + mediaType: item.MediaType + }); + } else { + var imageUrl = []; + pushImageUrl(item, {maxHeight: 400}, imageUrl); + + if (imageUrl.length) { + imageUrl = imageUrl[0].src; + } else { + imageUrl = null; + } + + window.NativeShell.updateMediaSession({ + action: eventName, + isLocalPlayer: isLocalPlayer, + itemId: itemId, + title: title, + artist: artist, + album: album, + duration: duration, + position: currentTime, + imageUrl: imageUrl, + canSeek: canSeek, + isPaused: isPaused + }); + } } function onGeneralEvent(e) { @@ -191,7 +243,13 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f } function hideMediaControls() { - navigator.mediaSession.metadata = null; + lastUpdateTime = 0; + + if (navigator.mediaSession) { + navigator.mediaSession.metadata = null; + } else { + window.NativeShell.hideMediaSession(); + } } function bindToPlayer(player) { @@ -215,34 +273,37 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f events.on(currentPlayer, 'timeupdate', onGeneralEvent); } - function execute(name) { - playbackManager[name](currentPlayer); + if (navigator.mediaSession) { + + function execute(name) { + playbackManager[name](currentPlayer); + } + + navigator.mediaSession.setActionHandler('previoustrack', function () { + execute('previousTrack'); + }); + + navigator.mediaSession.setActionHandler('nexttrack', function () { + execute('nextTrack'); + }); + + navigator.mediaSession.setActionHandler('play', function () { + execute('unpause'); + }); + + navigator.mediaSession.setActionHandler('pause', function () { + execute('pause'); + }); + + navigator.mediaSession.setActionHandler('seekbackward', function () { + execute('rewind'); + }); + + navigator.mediaSession.setActionHandler('seekforward', function () { + execute('fastForward'); + }); } - navigator.mediaSession.setActionHandler('previoustrack', function () { - execute('previousTrack'); - }); - - navigator.mediaSession.setActionHandler('nexttrack', function () { - execute('nextTrack'); - }); - - navigator.mediaSession.setActionHandler('play', function () { - execute('unpause'); - }); - - navigator.mediaSession.setActionHandler('pause', function () { - execute('pause'); - }); - - navigator.mediaSession.setActionHandler('seekbackward', function () { - execute('rewind'); - }); - - navigator.mediaSession.setActionHandler('seekforward', function () { - execute('fastForward'); - }); - events.on(playbackManager, 'playerchange', function () { bindToPlayer(playbackManager.getCurrentPlayer()); diff --git a/src/bower_components/emby-webcomponents/playback/nowplayinghelper.js b/src/components/playback/nowplayinghelper.js similarity index 100% rename from src/bower_components/emby-webcomponents/playback/nowplayinghelper.js rename to src/components/playback/nowplayinghelper.js diff --git a/src/bower_components/emby-webcomponents/playback/playaccessvalidation.js b/src/components/playback/playaccessvalidation.js similarity index 99% rename from src/bower_components/emby-webcomponents/playback/playaccessvalidation.js rename to src/components/playback/playaccessvalidation.js index bb0b8db3e0..35d8314fc1 100644 --- a/src/bower_components/emby-webcomponents/playback/playaccessvalidation.js +++ b/src/components/playback/playaccessvalidation.js @@ -2,16 +2,13 @@ define(['connectionManager', 'globalize'], function (connectionManager, globaliz "use strict"; function getRequirePromise(deps) { - return new Promise(function (resolve, reject) { - require(deps, resolve); }); } function showErrorMessage() { return getRequirePromise(['alert']).then(function (alert) { - return alert(globalize.translate('MessagePlayAccessRestricted')).then(function () { return Promise.reject(); }); @@ -19,7 +16,6 @@ define(['connectionManager', 'globalize'], function (connectionManager, globaliz } function PlayAccessValidation() { - this.name = 'Playback validation'; this.type = 'preplayintercept'; this.id = 'playaccessvalidation'; @@ -27,7 +23,6 @@ define(['connectionManager', 'globalize'], function (connectionManager, globaliz } PlayAccessValidation.prototype.intercept = function (options) { - var item = options.item; if (!item) { return Promise.resolve(); @@ -38,7 +33,6 @@ define(['connectionManager', 'globalize'], function (connectionManager, globaliz } return connectionManager.getApiClient(serverId).getCurrentUser().then(function (user) { - if (user.Policy.EnableMediaPlayback) { return Promise.resolve(); } diff --git a/src/bower_components/emby-webcomponents/playback/playbackmanager.js b/src/components/playback/playbackmanager.js similarity index 99% rename from src/bower_components/emby-webcomponents/playback/playbackmanager.js rename to src/components/playback/playbackmanager.js index 59a7ffd8bb..fedf7924ba 100644 --- a/src/bower_components/emby-webcomponents/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1731,7 +1731,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla var maxBitrate = params.MaxStreamingBitrate || self.getMaxStreamingBitrate(player); - var currentPlayOptions = currentItem.playOptions || {}; + var currentPlayOptions = currentItem.playOptions || getDefaultPlayOptions(); getPlaybackInfo(player, apiClient, currentItem, deviceProfile, maxBitrate, ticks, true, currentMediaSource.Id, audioStreamIndex, subtitleStreamIndex, liveStreamId, params.EnableDirectPlay, params.EnableDirectStream, params.AllowVideoStreamCopy, params.AllowAudioStreamCopy).then(function (result) { @@ -1806,6 +1806,12 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function translateItemsForPlayback(items, options) { + if (items.length > 1 && options && options.ids) { + // Use the original request id array for sorting the result in the proper order + items.sort(function (a, b) { + return options.ids.indexOf(a.Id) - options.ids.indexOf(b.Id); + }); + } var firstItem = items[0]; var promise; @@ -2692,7 +2698,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla if (newItem) { - var newItemPlayOptions = newItem.playOptions || {}; + var newItemPlayOptions = newItem.playOptions || getDefaultPlayOptions(); playInternal(newItem, newItemPlayOptions, function () { setPlaylistState(newItem.PlaylistItemId, newItemIndex); @@ -2797,7 +2803,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla console.log('playing next track'); - var newItemPlayOptions = newItemInfo.item.playOptions || {}; + var newItemPlayOptions = newItemInfo.item.playOptions || getDefaultPlayOptions(); playInternal(newItemInfo.item, newItemPlayOptions, function () { setPlaylistState(newItemInfo.item.PlaylistItemId, newItemInfo.index); @@ -2820,7 +2826,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla if (newItem) { - var newItemPlayOptions = newItem.playOptions || {}; + var newItemPlayOptions = newItem.playOptions || getDefaultPlayOptions(); newItemPlayOptions.startPositionTicks = 0; playInternal(newItem, newItemPlayOptions, function () { @@ -2991,7 +2997,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla var player = this; setCurrentPlayerInternal(player); - var playOptions = item.playOptions || {}; + var playOptions = item.playOptions || getDefaultPlayOptions(); var isFirstItem = playOptions.isFirstItem; var fullscreen = playOptions.fullscreen; @@ -3799,8 +3805,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla player = player || this._currentPlayer || { isLocalPlayer: true }; if (player.isLocalPlayer) { - // Full list - // https://github.com/MediaBrowser/MediaBrowser/blob/master/MediaBrowser.Model/Session/GeneralCommand.cs + // https://github.com/jellyfin/jellyfin/blob/master/MediaBrowser.Model/Session/GeneralCommandType.cs var list = [ "GoHome", "GoToSettings", @@ -3928,12 +3933,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla }; PlaybackManager.prototype.sendCommand = function (cmd, player) { - - // Full list - // https://github.com/MediaBrowser/MediaBrowser/blob/master/MediaBrowser.Model/Session/GeneralCommand.cs#L23 + // https://github.com/jellyfin/jellyfin/blob/master/MediaBrowser.Model/Session/GeneralCommandType.cs console.log('MediaController received command: ' + cmd.Name); switch (cmd.Name) { - case 'SetRepeatMode': this.setRepeatMode(cmd.Arguments.RepeatMode, player); break; @@ -3975,12 +3977,10 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla this.toggleFullscreen(player); break; default: - { - if (player.sendCommand) { - player.sendCommand(cmd); - } - break; + if (player.sendCommand) { + player.sendCommand(cmd); } + break; } }; diff --git a/src/bower_components/emby-webcomponents/playback/playbackorientation.js b/src/components/playback/playbackorientation.js similarity index 100% rename from src/bower_components/emby-webcomponents/playback/playbackorientation.js rename to src/components/playback/playbackorientation.js diff --git a/src/bower_components/emby-webcomponents/playback/playerselection.js b/src/components/playback/playerSelectionMenu.js similarity index 100% rename from src/bower_components/emby-webcomponents/playback/playerselection.js rename to src/components/playback/playerSelectionMenu.js diff --git a/src/bower_components/emby-webcomponents/playback/playersettingsmenu.js b/src/components/playback/playersettingsmenu.js similarity index 100% rename from src/bower_components/emby-webcomponents/playback/playersettingsmenu.js rename to src/components/playback/playersettingsmenu.js diff --git a/src/bower_components/emby-webcomponents/playback/playmethodhelper.js b/src/components/playback/playmethodhelper.js similarity index 100% rename from src/bower_components/emby-webcomponents/playback/playmethodhelper.js rename to src/components/playback/playmethodhelper.js diff --git a/src/bower_components/emby-webcomponents/playback/playqueuemanager.js b/src/components/playback/playqueuemanager.js similarity index 100% rename from src/bower_components/emby-webcomponents/playback/playqueuemanager.js rename to src/components/playback/playqueuemanager.js diff --git a/src/bower_components/emby-webcomponents/playback/remotecontrolautoplay.js b/src/components/playback/remotecontrolautoplay.js similarity index 100% rename from src/bower_components/emby-webcomponents/playback/remotecontrolautoplay.js rename to src/components/playback/remotecontrolautoplay.js diff --git a/src/bower_components/emby-webcomponents/playback/volumeosd.js b/src/components/playback/volumeosd.js similarity index 100% rename from src/bower_components/emby-webcomponents/playback/volumeosd.js rename to src/components/playback/volumeosd.js diff --git a/src/bower_components/emby-webcomponents/playbacksettings/playbacksettings.js b/src/components/playbacksettings/playbacksettings.js similarity index 100% rename from src/bower_components/emby-webcomponents/playbacksettings/playbacksettings.js rename to src/components/playbacksettings/playbacksettings.js diff --git a/src/bower_components/emby-webcomponents/playbacksettings/playbacksettings.template.html b/src/components/playbacksettings/playbacksettings.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/playbacksettings/playbacksettings.template.html rename to src/components/playbacksettings/playbacksettings.template.html diff --git a/src/bower_components/emby-webcomponents/playerstats/playerstats.css b/src/components/playerstats/playerstats.css similarity index 100% rename from src/bower_components/emby-webcomponents/playerstats/playerstats.css rename to src/components/playerstats/playerstats.css diff --git a/src/bower_components/emby-webcomponents/playerstats/playerstats.js b/src/components/playerstats/playerstats.js similarity index 100% rename from src/bower_components/emby-webcomponents/playerstats/playerstats.js rename to src/components/playerstats/playerstats.js diff --git a/src/bower_components/emby-webcomponents/playlisteditor/playlisteditor.js b/src/components/playlisteditor/playlisteditor.js similarity index 100% rename from src/bower_components/emby-webcomponents/playlisteditor/playlisteditor.js rename to src/components/playlisteditor/playlisteditor.js diff --git a/src/bower_components/emby-webcomponents/playmenu.js b/src/components/playmenu.js similarity index 100% rename from src/bower_components/emby-webcomponents/playmenu.js rename to src/components/playmenu.js diff --git a/src/bower_components/emby-webcomponents/pluginmanager.js b/src/components/pluginmanager.js similarity index 100% rename from src/bower_components/emby-webcomponents/pluginmanager.js rename to src/components/pluginmanager.js diff --git a/src/bower_components/emby-webcomponents/prompt/nativeprompt.js b/src/components/prompt/nativeprompt.js similarity index 100% rename from src/bower_components/emby-webcomponents/prompt/nativeprompt.js rename to src/components/prompt/nativeprompt.js diff --git a/src/bower_components/emby-webcomponents/prompt/prompt.js b/src/components/prompt/prompt.js similarity index 100% rename from src/bower_components/emby-webcomponents/prompt/prompt.js rename to src/components/prompt/prompt.js diff --git a/src/bower_components/emby-webcomponents/prompt/prompt.template.html b/src/components/prompt/prompt.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/prompt/prompt.template.html rename to src/components/prompt/prompt.template.html diff --git a/src/bower_components/emby-webcomponents/qualityoptions.js b/src/components/qualityoptions.js similarity index 100% rename from src/bower_components/emby-webcomponents/qualityoptions.js rename to src/components/qualityoptions.js diff --git a/src/bower_components/emby-webcomponents/recordingcreator/empty.png b/src/components/recordingcreator/empty.png similarity index 100% rename from src/bower_components/emby-webcomponents/recordingcreator/empty.png rename to src/components/recordingcreator/empty.png diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingbutton.js b/src/components/recordingcreator/recordingbutton.js similarity index 92% rename from src/bower_components/emby-webcomponents/recordingcreator/recordingbutton.js rename to src/components/recordingcreator/recordingbutton.js index ef4645e6bb..0a76d3914c 100644 --- a/src/bower_components/emby-webcomponents/recordingcreator/recordingbutton.js +++ b/src/components/recordingcreator/recordingbutton.js @@ -1,4 +1,4 @@ -define(['globalize', 'connectionManager', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'registrationServices', 'paper-icon-button-light', 'emby-button', 'css!./recordingfields'], function (globalize, connectionManager, require, loading, appHost, dom, recordingHelper, events, registrationServices) { +define(['globalize', 'connectionManager', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'paper-icon-button-light', 'emby-button', 'css!./recordingfields'], function (globalize, connectionManager, require, loading, appHost, dom, recordingHelper, events) { 'use strict'; function onRecordingButtonClick(e) { diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingcreator.css b/src/components/recordingcreator/recordingcreator.css similarity index 100% rename from src/bower_components/emby-webcomponents/recordingcreator/recordingcreator.css rename to src/components/recordingcreator/recordingcreator.css diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingcreator.js b/src/components/recordingcreator/recordingcreator.js similarity index 100% rename from src/bower_components/emby-webcomponents/recordingcreator/recordingcreator.js rename to src/components/recordingcreator/recordingcreator.js diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingcreator.template.html b/src/components/recordingcreator/recordingcreator.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/recordingcreator/recordingcreator.template.html rename to src/components/recordingcreator/recordingcreator.template.html diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingeditor.js b/src/components/recordingcreator/recordingeditor.js similarity index 100% rename from src/bower_components/emby-webcomponents/recordingcreator/recordingeditor.js rename to src/components/recordingcreator/recordingeditor.js diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingeditor.template.html b/src/components/recordingcreator/recordingeditor.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/recordingcreator/recordingeditor.template.html rename to src/components/recordingcreator/recordingeditor.template.html diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingfields.css b/src/components/recordingcreator/recordingfields.css similarity index 100% rename from src/bower_components/emby-webcomponents/recordingcreator/recordingfields.css rename to src/components/recordingcreator/recordingfields.css diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingfields.js b/src/components/recordingcreator/recordingfields.js similarity index 73% rename from src/bower_components/emby-webcomponents/recordingcreator/recordingfields.js rename to src/components/recordingcreator/recordingfields.js index ac21784eb9..bb2582320c 100644 --- a/src/bower_components/emby-webcomponents/recordingcreator/recordingfields.js +++ b/src/components/recordingcreator/recordingfields.js @@ -1,81 +1,11 @@ -define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'registrationServices', 'paper-icon-button-light', 'emby-button', 'css!./recordingfields', 'flexStyles'], function (globalize, connectionManager, serverNotifications, require, loading, appHost, dom, recordingHelper, events, registrationServices) { +define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'paper-icon-button-light', 'emby-button', 'css!./recordingfields', 'flexStyles'], function (globalize, connectionManager, serverNotifications, require, loading, appHost, dom, recordingHelper, events) { 'use strict'; - function getRegistration(apiClient, feature) { - - return registrationServices.validateFeature(feature, { - showDialog: false, - viewOnly: true - }); - } - - function showConvertRecordingsUnlockMessage(context, apiClient) { - - getRegistration(apiClient, getDvrFeatureCode()).then(function () { - - context.querySelector('.convertRecordingsContainer').classList.add('hide'); - }, function () { - context.querySelector('.convertRecordingsContainer').classList.remove('hide'); - }); - } - - function showSeriesRecordingFields(context, programId, apiClient) { - - getRegistration(apiClient, getDvrFeatureCode()).then(function () { - - context.querySelector('.supporterContainer').classList.add('hide'); - context.querySelector('.convertRecordingsContainer').classList.add('hide'); - context.querySelector('.recordSeriesContainer').classList.remove('hide'); - - }, function () { - - context.querySelector('.supporterContainerText').innerHTML = globalize.translate('MessageActiveSubscriptionRequiredSeriesRecordings'); - context.querySelector('.supporterContainer').classList.remove('hide'); - context.querySelector('.recordSeriesContainer').classList.add('hide'); - context.querySelector('.convertRecordingsContainer').classList.add('hide'); - }); - } - - function getDvrFeatureCode() { - - return 'dvr'; - } - - function showSingleRecordingFields(context, programId, apiClient) { - - getRegistration(apiClient, getDvrFeatureCode()).then(function () { - - context.querySelector('.supporterContainer').classList.add('hide'); - showConvertRecordingsUnlockMessage(context, apiClient); - - }, function () { - - context.querySelector('.supporterContainerText').innerHTML = globalize.translate('DvrSubscriptionRequired'); - context.querySelector('.supporterContainer').classList.remove('hide'); - context.querySelector('.convertRecordingsContainer').classList.add('hide'); - }); - } - - function showRecordingFieldsContainer(context, programId, apiClient) { - - getRegistration(apiClient, getDvrFeatureCode()).then(function () { - - context.querySelector('.recordingFields').classList.remove('hide'); - - }, function () { - - context.querySelector('.recordingFields').classList.add('hide'); - }); - } - function loadData(parent, program, apiClient) { - if (program.IsSeries) { parent.querySelector('.recordSeriesContainer').classList.remove('hide'); - showSeriesRecordingFields(parent, program.Id, apiClient); } else { parent.querySelector('.recordSeriesContainer').classList.add('hide'); - showSingleRecordingFields(parent, program.Id, apiClient); } if (program.SeriesTimerId) { @@ -91,13 +21,11 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa if (program.TimerId && program.Status !== 'Cancelled') { parent.querySelector('.btnManageRecording').classList.remove('hide'); parent.querySelector('.singleRecordingButton .recordingIcon').classList.add('recordingIcon-active'); - if (program.Status === 'InProgress') { parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('StopRecording'); } else { parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('DoNotRecord'); } - } else { parent.querySelector('.btnManageRecording').classList.add('hide'); parent.querySelector('.singleRecordingButton .recordingIcon').classList.remove('recordingIcon-active'); @@ -110,20 +38,16 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa var options = instance.options; var apiClient = connectionManager.getApiClient(options.serverId); - showRecordingFieldsContainer(options.parent, options.programId, apiClient); - + instance.querySelector('.recordingFields').classList.remove('hide'); return apiClient.getLiveTvProgram(options.programId, apiClient.getCurrentUserId()).then(function (program) { - instance.TimerId = program.TimerId; instance.Status = program.Status; instance.SeriesTimerId = program.SeriesTimerId; - loadData(options.parent, program, apiClient); }); } function onTimerChangedExternally(e, apiClient, data) { - var options = this.options; var refresh = false; @@ -144,7 +68,6 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa } function onSeriesTimerChangedExternally(e, apiClient, data) { - var options = this.options; var refresh = false; @@ -181,26 +104,16 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa events.on(serverNotifications, 'SeriesTimerCancelled', seriesTimerChangedHandler); } - function onSupporterButtonClick() { - registrationServices.showPremiereInfo(); - } - function onManageRecordingClick(e) { - var options = this.options; - if (!this.TimerId || this.Status === 'Cancelled') { return; } var self = this; - require(['recordingEditor'], function (recordingEditor) { - recordingEditor.show(self.TimerId, options.serverId, { - enableCancel: false - }).then(function () { self.changed = true; }); @@ -281,22 +194,16 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa var isChecked = !button.querySelector('i').classList.contains('recordingIcon-active'); if (isChecked) { - showSeriesRecordingFields(options.parent, options.programId, apiClient); - + context.querySelector('.recordSeriesContainer').classList.remove('hide'); if (!this.SeriesTimerId) { - var promise = this.TimerId ? recordingHelper.changeRecordingToSeries(apiClient, this.TimerId, options.programId) : recordingHelper.createRecording(apiClient, options.programId, true); - promise.then(function () { fetchData(self); }); } } else { - - showSingleRecordingFields(options.parent, options.programId, apiClient); - if (this.SeriesTimerId) { apiClient.cancelLiveTvSeriesTimer(this.SeriesTimerId).then(function () { sendToast(globalize.translate('RecordingCancelled')); @@ -307,22 +214,13 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa } RecordingEditor.prototype.embed = function () { - var self = this; - return new Promise(function (resolve, reject) { - require(['text!./recordingfields.template.html'], function (template) { - var options = self.options; var context = options.parent; context.innerHTML = globalize.translateDocument(template, 'core'); - var supporterButtons = context.querySelectorAll('.btnSupporter'); - for (var i = 0, length = supporterButtons.length; i < length; i++) { - supporterButtons[i].addEventListener('click', onSupporterButtonClick); - } - context.querySelector('.singleRecordingButton').addEventListener('click', onRecordChange.bind(self)); context.querySelector('.seriesRecordingButton').addEventListener('click', onRecordSeriesChange.bind(self)); context.querySelector('.btnManageRecording').addEventListener('click', onManageRecordingClick.bind(self)); @@ -334,17 +232,14 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa }; RecordingEditor.prototype.hasChanged = function () { - return this.changed; }; RecordingEditor.prototype.refresh = function () { - fetchData(this); }; RecordingEditor.prototype.destroy = function () { - var timerChangedHandler = this.timerChangedHandler; this.timerChangedHandler = null; diff --git a/src/bower_components/emby-webcomponents/recordingcreator/recordingfields.template.html b/src/components/recordingcreator/recordingfields.template.html similarity index 62% rename from src/bower_components/emby-webcomponents/recordingcreator/recordingfields.template.html rename to src/components/recordingcreator/recordingfields.template.html index 4e4fb4878b..76ea5cee25 100644 --- a/src/bower_components/emby-webcomponents/recordingcreator/recordingfields.template.html +++ b/src/components/recordingcreator/recordingfields.template.html @@ -1,20 +1,4 @@ -
-

${HeaderConvertYourRecordings}

-
${PromoConvertRecordingsToStreamingFormat}
-
- -
-
-
-
- -
-
'; } diff --git a/src/bower_components/emby-webcomponents/serviceworker/notifications.js b/src/components/serviceworker/notifications.js similarity index 94% rename from src/bower_components/emby-webcomponents/serviceworker/notifications.js rename to src/components/serviceworker/notifications.js index c566715bb7..9c5be840bf 100644 --- a/src/bower_components/emby-webcomponents/serviceworker/notifications.js +++ b/src/components/serviceworker/notifications.js @@ -4,20 +4,14 @@ var connectionManager; function getApiClient(serverId) { - if (connectionManager) { return Promise.resolve(connectionManager.getApiClient(serverId)); } - - //importScripts('serviceworker-cache-polyfill.js'); - return Promise.reject(); } function executeAction(action, data, serverId) { - return getApiClient(serverId).then(function (apiClient) { - switch (action) { case 'cancel-install': var id = data.id; @@ -32,7 +26,6 @@ } self.addEventListener('notificationclick', function (event) { - var notification = event.notification; notification.close(); @@ -47,6 +40,5 @@ } event.waitUntil(executeAction(action, data, serverId)); - }, false); })(); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/sessionplayer.js b/src/components/sessionplayer.js similarity index 100% rename from src/bower_components/emby-webcomponents/sessionplayer.js rename to src/components/sessionplayer.js diff --git a/src/components/shell.js b/src/components/shell.js new file mode 100644 index 0000000000..762039ac42 --- /dev/null +++ b/src/components/shell.js @@ -0,0 +1,30 @@ +define([], function () { + 'use strict'; + + return { + openUrl: function (url, target) { + if (window.NativeShell) { + window.NativeShell.openUrl(url, target); + } else { + window.open(url, target || '_blank'); + } + + }, + canExec: false, + exec: function (options) { + // options.path + // options.arguments + return Promise.reject(); + }, + enableFullscreen: function () { + if (window.NativeShell) { + window.NativeShell.enableFullscreen(); + } + }, + disableFullscreen: function () { + if (window.NativeShell) { + window.NativeShell.disableFullscreen(); + } + } + }; +}); \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/shortcuts.js b/src/components/shortcuts.js similarity index 100% rename from src/bower_components/emby-webcomponents/shortcuts.js rename to src/components/shortcuts.js diff --git a/src/components/skinManager.js b/src/components/skinManager.js new file mode 100644 index 0000000000..d5dd0aa07a --- /dev/null +++ b/src/components/skinManager.js @@ -0,0 +1,205 @@ +define(['apphost', 'userSettings', 'browser', 'events', 'pluginManager', 'backdrop', 'globalize', 'require', 'appSettings'], function (appHost, userSettings, browser, events, pluginManager, backdrop, globalize, require, appSettings) { + 'use strict'; + + var themeStyleElement; + var currentThemeId; + + function unloadTheme() { + var elem = themeStyleElement; + if (elem) { + + elem.parentNode.removeChild(elem); + themeStyleElement = null; + currentThemeId = null; + } + } + + function loadUserSkin(options) { + options = options || {}; + + if (options.start) { + Emby.Page.invokeShortcut(options.start); + } else { + Emby.Page.goHome(); + } + }; + + function getThemes() { + return [{ + name: "Apple TV", + id: "appletv" + }, { + name: "Blue Radiance", + id: "blueradiance" + }, { + name: "Dark", + id: "dark", + isDefault: true, + isDefaultServerDashboard: true + }, { + name: "Dark (green accent)", + id: "dark-green" + }, { + name: "Dark (red accent)", + id: "dark-red" + }, { + name: "Light", + id: "light" + }, { + name: "Light (blue accent)", + id: "light-blue" + }, { + name: "Light (green accent)", + id: "light-green" + }, { + name: "Light (pink accent)", + id: "light-pink" + }, { + name: "Light (purple accent)", + id: "light-purple" + }, { + name: "Light (red accent)", + id: "light-red" + }, { + name: "Windows Media Center", + id: "wmc" + }]; + }; + + var skinManager = { + getThemes: getThemes, + loadUserSkin: loadUserSkin + }; + + 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; + return { + stylesheetPath: require.toUrl('components/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; +}); diff --git a/src/bower_components/emby-webcomponents/slideshow/slideshow.js b/src/components/slideshow/slideshow.js similarity index 100% rename from src/bower_components/emby-webcomponents/slideshow/slideshow.js rename to src/components/slideshow/slideshow.js diff --git a/src/bower_components/emby-webcomponents/slideshow/style.css b/src/components/slideshow/style.css similarity index 100% rename from src/bower_components/emby-webcomponents/slideshow/style.css rename to src/components/slideshow/style.css diff --git a/src/bower_components/emby-webcomponents/sortmenu/sortmenu.js b/src/components/sortmenu/sortmenu.js similarity index 95% rename from src/bower_components/emby-webcomponents/sortmenu/sortmenu.js rename to src/components/sortmenu/sortmenu.js index 90dc1790d1..da2fcdaa7c 100644 --- a/src/bower_components/emby-webcomponents/sortmenu/sortmenu.js +++ b/src/components/sortmenu/sortmenu.js @@ -1,4 +1,4 @@ -define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'layoutManager', 'connectionManager', 'globalize', 'userSettings', 'emby-select', 'paper-icon-button-light', 'material-icons', 'css!./../formdialog', 'emby-button', 'emby-linkbutton', 'flexStyles'], function (require, dom, focusManager, dialogHelper, loading, layoutManager, connectionManager, globalize, userSettings) { +define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'layoutManager', 'connectionManager', 'globalize', 'userSettings', 'emby-select', 'paper-icon-button-light', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (require, dom, focusManager, dialogHelper, loading, layoutManager, connectionManager, globalize, userSettings) { 'use strict'; function onSubmit(e) { diff --git a/src/bower_components/emby-webcomponents/sortmenu/sortmenu.template.html b/src/components/sortmenu/sortmenu.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/sortmenu/sortmenu.template.html rename to src/components/sortmenu/sortmenu.template.html diff --git a/src/bower_components/emby-webcomponents/staticbackdrops.js b/src/components/staticbackdrops.js similarity index 100% rename from src/bower_components/emby-webcomponents/staticbackdrops.js rename to src/components/staticbackdrops.js diff --git a/src/bower_components/emby-webcomponents/subtitleeditor/subtitleeditor.css b/src/components/subtitleeditor/subtitleeditor.css similarity index 100% rename from src/bower_components/emby-webcomponents/subtitleeditor/subtitleeditor.css rename to src/components/subtitleeditor/subtitleeditor.css diff --git a/src/bower_components/emby-webcomponents/subtitleeditor/subtitleeditor.js b/src/components/subtitleeditor/subtitleeditor.js similarity index 100% rename from src/bower_components/emby-webcomponents/subtitleeditor/subtitleeditor.js rename to src/components/subtitleeditor/subtitleeditor.js diff --git a/src/bower_components/emby-webcomponents/subtitleeditor/subtitleeditor.template.html b/src/components/subtitleeditor/subtitleeditor.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/subtitleeditor/subtitleeditor.template.html rename to src/components/subtitleeditor/subtitleeditor.template.html diff --git a/src/bower_components/emby-webcomponents/subtitlesettings/subtitleappearancehelper.js b/src/components/subtitlesettings/subtitleappearancehelper.js similarity index 100% rename from src/bower_components/emby-webcomponents/subtitlesettings/subtitleappearancehelper.js rename to src/components/subtitlesettings/subtitleappearancehelper.js diff --git a/src/bower_components/emby-webcomponents/subtitlesettings/subtitlesettings.js b/src/components/subtitlesettings/subtitlesettings.js similarity index 100% rename from src/bower_components/emby-webcomponents/subtitlesettings/subtitlesettings.js rename to src/components/subtitlesettings/subtitlesettings.js diff --git a/src/bower_components/emby-webcomponents/subtitlesettings/subtitlesettings.template.html b/src/components/subtitlesettings/subtitlesettings.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/subtitlesettings/subtitlesettings.template.html rename to src/components/subtitlesettings/subtitlesettings.template.html diff --git a/src/bower_components/emby-webcomponents/tabbedview/itemstab.js b/src/components/tabbedview/itemstab.js similarity index 100% rename from src/bower_components/emby-webcomponents/tabbedview/itemstab.js rename to src/components/tabbedview/itemstab.js diff --git a/src/bower_components/emby-webcomponents/tabbedview/tabbedview.js b/src/components/tabbedview/tabbedview.js similarity index 100% rename from src/bower_components/emby-webcomponents/tabbedview/tabbedview.js rename to src/components/tabbedview/tabbedview.js diff --git a/src/bower_components/emby-webcomponents/thememediaplayer.js b/src/components/thememediaplayer.js similarity index 100% rename from src/bower_components/emby-webcomponents/thememediaplayer.js rename to src/components/thememediaplayer.js diff --git a/src/bower_components/emby-webcomponents/themes/appletv/theme.css b/src/components/themes/appletv/theme.css similarity index 100% rename from src/bower_components/emby-webcomponents/themes/appletv/theme.css rename to src/components/themes/appletv/theme.css diff --git a/src/bower_components/emby-webcomponents/themes/blueradiance/bg.jpg b/src/components/themes/blueradiance/bg.jpg similarity index 100% rename from src/bower_components/emby-webcomponents/themes/blueradiance/bg.jpg rename to src/components/themes/blueradiance/bg.jpg diff --git a/src/bower_components/emby-webcomponents/themes/blueradiance/theme.css b/src/components/themes/blueradiance/theme.css similarity index 100% rename from src/bower_components/emby-webcomponents/themes/blueradiance/theme.css rename to src/components/themes/blueradiance/theme.css diff --git a/src/bower_components/emby-webcomponents/themes/dark-classic/theme.css b/src/components/themes/dark-classic/theme.css similarity index 100% rename from src/bower_components/emby-webcomponents/themes/dark-classic/theme.css rename to src/components/themes/dark-classic/theme.css diff --git a/src/bower_components/emby-webcomponents/themes/dark-green/theme.css b/src/components/themes/dark-green/theme.css similarity index 100% rename from src/bower_components/emby-webcomponents/themes/dark-green/theme.css rename to src/components/themes/dark-green/theme.css diff --git a/src/bower_components/emby-webcomponents/themes/dark-red/theme.css b/src/components/themes/dark-red/theme.css similarity index 100% rename from src/bower_components/emby-webcomponents/themes/dark-red/theme.css rename to src/components/themes/dark-red/theme.css diff --git a/src/bower_components/emby-webcomponents/themes/dark/theme.css b/src/components/themes/dark/theme.css similarity index 100% rename from src/bower_components/emby-webcomponents/themes/dark/theme.css rename to src/components/themes/dark/theme.css diff --git a/src/bower_components/emby-webcomponents/themes/light-blue/theme.css b/src/components/themes/light-blue/theme.css similarity index 100% rename from src/bower_components/emby-webcomponents/themes/light-blue/theme.css rename to src/components/themes/light-blue/theme.css diff --git a/src/bower_components/emby-webcomponents/themes/light-classic/theme.css b/src/components/themes/light-classic/theme.css similarity index 100% rename from src/bower_components/emby-webcomponents/themes/light-classic/theme.css rename to src/components/themes/light-classic/theme.css diff --git a/src/bower_components/emby-webcomponents/themes/light-green/theme.css b/src/components/themes/light-green/theme.css similarity index 100% rename from src/bower_components/emby-webcomponents/themes/light-green/theme.css rename to src/components/themes/light-green/theme.css diff --git a/src/bower_components/emby-webcomponents/themes/light-pink/theme.css b/src/components/themes/light-pink/theme.css similarity index 100% rename from src/bower_components/emby-webcomponents/themes/light-pink/theme.css rename to src/components/themes/light-pink/theme.css diff --git a/src/bower_components/emby-webcomponents/themes/light-purple/theme.css b/src/components/themes/light-purple/theme.css similarity index 100% rename from src/bower_components/emby-webcomponents/themes/light-purple/theme.css rename to src/components/themes/light-purple/theme.css diff --git a/src/bower_components/emby-webcomponents/themes/light-red/theme.css b/src/components/themes/light-red/theme.css similarity index 100% rename from src/bower_components/emby-webcomponents/themes/light-red/theme.css rename to src/components/themes/light-red/theme.css diff --git a/src/bower_components/emby-webcomponents/themes/light/theme.css b/src/components/themes/light/theme.css similarity index 100% rename from src/bower_components/emby-webcomponents/themes/light/theme.css rename to src/components/themes/light/theme.css diff --git a/src/components/themes/logodark.png b/src/components/themes/logodark.png new file mode 100644 index 0000000000..81a83818f8 Binary files /dev/null and b/src/components/themes/logodark.png differ diff --git a/src/components/themes/logowhite.png b/src/components/themes/logowhite.png new file mode 100644 index 0000000000..560d910d74 Binary files /dev/null and b/src/components/themes/logowhite.png differ diff --git a/src/bower_components/emby-webcomponents/themes/wmc/theme.css b/src/components/themes/wmc/theme.css similarity index 100% rename from src/bower_components/emby-webcomponents/themes/wmc/theme.css rename to src/components/themes/wmc/theme.css diff --git a/src/components/toast/package.json b/src/components/toast/package.json new file mode 100644 index 0000000000..2e64841a7f --- /dev/null +++ b/src/components/toast/package.json @@ -0,0 +1,3 @@ +{ + "main": "toast.js" +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/toast/toast.css b/src/components/toast/toast.css similarity index 100% rename from src/bower_components/emby-webcomponents/toast/toast.css rename to src/components/toast/toast.css diff --git a/src/bower_components/emby-webcomponents/toast/toast.js b/src/components/toast/toast.js similarity index 100% rename from src/bower_components/emby-webcomponents/toast/toast.js rename to src/components/toast/toast.js diff --git a/src/bower_components/emby-webcomponents/touchhelper.js b/src/components/touchhelper.js similarity index 100% rename from src/bower_components/emby-webcomponents/touchhelper.js rename to src/components/touchhelper.js diff --git a/src/components/tvproviders/schedulesdirect.js b/src/components/tvproviders/schedulesdirect.js index 0eb54a472d..9af7e5be72 100644 --- a/src/components/tvproviders/schedulesdirect.js +++ b/src/components/tvproviders/schedulesdirect.js @@ -1,4 +1,4 @@ -define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "emby-select", "emby-linkbutton", "flexStyles"], function($, loading) { +define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "emby-select", "emby-button", "flexStyles"], function($, loading) { "use strict"; return function(page, providerId, options) { function reload() { diff --git a/src/bower_components/emby-webcomponents/upnextdialog/upnextdialog.css b/src/components/upnextdialog/upnextdialog.css similarity index 100% rename from src/bower_components/emby-webcomponents/upnextdialog/upnextdialog.css rename to src/components/upnextdialog/upnextdialog.css diff --git a/src/bower_components/emby-webcomponents/upnextdialog/upnextdialog.js b/src/components/upnextdialog/upnextdialog.js similarity index 100% rename from src/bower_components/emby-webcomponents/upnextdialog/upnextdialog.js rename to src/components/upnextdialog/upnextdialog.js diff --git a/src/bower_components/emby-webcomponents/userdatabuttons/emby-playstatebutton.js b/src/components/userdatabuttons/emby-playstatebutton.js similarity index 100% rename from src/bower_components/emby-webcomponents/userdatabuttons/emby-playstatebutton.js rename to src/components/userdatabuttons/emby-playstatebutton.js diff --git a/src/bower_components/emby-webcomponents/userdatabuttons/emby-ratingbutton.js b/src/components/userdatabuttons/emby-ratingbutton.js similarity index 100% rename from src/bower_components/emby-webcomponents/userdatabuttons/emby-ratingbutton.js rename to src/components/userdatabuttons/emby-ratingbutton.js diff --git a/src/bower_components/emby-webcomponents/userdatabuttons/userdatabuttons.css b/src/components/userdatabuttons/userdatabuttons.css similarity index 100% rename from src/bower_components/emby-webcomponents/userdatabuttons/userdatabuttons.css rename to src/components/userdatabuttons/userdatabuttons.css diff --git a/src/bower_components/emby-webcomponents/userdatabuttons/userdatabuttons.js b/src/components/userdatabuttons/userdatabuttons.js similarity index 100% rename from src/bower_components/emby-webcomponents/userdatabuttons/userdatabuttons.js rename to src/components/userdatabuttons/userdatabuttons.js diff --git a/src/bower_components/emby-webcomponents/usersettings/usersettings.js b/src/components/usersettings/usersettings.js similarity index 100% rename from src/bower_components/emby-webcomponents/usersettings/usersettings.js rename to src/components/usersettings/usersettings.js diff --git a/src/bower_components/emby-webcomponents/usersettings/usersettingsbuilder.js b/src/components/usersettings/usersettingsbuilder.js similarity index 100% rename from src/bower_components/emby-webcomponents/usersettings/usersettingsbuilder.js rename to src/components/usersettings/usersettingsbuilder.js diff --git a/src/components/viewcontainer-lite.js b/src/components/viewContainer.js similarity index 97% rename from src/components/viewcontainer-lite.js rename to src/components/viewContainer.js index d1729f1fab..4c02ba3c6e 100644 --- a/src/components/viewcontainer-lite.js +++ b/src/components/viewContainer.js @@ -1,4 +1,4 @@ -define(["browser", "dom", "layoutManager", "css!bower_components/emby-webcomponents/viewmanager/viewcontainer-lite"], function(browser, dom, layoutManager) { +define(["browser", "dom", "layoutManager", "css!components/viewManager/viewContainer"], function(browser, dom, layoutManager) { "use strict"; function setControllerClass(view, options) { diff --git a/src/components/viewManager/package.json b/src/components/viewManager/package.json new file mode 100644 index 0000000000..819371af71 --- /dev/null +++ b/src/components/viewManager/package.json @@ -0,0 +1,3 @@ +{ + "main": "viewManager.js" +} \ No newline at end of file diff --git a/src/bower_components/emby-webcomponents/viewmanager/viewcontainer-lite.css b/src/components/viewManager/viewContainer.css similarity index 100% rename from src/bower_components/emby-webcomponents/viewmanager/viewcontainer-lite.css rename to src/components/viewManager/viewContainer.css diff --git a/src/bower_components/emby-webcomponents/viewmanager/viewmanager.js b/src/components/viewManager/viewManager.js similarity index 100% rename from src/bower_components/emby-webcomponents/viewmanager/viewmanager.js rename to src/components/viewManager/viewManager.js diff --git a/src/bower_components/emby-webcomponents/viewsettings/viewsettings.js b/src/components/viewsettings/viewsettings.js similarity index 96% rename from src/bower_components/emby-webcomponents/viewsettings/viewsettings.js rename to src/components/viewsettings/viewsettings.js index af2167fa6f..617e021115 100644 --- a/src/bower_components/emby-webcomponents/viewsettings/viewsettings.js +++ b/src/components/viewsettings/viewsettings.js @@ -1,4 +1,4 @@ -define(['require', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'userSettings', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'emby-linkbutton', 'flexStyles'], function (require, dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize, userSettings) { +define(['require', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'userSettings', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (require, dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize, userSettings) { 'use strict'; function onSubmit(e) { diff --git a/src/bower_components/emby-webcomponents/viewsettings/viewsettings.template.html b/src/components/viewsettings/viewsettings.template.html similarity index 100% rename from src/bower_components/emby-webcomponents/viewsettings/viewsettings.template.html rename to src/components/viewsettings/viewsettings.template.html diff --git a/src/bower_components/emby-webcomponents/visibleinviewport.js b/src/components/visibleinviewport.js similarity index 100% rename from src/bower_components/emby-webcomponents/visibleinviewport.js rename to src/components/visibleinviewport.js diff --git a/src/bower_components/emby-webcomponents/youtubeplayer/plugin.js b/src/components/youtubeplayer/plugin.js similarity index 100% rename from src/bower_components/emby-webcomponents/youtubeplayer/plugin.js rename to src/components/youtubeplayer/plugin.js diff --git a/src/bower_components/emby-webcomponents/youtubeplayer/style.css b/src/components/youtubeplayer/style.css similarity index 100% rename from src/bower_components/emby-webcomponents/youtubeplayer/style.css rename to src/components/youtubeplayer/style.css diff --git a/src/controllers/addpluginpage.js b/src/controllers/addpluginpage.js new file mode 100644 index 0000000000..0ecb65ab75 --- /dev/null +++ b/src/controllers/addpluginpage.js @@ -0,0 +1,155 @@ +define(["jQuery", "loading", "libraryMenu", "globalize", "connectionManager", "emby-button"], function($, loading, libraryMenu, globalize, connectionManager) { + "use strict"; + + function populateHistory(packageInfo, page) { + var html = ""; + var length = Math.min(packageInfo.versions.length, 10); + for (var i = 0; i < length; i++) { + var version = packageInfo.versions[i]; + html += '

' + version.versionStr + " (" + version.classification + ")

"; + html += '
' + version.description + "
"; + } + $("#revisionHistory", page).html(html); + } + + function populateVersions(packageInfo, page, installedPlugin) { + var html = ""; + for (var i = 0; i < packageInfo.versions.length; i++) { + var version = packageInfo.versions[i]; + html += '"; + } + var selectmenu = $("#selectVersion", page).html(html); + if (!installedPlugin) { + $("#pCurrentVersion", page).hide().html(""); + } + var packageVersion = packageInfo.versions.filter(function(current) { + return "Release" == current.classification; + })[0]; + packageVersion = packageVersion || packageInfo.versions.filter(function(current) { + return "Beta" == current.classification; + })[0]; + + if (packageVersion) { + var val = packageVersion.versionStr + "|" + packageVersion.classification; + selectmenu.val(val); + } + } + + function renderPackage(pkg, installedPlugins, page) { + var installedPlugin = installedPlugins.filter(function(ip) { + return ip.Name == pkg.name + })[0]; + populateVersions(pkg, page, installedPlugin); + populateHistory(pkg, page); + $(".pluginName", page).html(pkg.name); + if ("Server" == pkg.targetSystem) { + $("#btnInstallDiv", page).removeClass("hide"); + $("#nonServerMsg", page).hide(); + $("#pSelectVersion", page).removeClass("hide"); + } else { + $("#btnInstallDiv", page).addClass("hide"); + $("#pSelectVersion", page).addClass("hide"); + var msg = globalize.translate("MessageInstallPluginFromApp"); + $("#nonServerMsg", page).html(msg).show(); + } + if (pkg.shortDescription) { + $("#tagline", page).show().html(pkg.shortDescription); + } else { + $("#tagline", page).hide(); + } + $("#overview", page).html(pkg.overview || ""); + $("#developer", page).html(pkg.owner); + if (pkg.richDescUrl) { + $("#pViewWebsite", page).show(); + $("#pViewWebsite a", page).attr("href", pkg.richDescUrl); + } else { + $("#pViewWebsite", page).hide(); + } + if (pkg.previewImage || pkg.thumbImage) { + var img = pkg.previewImage ? pkg.previewImage : pkg.thumbImage; + $("#pPreviewImage", page).show().html(""); + } else { + $("#pPreviewImage", page).hide().html(""); + } + if (installedPlugin) { + var currentVersionText = globalize.translate("MessageYouHaveVersionInstalled").replace("{0}", "" + installedPlugin.Version + ""); + $("#pCurrentVersion", page).show().html(currentVersionText); + } else { + $("#pCurrentVersion", page).hide().html(""); + } + loading.hide(); + } + + function alertText(options) { + require(["alert"], function(alert) { + alert(options) + }) + } + + function performInstallation(page, packageName, guid, updateClass, version) { + var developer = $("#developer", page).html().toLowerCase(); + var alertCallback = function() { + loading.show(); + page.querySelector("#btnInstall").disabled = true; + ApiClient.installPlugin(packageName, guid, updateClass, version).then(function() { + loading.hide(); + alertText(globalize.translate("PluginInstalledMessage")); + }); + }; + if (developer !== 'jellyfin') { + loading.hide(); + var msg = globalize.translate("MessagePluginInstallDisclaimer"); + msg += "
"; + msg += "
"; + msg += globalize.translate("PleaseConfirmPluginInstallation"); + require(["confirm"], function(confirm) { + confirm(msg, globalize.translate("HeaderConfirmPluginInstallation")).then(function() { + alertCallback(); + }, function() { + console.log('plugin not installed'); + }); + }); + } else { + alertCallback(); + } + } + + return function(view, params) { + $(".addPluginForm", view).on("submit", function() { + loading.show(); + var page = $(this).parents("#addPluginPage")[0]; + var name = params.name; + var guid = params.guid; + ApiClient.getInstalledPlugins().then(function(plugins) { + var installedPlugin = plugins.filter(function(plugin) { + return plugin.Name == name; + })[0]; + var vals = $("#selectVersion", page).val().split("|"); + var version = vals[0]; + if (installedPlugin) { + if (installedPlugin.Version === version) { + loading.hide(); + Dashboard.alert({ + message: globalize.translate("MessageAlreadyInstalled"), + title: globalize.translate("HeaderPluginInstallation") + }); + } + } else { + performInstallation(page, name, guid, vals[1], version); + } + }); + return false; + }); + view.addEventListener("viewshow", function() { + var page = this; + loading.show(); + var name = params.name; + var guid = params.guid; + var promise1 = ApiClient.getPackageInfo(name, guid); + var promise2 = ApiClient.getInstalledPlugins(); + Promise.all([promise1, promise2]).then(function(responses) { + renderPackage(responses[0], responses[1], page); + }); + }) + } +}); diff --git a/src/scripts/addserver.js b/src/controllers/addserver.js similarity index 95% rename from src/scripts/addserver.js rename to src/controllers/addserver.js index 3afb9c68a8..45fa427420 100644 --- a/src/scripts/addserver.js +++ b/src/controllers/addserver.js @@ -1,4 +1,4 @@ -define(["appSettings", "loading", "browser", "emby-linkbutton"], function(appSettings, loading, browser) { +define(["appSettings", "loading", "browser", "emby-button"], function(appSettings, loading, browser) { "use strict"; function handleConnectionResult(page, result) { diff --git a/src/scripts/plugincatalogpage.js b/src/controllers/availableplugins.js similarity index 50% rename from src/scripts/plugincatalogpage.js rename to src/controllers/availableplugins.js index ed237a02d4..62131456da 100644 --- a/src/scripts/plugincatalogpage.js +++ b/src/controllers/availableplugins.js @@ -1,10 +1,9 @@ -define(["loading", "libraryMenu", "globalize", "cardStyle", "emby-linkbutton", "emby-checkbox", "emby-select"], function (loading, libraryMenu, globalize) { +define(["loading", "libraryMenu", "globalize", "cardStyle", "emby-button", "emby-checkbox", "emby-select"], function (loading, libraryMenu, globalize) { "use strict"; function reloadList(page) { loading.show(); - query.IsAppStoreSafe = true; - var promise1 = ApiClient.getAvailablePlugins(query); + var promise1 = ApiClient.getAvailablePlugins(); var promise2 = ApiClient.getInstalledPlugins(); Promise.all([promise1, promise2]).then(function (responses) { populateList({ @@ -16,13 +15,8 @@ define(["loading", "libraryMenu", "globalize", "cardStyle", "emby-linkbutton", " }); } - function populateList(options) { - populateListInternal(options); - } - function getHeaderText(category) { category = category.replace(" ", ""); - if ("Channel" === category) { category = "Channels"; } else if ("Theme" === category) { @@ -36,128 +30,54 @@ define(["loading", "libraryMenu", "globalize", "cardStyle", "emby-linkbutton", " return globalize.translate(category); } - function isUserInstalledPlugin(plugin) { - return -1 === ["02528C96-F727-44D7-BE87-9EEF040758C3", "0277E613-3EC0-4360-A3DE-F8AF0AABB5E9", "4DCB591C-0FA2-4C5D-A7E5-DABE37164C8B"].indexOf(plugin.guid); - } - - function populateListInternal(options) { + function populateList(options) { var availablePlugins = options.availablePlugins; var installedPlugins = options.installedPlugins; - var allPlugins = availablePlugins.filter(function (plugin) { - plugin.category = plugin.category || "General"; + + var categories = []; + availablePlugins.forEach(function (plugin, index, array) { + plugin.category = plugin.category || 'General'; plugin.categoryDisplayName = getHeaderText(plugin.category); - - if (!options.categories || -1 != options.categories.indexOf(plugin.category)) { - if (!options.targetSystem || plugin.targetSystem == options.targetSystem) { - return "UserInstalled" == plugin.type; - } - - return false; - } - - return false; + array[index] = plugin; }); - availablePlugins = allPlugins.sort(function (a__e, b__r) { - var aName = a__e.category; - var bName = b__r.category; - if (aName > bName) { + availablePlugins.sort(function (a, b) { + if (a.category > b.category) { return 1; - } - - if (bName > aName) { + } else if (b.category > a.category) { return -1; } - - aName = a__e.name; - bName = b__r.name; - - if (aName > bName) { + if (a.name > b.name) { return 1; - } - - if (bName > aName) { + } else if (b.name > a.name) { return -1; } - return 0; }); - var i__q; - var length; - var plugin; - var currentCategory; + + var currentCategory = null; var html = ""; - if (!options.categories) { - currentCategory = globalize.translate("HeaderTopPlugins"); - html += '
'; - html += '

' + currentCategory + "

"; - var topPlugins = allPlugins.slice(0).sort(function (a__t, b__y) { - if (a__t.installs > b__y.installs) { - return -1; - } - - if (b__y.installs > a__t.installs) { - return 1; - } - - var aName = a__t.name; - var bName = b__y.name; - - if (aName > bName) { - return 1; - } - - if (bName > aName) { - return -1; - } - - return 0; - }).filter(isUserInstalledPlugin); - html += '
'; - var limit = screen.availWidth >= 1920 ? 15 : 12; - - for (i__q = 0, length = Math.min(topPlugins.length, limit); i__q < length; i__q++) { - html += getPluginHtml(topPlugins[i__q], options, installedPlugins); - } - - html += "
"; - html += "
"; - } - - var hasOpenTag = false; - - for (currentCategory = null, false === options.showCategory && (html += '
', hasOpenTag = true), i__q = 0, length = availablePlugins.length; i__q < length; i__q++) { - plugin = availablePlugins[i__q]; + for (var i = 0; i < availablePlugins.length; i++) { + var plugin = availablePlugins[i]; var category = plugin.categoryDisplayName; - if (category != currentCategory) { - if (false !== options.showCategory) { - if (currentCategory) { - hasOpenTag = false; - html += "
"; - html += "
"; - } - - html += '
'; - html += '

' + category + "

"; - html += '
'; - hasOpenTag = true; + if (currentCategory) { + html += "
"; + html += "
"; } - + html += '
'; + html += '

' + category + "

"; + html += '
'; currentCategory = category; } - html += getPluginHtml(plugin, options, installedPlugins); } - - if (hasOpenTag) { - html += "
"; - html += "
"; - } + html += "
"; + html += "
"; if (!availablePlugins.length && options.noItemsElement) { - options.noItemsElement.classList.add("hide"); + options.noItemsElement.classList.remove("hide"); } options.catalogElement.innerHTML = html; @@ -205,26 +125,19 @@ define(["loading", "libraryMenu", "globalize", "cardStyle", "emby-linkbutton", " function getTabs() { return [{ - href: "plugins.html", + href: "installedplugins.html", name: globalize.translate("TabMyPlugins") }, { - href: "plugincatalog.html", + href: "availableplugins.html", name: globalize.translate("TabCatalog") }]; } - var query = { - TargetSystems: "Server", - IsAdult: false - }; window.PluginCatalog = { renderCatalog: populateList }; + return function (view, params) { - view.querySelector("#selectSystem").addEventListener("change", function () { - query.TargetSystems = this.value; - reloadList(view); - }); view.addEventListener("viewshow", function () { libraryMenu.setTabs("plugins", 1, getTabs); reloadList(this); diff --git a/src/controllers/dashboardgeneral.js b/src/controllers/dashboardgeneral.js new file mode 100644 index 0000000000..09aa1ec08e --- /dev/null +++ b/src/controllers/dashboardgeneral.js @@ -0,0 +1,129 @@ +define(["jQuery", "loading", "fnchecked", "emby-checkbox", "emby-textarea", "emby-input", "emby-select", "emby-button"], function($, loading) { + "use strict"; + + function loadPage(page, config, languageOptions, systemInfo) { + page.querySelector("#txtServerName").value = systemInfo.ServerName; + if (systemInfo.CanLaunchWebBrowser) { + page.querySelector("#fldRunWebAppAtStartup").classList.remove("hide"); + } else { + page.querySelector("#fldRunWebAppAtStartup").classList.add("hide"); + } + page.querySelector("#txtCachePath").value = systemInfo.CachePath || ""; + $("#txtMetadataPath", page).val(systemInfo.InternalMetadataPath || ""); + $("#txtMetadataNetworkPath", page).val(systemInfo.MetadataNetworkPath || ""); + $("#selectLocalizationLanguage", page).html(languageOptions.map(function(language) { + return '" + })).val(config.UICulture); + currentLanguage = config.UICulture; + if (systemInfo.CanSelfUpdate) { + page.querySelector(".fldAutomaticUpdates").classList.remove("hide"); + } else { + page.querySelector(".fldAutomaticUpdates").classList.add("hide"); + } + $("#chkEnableAutomaticServerUpdates", page).checked(config.EnableAutoUpdate); + $("#chkEnableAutomaticRestart", page).checked(config.EnableAutomaticRestart); + if (systemInfo.CanSelfRestart) { + page.querySelector("#fldEnableAutomaticRestart").classList.remove("hide"); + } else { + page.querySelector("#fldEnableAutomaticRestart").classList.add("hide"); + } + if (systemInfo.CanSelfRestart || systemInfo.CanSelfUpdate) { + $(".autoUpdatesContainer", page).removeClass("hide"); + } else { + $(".autoUpdatesContainer", page).addClass("hide"); + } + loading.hide(); + } + + function onSubmit() { + loading.show(); + var form = this; + $(form).parents(".page"); + return ApiClient.getServerConfiguration().then(function(config) { + config.ServerName = $("#txtServerName", form).val(); + config.UICulture = $("#selectLocalizationLanguage", form).val(); + config.CachePath = form.querySelector("#txtCachePath").value; + config.MetadataPath = $("#txtMetadataPath", form).val(); + config.MetadataNetworkPath = $("#txtMetadataNetworkPath", form).val(); + var requiresReload = (config.UICulture !== currentLanguage); + config.EnableAutomaticRestart = $("#chkEnableAutomaticRestart", form).checked(); + config.EnableAutoUpdate = $("#chkEnableAutomaticServerUpdates", form).checked(); + ApiClient.updateServerConfiguration(config).then(function() { + ApiClient.getNamedConfiguration(brandingConfigKey).then(function(brandingConfig) { + brandingConfig.LoginDisclaimer = form.querySelector("#txtLoginDisclaimer").value; + brandingConfig.CustomCss = form.querySelector("#txtCustomCss").value; + if (currentBrandingOptions && brandingConfig.CustomCss !== currentBrandingOptions.CustomCss) { + requiresReload = true; + } + ApiClient.updateNamedConfiguration(brandingConfigKey, brandingConfig).then(function() { + Dashboard.processServerConfigurationUpdateResult(); + if (requiresReload && !AppInfo.isNativeApp) { + window.location.reload(true); + } + }); + }) + }) + }), !1 + } + + var currentBrandingOptions; + var currentLanguage; + var brandingConfigKey = "branding"; + + return function(view, params) { + $("#btnSelectCachePath", view).on("click.selectDirectory", function() { + require(["directorybrowser"], function(directoryBrowser) { + var picker = new directoryBrowser; + picker.show({ + callback: function(path) { + if (path) { + view.querySelector("#txtCachePath").value = path; + } + picker.close(); + }, + validateWriteable: true, + header: Globalize.translate("HeaderSelectServerCachePath"), + instruction: Globalize.translate("HeaderSelectServerCachePathHelp") + }) + }) + }); + + $("#btnSelectMetadataPath", view).on("click.selectDirectory", function() { + require(["directorybrowser"], function(directoryBrowser) { + var picker = new directoryBrowser(); + picker.show({ + path: $("#txtMetadataPath", view).val(), + networkSharePath: $("#txtMetadataNetworkPath", view).val(), + callback: function(path, networkPath) { + if (path) { + $("#txtMetadataPath", view).val(path); + } + if (networkPath) { + $("#txtMetadataNetworkPath", view).val(networkPath); + } + picker.close(); + }, + validateWriteable: true, + header: Globalize.translate("HeaderSelectMetadataPath"), + instruction: Globalize.translate("HeaderSelectMetadataPathHelp"), + enableNetworkSharePath: true + }) + }) + }); + + $(".dashboardGeneralForm", view).off("submit", onSubmit).on("submit", onSubmit); + view.addEventListener("viewshow", function() { + var promiseConfig = ApiClient.getServerConfiguration(); + var promiseLanguageOptions = ApiClient.getJSON(ApiClient.getUrl("Localization/Options")); + var promiseSystemInfo = ApiClient.getSystemInfo(); + Promise.all([promiseConfig, promiseLanguageOptions, promiseSystemInfo]).then(function(responses) { + loadPage(view, responses[0], responses[1], responses[2]); + }); + ApiClient.getNamedConfiguration(brandingConfigKey).then(function(config) { + currentBrandingOptions = config; + view.querySelector("#txtLoginDisclaimer").value = config.LoginDisclaimer || ""; + view.querySelector("#txtCustomCss").value = config.CustomCss || ""; + }); + }); + } +}); diff --git a/src/dashboard/dashboardhosting.js b/src/controllers/dashboardhosting.js similarity index 100% rename from src/dashboard/dashboardhosting.js rename to src/controllers/dashboardhosting.js diff --git a/src/scripts/dashboardpage.js b/src/controllers/dashboardpage.js similarity index 95% rename from src/scripts/dashboardpage.js rename to src/controllers/dashboardpage.js index f7bbc86866..79e5f8cf91 100644 --- a/src/scripts/dashboardpage.js +++ b/src/controllers/dashboardpage.js @@ -1,11 +1,6 @@ -define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globalize", "loading", "connectionManager", "playMethodHelper", "cardBuilder", "imageLoader", "components/activitylog", "humanedate", "listViewStyle", "emby-linkbutton", "flexStyles", "emby-button", "emby-itemscontainer"], function (datetime, events, itemHelper, serverNotifications, dom, globalize, loading, connectionManager, playMethodHelper, cardBuilder, imageLoader, ActivityLog) { +define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globalize", "loading", "connectionManager", "playMethodHelper", "cardBuilder", "imageLoader", "components/activitylog", "humanedate", "listViewStyle", "emby-button", "flexStyles", "emby-button", "emby-itemscontainer"], function (datetime, events, itemHelper, serverNotifications, dom, globalize, loading, connectionManager, playMethodHelper, cardBuilder, imageLoader, ActivityLog) { "use strict"; - function onConnectionHelpClick(evt) { - evt.preventDefault(); - return false; - } - function buttonEnabled(elem, enabled) { if (enabled) { elem.setAttribute("disabled", ""); @@ -15,31 +10,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } } - function onEditServerNameClick(evt) { - var page = dom.parentWithClass(this, "page"); - - require(["prompt"], function (prompt) { - prompt({ - label: globalize.translate("LabelFriendlyServerName"), - description: globalize.translate("LabelFriendlyServerNameHelp"), - value: page.querySelector(".serverNameHeader").innerHTML, - confirmText: globalize.translate("ButtonSave") - }).then(function (value) { - loading.show(); - ApiClient.getServerConfiguration().then(function (config) { - config.ServerName = value; - ApiClient.updateServerConfiguration(config).then(function () { - page.querySelector(".serverNameHeader").innerHTML = value; - loading.hide(); - }); - }); - }); - }); - - evt.preventDefault(); - return false; - } - function showPlaybackInfo(btn, session) { require(["alert"], function (alert) { var showTranscodeReasons; @@ -207,20 +177,13 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa function reloadSystemInfo(view, apiClient) { apiClient.getSystemInfo().then(function (systemInfo) { - view.querySelector(".serverNameHeader").innerHTML = systemInfo.ServerName; - var localizedVersion = globalize.translate("LabelVersionNumber", systemInfo.Version); + view.querySelector("#serverName").innerHTML = globalize.translate("DashboardServerName", systemInfo.ServerName); + var localizedVersion = globalize.translate("DashboardVersionNumber", systemInfo.Version); if (systemInfo.SystemUpdateLevel && "Release" != systemInfo.SystemUpdateLevel) { localizedVersion += " " + globalize.translate("Option" + systemInfo.SystemUpdateLevel).toLowerCase(); } - - if (systemInfo.CanSelfRestart) { - view.querySelector("#btnRestartServer").classList.remove("hide"); - } else { - view.querySelector("#btnRestartServer").classList.add("hide"); - } - - view.querySelector("#appVersionNumber").innerHTML = localizedVersion; + view.querySelector("#versionNumber").innerHTML = localizedVersion; if (systemInfo.SupportsHttps) { view.querySelector("#ports").innerHTML = globalize.translate("LabelRunningOnPorts", systemInfo.HttpServerPortNumber, systemInfo.HttpsPortNumber); @@ -230,6 +193,12 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa DashboardPage.renderUrls(view, systemInfo); DashboardPage.renderPaths(view, systemInfo); + + if (systemInfo.CanSelfRestart) { + view.querySelector("#btnRestartServer").classList.remove("hide"); + } else { + view.querySelector("#btnRestartServer").classList.add("hide"); + } }); } @@ -383,7 +352,7 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa for (var i = 0, length = tasks.length; i < length; i++) { var task = tasks[i]; - + html += "

"; html += task.Name + "
"; if (task.State === "Running") { @@ -407,8 +376,9 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa renderPaths: function (page, systemInfo) { page.querySelector("#cachePath").innerHTML = systemInfo.CachePath; page.querySelector("#logPath").innerHTML = systemInfo.LogPath; - page.querySelector("#transcodingTemporaryPath").innerHTML = systemInfo.TranscodingTempPath; + page.querySelector("#transcodePath").innerHTML = systemInfo.TranscodingTempPath; page.querySelector("#metadataPath").innerHTML = systemInfo.InternalMetadataPath; + page.querySelector("#webPath").innerHTML = systemInfo.WebPath; }, startInterval: function (apiClient) { apiClient.sendMessage("SessionsStart", "0,1500"); @@ -780,7 +750,7 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa var page = dom.parentWithClass(btn, "page"); buttonEnabled(page.querySelector("#btnRestartServer"), false); buttonEnabled(page.querySelector("#btnShutdown"), false); - Dashboard.restartServer(); + ApiClient.restartServer(); }); }); }, @@ -846,8 +816,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } var serverId = ApiClient.serverId(); - view.querySelector(".btnConnectionHelp").addEventListener("click", onConnectionHelpClick); - view.querySelector(".btnEditServerName").addEventListener("click", onEditServerNameClick); view.querySelector(".activeDevices").addEventListener("click", onActiveDevicesClick); view.addEventListener("viewshow", function () { var page = this; diff --git a/src/devices/device.js b/src/controllers/device.js similarity index 100% rename from src/devices/device.js rename to src/controllers/device.js diff --git a/src/devices/devices.js b/src/controllers/devices.js similarity index 97% rename from src/devices/devices.js rename to src/controllers/devices.js index e5e5d16dc7..e4c2f6b44b 100644 --- a/src/devices/devices.js +++ b/src/controllers/devices.js @@ -1,4 +1,4 @@ -define(["loading", "dom", "libraryMenu", "globalize", "humanedate", "emby-linkbutton", "emby-itemscontainer", "cardStyle"], function(loading, dom, libraryMenu, globalize) { +define(["loading", "dom", "libraryMenu", "globalize", "humanedate", "emby-button", "emby-itemscontainer", "cardStyle"], function(loading, dom, libraryMenu, globalize) { "use strict"; function canDelete(deviceId) { diff --git a/src/scripts/edititemmetadata.js b/src/controllers/edititemmetadata.js similarity index 100% rename from src/scripts/edititemmetadata.js rename to src/controllers/edititemmetadata.js diff --git a/src/home/favorites.js b/src/controllers/favorites.js similarity index 100% rename from src/home/favorites.js rename to src/controllers/favorites.js diff --git a/src/scripts/forgotpassword.js b/src/controllers/forgotpassword.js similarity index 85% rename from src/scripts/forgotpassword.js rename to src/controllers/forgotpassword.js index fc944a410a..bb9489a11a 100644 --- a/src/scripts/forgotpassword.js +++ b/src/controllers/forgotpassword.js @@ -12,7 +12,7 @@ define([], function() { }); if ("PinCode" == result.Action) { var msg = Globalize.translate("MessageForgotPasswordFileCreated"); - return msg += "
", msg += "
", msg += result.PinFile, msg += "
", void Dashboard.alert({ + return msg += "
", msg += "
", msg += "
Enter PIN here to finish Password Reset" ,msg += "
",msg += result.PinFile, msg += "
", void Dashboard.alert({ message: msg, title: Globalize.translate("HeaderForgotPassword") }) diff --git a/src/scripts/forgotpasswordpin.js b/src/controllers/forgotpasswordpin.js similarity index 100% rename from src/scripts/forgotpasswordpin.js rename to src/controllers/forgotpasswordpin.js diff --git a/src/home/home.js b/src/controllers/home.js similarity index 94% rename from src/home/home.js rename to src/controllers/home.js index 57b2e38bf8..0ab31f291d 100644 --- a/src/home/home.js +++ b/src/controllers/home.js @@ -24,10 +24,10 @@ define(["tabbedView", "globalize", "require", "emby-tabs", "emby-button", "emby- var depends = []; switch (index) { case 0: - depends.push("./hometab"); + depends.push("controllers/hometab"); break; case 1: - depends.push("./favorites") + depends.push("controllers/favorites") } var instance = this; return getRequirePromise(depends).then(function(controllerFactory) { diff --git a/src/home/hometab.js b/src/controllers/hometab.js similarity index 100% rename from src/home/hometab.js rename to src/controllers/hometab.js diff --git a/src/controllers/installedplugins.js b/src/controllers/installedplugins.js new file mode 100644 index 0000000000..40de0cc191 --- /dev/null +++ b/src/controllers/installedplugins.js @@ -0,0 +1,171 @@ +define(["loading", "libraryMenu", "dom", "globalize", "cardStyle", "emby-button"], function(loading, libraryMenu, dom, globalize) { + "use strict"; + + function deletePlugin(page, uniqueid, name) { + var msg = globalize.translate("UninstallPluginConfirmation").replace("{0}", name); + require(["confirm"], function(confirm) { + confirm({ + title: globalize.translate("UninstallPluginHeader"), + text: msg, + primary: "cancel", + confirmText: globalize.translate("UninstallPluginHeader") + }).then(function() { + loading.show(); + ApiClient.uninstallPlugin(uniqueid).then(function() { + reloadList(page); + }); + }) + }) + } + + function showNoConfigurationMessage() { + Dashboard.alert({ + message: globalize.translate("NoPluginConfigurationMessage") + }); + } + + function showConnectMessage() { + Dashboard.alert({ + message: globalize.translate("MessagePluginConfigurationRequiresLocalAccess") + }); + } + + function getPluginCardHtml(plugin, pluginConfigurationPages) { + var configPage = pluginConfigurationPages.filter(function(pluginConfigurationPage) { + return pluginConfigurationPage.PluginId == plugin.Id; + })[0]; + var configPageUrl = configPage ? Dashboard.getConfigurationPageUrl(configPage.Name) : null; + + var html = ""; + html += "

"; + html += '
'; + html += '"; + html += '
'; + html += '
'; + html += ''; + html += "
"; + html += "
"; + html += configPage ? configPage.DisplayName || plugin.Name : plugin.Name; + html += "
"; + html += "
"; + html += plugin.Version; + html += "
"; + html += "
"; + html += "
"; + html += "
"; + return html; + } + + function renderPlugins(page, plugins) { + ApiClient.getJSON(ApiClient.getUrl("web/configurationpages") + "?pageType=PluginConfiguration").then(function(configPages) { + populateList(page, plugins, configPages); + }); + } + + function populateList(page, plugins, pluginConfigurationPages) { + plugins = plugins.sort(function(plugin1, plugin2) { + return plugin1.Name > plugin2.Name ? 1 : -1 + }); + var html = plugins.map(function(p) { + return getPluginCardHtml(p, pluginConfigurationPages) + }).join(""); + var installedPluginsElement = page.querySelector(".installedPlugins"); + installedPluginsElement.removeEventListener("click", onInstalledPluginsClick); + installedPluginsElement.addEventListener("click", onInstalledPluginsClick); + if (plugins.length) { + installedPluginsElement.classList.add("itemsContainer"); + installedPluginsElement.classList.add("vertical-wrap"); + } else { + html += '
'; + html += "

" + globalize.translate("MessageNoPluginsInstalled") + "

"; + html += '

'; + html += globalize.translate("BrowsePluginCatalogMessage"); + html += "

"; + html += "
"; + } + installedPluginsElement.innerHTML = html; + loading.hide(); + } + + function showPluginMenu(page, elem) { + var card = dom.parentWithClass(elem, "card"); + var id = card.getAttribute("data-id"); + var name = card.getAttribute("data-name"); + var configHref = card.querySelector(".cardContent").getAttribute("href"); + var menuItems = []; + if (configHref) { + menuItems.push({ + name: globalize.translate("ButtonSettings"), + id: "open", + ironIcon: "mode-edit" + }); + } + menuItems.push({ + name: globalize.translate("ButtonUninstall"), + id: "delete", + ironIcon: "delete" + }); + require(["actionsheet"], function(actionsheet) { + actionsheet.show({ + items: menuItems, + positionTo: elem, + callback: function(resultId) { + switch (resultId) { + case "open": + Dashboard.navigate(configHref); + break; + case "delete": + deletePlugin(page, id, name) + } + } + }); + }); + } + + function reloadList(page) { + loading.show(); + ApiClient.getInstalledPlugins().then(function(plugins) { + renderPlugins(page, plugins); + }); + } + + function getTabs() { + return [{ + href: "installedplugins.html", + name: globalize.translate("TabMyPlugins") + }, { + href: "availableplugins.html", + name: globalize.translate("TabCatalog") + }] + } + + function onInstalledPluginsClick(e) { + if (dom.parentWithClass(e.target, "noConfigPluginCard")) { + showNoConfigurationMessage(); + } else if (dom.parentWithClass(e.target, "connectModePluginCard")) { + showConnectMessage(); + } else { + var btnCardMenu = dom.parentWithClass(e.target, "btnCardMenu"); + btnCardMenu && showPluginMenu(dom.parentWithClass(btnCardMenu, "page"), btnCardMenu); + } + } + + pageIdOn("pageshow", "pluginsPage", function() { + libraryMenu.setTabs("plugins", 0, getTabs); + reloadList(this); + }); + + window.PluginsPage = { + renderPlugins: renderPlugins + } +}); diff --git a/src/scripts/itemdetailpage.js b/src/controllers/itemdetailpage.js similarity index 95% rename from src/scripts/itemdetailpage.js rename to src/controllers/itemdetailpage.js index d8d952cba0..3a0e776d3f 100644 --- a/src/scripts/itemdetailpage.js +++ b/src/controllers/itemdetailpage.js @@ -1,4 +1,4 @@ -define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuilder", "datetime", "mediaInfo", "backdrop", "listView", "itemContextMenu", "itemHelper", "dom", "indicators", "apphost", "imageLoader", "libraryMenu", "globalize", "browser", "events", "scrollHelper", "playbackManager", "libraryBrowser", "scrollStyles", "emby-itemscontainer", "emby-checkbox", "emby-linkbutton", "emby-playstatebutton", "emby-ratingbutton", "emby-downloadbutton", "emby-scroller", "emby-select"], function(loading, appRouter, layoutManager, connectionManager, cardBuilder, datetime, mediaInfo, backdrop, listView, itemContextMenu, itemHelper, dom, indicators, appHost, imageLoader, libraryMenu, globalize, browser, events, scrollHelper, playbackManager, libraryBrowser) { +define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuilder", "datetime", "mediaInfo", "backdrop", "listView", "itemContextMenu", "itemHelper", "dom", "indicators", "apphost", "imageLoader", "libraryMenu", "globalize", "browser", "events", "scrollHelper", "playbackManager", "libraryBrowser", "scrollStyles", "emby-itemscontainer", "emby-checkbox", "emby-button", "emby-playstatebutton", "emby-ratingbutton", "emby-scroller", "emby-select"], function(loading, appRouter, layoutManager, connectionManager, cardBuilder, datetime, mediaInfo, backdrop, listView, itemContextMenu, itemHelper, dom, indicators, appHost, imageLoader, libraryMenu, globalize, browser, events, scrollHelper, playbackManager, libraryBrowser) { "use strict"; function getPromise(apiClient, params) { @@ -33,12 +33,7 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuild user: user, share: !0 }; - return appHost.supports("sync") && (options.syncLocal = !1), options - } - - function renderSyncLocalContainer(page, params, user, item) { - if (appHost.supports("sync")) - for (var canSync = itemHelper.canSync(user, item), buttons = page.querySelectorAll(".btnSyncDownload"), i = 0, length = buttons.length; i < length; i++) buttons[i].setItem(item), canSync ? buttons[i].classList.remove("hide") : buttons[i].classList.add("hide") + return options; } function getProgramScheduleHtml(items, options) { @@ -286,7 +281,23 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuild var apiClient = connectionManager.getApiClient(item.ServerId); renderSeriesTimerEditor(page, item, apiClient, user), renderTimerEditor(page, item, apiClient, user), renderImage(page, item, apiClient, user), renderLogo(page, item, apiClient), setTitle(item, apiClient), setInitialCollapsibleState(page, item, apiClient, context, user), renderDetails(page, item, apiClient, context), renderTrackSelections(page, instance, item), dom.getWindowSize().innerWidth >= 1e3 ? backdrop.setBackdrops([item]) : backdrop.clear(), renderDetailPageBackdrop(page, item, apiClient); var canPlay = reloadPlayButtons(page, item); - (item.LocalTrailerCount || item.RemoteTrailers && item.RemoteTrailers.length) && -1 !== playbackManager.getSupportedCommands().indexOf("PlayTrailers") ? hideAll(page, "btnPlayTrailer", !0) : hideAll(page, "btnPlayTrailer"), setTrailerButtonVisibility(page, item), item.CanDelete && !item.IsFolder ? hideAll(page, "btnDeleteItem", !0) : hideAll(page, "btnDeleteItem"), renderSyncLocalContainer(page, params, user, item), "Program" !== item.Type || canPlay ? hideAll(page, "mainDetailButtons", !0) : hideAll(page, "mainDetailButtons"), showRecordingFields(instance, page, item, user); + if ((item.LocalTrailerCount || item.RemoteTrailers && item.RemoteTrailers.length) && -1 !== playbackManager.getSupportedCommands().indexOf("PlayTrailers")) { + hideAll(page, "btnPlayTrailer", true); + } else { + hideAll(page, "btnPlayTrailer"); + } + setTrailerButtonVisibility(page, item); + if (item.CanDelete && !item.IsFolder) { + hideAll(page, "btnDeleteItem", true); + } else { + hideAll(page, "btnDeleteItem"); + } + if ("Program" !== item.Type || canPlay) { + hideAll(page, "mainDetailButtons", true); + } else { + hideAll(page, "mainDetailButtons"); + } + showRecordingFields(instance, page, item, user); var groupedVersions = (item.MediaSources || []).filter(function(g) { return "Grouping" == g.Type }); @@ -1166,30 +1177,55 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuild })) } } - var currentItem, self = this, - apiClient = params.serverId ? connectionManager.getApiClient(params.serverId) : ApiClient; + + var currentItem; + var self = this; + var apiClient = params.serverId ? connectionManager.getApiClient(params.serverId) : ApiClient; view.querySelectorAll(".btnPlay"); - bindAll(view, ".btnPlay", "click", onPlayClick), bindAll(view, ".btnResume", "click", onPlayClick), bindAll(view, ".btnInstantMix", "click", onInstantMixClick), bindAll(view, ".btnShuffle", "click", onShuffleClick), bindAll(view, ".btnPlayTrailer", "click", onPlayTrailerClick), bindAll(view, ".btnCancelSeriesTimer", "click", onCancelSeriesTimerClick), bindAll(view, ".btnCancelTimer", "click", onCancelTimerClick), bindAll(view, ".btnDeleteItem", "click", onDeleteClick), bindAll(view, ".btnSyncDownload", "download", onDownloadChange), bindAll(view, ".btnSyncDownload", "download-cancel", onDownloadChange), view.querySelector(".btnMoreCommands i").innerHTML = "", view.querySelector(".trackSelections").addEventListener("submit", onTrackSelectionsSubmit), view.querySelector(".btnSplitVersions").addEventListener("click", function() { + bindAll(view, ".btnPlay", "click", onPlayClick); + bindAll(view, ".btnResume", "click", onPlayClick); + bindAll(view, ".btnInstantMix", "click", onInstantMixClick); + bindAll(view, ".btnShuffle", "click", onShuffleClick); + bindAll(view, ".btnPlayTrailer", "click", onPlayTrailerClick); + bindAll(view, ".btnCancelSeriesTimer", "click", onCancelSeriesTimerClick); + bindAll(view, ".btnCancelTimer", "click", onCancelTimerClick); + bindAll(view, ".btnDeleteItem", "click", onDeleteClick); + view.querySelector(".btnMoreCommands i").innerHTML = ""; + view.querySelector(".trackSelections").addEventListener("submit", onTrackSelectionsSubmit); + view.querySelector(".btnSplitVersions").addEventListener("click", function() { splitVersions(self, view, apiClient, params) - }), bindAll(view, ".btnMoreCommands", "click", onMoreCommandsClick), view.querySelector(".selectSource").addEventListener("change", function() { - renderVideoSelections(view, self._currentPlaybackMediaSources), renderAudioSelections(view, self._currentPlaybackMediaSources), renderSubtitleSelections(view, self._currentPlaybackMediaSources) - }), view.addEventListener("click", function(e) { + }); + bindAll(view, ".btnMoreCommands", "click", onMoreCommandsClick); + view.querySelector(".selectSource").addEventListener("change", function() { + renderVideoSelections(view, self._currentPlaybackMediaSources); + renderAudioSelections(view, self._currentPlaybackMediaSources); + renderSubtitleSelections(view, self._currentPlaybackMediaSources); + }); + view.addEventListener("click", function(e) { dom.parentWithClass(e.target, "moreScenes") ? apiClient.getCurrentUser().then(function(user) { renderScenes(view, currentItem) }) : dom.parentWithClass(e.target, "morePeople") ? renderCast(view, currentItem, params.context) : dom.parentWithClass(e.target, "moreSpecials") && apiClient.getCurrentUser().then(function(user) { renderSpecials(view, currentItem, user) }) - }), view.querySelector(".detailImageContainer").addEventListener("click", function(e) { + }); + view.querySelector(".detailImageContainer").addEventListener("click", function(e) { dom.parentWithClass(e.target, "itemDetailGalleryLink") && editImages().then(function() { reload(self, view, params) }) - }), view.addEventListener("viewshow", function(e) { + }); + view.addEventListener("viewshow", function(e) { var page = this; libraryMenu.setTransparentMenu(!0), e.detail.isRestored ? currentItem && (setTitle(currentItem, connectionManager.getApiClient(currentItem.ServerId)), renderTrackSelections(page, self, currentItem, !0)) : reload(self, page, params), events.on(apiClient, "message", onWebSocketMessage), events.on(playbackManager, "playerchange", onPlayerChange) - }), view.addEventListener("viewbeforehide", function() { - events.off(apiClient, "message", onWebSocketMessage), events.off(playbackManager, "playerchange", onPlayerChange), libraryMenu.setTransparentMenu(!1) - }), view.addEventListener("viewdestroy", function() { - currentItem = null, self._currentPlaybackMediaSources = null, self.currentRecordingFields = null + }); + view.addEventListener("viewbeforehide", function() { + events.off(apiClient, "message", onWebSocketMessage); + events.off(playbackManager, "playerchange", onPlayerChange); + libraryMenu.setTransparentMenu(false); + }); + view.addEventListener("viewdestroy", function() { + currentItem = null; + self._currentPlaybackMediaSources = null; + self.currentRecordingFields = null; }) } }); diff --git a/src/dashboard/librarydisplay.js b/src/controllers/librarydisplay.js similarity index 96% rename from src/dashboard/librarydisplay.js rename to src/controllers/librarydisplay.js index 924641d743..80f5bbc09b 100644 --- a/src/dashboard/librarydisplay.js +++ b/src/controllers/librarydisplay.js @@ -1,4 +1,4 @@ -define(["globalize", "loading", "libraryMenu", "emby-checkbox", "emby-button", "emby-linkbutton"], function(globalize, loading, libraryMenu) { +define(["globalize", "loading", "libraryMenu", "emby-checkbox", "emby-button", "emby-button"], function(globalize, loading, libraryMenu) { "use strict"; function getTabs() { diff --git a/src/controllers/librarysettings.js b/src/controllers/librarysettings.js new file mode 100644 index 0000000000..3fc9c40d98 --- /dev/null +++ b/src/controllers/librarysettings.js @@ -0,0 +1,91 @@ +define(["jQuery", "loading", "libraryMenu", "fnchecked", "emby-checkbox", "emby-button"], function($, loading, libraryMenu) { + "use strict"; + + function loadPage(page, config) { + $("#chkSaveMetadataHidden", page).checked(config.SaveMetadataHidden); + loading.hide(); + } + + function loadMetadataConfig(page, config) { + $("#selectDateAdded", page).val(config.UseFileCreationTimeForDateAdded ? "1" : "0"); + } + + function loadFanartConfig(page, config) { + $("#txtFanartApiKey", page).val(config.UserApiKey || ""); + } + + function saveFanart(form) { + ApiClient.getNamedConfiguration("fanart").then(function(config) { + config.UserApiKey = $("#txtFanartApiKey", form).val(), ApiClient.updateNamedConfiguration("fanart", config); + }); + } + + function saveMetadata(form) { + ApiClient.getNamedConfiguration("metadata").then(function(config) { + config.UseFileCreationTimeForDateAdded = "1" === $("#selectDateAdded", form).val(), ApiClient.updateNamedConfiguration("metadata", config); + }) + } + + function alertText(options) { + require(["alert"], function(alert) { + alert(options); + }); + } + + function onSubmit() { + loading.show(); + var form = this; + ApiClient.getServerConfiguration().then(function(config) { + config.SaveMetadataHidden = $("#chkSaveMetadataHidden", form).checked(); + config.FanartApiKey = $("#txtFanartApiKey", form).val(); + ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult); + }); + saveMetadata(form); + saveFanart(form); + return false; + } + + function getTabs() { + return [{ + href: "library.html", + name: Globalize.translate("HeaderLibraries") + }, { + href: "librarydisplay.html", + name: Globalize.translate("TabDisplay") + }, { + href: "metadataimages.html", + name: Globalize.translate("TabMetadata") + }, { + href: "metadatanfo.html", + name: Globalize.translate("TabNfoSettings") + }, { + href: "librarysettings.html", + name: Globalize.translate("TabAdvanced") + }] + } + + return function(view, params) { + $(".librarySettingsForm").off("submit", onSubmit).on("submit", onSubmit); + view.addEventListener("viewshow", function() { + libraryMenu.setTabs("librarysetup", 4, getTabs); + loading.show(); + var page = this; + ApiClient.getServerConfiguration().then(function(config) { + loadPage(page, config) + }); + ApiClient.getNamedConfiguration("metadata").then(function(metadata) { + loadMetadataConfig(page, metadata) + }); + ApiClient.getNamedConfiguration("fanart").then(function(metadata) { + loadFanartConfig(page, metadata) + }); + ApiClient.getSystemInfo().then(function(info) { + if ("Windows" === info.OperatingSystem) { + page.querySelector(".fldSaveMetadataHidden").classList.remove("hide"); + } else { + page.querySelector(".fldSaveMetadataHidden").classList.add("hide"); + } + }); + }); + } +}); \ No newline at end of file diff --git a/src/list/list.js b/src/controllers/list.js similarity index 100% rename from src/list/list.js rename to src/controllers/list.js diff --git a/src/scripts/livetvseriestimers.js b/src/controllers/livetvseriestimers.js similarity index 100% rename from src/scripts/livetvseriestimers.js rename to src/controllers/livetvseriestimers.js diff --git a/src/scripts/livetvsuggested.js b/src/controllers/livetvsuggested.js similarity index 100% rename from src/scripts/livetvsuggested.js rename to src/controllers/livetvsuggested.js diff --git a/src/dashboard/livetvtuner.js b/src/controllers/livetvtuner.js similarity index 75% rename from src/dashboard/livetvtuner.js rename to src/controllers/livetvtuner.js index b32e01b2d2..8d27093af1 100644 --- a/src/dashboard/livetvtuner.js +++ b/src/controllers/livetvtuner.js @@ -2,31 +2,57 @@ define(["globalize", "loading", "libraryMenu", "dom", "emby-input", "emby-button "use strict"; function isM3uVariant(type) { - return -1 !== ["nextpvr"].indexOf(type || "") + return ["nextpvr"].indexOf(type || "") !== -1; } function fillTypes(view, currentId) { - return ApiClient.getJSON(ApiClient.getUrl("LiveTv/TunerHosts/Types")).then(function(types) { + ApiClient.getJSON(ApiClient.getUrl("LiveTv/TunerHosts/Types")).then(function(types) { var selectType = view.querySelector(".selectType"); - selectType.innerHTML = types.map(function(t) { - return '" - }).join("") + '", selectType.disabled = null != currentId, selectType.value = "", onTypeChange.call(selectType) - }) + var html = ""; + html += types.map(function(tuner) { + return '"; + }).join(""); + html += '"; + selectType.innerHTML = html; + + selectType.disabled = null != currentId; + selectType.value = ""; + onTypeChange.call(selectType); + }); } function reload(view, providerId) { - view.querySelector(".txtDevicePath").value = "", view.querySelector(".chkFavorite").checked = !1, view.querySelector(".txtDevicePath").value = "", providerId && ApiClient.getNamedConfiguration("livetv").then(function(config) { - var info = config.TunerHosts.filter(function(i) { - return i.Id === providerId - })[0]; - fillTunerHostInfo(view, info) - }) + view.querySelector(".txtDevicePath").value = ""; + view.querySelector(".chkFavorite").checked = false; + view.querySelector(".txtDevicePath").value = ""; + if (providerId) { + ApiClient.getNamedConfiguration("livetv").then(function(config) { + var info = config.TunerHosts.filter(function(i) { + return i.Id === providerId; + })[0]; + fillTunerHostInfo(view, info); + }); + } } function fillTunerHostInfo(view, info) { - var selectType = view.querySelector(".selectType"), - type = info.Type || ""; - info.Source && isM3uVariant(info.Source) && (type = info.Source), selectType.value = type, onTypeChange.call(selectType), view.querySelector(".txtDevicePath").value = info.Url || "", view.querySelector(".txtFriendlyName").value = info.FriendlyName || "", view.querySelector(".txtUserAgent").value = info.UserAgent || "", view.querySelector(".fldDeviceId").value = info.DeviceId || "", view.querySelector(".chkFavorite").checked = info.ImportFavoritesOnly, view.querySelector(".chkTranscode").checked = info.AllowHWTranscoding, view.querySelector(".chkStreamLoop").checked = info.EnableStreamLooping, view.querySelector(".txtTunerCount").value = info.TunerCount || "0" + var selectType = view.querySelector(".selectType"); + var type = info.Type || ""; + if (info.Source && isM3uVariant(info.Source)) { + type = info.Source; + } + selectType.value = type; + onTypeChange.call(selectType); + view.querySelector(".txtDevicePath").value = info.Url || ""; + view.querySelector(".txtFriendlyName").value = info.FriendlyName || ""; + view.querySelector(".txtUserAgent").value = info.UserAgent || ""; + view.querySelector(".fldDeviceId").value = info.DeviceId || ""; + view.querySelector(".chkFavorite").checked = info.ImportFavoritesOnly; + view.querySelector(".chkTranscode").checked = info.AllowHWTranscoding; + view.querySelector(".chkStreamLoop").checked = info.EnableStreamLooping; + view.querySelector(".txtTunerCount").value = info.TunerCount || "0"; } function submitForm(page) { @@ -74,16 +100,6 @@ define(["globalize", "loading", "libraryMenu", "dom", "emby-input", "emby-button }) } - function getTabs() { - return [{ - href: "livetvstatus.html", - name: globalize.translate("TabDevices") - }, { - href: "appservices.html?context=livetv", - name: globalize.translate("TabServices") - }] - } - function onTypeChange() { var value = this.value, view = dom.parentWithClass(this, "page"), @@ -102,7 +118,6 @@ define(["globalize", "loading", "libraryMenu", "dom", "emby-input", "emby-button } return function(view, params) { params.id || view.querySelector(".btnDetect").classList.remove("hide"), view.addEventListener("viewshow", function() { - libraryMenu.setTabs("livetvadmin", 0, getTabs); var currentId = params.id; fillTypes(view, currentId).then(function() { reload(view, currentId) diff --git a/src/controllers/loginpage.js b/src/controllers/loginpage.js new file mode 100644 index 0000000000..2f396ff5eb --- /dev/null +++ b/src/controllers/loginpage.js @@ -0,0 +1,169 @@ +define(["apphost", "appSettings", "dom", "connectionManager", "loading", "cardStyle", "emby-checkbox"], function(appHost, appSettings, dom, connectionManager, loading) { + "use strict"; + + function authenticateUserByName(page, apiClient, username, password) { + loading.show(); + apiClient.authenticateUserByName(username, password).then(function(result) { + var user = result.User; + var serverId = getParameterByName("serverid"); + var newUrl = user.Policy.IsAdministrator && !serverId ? "dashboard.html" : "home.html"; + loading.hide(); + Dashboard.onServerChanged(user.Id, result.AccessToken, apiClient); + Dashboard.navigate(newUrl); + }, function(response) { + page.querySelector("#txtManualName").value = ""; + page.querySelector("#txtManualPassword").value = ""; + loading.hide(); + if (response.status === 401) { + require(["toast"], function(toast) { + toast(Globalize.translate("MessageInvalidUser")); + }); + } else { + Dashboard.alert({ + message: Globalize.translate("MessageUnableToConnectToServer"), + title: Globalize.translate("HeaderConnectionFailure") + }); + } + }); + } + + function showManualForm(context, showCancel, focusPassword) { + context.querySelector(".chkRememberLogin").checked = appSettings.enableAutoLogin(); + context.querySelector(".manualLoginForm").classList.remove("hide"); + context.querySelector(".visualLoginForm").classList.add("hide"); + focusPassword ? context.querySelector("#txtManualPassword").focus() : context.querySelector("#txtManualName").focus(); + showCancel ? context.querySelector(".btnCancel").classList.remove("hide") : context.querySelector(".btnCancel").classList.add("hide"); + } + + var metroColors = ["#6FBD45", "#4BB3DD", "#4164A5", "#E12026", "#800080", "#E1B222", "#008040", "#0094FF", "#FF00C7", "#FF870F", "#7F0037"]; + + function getRandomMetroColor() { + var index = Math.floor(Math.random() * (metroColors.length - 1)); + return metroColors[index]; + } + + function getMetroColor(str) { + if (str) { + var character = String(str.substr(0, 1).charCodeAt()); + var sum = 0; + for (var i = 0; i < character.length; i++) { + sum += parseInt(character.charAt(i)); + } + var index = String(sum).substr(-1); + return metroColors[index]; + } + return getRandomMetroColor(); + } + + function loadUserList(context, apiClient, users) { + var html = ""; + for (var i = 0; i < users.length; i++) { + var user = users[i]; + html += '"; + } + context.querySelector("#divUsers").innerHTML = html; + } + + return function(view, params) { + function getApiClient() { + var serverId = params.serverid; + return serverId ? connectionManager.getOrCreateApiClient(serverId) : ApiClient; + } + + function showVisualForm() { + view.querySelector(".visualLoginForm").classList.remove("hide"); + view.querySelector(".manualLoginForm").classList.add("hide"); + } + + view.querySelector("#divUsers").addEventListener("click", function(e) { + var card = dom.parentWithClass(e.target, "card"); + var cardContent = card ? card.querySelector(".cardContent") : null; + if (cardContent) { + var context = view; + var id = cardContent.getAttribute("data-userid"); + var name = cardContent.getAttribute("data-username"); + var haspw = cardContent.getAttribute("data-haspw"); + if (id === 'manual') { + context.querySelector("#txtManualName").value = ""; + showManualForm(context, true); + } else if (haspw == 'false') { + authenticateUserByName(context, getApiClient(), name, ""); + } else { + context.querySelector("#txtManualName").value = name; + context.querySelector("#txtManualPassword").value = ""; + showManualForm(context, true, true); + } + } + }); + + view.querySelector(".manualLoginForm").addEventListener("submit", function(e) { + appSettings.enableAutoLogin(view.querySelector(".chkRememberLogin").checked); + var apiClient = getApiClient(); + authenticateUserByName(view, apiClient, view.querySelector("#txtManualName").value, view.querySelector("#txtManualPassword").value); + e.preventDefault(); + return false; + }); + + view.querySelector(".btnForgotPassword").addEventListener("click", function() { + Dashboard.navigate("forgotpassword.html"); + }); + + view.querySelector(".btnCancel").addEventListener("click", showVisualForm); + + view.querySelector(".btnManual").addEventListener("click", function() { + view.querySelector("#txtManualName").value = ""; + showManualForm(view, true); + }); + + view.addEventListener("viewshow", function(e) { + loading.show(); + if (!appHost.supports('multiserver')) { + view.querySelector(".btnSelectServer").classList.add("hide"); + } + var apiClient = getApiClient(); + apiClient.getPublicUsers().then(function(users) { + if (users.length) { + if (users[0].EnableAutoLogin) { + authenticateUserByName(view, apiClient, users[0].Name, ""); + } else { + showVisualForm(); + loadUserList(view, apiClient, users); + } + } else { + view.querySelector("#txtManualName").value = ""; + showManualForm(view, false, false); + } + + }).finally(function () { + loading.hide(); + }); + + apiClient.getJSON(apiClient.getUrl("Branding/Configuration")).then(function(options) { + view.querySelector(".disclaimer").textContent = options.LoginDisclaimer || ""; + }); + }); + } +}); \ No newline at end of file diff --git a/src/dashboard/logpage.js b/src/controllers/logpage.js similarity index 96% rename from src/dashboard/logpage.js rename to src/controllers/logpage.js index 0c29389255..4b288b288f 100644 --- a/src/dashboard/logpage.js +++ b/src/controllers/logpage.js @@ -1,4 +1,4 @@ -define(["datetime", "loading", "apphost", "listViewStyle", "emby-linkbutton", "flexStyles"], function(datetime, loading, appHost) { +define(["datetime", "loading", "apphost", "listViewStyle", "emby-button", "flexStyles"], function(datetime, loading, appHost) { "use strict"; return function(view, params) { view.querySelector("#chkDebugLog").addEventListener("change", function() { diff --git a/src/scripts/moviesrecommended.js b/src/controllers/moviesrecommended.js similarity index 96% rename from src/scripts/moviesrecommended.js rename to src/controllers/moviesrecommended.js index 31c9bfba47..9f0379861f 100644 --- a/src/scripts/moviesrecommended.js +++ b/src/controllers/moviesrecommended.js @@ -1,4 +1,4 @@ -define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu", "mainTabsManager", "components/categorysyncbuttons", "cardBuilder", "dom", "imageLoader", "playbackManager", "emby-itemscontainer", "emby-tabs", "emby-button"], function(events, layoutManager, inputManager, userSettings, libraryMenu, mainTabsManager, categorysyncbuttons, cardBuilder, dom, imageLoader, playbackManager) { +define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu", "mainTabsManager", "cardBuilder", "dom", "imageLoader", "playbackManager", "emby-itemscontainer", "emby-tabs", "emby-button"], function(events, layoutManager, inputManager, userSettings, libraryMenu, mainTabsManager, cardBuilder, dom, imageLoader, playbackManager) { "use strict"; function enableScrollX() { @@ -250,7 +250,7 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu" suggestionsTabIndex = 1; self.initTab = function() { var tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']"); - categorysyncbuttons.init(tabContent), initSuggestedTab(view, tabContent) + initSuggestedTab(view, tabContent); }, self.renderTab = function() { var tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']"); loadSuggestionsTab(view, params, tabContent) diff --git a/src/scripts/musicrecommended.js b/src/controllers/musicrecommended.js similarity index 100% rename from src/scripts/musicrecommended.js rename to src/controllers/musicrecommended.js diff --git a/src/scripts/mypreferencescommon.js b/src/controllers/mypreferencescommon.js similarity index 94% rename from src/scripts/mypreferencescommon.js rename to src/controllers/mypreferencescommon.js index c30d6f723a..e52fcc1b34 100644 --- a/src/scripts/mypreferencescommon.js +++ b/src/controllers/mypreferencescommon.js @@ -1,4 +1,4 @@ -define(["apphost", "connectionManager", "listViewStyle", "emby-linkbutton"], function(appHost, connectionManager) { +define(["apphost", "connectionManager", "listViewStyle", "emby-button"], function(appHost, connectionManager) { "use strict"; return function(view, params) { diff --git a/src/scripts/mypreferencesdisplay.js b/src/controllers/mypreferencesdisplay.js similarity index 100% rename from src/scripts/mypreferencesdisplay.js rename to src/controllers/mypreferencesdisplay.js diff --git a/src/scripts/mypreferenceshome.js b/src/controllers/mypreferenceshome.js similarity index 100% rename from src/scripts/mypreferenceshome.js rename to src/controllers/mypreferenceshome.js diff --git a/src/scripts/mypreferenceslanguages.js b/src/controllers/mypreferenceslanguages.js similarity index 100% rename from src/scripts/mypreferenceslanguages.js rename to src/controllers/mypreferenceslanguages.js diff --git a/src/scripts/mypreferencessubtitles.js b/src/controllers/mypreferencessubtitles.js similarity index 100% rename from src/scripts/mypreferencessubtitles.js rename to src/controllers/mypreferencessubtitles.js diff --git a/src/scripts/myprofile.js b/src/controllers/myprofile.js similarity index 96% rename from src/scripts/myprofile.js rename to src/controllers/myprofile.js index 7554b302e8..be8f1b446e 100644 --- a/src/scripts/myprofile.js +++ b/src/controllers/myprofile.js @@ -1,4 +1,4 @@ -define(["scripts/userpasswordpage", "loading", "libraryMenu", "apphost", "emby-linkbutton"], function (Userpasswordpage, loading, libraryMenu, appHost) { +define(["controllers/userpasswordpage", "loading", "libraryMenu", "apphost", "emby-button"], function (Userpasswordpage, loading, libraryMenu, appHost) { "use strict"; function reloadUser(page) { @@ -10,7 +10,7 @@ define(["scripts/userpasswordpage", "loading", "libraryMenu", "apphost", "emby-l uploadUserImage.value = ""; uploadUserImage.dispatchEvent(new CustomEvent("change", {})); libraryMenu.setTitle(user.Name); - var imageUrl = "css/images/logindefault.png"; + var imageUrl = "img/logindefault.png"; if (user.PrimaryImageTag) { imageUrl = ApiClient.getUserImageUrl(user.Id, { height: 200, diff --git a/src/controllers/notificationsettings.js b/src/controllers/notificationsettings.js new file mode 100644 index 0000000000..092d92e24b --- /dev/null +++ b/src/controllers/notificationsettings.js @@ -0,0 +1,60 @@ +define(["loading", "libraryMenu", "globalize", "listViewStyle", "emby-button"], function(loading, libraryMenu, globalize) { + "use strict"; + + function reload(page) { + loading.show(); + ApiClient.getJSON(ApiClient.getUrl("Notifications/Types")).then(function(list) { + var html = ""; + var lastCategory = ""; + var showHelp = true; + html += list.map(function(notification) { + var itemHtml = ""; + if (notification.Category !== lastCategory) { + lastCategory = notification.Category; + if (lastCategory) { + itemHtml += "
"; + itemHtml += ""; + } + itemHtml += '
'; + itemHtml += '
'; + itemHtml += '

'; + itemHtml += notification.Category; + itemHtml += "

"; + if (showHelp) { + showHelp = false; + itemHtml += ''; + itemHtml += globalize.translate("Help"); + itemHtml += ""; + } + itemHtml += "
"; + itemHtml += '
'; + } + itemHtml += ''; + if (notification.Enabled) { + itemHtml += 'notifications_active'; + } else { + itemHtml += 'notifications_off'; + } + itemHtml += '
'; + itemHtml += '
' + notification.Name + "
"; + itemHtml += "
"; + itemHtml += ''; + itemHtml += "
"; + return itemHtml; + }).join(""); + + if (list.length) { + html += "
"; + html += "
"; + } + page.querySelector(".notificationList").innerHTML = html; + loading.hide(); + }) + } + + return function(view, params) { + view.addEventListener("viewshow", function() { + reload(view); + }); + } +}); diff --git a/src/scripts/nowplayingpage.js b/src/controllers/nowplayingpage.js similarity index 100% rename from src/scripts/nowplayingpage.js rename to src/controllers/nowplayingpage.js diff --git a/src/scripts/scheduledtaskpage.js b/src/controllers/scheduledtaskpage.js similarity index 100% rename from src/scripts/scheduledtaskpage.js rename to src/controllers/scheduledtaskpage.js diff --git a/src/scripts/scheduledtaskspage.js b/src/controllers/scheduledtaskspage.js similarity index 98% rename from src/scripts/scheduledtaskspage.js rename to src/controllers/scheduledtaskspage.js index 50c2ef53a0..1580f1a4c3 100644 --- a/src/scripts/scheduledtaskspage.js +++ b/src/controllers/scheduledtaskspage.js @@ -1,4 +1,4 @@ -define(["jQuery", "loading", "events", "globalize", "serverNotifications", "humanedate", "listViewStyle", "emby-linkbutton"], function($, loading, events, globalize, serverNotifications) { +define(["jQuery", "loading", "events", "globalize", "serverNotifications", "humanedate", "listViewStyle", "emby-button"], function($, loading, events, globalize, serverNotifications) { "use strict"; function reloadList(page) { diff --git a/src/scripts/searchpage.js b/src/controllers/searchpage.js similarity index 100% rename from src/scripts/searchpage.js rename to src/controllers/searchpage.js diff --git a/src/scripts/selectserver.js b/src/controllers/selectserver.js similarity index 100% rename from src/scripts/selectserver.js rename to src/controllers/selectserver.js diff --git a/src/dashboard/serveractivity.js b/src/controllers/serveractivity.js similarity index 100% rename from src/dashboard/serveractivity.js rename to src/controllers/serveractivity.js diff --git a/src/scripts/tvrecommended.js b/src/controllers/tvrecommended.js similarity index 96% rename from src/scripts/tvrecommended.js rename to src/controllers/tvrecommended.js index 12fbd9081b..d7055fe2b3 100644 --- a/src/scripts/tvrecommended.js +++ b/src/controllers/tvrecommended.js @@ -1,4 +1,4 @@ -define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "dom", "components/categorysyncbuttons", "userSettings", "cardBuilder", "playbackManager", "mainTabsManager", "scrollStyles", "emby-itemscontainer", "emby-button"], function(events, inputManager, libraryMenu, layoutManager, loading, dom, categorysyncbuttons, userSettings, cardBuilder, playbackManager, mainTabsManager) { +define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "dom", "userSettings", "cardBuilder", "playbackManager", "mainTabsManager", "scrollStyles", "emby-itemscontainer", "emby-button"], function(events, inputManager, libraryMenu, layoutManager, loading, dom, userSettings, cardBuilder, playbackManager, mainTabsManager) { "use strict"; function getTabs() { @@ -204,7 +204,7 @@ define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "do initialTabIndex = currentTabIndex; self.initTab = function() { var tabContent = self.tabContent; - setScrollClasses(tabContent.querySelector("#resumableItems"), enableScrollX()), categorysyncbuttons.init(tabContent) + setScrollClasses(tabContent.querySelector("#resumableItems"), enableScrollX()); }, self.renderTab = function() { reload() }; @@ -226,4 +226,4 @@ define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "do }) }) } -}); \ No newline at end of file +}); diff --git a/src/scripts/userpasswordpage.js b/src/controllers/userpasswordpage.js similarity index 98% rename from src/scripts/userpasswordpage.js rename to src/controllers/userpasswordpage.js index 478ba95724..d1eef004f6 100644 --- a/src/scripts/userpasswordpage.js +++ b/src/controllers/userpasswordpage.js @@ -1,4 +1,4 @@ -define(["loading", "libraryMenu", "emby-linkbutton"], function(loading, libraryMenu) { +define(["loading", "libraryMenu", "emby-button"], function(loading, libraryMenu) { "use strict"; function loadUser(page, params) { diff --git a/src/scripts/videoosd.js b/src/controllers/videoosd.js similarity index 100% rename from src/scripts/videoosd.js rename to src/controllers/videoosd.js diff --git a/src/dashboard/wizardfinishpage.js b/src/controllers/wizardfinishpage.js similarity index 100% rename from src/dashboard/wizardfinishpage.js rename to src/controllers/wizardfinishpage.js diff --git a/src/dashboard/wizardremoteaccess.js b/src/controllers/wizardremoteaccess.js similarity index 100% rename from src/dashboard/wizardremoteaccess.js rename to src/controllers/wizardremoteaccess.js diff --git a/src/dashboard/wizardsettings.js b/src/controllers/wizardsettings.js similarity index 100% rename from src/dashboard/wizardsettings.js rename to src/controllers/wizardsettings.js diff --git a/src/dashboard/wizardstart.js b/src/controllers/wizardstart.js similarity index 100% rename from src/dashboard/wizardstart.js rename to src/controllers/wizardstart.js diff --git a/src/scripts/wizarduserpage.js b/src/controllers/wizarduserpage.js similarity index 63% rename from src/scripts/wizarduserpage.js rename to src/controllers/wizarduserpage.js index 252e005a80..a3654edf0e 100644 --- a/src/scripts/wizarduserpage.js +++ b/src/controllers/wizarduserpage.js @@ -1,23 +1,18 @@ -define(["loading", "globalize", "dashboardcss", "emby-input", "emby-button", "emby-linkbutton"], function(loading, globalize) { +define(["loading", "globalize", "dashboardcss", "emby-input", "emby-button", "emby-button"], function(loading, globalize) { "use strict"; function getApiClient() { - return ApiClient + return ApiClient; } function nextWizardPage() { - Dashboard.navigate("wizardlibrary.html") + Dashboard.navigate("wizardlibrary.html"); } function onUpdateUserComplete(result) { - if (loading.hide(), result.UserLinkResult) { - var msgKey = result.UserLinkResult.IsPending ? "MessagePendingEmbyAccountAdded" : "MessageEmbyAccountAdded"; - Dashboard.alert({ - message: globalize.translate(msgKey), - title: globalize.translate("HeaderEmbyAccountAdded"), - callback: nextWizardPage - }) - } else nextWizardPage() + console.log(result); + loading.hide(); + nextWizardPage(); } function submit(form) { @@ -27,12 +22,10 @@ define(["loading", "globalize", "dashboardcss", "emby-input", "emby-button", "em type: "POST", data: { Name: form.querySelector("#txtUsername").value, - Password: form.querySelector("#txtManualPassword").value + Password: form.querySelector("#txtManualPassword").value }, url: apiClient.getUrl("Startup/User") - }).then(onUpdateUserComplete, function(response) { - console.log(response); - }) + }).then(onUpdateUserComplete); } function onSubmit(e) { @@ -50,8 +43,8 @@ define(["loading", "globalize", "dashboardcss", "emby-input", "emby-button", "em function onViewShow() { loading.show(); - var page = this, - apiClient = getApiClient(); + var page = this; + var apiClient = getApiClient(); apiClient.getJSON(apiClient.getUrl("Startup/User")).then(function(user) { page.querySelector("#txtUsername").value = user.Name || ""; page.querySelector("#txtManualPassword").value = user.Password || ""; @@ -59,10 +52,13 @@ define(["loading", "globalize", "dashboardcss", "emby-input", "emby-button", "em }) } return function(view, params) { - view.querySelector(".wizardUserForm").addEventListener("submit", onSubmit), view.addEventListener("viewshow", function() { + view.querySelector(".wizardUserForm").addEventListener("submit", onSubmit); + view.addEventListener("viewshow", function() { document.querySelector(".skinHeader").classList.add("noHomeButtonHeader") - }), view.addEventListener("viewhide", function() { + }); + view.addEventListener("viewhide", function() { document.querySelector(".skinHeader").classList.remove("noHomeButtonHeader") - }), view.addEventListener("viewshow", onViewShow) + }); + view.addEventListener("viewshow", onViewShow); } }); diff --git a/src/bower_components/emby-webcomponents/fonts/fonts.css b/src/css/fonts.css similarity index 100% rename from src/bower_components/emby-webcomponents/fonts/fonts.css rename to src/css/fonts.css diff --git a/src/bower_components/emby-webcomponents/fonts/fonts.sized.css b/src/css/fonts.sized.css similarity index 100% rename from src/bower_components/emby-webcomponents/fonts/fonts.sized.css rename to src/css/fonts.sized.css diff --git a/src/css/images/logoblack.png b/src/css/images/logoblack.png deleted file mode 100644 index 3511abc23b..0000000000 Binary files a/src/css/images/logoblack.png and /dev/null differ diff --git a/src/devices/ios/ios.css b/src/css/ios.css similarity index 100% rename from src/devices/ios/ios.css rename to src/css/ios.css diff --git a/src/bower_components/emby-webcomponents/fonts/material-icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff b/src/css/material-icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff similarity index 100% rename from src/bower_components/emby-webcomponents/fonts/material-icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff rename to src/css/material-icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff diff --git a/src/bower_components/emby-webcomponents/fonts/material-icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 b/src/css/material-icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 similarity index 100% rename from src/bower_components/emby-webcomponents/fonts/material-icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 rename to src/css/material-icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 diff --git a/src/bower_components/emby-webcomponents/fonts/material-icons/style.css b/src/css/material-icons/style.css similarity index 100% rename from src/bower_components/emby-webcomponents/fonts/material-icons/style.css rename to src/css/material-icons/style.css diff --git a/src/css/nowplaying.css b/src/css/nowplaying.css index 93765d541b..9bedb33c83 100644 --- a/src/css/nowplaying.css +++ b/src/css/nowplaying.css @@ -178,7 +178,7 @@ .playlistIndexIndicatorImage { -webkit-background-size: initial initial !important; background-size: initial !important; - background-image: url(images/ani_equalizer_white.gif) !important + background-image: url(../img/equalizer.gif) !important } .hideVideoButtons .videoButton { @@ -186,14 +186,26 @@ } .nowPlayingVolumeSliderContainer { - width: 6em + width: 9em +} + +@media all and (max-width:50em) { + .nowPlayingInfoButtons .nowPlayingPageUserDataButtons { + display: none !important + } +} + +@media all and (max-width:47em) { + .nowPlayingInfoButtons .repeatToggleButton { + display: none !important + } } @media all and (max-width:34em) { - .btnNowPlayingFastForward, - .btnNowPlayingRewind, - .playlist .listItemMediaInfo { + .nowPlayingInfoButtons .btnNowPlayingFastForward, + .nowPlayingInfoButtons .btnNowPlayingRewind, + .nowPlayingInfoButtons .playlist .listItemMediaInfo { display: none !important } -} \ No newline at end of file +} diff --git a/src/css/site.css b/src/css/site.css index 0111b3823d..f048f4b8f4 100644 --- a/src/css/site.css +++ b/src/css/site.css @@ -74,7 +74,8 @@ div[data-role=page] { .padded-bottom-page, .page, .pageWithAbsoluteTabs .pageTabContent { - padding-bottom: 2em !important + /* provides room for the music controls */ + padding-bottom: 5em !important } @media all and (min-width:50em) { diff --git a/src/css/videoosd.css b/src/css/videoosd.css index a8904b9945..bd24e41309 100644 --- a/src/css/videoosd.css +++ b/src/css/videoosd.css @@ -138,7 +138,7 @@ } .osdVolumeSliderContainer { - width: 6.5em; + width: 9em; -webkit-box-flex: 1; -webkit-flex-grow: 1; flex-grow: 1 @@ -244,14 +244,19 @@ } } -@media all and (max-width:37.5em) { +@media all and (max-width:43em) { .videoOsdBottom .volumeButtons { display: none !important } } +@media all and (max-width:50em) { + .videoOsdBottom .btnFastForward, .videoOsdBottom .btnRewind { + display: none !important + } +} @media all and (max-width:75em) { .videoOsdBottom .endsAtText { display: none !important } -} \ No newline at end of file +} diff --git a/src/dashboard.html b/src/dashboard.html index 61b7a7516d..ba973280ef 100644 --- a/src/dashboard.html +++ b/src/dashboard.html @@ -1,30 +1,19 @@
-
-
-
-
+ +

${TabServer}

+ +
-

- - -
-

-

+

+

-

-

-

- ${HowToConnectFromEmbyApps} -

@@ -36,13 +25,11 @@
-

${HeaderRunningTasks}

-
@@ -50,10 +37,8 @@

${HeaderActiveDevices}

-
-
@@ -76,7 +61,6 @@
+
-

${HeaderPaths}

+
+

${HeaderPaths}

+ +
@@ -107,8 +95,14 @@
-
${LabelTranscodingTemporaryFiles}
-
+
${LabelTranscodes}
+
+
+
+
+
+
${LabelWeb}
+
diff --git a/src/dashboard/aboutpage.js b/src/dashboard/aboutpage.js deleted file mode 100644 index 7ad9285455..0000000000 --- a/src/dashboard/aboutpage.js +++ /dev/null @@ -1,9 +0,0 @@ -define([], function() { - "use strict"; - return function(view, params) { - view.addEventListener("viewbeforeshow", function(e) { - var elem = view.querySelector("#appVersionNumber"); - elem.innerHTML = elem.innerHTML.replace("{0}", ConnectionManager.appVersion()) - }) - } -}); \ No newline at end of file diff --git a/src/dashboard/dashboardgeneral.js b/src/dashboard/dashboardgeneral.js deleted file mode 100644 index f220be4cc0..0000000000 --- a/src/dashboard/dashboardgeneral.js +++ /dev/null @@ -1,51 +0,0 @@ -define(["jQuery", "loading", "fnchecked", "emby-checkbox", "emby-textarea", "emby-input", "emby-select", "emby-linkbutton"], function($, loading) { - "use strict"; - - function loadPage(page, config, languageOptions, systemInfo) { - systemInfo.CanLaunchWebBrowser ? page.querySelector("#fldRunWebAppAtStartup").classList.remove("hide") : page.querySelector("#fldRunWebAppAtStartup").classList.add("hide"), page.querySelector("#txtCachePath").value = config.CachePath || "", $("#selectLocalizationLanguage", page).html(languageOptions.map(function(l) { - return '" - })).val(config.UICulture), currentLanguage = config.UICulture, systemInfo.CanSelfUpdate ? page.querySelector(".fldAutomaticUpdates").classList.remove("hide") : page.querySelector(".fldAutomaticUpdates").classList.add("hide"), $("#chkEnableAutomaticServerUpdates", page).checked(config.EnableAutoUpdate), $("#chkEnableAutomaticRestart", page).checked(config.EnableAutomaticRestart), systemInfo.CanSelfRestart ? page.querySelector("#fldEnableAutomaticRestart").classList.remove("hide") : page.querySelector("#fldEnableAutomaticRestart").classList.add("hide"), systemInfo.CanSelfRestart || systemInfo.CanSelfUpdate ? $(".autoUpdatesContainer", page).removeClass("hide") : $(".autoUpdatesContainer", page).addClass("hide"), loading.hide() - } - - function onSubmit() { - loading.show(); - var form = this; - $(form).parents(".page"); - return ApiClient.getServerConfiguration().then(function(config) { - config.UICulture = $("#selectLocalizationLanguage", form).val(), config.CachePath = form.querySelector("#txtCachePath").value; - var requiresReload = !1; - config.UICulture !== currentLanguage && (requiresReload = !0), config.EnableAutomaticRestart = $("#chkEnableAutomaticRestart", form).checked(), config.EnableAutoUpdate = $("#chkEnableAutomaticServerUpdates", form).checked(), ApiClient.updateServerConfiguration(config).then(function() { - ApiClient.getNamedConfiguration(brandingConfigKey).then(function(brandingConfig) { - brandingConfig.LoginDisclaimer = form.querySelector("#txtLoginDisclaimer").value, brandingConfig.CustomCss = form.querySelector("#txtCustomCss").value, currentBrandingOptions && brandingConfig.CustomCss !== currentBrandingOptions.CustomCss && (requiresReload = !0), ApiClient.updateNamedConfiguration(brandingConfigKey, brandingConfig).then(function() { - Dashboard.processServerConfigurationUpdateResult(), requiresReload && !AppInfo.isNativeApp && window.location.reload(!0) - }) - }) - }) - }), !1 - } - var currentBrandingOptions, currentLanguage, brandingConfigKey = "branding"; - return function(view, params) { - $("#btnSelectCachePath", view).on("click.selectDirectory", function() { - require(["directorybrowser"], function(directoryBrowser) { - var picker = new directoryBrowser; - picker.show({ - callback: function(path) { - path && (view.querySelector("#txtCachePath").value = path), picker.close() - }, - validateWriteable: !0, - header: Globalize.translate("HeaderSelectServerCachePath"), - instruction: Globalize.translate("HeaderSelectServerCachePathHelp") - }) - }) - }), $(".dashboardGeneralForm", view).off("submit", onSubmit).on("submit", onSubmit), view.addEventListener("viewshow", function() { - var promise1 = ApiClient.getServerConfiguration(), - promise2 = ApiClient.getJSON(ApiClient.getUrl("Localization/Options")), - promise3 = ApiClient.getSystemInfo(); - Promise.all([promise1, promise2, promise3]).then(function(responses) { - loadPage(view, responses[0], responses[1], responses[2]) - }), ApiClient.getNamedConfiguration(brandingConfigKey).then(function(config) { - currentBrandingOptions = config, view.querySelector("#txtLoginDisclaimer").value = config.LoginDisclaimer || "", view.querySelector("#txtCustomCss").value = config.CustomCss || "" - }) - }) - } -}); diff --git a/src/dashboard/librarysettings.js b/src/dashboard/librarysettings.js deleted file mode 100644 index afbf033dfb..0000000000 --- a/src/dashboard/librarysettings.js +++ /dev/null @@ -1,94 +0,0 @@ -define(["jQuery", "loading", "libraryMenu", "fnchecked", "emby-checkbox", "emby-linkbutton"], function($, loading, libraryMenu) { - "use strict"; - - function loadPage(page, config) { - config.MergeMetadataAndImagesByName ? $(".fldImagesByName", page).hide() : $(".fldImagesByName", page).show(), $("#chkSaveMetadataHidden", page).checked(config.SaveMetadataHidden), $("#txtMetadataPath", page).val(config.MetadataPath || ""), $("#txtMetadataNetworkPath", page).val(config.MetadataNetworkPath || ""), loading.hide() - } - - function loadMetadataConfig(page, config) { - $("#selectDateAdded", page).val(config.UseFileCreationTimeForDateAdded ? "1" : "0") - } - - function loadFanartConfig(page, config) { - $("#txtFanartApiKey", page).val(config.UserApiKey || "") - } - - function saveFanart(form) { - ApiClient.getNamedConfiguration("fanart").then(function(config) { - config.UserApiKey = $("#txtFanartApiKey", form).val(), ApiClient.updateNamedConfiguration("fanart", config) - }) - } - - function saveMetadata(form) { - ApiClient.getNamedConfiguration("metadata").then(function(config) { - config.UseFileCreationTimeForDateAdded = "1" === $("#selectDateAdded", form).val(), ApiClient.updateNamedConfiguration("metadata", config) - }) - } - - function alertText(options) { - require(["alert"], function(alert) { - alert(options) - }) - } - - function onSubmitFail(response) { - loading.hide(), response && 404 === response.status ? alertText("The metadata path entered could not be found. Please ensure the path is valid and try again.") : response && 500 === response.status && alertText("The metadata path entered is not valid. Please ensure the path exists and that Jellyfin server has write access to the folder.") - } - - function onSubmit() { - loading.show(); - var form = this; - return ApiClient.getServerConfiguration().then(function(config) { - config.SaveMetadataHidden = $("#chkSaveMetadataHidden", form).checked(), config.EnableTvDbUpdates = $("#chkEnableTvdbUpdates", form).checked(), config.EnableTmdbUpdates = $("#chkEnableTmdbUpdates", form).checked(), config.EnableFanArtUpdates = $("#chkEnableFanartUpdates", form).checked(), config.MetadataPath = $("#txtMetadataPath", form).val(), config.MetadataNetworkPath = $("#txtMetadataNetworkPath", form).val(), config.FanartApiKey = $("#txtFanartApiKey", form).val(), ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult, onSubmitFail) - }), saveMetadata(form), saveFanart(form), !1 - } - - function getTabs() { - return [{ - href: "library.html", - name: Globalize.translate("HeaderLibraries") - }, { - href: "librarydisplay.html", - name: Globalize.translate("TabDisplay") - }, { - href: "metadataimages.html", - name: Globalize.translate("TabMetadata") - }, { - href: "metadatanfo.html", - name: Globalize.translate("TabNfoSettings") - }, { - href: "librarysettings.html", - name: Globalize.translate("TabAdvanced") - }] - } - return function(view, params) { - $("#btnSelectMetadataPath", view).on("click.selectDirectory", function() { - require(["directorybrowser"], function(directoryBrowser) { - var picker = new directoryBrowser; - picker.show({ - path: $("#txtMetadataPath", view).val(), - networkSharePath: $("#txtMetadataNetworkPath", view).val(), - callback: function(path, networkPath) { - path && ($("#txtMetadataPath", view).val(path), $("#txtMetadataNetworkPath", view).val(networkPath)), picker.close() - }, - validateWriteable: !0, - header: Globalize.translate("HeaderSelectMetadataPath"), - instruction: Globalize.translate("HeaderSelectMetadataPathHelp"), - enableNetworkSharePath: !0 - }) - }) - }), $(".librarySettingsForm").off("submit", onSubmit).on("submit", onSubmit), view.addEventListener("viewshow", function() { - libraryMenu.setTabs("librarysetup", 4, getTabs), loading.show(); - var page = this; - ApiClient.getServerConfiguration().then(function(config) { - loadPage(page, config) - }), ApiClient.getNamedConfiguration("metadata").then(function(metadata) { - loadMetadataConfig(page, metadata) - }), ApiClient.getNamedConfiguration("fanart").then(function(metadata) { - loadFanartConfig(page, metadata) - }), ApiClient.getSystemInfo().then(function(info) { - "Windows" === info.OperatingSystem ? page.querySelector(".fldSaveMetadataHidden").classList.remove("hide") : page.querySelector(".fldSaveMetadataHidden").classList.add("hide") - }) - }) - } -}); diff --git a/src/dashboardgeneral.html b/src/dashboardgeneral.html index 16d170e62b..f41fc80d46 100644 --- a/src/dashboardgeneral.html +++ b/src/dashboardgeneral.html @@ -13,12 +13,16 @@
+
+ +
${LabelServerNameHelp}
+
${LabelPreferredDisplayLanguageHelp}
@@ -34,7 +38,7 @@
-

${Advanced}

+

${HeaderPaths}

@@ -44,6 +48,17 @@
${LabelCachePathHelp}
+ +
+
+
+ +
+ +
+
${LabelMetadataPathHelp}
+ +
@@ -62,6 +77,7 @@
+

${HeaderBranding}

${LabelLoginDisclaimerHelp}
diff --git a/src/devices/devices.html b/src/devices/devices.html index f79d7954fd..6997f42eda 100644 --- a/src/devices/devices.html +++ b/src/devices/devices.html @@ -1,8 +1,6 @@
-
-

${TabDevices}

@@ -11,9 +9,6 @@
- - -
diff --git a/src/dlnasettings.html b/src/dlnasettings.html index a3cb1f10fa..5eb5cd452d 100644 --- a/src/dlnasettings.html +++ b/src/dlnasettings.html @@ -10,11 +10,6 @@

${TabSettings}

${Help}
- -
- -
${LabelRemoteClientBitrateLimitHelp}
-
diff --git a/src/edititemmetadata.html b/src/edititemmetadata.html index adfd3568f5..86712a24fa 100644 --- a/src/edititemmetadata.html +++ b/src/edititemmetadata.html @@ -1,4 +1,4 @@ -
+