mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2024-11-17 19:08:18 -07:00
Merge branch 'release-10.3.z' into translations
This commit is contained in:
commit
ec8d0de8f1
9
.drone.yml
Normal file
9
.drone.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: eslint
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: run
|
||||||
|
image: nextcloudci/eslint:eslint-1
|
||||||
|
commands:
|
||||||
|
- ./run-eslint.sh
|
3
.eslintrc.yml
Normal file
3
.eslintrc.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
env:
|
||||||
|
browser: true
|
||||||
|
amd: true
|
35
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
35
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a bug report
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
<!-- A clear and concise description of what the bug is. -->
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
<!-- Steps to reproduce the behavior: -->
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
<!-- A clear and concise description of what you expected to happen. -->
|
||||||
|
|
||||||
|
**Logs**
|
||||||
|
<!-- Please paste any log errors. -->
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
<!-- If applicable, add screenshots to help explain your problem. -->
|
||||||
|
|
||||||
|
**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**
|
||||||
|
<!-- Add any other context about the problem here. -->
|
20
.github/ISSUE_TEMPLATE/enhancement-request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/enhancement-request.md
vendored
Normal file
@ -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.**
|
||||||
|
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
<!-- A clear and concise description of what you want to happen. -->
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
<!-- Add any other context or screenshots about the feature request here. -->
|
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest a new feature
|
||||||
|
title: ''
|
||||||
|
labels: feature
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the feature you'd like**
|
||||||
|
<!-- A clear and concise description of what you want to happen. -->
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
<!-- Add any other context or screenshots about the feature request here. -->
|
11
.github/pull_request_template.md
vendored
Normal file
11
.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<!--
|
||||||
|
Ensure your title is short, descriptive, and in the imperative mood (Fix X, Change Y, instead of Fixed X, Changed Y).
|
||||||
|
For a good inspiration of what to write in commit messages and PRs please review https://chris.beams.io/posts/git-commit/ and our https://jellyfin.readthedocs.io/en/latest/developer-docs/contributing/ page.
|
||||||
|
-->
|
||||||
|
|
||||||
|
**Changes**
|
||||||
|
<!-- Describe your changes here in 1-5 sentences. -->
|
||||||
|
|
||||||
|
**Issues**
|
||||||
|
<!-- Tag any issues that this PR solves here.
|
||||||
|
ex. Fixes # -->
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -71,9 +71,6 @@ coverage
|
|||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
.grunt
|
.grunt
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
|
||||||
bower_components
|
|
||||||
|
|
||||||
# node-waf configuration
|
# node-waf configuration
|
||||||
.lock-wscript
|
.lock-wscript
|
||||||
|
|
||||||
@ -573,3 +570,6 @@ ASALocalRun/
|
|||||||
healthchecksdb
|
healthchecksdb
|
||||||
|
|
||||||
# End of https://www.gitignore.io/api/node,rider,macos,linux,windows,visualstudio,visualstudiocode
|
# End of https://www.gitignore.io/api/node,rider,macos,linux,windows,visualstudio,visualstudiocode
|
||||||
|
|
||||||
|
# dist for webpack output
|
||||||
|
dist
|
@ -19,7 +19,8 @@
|
|||||||
- [nkmerrill](https://github.com/nkmerrill)
|
- [nkmerrill](https://github.com/nkmerrill)
|
||||||
- [TtheCreator](https://github.com/Tthecreator)
|
- [TtheCreator](https://github.com/Tthecreator)
|
||||||
- [RazeLighter777](https://github.com/RazeLighter777)
|
- [RazeLighter777](https://github.com/RazeLighter777)
|
||||||
- [anthonylavado](https://github.com/anthonylavado)
|
- [LogicalPhallacy](https://github.com/LogicalPhallacy)
|
||||||
|
- [thornbill](https://github.com/thornbill)
|
||||||
|
|
||||||
# Emby Contributors
|
# Emby Contributors
|
||||||
|
|
||||||
|
11
package.json
Normal file
11
package.json
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
}
|
18
run-eslint.sh
Executable file
18
run-eslint.sh
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# used this pull request for reference
|
||||||
|
# https://github.com/nextcloud/spreed/pull/48
|
||||||
|
ESLINT=$(which eslint || true)
|
||||||
|
if [ -z "$ESLINT" ]
|
||||||
|
then
|
||||||
|
echo "could not find eslint in $PATH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo checking scripts with $ESLINT
|
||||||
|
find -name "*.js" -print0 | xargs -0 $ESLINT
|
||||||
|
|
||||||
|
# use this line to test changes locally
|
||||||
|
#find src -name "*.js" -exec sh -c 'npx eslint $1' -- {} \;
|
@ -1,4 +1,4 @@
|
|||||||
<div id="addPluginPage" data-role="page" class="page type-interior pluginConfigurationPage" data-backbutton="true" data-require="emby-select,emby-collapse,emby-linkbutton">
|
<div id="addPluginPage" data-role="page" class="page type-interior pluginConfigurationPage" data-backbutton="true" data-require="emby-select,emby-collapse,emby-button">
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="content-primary">
|
<div class="content-primary">
|
||||||
@ -8,7 +8,7 @@
|
|||||||
<div class="verticalSection">
|
<div class="verticalSection">
|
||||||
<div class="sectionTitleContainer flex align-items-center">
|
<div class="sectionTitleContainer flex align-items-center">
|
||||||
<h1 class="sectionTitle pluginName"></h1>
|
<h1 class="sectionTitle pluginName"></h1>
|
||||||
<a is="emby-linkbutton" class="raised button-alt headerHelpButton" target="_blank" href="https://web.archive.org/web/20181216120305/https://github.com/MediaBrowser/Wiki/wiki/Plugins">${Help}</a>
|
<a is="emby-linkbutton" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.readthedocs.io/en/latest/administrator-docs/plugins/">${Help}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p id="tagline" style="font-style: italic;"></p>
|
<p id="tagline" style="font-style: italic;"></p>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<form class="manualServerForm" style="margin: 0 auto;">
|
<form class="manualServerForm" style="margin: 0 auto;">
|
||||||
<h1 style="text-align: left;">${HeaderConnectToServer}</h1>
|
<h1 style="text-align: left;">${HeaderConnectToServer}</h1>
|
||||||
<div class="inputContainer">
|
<div class="inputContainer">
|
||||||
<input is="emby-input" type="text" id="txtServerHost" required="required" label="${LabelServerHost}" />
|
<input is="emby-input" type="url" id="txtServerHost" required="required" label="${LabelServerHost}" />
|
||||||
<div class="fieldDescription" style="text-align: left;">${LabelServerHostHelp}</div>
|
<div class="fieldDescription" style="text-align: left;">${LabelServerHostHelp}</div>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
@ -19,4 +19,4 @@
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
<div id="appServicesPage" data-role="page" class="page type-interior appServicesPage withTabs fullWidthContent" data-require="scripts/appservices">
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div class="content-primary">
|
|
||||||
|
|
||||||
<div class="verticalSection">
|
|
||||||
|
|
||||||
<div class="sectionTitleContainer sectionTitleContainer-cards flex align-items-center">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards">${HeaderInstalledServices}</h2>
|
|
||||||
<a is="emby-linkbutton" class="raised button-alt headerHelpButton" target="_blank" href="https://web.archive.org/web/20181216120305/https://github.com/MediaBrowser/Wiki/wiki/Plugins">${Help}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="installedPlugins"></div>
|
|
||||||
</div>
|
|
||||||
<div class="verticalSection">
|
|
||||||
<h2 class="sectionTitle sectionTitle-cards">${HeaderAvailableServices}</h2>
|
|
||||||
<div class="catalog"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
8
src/availableplugins.html
Normal file
8
src/availableplugins.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<div id="pluginCatalogPage" data-role="page" class="page type-interior pluginConfigurationPage withTabs fullWidthContent">
|
||||||
|
<div>
|
||||||
|
<div class="content-primary">
|
||||||
|
<div id="noPlugins" class="hide">${MessageNoAvailablePlugins}</div>
|
||||||
|
<div id="pluginTiles" style="text-align:left;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -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";
|
"use strict";
|
||||||
|
|
||||||
|
if ("cordova" !== window.appMode && "android" !== window.appMode) {
|
||||||
|
return ApiClient;
|
||||||
|
}
|
||||||
|
|
||||||
function isLocalId(str) {
|
function isLocalId(str) {
|
||||||
return startsWith(str, localPrefix)
|
return startsWith(str, localPrefix)
|
||||||
}
|
}
|
53
src/bower_components/apiclient/appStorage.js
vendored
Normal file
53
src/bower_components/apiclient/appStorage.js
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
define([], function() {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function onCachePutFail(e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCache(instance) {
|
||||||
|
if (instance.cache) {
|
||||||
|
instance.cache.put("data", new Response(JSON.stringify(instance.localData))).catch(onCachePutFail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCacheOpened(result) {
|
||||||
|
this.cache = result;
|
||||||
|
this.localData = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function MyStore() {
|
||||||
|
|
||||||
|
this.setItem = function(name, value) {
|
||||||
|
localStorage.setItem(name, value);
|
||||||
|
|
||||||
|
if (this.localData && this.localData[name] !== value) {
|
||||||
|
this.localData[name] = value;
|
||||||
|
updateCache(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getItem = function(name) {
|
||||||
|
return localStorage.getItem(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.removeItem = function(name) {
|
||||||
|
localStorage.removeItem(name);
|
||||||
|
|
||||||
|
if (this.localData) {
|
||||||
|
delete this.localData[name];
|
||||||
|
updateCache(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (self.caches) {
|
||||||
|
self.caches.open("embydata").then(onCacheOpened.bind(this));
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Error opening cache: " + err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MyStore;
|
||||||
|
});
|
@ -269,12 +269,15 @@ define(["events", "apiclient", "appStorage"], function(events, apiClientFactory,
|
|||||||
});
|
});
|
||||||
resolve(servers)
|
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([])
|
onFinish([])
|
||||||
})
|
});
|
||||||
})
|
} else {
|
||||||
})
|
resolve([]);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertEndpointAddressToManualAddress(info) {
|
function convertEndpointAddressToManualAddress(info) {
|
3
src/bower_components/apiclient/package.json
vendored
Normal file
3
src/bower_components/apiclient/package.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"main": "apiclient.js"
|
||||||
|
}
|
@ -1,23 +0,0 @@
|
|||||||
define([], function() {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function MyStore() {}
|
|
||||||
|
|
||||||
function updateCache(instance) {
|
|
||||||
instance.cache.put("data", new Response(JSON.stringify(instance.localData)))
|
|
||||||
}
|
|
||||||
return MyStore.prototype.init = function() {
|
|
||||||
var instance = this;
|
|
||||||
return caches.open("embydata").then(function(result) {
|
|
||||||
instance.cache = result, instance.localData = {}
|
|
||||||
})
|
|
||||||
}, MyStore.prototype.setItem = function(name, value) {
|
|
||||||
if (this.localData) {
|
|
||||||
this.localData[name] !== value && (this.localData[name] = value, updateCache(this))
|
|
||||||
}
|
|
||||||
}, MyStore.prototype.getItem = function(name) {
|
|
||||||
if (this.localData) return this.localData[name]
|
|
||||||
}, MyStore.prototype.removeItem = function(name) {
|
|
||||||
this.localData && (this.localData[name] = null, delete this.localData[name], updateCache(this))
|
|
||||||
}, new MyStore
|
|
||||||
});
|
|
@ -1,37 +0,0 @@
|
|||||||
define([], function() {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function onCachePutFail(e) {
|
|
||||||
console.log(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateCache(instance) {
|
|
||||||
var cache = instance.cache;
|
|
||||||
cache && cache.put("data", new Response(JSON.stringify(instance.localData))).catch(onCachePutFail)
|
|
||||||
}
|
|
||||||
|
|
||||||
function onCacheOpened(result) {
|
|
||||||
this.cache = result, this.localData = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
function MyStore() {
|
|
||||||
try {
|
|
||||||
self.caches && caches.open("embydata").then(onCacheOpened.bind(this))
|
|
||||||
} catch (err) {
|
|
||||||
console.log("Error opening cache: " + err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return MyStore.prototype.setItem = function(name, value) {
|
|
||||||
localStorage.setItem(name, value);
|
|
||||||
var localData = this.localData;
|
|
||||||
if (localData) {
|
|
||||||
localData[name] !== value && (localData[name] = value, updateCache(this))
|
|
||||||
}
|
|
||||||
}, MyStore.prototype.getItem = function(name) {
|
|
||||||
return localStorage.getItem(name)
|
|
||||||
}, MyStore.prototype.removeItem = function(name) {
|
|
||||||
localStorage.removeItem(name);
|
|
||||||
var localData = this.localData;
|
|
||||||
localData && (localData[name] = null, delete localData[name], updateCache(this))
|
|
||||||
}, new MyStore
|
|
||||||
});
|
|
@ -1,14 +0,0 @@
|
|||||||
define([], function() {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function MyStore() {
|
|
||||||
this.localData = {}
|
|
||||||
}
|
|
||||||
return MyStore.prototype.setItem = function(name, value) {
|
|
||||||
this.localData[name] = value
|
|
||||||
}, MyStore.prototype.getItem = function(name) {
|
|
||||||
return this.localData[name]
|
|
||||||
}, MyStore.prototype.removeItem = function(name) {
|
|
||||||
this.localData[name] = null
|
|
||||||
}, new MyStore
|
|
||||||
});
|
|
@ -1,8 +0,0 @@
|
|||||||
define([], function() {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function FileUpload() {}
|
|
||||||
return FileUpload.prototype.upload = function(file, url) {
|
|
||||||
return Promise.reject()
|
|
||||||
}, FileUpload
|
|
||||||
});
|
|
@ -1,8 +0,0 @@
|
|||||||
define([], function() {
|
|
||||||
"use strict";
|
|
||||||
return {
|
|
||||||
findServers: function(timeoutMs) {
|
|
||||||
return Promise.resolve([])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
15
src/bower_components/emby-apiclient/wakeonlan.js
vendored
15
src/bower_components/emby-apiclient/wakeonlan.js
vendored
@ -1,15 +0,0 @@
|
|||||||
define([], function() {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function send(info) {
|
|
||||||
return Promise.reject()
|
|
||||||
}
|
|
||||||
|
|
||||||
function isSupported() {
|
|
||||||
return !1
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
send: send,
|
|
||||||
isSupported: isSupported
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,34 +0,0 @@
|
|||||||
define(['dialog', 'globalize'], function (dialog, globalize) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return function (text, title) {
|
|
||||||
|
|
||||||
var options;
|
|
||||||
if (typeof text === 'string') {
|
|
||||||
options = {
|
|
||||||
title: title,
|
|
||||||
text: text
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
options = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
var items = [];
|
|
||||||
|
|
||||||
items.push({
|
|
||||||
name: globalize.translate('ButtonGotIt'),
|
|
||||||
id: 'ok',
|
|
||||||
type: 'submit'
|
|
||||||
});
|
|
||||||
|
|
||||||
options.buttons = items;
|
|
||||||
|
|
||||||
return dialog(options).then(function (result) {
|
|
||||||
if (result === 'ok') {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.reject();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
@ -1,23 +0,0 @@
|
|||||||
define([], function () {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
function replaceAll(str, find, replace) {
|
|
||||||
|
|
||||||
return str.split(find).join(replace);
|
|
||||||
}
|
|
||||||
|
|
||||||
return function (options) {
|
|
||||||
|
|
||||||
if (typeof options === 'string') {
|
|
||||||
options = {
|
|
||||||
text: options
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var text = replaceAll(options.text || '', '<br/>', '\n');
|
|
||||||
|
|
||||||
alert(text);
|
|
||||||
|
|
||||||
return Promise.resolve();
|
|
||||||
};
|
|
||||||
});
|
|
@ -1,12 +0,0 @@
|
|||||||
define(['multi-download'], function (multiDownload) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return {
|
|
||||||
download: function (items) {
|
|
||||||
|
|
||||||
multiDownload(items.map(function (item) {
|
|
||||||
return item.url;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
@ -1,12 +0,0 @@
|
|||||||
define([], function () {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return {
|
|
||||||
fileExists: function (path) {
|
|
||||||
return Promise.reject();
|
|
||||||
},
|
|
||||||
directoryExists: function (path) {
|
|
||||||
return Promise.reject();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
@ -1,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
|
|
||||||
});
|
|
||||||
});
|
|
Binary file not shown.
Before Width: | Height: | Size: 38 KiB |
Binary file not shown.
Before Width: | Height: | Size: 38 KiB |
@ -1,80 +0,0 @@
|
|||||||
define(['playbackManager', 'itemHelper'], function (playbackManager, itemHelper) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function getRequirePromise(deps) {
|
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
|
|
||||||
require(deps, resolve);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function validatePlayback(options) {
|
|
||||||
|
|
||||||
var feature = 'playback';
|
|
||||||
if (options.item && (options.item.Type === 'TvChannel' || options.item.Type === 'Recording')) {
|
|
||||||
feature = 'livetv';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (feature === 'playback') {
|
|
||||||
var player = playbackManager.getCurrentPlayer();
|
|
||||||
if (player && !player.isLocalPlayer) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getRequirePromise(["registrationServices"]).then(function (registrationServices) {
|
|
||||||
|
|
||||||
return registrationServices.validateFeature(feature, options).then(function (result) {
|
|
||||||
|
|
||||||
if (result && result.enableTimeLimit) {
|
|
||||||
startAutoStopTimer();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var autoStopTimeout;
|
|
||||||
function startAutoStopTimer() {
|
|
||||||
stopAutoStopTimer();
|
|
||||||
autoStopTimeout = setTimeout(onAutoStopTimeout, 63000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onAutoStopTimeout() {
|
|
||||||
stopAutoStopTimer();
|
|
||||||
playbackManager.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopAutoStopTimer() {
|
|
||||||
|
|
||||||
var timeout = autoStopTimeout;
|
|
||||||
if (timeout) {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
autoStopTimeout = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function PlaybackValidation() {
|
|
||||||
|
|
||||||
this.name = 'Playback validation';
|
|
||||||
this.type = 'preplayintercept';
|
|
||||||
this.id = 'playbackvalidation';
|
|
||||||
this.order = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
PlaybackValidation.prototype.intercept = function (options) {
|
|
||||||
|
|
||||||
// Don't care about video backdrops, or theme music or any kind of non-fullscreen playback
|
|
||||||
if (!options.fullscreen) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.item && itemHelper.isLocalItem(options.item)) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
return validatePlayback(options);
|
|
||||||
};
|
|
||||||
|
|
||||||
return PlaybackValidation;
|
|
||||||
});
|
|
@ -1,25 +0,0 @@
|
|||||||
if (!Array.prototype.filter) {
|
|
||||||
Array.prototype.filter = function (fun /*, thisp*/) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
if (this == null)
|
|
||||||
throw new TypeError();
|
|
||||||
|
|
||||||
var t = Object(this);
|
|
||||||
var len = t.length >>> 0;
|
|
||||||
if (typeof fun != "function")
|
|
||||||
throw new TypeError();
|
|
||||||
|
|
||||||
var res = [];
|
|
||||||
var thisp = arguments[1];
|
|
||||||
for (var i = 0; i < len; i++) {
|
|
||||||
if (i in t) {
|
|
||||||
var val = t[i]; // in case fun mutates this
|
|
||||||
if (fun.call(thisp, val, i, t))
|
|
||||||
res.push(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
if (!Function.prototype.bind) {
|
|
||||||
Function.prototype.bind = function (oThis) {
|
|
||||||
if (typeof this !== 'function') {
|
|
||||||
// closest thing possible to the ECMAScript 5
|
|
||||||
// internal IsCallable function
|
|
||||||
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
|
||||||
}
|
|
||||||
|
|
||||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
|
||||||
fToBind = this,
|
|
||||||
fNOP = function () { },
|
|
||||||
fBound = function () {
|
|
||||||
return fToBind.apply(this instanceof fNOP
|
|
||||||
? this
|
|
||||||
: oThis,
|
|
||||||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.prototype) {
|
|
||||||
// Function.prototype doesn't have a prototype property
|
|
||||||
fNOP.prototype = this.prototype;
|
|
||||||
}
|
|
||||||
fBound.prototype = new fNOP();
|
|
||||||
|
|
||||||
return fBound;
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
if (typeof Object.assign != 'function') {
|
|
||||||
(function () {
|
|
||||||
Object.assign = function (target) {
|
|
||||||
'use strict';
|
|
||||||
if (target === undefined || target === null) {
|
|
||||||
throw new TypeError('Cannot convert undefined or null to object');
|
|
||||||
}
|
|
||||||
|
|
||||||
var output = Object(target);
|
|
||||||
for (var index = 1; index < arguments.length; index++) {
|
|
||||||
var source = arguments[index];
|
|
||||||
if (source !== undefined && source !== null) {
|
|
||||||
for (var nextKey in source) {
|
|
||||||
if (source.hasOwnProperty(nextKey)) {
|
|
||||||
output[nextKey] = source[nextKey];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
|
|
||||||
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
|
|
||||||
|
|
||||||
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
|
|
||||||
|
|
||||||
// MIT license
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
var lastTime = 0;
|
|
||||||
var vendors = ['ms', 'moz', 'webkit', 'o'];
|
|
||||||
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
|
||||||
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
|
|
||||||
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame']
|
|
||||||
|| window[vendors[x] + 'CancelRequestAnimationFrame'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!window.requestAnimationFrame)
|
|
||||||
window.requestAnimationFrame = function (callback, element) {
|
|
||||||
var currTime = new Date().getTime();
|
|
||||||
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
|
|
||||||
var id = window.setTimeout(function () { callback(currTime + timeToCall); },
|
|
||||||
timeToCall);
|
|
||||||
lastTime = currTime + timeToCall;
|
|
||||||
return id;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!window.cancelAnimationFrame)
|
|
||||||
window.cancelAnimationFrame = function (id) {
|
|
||||||
clearTimeout(id);
|
|
||||||
};
|
|
||||||
}());
|
|
@ -1,16 +0,0 @@
|
|||||||
define(['appSettings', 'loading', 'apphost', 'events', 'shell', 'globalize', 'dialogHelper', 'connectionManager', 'layoutManager', 'emby-button', 'emby-linkbutton'], function (appSettings, loading, appHost, events, shell, globalize, dialogHelper, connectionManager, layoutManager) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
function validateFeature(feature, options) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
function showPremiereInfo() {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
validateFeature: validateFeature,
|
|
||||||
showPremiereInfo: showPremiereInfo
|
|
||||||
};
|
|
||||||
});
|
|
@ -1,6 +0,0 @@
|
|||||||
self.addEventListener('sync', function (event) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
if (event.tag === 'emby-sync') {
|
|
||||||
}
|
|
||||||
});
|
|
21
src/bower_components/emby-webcomponents/shell.js
vendored
21
src/bower_components/emby-webcomponents/shell.js
vendored
@ -1,21 +0,0 @@
|
|||||||
define([], function () {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
return {
|
|
||||||
openUrl: function (url) {
|
|
||||||
window.open(url, '_blank');
|
|
||||||
},
|
|
||||||
canExec: false,
|
|
||||||
exec: function (options) {
|
|
||||||
// options.path
|
|
||||||
// options.arguments
|
|
||||||
return Promise.reject();
|
|
||||||
},
|
|
||||||
enableFullscreen: function () {
|
|
||||||
// do nothing since this is for native apps
|
|
||||||
},
|
|
||||||
disableFullscreen: function () {
|
|
||||||
// do nothing since this is for native apps
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
@ -1,355 +0,0 @@
|
|||||||
define(['apphost', 'userSettings', 'browser', 'events', 'pluginManager', 'backdrop', 'globalize', 'require', 'appSettings'], function (appHost, userSettings, browser, events, pluginManager, backdrop, globalize, require, appSettings) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var currentSkin;
|
|
||||||
|
|
||||||
function getCurrentSkin() {
|
|
||||||
return currentSkin;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRequirePromise(deps) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
|
|
||||||
require(deps, resolve);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadSkin(id) {
|
|
||||||
|
|
||||||
var newSkin = pluginManager.plugins().filter(function (p) {
|
|
||||||
return p.id === id;
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
if (!newSkin) {
|
|
||||||
newSkin = pluginManager.plugins().filter(function (p) {
|
|
||||||
return p.id === 'defaultskin';
|
|
||||||
})[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
var unloadPromise;
|
|
||||||
|
|
||||||
if (currentSkin) {
|
|
||||||
|
|
||||||
if (currentSkin.id === newSkin.id) {
|
|
||||||
// Nothing to do, it's already the active skin
|
|
||||||
return Promise.resolve(currentSkin);
|
|
||||||
}
|
|
||||||
unloadPromise = unloadSkin(currentSkin);
|
|
||||||
} else {
|
|
||||||
unloadPromise = Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
return unloadPromise.then(function () {
|
|
||||||
var deps = newSkin.getDependencies();
|
|
||||||
|
|
||||||
console.log('Loading skin dependencies');
|
|
||||||
|
|
||||||
return getRequirePromise(deps).then(function () {
|
|
||||||
|
|
||||||
console.log('Skin dependencies loaded');
|
|
||||||
|
|
||||||
var strings = newSkin.getTranslations ? newSkin.getTranslations() : [];
|
|
||||||
|
|
||||||
return globalize.loadStrings({
|
|
||||||
|
|
||||||
name: newSkin.id,
|
|
||||||
strings: strings
|
|
||||||
|
|
||||||
}).then(function () {
|
|
||||||
|
|
||||||
globalize.defaultModule(newSkin.id);
|
|
||||||
return loadSkinHeader(newSkin);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function unloadSkin(skin) {
|
|
||||||
|
|
||||||
unloadTheme();
|
|
||||||
backdrop.clear();
|
|
||||||
|
|
||||||
console.log('Unloading skin: ' + skin.name);
|
|
||||||
|
|
||||||
// TODO: unload css
|
|
||||||
|
|
||||||
return skin.unload().then(function () {
|
|
||||||
document.dispatchEvent(new CustomEvent("skinunload", {
|
|
||||||
detail: {
|
|
||||||
name: skin.name
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadSkinHeader(skin) {
|
|
||||||
|
|
||||||
return getSkinHeader(skin).then(function (headerHtml) {
|
|
||||||
|
|
||||||
document.querySelector('.skinHeader').innerHTML = headerHtml;
|
|
||||||
|
|
||||||
currentSkin = skin;
|
|
||||||
skin.load();
|
|
||||||
|
|
||||||
return skin;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var cacheParam = new Date().getTime();
|
|
||||||
|
|
||||||
function getSkinHeader(skin) {
|
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
|
|
||||||
if (!skin.getHeaderTemplate) {
|
|
||||||
resolve('');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var xhr = new XMLHttpRequest();
|
|
||||||
|
|
||||||
var url = skin.getHeaderTemplate();
|
|
||||||
url += url.indexOf('?') === -1 ? '?' : '&';
|
|
||||||
url += 'v=' + cacheParam;
|
|
||||||
|
|
||||||
xhr.open('GET', url, true);
|
|
||||||
|
|
||||||
xhr.onload = function (e) {
|
|
||||||
if (this.status < 400) {
|
|
||||||
resolve(this.response);
|
|
||||||
} else {
|
|
||||||
resolve('');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadUserSkin(options) {
|
|
||||||
|
|
||||||
var skin = userSettings.get('skin', false) || 'defaultskin';
|
|
||||||
|
|
||||||
loadSkin(skin).then(function (skin) {
|
|
||||||
|
|
||||||
options = options || {};
|
|
||||||
if (options.start) {
|
|
||||||
Emby.Page.invokeShortcut(options.start);
|
|
||||||
} else {
|
|
||||||
Emby.Page.goHome();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
events.on(userSettings, 'change', function (e, name) {
|
|
||||||
if (name === 'skin' || name === 'language') {
|
|
||||||
loadUserSkin();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var themeStyleElement;
|
|
||||||
var currentThemeId;
|
|
||||||
function unloadTheme() {
|
|
||||||
var elem = themeStyleElement;
|
|
||||||
if (elem) {
|
|
||||||
|
|
||||||
elem.parentNode.removeChild(elem);
|
|
||||||
themeStyleElement = null;
|
|
||||||
currentThemeId = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getThemes() {
|
|
||||||
|
|
||||||
if (currentSkin.getThemes) {
|
|
||||||
return currentSkin.getThemes();
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
var skinManager = {
|
|
||||||
getCurrentSkin: getCurrentSkin,
|
|
||||||
loadSkin: loadSkin,
|
|
||||||
loadUserSkin: loadUserSkin,
|
|
||||||
getThemes: getThemes
|
|
||||||
};
|
|
||||||
|
|
||||||
function onRegistrationSuccess() {
|
|
||||||
appSettings.set('appthemesregistered', 'true');
|
|
||||||
}
|
|
||||||
|
|
||||||
function onRegistrationFailure() {
|
|
||||||
appSettings.set('appthemesregistered', 'false');
|
|
||||||
}
|
|
||||||
|
|
||||||
function isRegistered() {
|
|
||||||
|
|
||||||
getRequirePromise(['registrationServices']).then(function (registrationServices) {
|
|
||||||
registrationServices.validateFeature('themes', {
|
|
||||||
|
|
||||||
showDialog: false
|
|
||||||
|
|
||||||
}).then(onRegistrationSuccess, onRegistrationFailure);
|
|
||||||
});
|
|
||||||
|
|
||||||
return appSettings.get('appthemesregistered') !== 'false';
|
|
||||||
}
|
|
||||||
|
|
||||||
function getThemeStylesheetInfo(id, requiresRegistration, isDefaultProperty) {
|
|
||||||
|
|
||||||
var themes = skinManager.getThemes();
|
|
||||||
var defaultTheme;
|
|
||||||
var selectedTheme;
|
|
||||||
|
|
||||||
for (var i = 0, length = themes.length; i < length; i++) {
|
|
||||||
|
|
||||||
var theme = themes[i];
|
|
||||||
if (theme[isDefaultProperty]) {
|
|
||||||
defaultTheme = theme;
|
|
||||||
}
|
|
||||||
if (id === theme.id) {
|
|
||||||
selectedTheme = theme;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
selectedTheme = selectedTheme || defaultTheme;
|
|
||||||
|
|
||||||
if (selectedTheme.id !== defaultTheme.id && requiresRegistration && !isRegistered()) {
|
|
||||||
selectedTheme = defaultTheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
var embyWebComponentsBowerPath = 'bower_components/emby-webcomponents';
|
|
||||||
|
|
||||||
return {
|
|
||||||
stylesheetPath: require.toUrl(embyWebComponentsBowerPath + '/themes/' + selectedTheme.id + '/theme.css'),
|
|
||||||
themeId: selectedTheme.id
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var themeResources = {};
|
|
||||||
var lastSound = 0;
|
|
||||||
var currentSound;
|
|
||||||
|
|
||||||
function loadThemeResources(id) {
|
|
||||||
|
|
||||||
lastSound = 0;
|
|
||||||
|
|
||||||
if (currentSound) {
|
|
||||||
currentSound.stop();
|
|
||||||
currentSound = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
backdrop.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
function onThemeLoaded() {
|
|
||||||
document.documentElement.classList.remove('preload');
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
var color = getComputedStyle(document.querySelector('.skinHeader')).getPropertyValue("background-color");
|
|
||||||
|
|
||||||
if (color) {
|
|
||||||
appHost.setThemeColor(color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.log('Error setting theme color: ' + err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
skinManager.setTheme = function (id, context) {
|
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
|
|
||||||
var requiresRegistration = true;
|
|
||||||
|
|
||||||
if (currentThemeId && currentThemeId === id) {
|
|
||||||
resolve();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var isDefaultProperty = context === 'serverdashboard' ? 'isDefaultServerDashboard' : 'isDefault';
|
|
||||||
var info = getThemeStylesheetInfo(id, requiresRegistration, isDefaultProperty);
|
|
||||||
|
|
||||||
if (currentThemeId && currentThemeId === info.themeId) {
|
|
||||||
resolve();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var linkUrl = info.stylesheetPath;
|
|
||||||
|
|
||||||
unloadTheme();
|
|
||||||
|
|
||||||
var link = document.createElement('link');
|
|
||||||
|
|
||||||
link.setAttribute('rel', 'stylesheet');
|
|
||||||
link.setAttribute('type', 'text/css');
|
|
||||||
link.onload = function () {
|
|
||||||
|
|
||||||
onThemeLoaded();
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
|
|
||||||
link.setAttribute('href', linkUrl);
|
|
||||||
document.head.appendChild(link);
|
|
||||||
themeStyleElement = link;
|
|
||||||
currentThemeId = info.themeId;
|
|
||||||
loadThemeResources(info.themeId);
|
|
||||||
|
|
||||||
onViewBeforeShow({});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function onViewBeforeShow(e) {
|
|
||||||
|
|
||||||
if (e.detail && e.detail.type === 'video-osd') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (themeResources.backdrop) {
|
|
||||||
|
|
||||||
backdrop.setBackdrop(themeResources.backdrop);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!browser.mobile && userSettings.enableThemeSongs()) {
|
|
||||||
if (lastSound === 0) {
|
|
||||||
|
|
||||||
if (themeResources.themeSong) {
|
|
||||||
playSound(themeResources.themeSong);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if ((new Date().getTime() - lastSound) > 30000) {
|
|
||||||
if (themeResources.effect) {
|
|
||||||
playSound(themeResources.effect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('viewshow', onViewBeforeShow);
|
|
||||||
|
|
||||||
function playSound(path, volume) {
|
|
||||||
|
|
||||||
lastSound = new Date().getTime();
|
|
||||||
|
|
||||||
require(['howler'], function (howler) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
var sound = new Howl({
|
|
||||||
src: [path],
|
|
||||||
volume: volume || 0.1
|
|
||||||
});
|
|
||||||
|
|
||||||
sound.play();
|
|
||||||
currentSound = sound;
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.log('Error playing sound: ' + err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return skinManager;
|
|
||||||
});
|
|
@ -1,188 +0,0 @@
|
|||||||
define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby-button'], function (connectionManager, serverNotifications, events, globalize, EmbyButtonPrototype) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
function onClick(e) {
|
|
||||||
|
|
||||||
var button = this;
|
|
||||||
var id = button.getAttribute('data-id');
|
|
||||||
var serverId = button.getAttribute('data-serverid');
|
|
||||||
var apiClient = connectionManager.getApiClient(serverId);
|
|
||||||
|
|
||||||
if (!button.classList.contains('downloadbutton-on')) {
|
|
||||||
|
|
||||||
require(['syncDialog'], function (syncDialog) {
|
|
||||||
syncDialog.showMenu({
|
|
||||||
|
|
||||||
items: [id],
|
|
||||||
mode: 'download',
|
|
||||||
serverId: serverId
|
|
||||||
|
|
||||||
}).then(function () {
|
|
||||||
|
|
||||||
button.dispatchEvent(new CustomEvent('download', {
|
|
||||||
cancelable: false
|
|
||||||
}));
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
require(['confirm'], function (confirm) {
|
|
||||||
|
|
||||||
confirm({
|
|
||||||
|
|
||||||
text: globalize.translate('ConfirmRemoveDownload'),
|
|
||||||
confirmText: globalize.translate('RemoveDownload'),
|
|
||||||
cancelText: globalize.translate('KeepDownload'),
|
|
||||||
primary: 'cancel'
|
|
||||||
|
|
||||||
}).then(function () {
|
|
||||||
apiClient.cancelSyncItems([id]);
|
|
||||||
|
|
||||||
button.dispatchEvent(new CustomEvent('download-cancel', {
|
|
||||||
cancelable: false
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateSyncStatus(button, syncPercent) {
|
|
||||||
|
|
||||||
var icon = button.iconElement;
|
|
||||||
if (!icon) {
|
|
||||||
button.iconElement = button.querySelector('i');
|
|
||||||
icon = button.iconElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (syncPercent != null) {
|
|
||||||
button.classList.add('downloadbutton-on');
|
|
||||||
|
|
||||||
if (icon) {
|
|
||||||
icon.classList.add('downloadbutton-icon-on');
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
button.classList.remove('downloadbutton-on');
|
|
||||||
|
|
||||||
if (icon) {
|
|
||||||
icon.classList.remove('downloadbutton-icon-on');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((syncPercent || 0) >= 100) {
|
|
||||||
button.classList.add('downloadbutton-complete');
|
|
||||||
|
|
||||||
if (icon) {
|
|
||||||
icon.classList.add('downloadbutton-icon-complete');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
button.classList.remove('downloadbutton-complete');
|
|
||||||
|
|
||||||
if (icon) {
|
|
||||||
icon.classList.remove('downloadbutton-icon-complete');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var text;
|
|
||||||
if ((syncPercent || 0) >= 100) {
|
|
||||||
text = globalize.translate('Downloaded');
|
|
||||||
} else if (syncPercent != null) {
|
|
||||||
text = globalize.translate('Downloading');
|
|
||||||
} else {
|
|
||||||
text = globalize.translate('Download');
|
|
||||||
}
|
|
||||||
|
|
||||||
var textElement = button.querySelector('.emby-downloadbutton-downloadtext');
|
|
||||||
if (textElement) {
|
|
||||||
textElement.innerHTML = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.title = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearEvents(button) {
|
|
||||||
|
|
||||||
button.removeEventListener('click', onClick);
|
|
||||||
}
|
|
||||||
|
|
||||||
function bindEvents(button) {
|
|
||||||
|
|
||||||
clearEvents(button);
|
|
||||||
|
|
||||||
button.addEventListener('click', onClick);
|
|
||||||
}
|
|
||||||
|
|
||||||
var EmbyDownloadButtonPrototype = Object.create(EmbyButtonPrototype);
|
|
||||||
|
|
||||||
EmbyDownloadButtonPrototype.createdCallback = function () {
|
|
||||||
|
|
||||||
// base method
|
|
||||||
if (EmbyButtonPrototype.createdCallback) {
|
|
||||||
EmbyButtonPrototype.createdCallback.call(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
EmbyDownloadButtonPrototype.attachedCallback = function () {
|
|
||||||
|
|
||||||
// base method
|
|
||||||
if (EmbyButtonPrototype.attachedCallback) {
|
|
||||||
EmbyButtonPrototype.attachedCallback.call(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
var itemId = this.getAttribute('data-id');
|
|
||||||
var serverId = this.getAttribute('data-serverid');
|
|
||||||
if (itemId && serverId) {
|
|
||||||
|
|
||||||
bindEvents(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
EmbyDownloadButtonPrototype.detachedCallback = function () {
|
|
||||||
|
|
||||||
// base method
|
|
||||||
if (EmbyButtonPrototype.detachedCallback) {
|
|
||||||
EmbyButtonPrototype.detachedCallback.call(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearEvents(this);
|
|
||||||
|
|
||||||
this.iconElement = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
function fetchAndUpdate(button, item) {
|
|
||||||
|
|
||||||
connectionManager.getApiClient(item.ServerId).getSyncStatus(item.Id).then(function (result) {
|
|
||||||
|
|
||||||
updateSyncStatus(button, result.Progress);
|
|
||||||
|
|
||||||
}, function () {
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
EmbyDownloadButtonPrototype.setItem = function (item) {
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
|
|
||||||
this.setAttribute('data-id', item.Id);
|
|
||||||
this.setAttribute('data-serverid', item.ServerId);
|
|
||||||
|
|
||||||
fetchAndUpdate(this, item);
|
|
||||||
|
|
||||||
bindEvents(this);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
this.removeAttribute('data-id');
|
|
||||||
this.removeAttribute('data-serverid');
|
|
||||||
clearEvents(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
document.registerElement('emby-downloadbutton', {
|
|
||||||
prototype: EmbyDownloadButtonPrototype,
|
|
||||||
extends: 'button'
|
|
||||||
});
|
|
||||||
});
|
|
736
src/bower_components/emby-webcomponents/sync/sync.js
vendored
736
src/bower_components/emby-webcomponents/sync/sync.js
vendored
@ -1,736 +0,0 @@
|
|||||||
define(['apphost', 'globalize', 'connectionManager', 'layoutManager', 'focusManager', 'scrollHelper', 'appSettings', 'registrationServices', 'dialogHelper', 'paper-icon-button-light', 'formDialogStyle'], function (appHost, globalize, connectionManager, layoutManager, focusManager, scrollHelper, appSettings, registrationServices, dialogHelper) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var currentDialogOptions;
|
|
||||||
|
|
||||||
function submitJob(dlg, apiClient, userId, syncOptions, form) {
|
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
throw new Error('userId cannot be null');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!syncOptions) {
|
|
||||||
throw new Error('syncOptions cannot be null');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!form) {
|
|
||||||
throw new Error('form cannot be null');
|
|
||||||
}
|
|
||||||
|
|
||||||
var selectSyncTarget = form.querySelector('#selectSyncTarget');
|
|
||||||
var target = selectSyncTarget ? selectSyncTarget.value : null;
|
|
||||||
|
|
||||||
if (!target) {
|
|
||||||
|
|
||||||
require(['toast'], function (toast) {
|
|
||||||
toast(globalize.translate('PleaseSelectDeviceToSyncTo'));
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
|
|
||||||
userId: userId,
|
|
||||||
TargetId: target,
|
|
||||||
|
|
||||||
ParentId: syncOptions.ParentId,
|
|
||||||
Category: syncOptions.Category
|
|
||||||
};
|
|
||||||
|
|
||||||
setJobValues(options, form);
|
|
||||||
|
|
||||||
if (syncOptions.items && syncOptions.items.length) {
|
|
||||||
options.ItemIds = (syncOptions.items || []).map(function (i) {
|
|
||||||
return i.Id || i;
|
|
||||||
}).join(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
apiClient.ajax({
|
|
||||||
|
|
||||||
type: "POST",
|
|
||||||
url: apiClient.getUrl("Sync/Jobs"),
|
|
||||||
data: JSON.stringify(options),
|
|
||||||
contentType: "application/json",
|
|
||||||
dataType: 'json'
|
|
||||||
|
|
||||||
}).then(function () {
|
|
||||||
|
|
||||||
dialogHelper.close(dlg);
|
|
||||||
require(['toast'], function (toast) {
|
|
||||||
|
|
||||||
showSubmissionToast(target, apiClient);
|
|
||||||
|
|
||||||
if (syncOptions.mode === 'download') {
|
|
||||||
syncNow();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function showSubmissionToast(targetId, apiClient) {
|
|
||||||
|
|
||||||
require(['toast'], function (toast) {
|
|
||||||
|
|
||||||
var msg = targetId === apiClient.deviceId() ?
|
|
||||||
globalize.translate('DownloadingDots') :
|
|
||||||
globalize.translate('SyncingDots');
|
|
||||||
|
|
||||||
toast(msg);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function syncNow() {
|
|
||||||
require(['localsync'], function (localSync) {
|
|
||||||
localSync.sync();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function submitQuickSyncJob(apiClient, userId, targetId, syncOptions) {
|
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
throw new Error('userId cannot be null');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!syncOptions) {
|
|
||||||
throw new Error('syncOptions cannot be null');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!targetId) {
|
|
||||||
throw new Error('targetId cannot be null');
|
|
||||||
}
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
|
|
||||||
userId: userId,
|
|
||||||
TargetId: targetId,
|
|
||||||
|
|
||||||
ParentId: syncOptions.ParentId,
|
|
||||||
Category: syncOptions.Category,
|
|
||||||
Quality: syncOptions.Quality,
|
|
||||||
Bitrate: syncOptions.Bitrate
|
|
||||||
};
|
|
||||||
|
|
||||||
if (syncOptions.items && syncOptions.items.length) {
|
|
||||||
options.ItemIds = (syncOptions.items || []).map(function (i) {
|
|
||||||
return i.Id || i;
|
|
||||||
}).join(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiClient.ajax({
|
|
||||||
|
|
||||||
type: "POST",
|
|
||||||
url: apiClient.getUrl("Sync/Jobs"),
|
|
||||||
data: JSON.stringify(options),
|
|
||||||
contentType: "application/json",
|
|
||||||
dataType: 'json'
|
|
||||||
|
|
||||||
}).then(function () {
|
|
||||||
|
|
||||||
require(['toast'], function (toast) {
|
|
||||||
|
|
||||||
showSubmissionToast(targetId, apiClient);
|
|
||||||
|
|
||||||
if (syncOptions.mode === 'download') {
|
|
||||||
syncNow();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setJobValues(job, form) {
|
|
||||||
|
|
||||||
var txtBitrate = form.querySelector('#txtBitrate');
|
|
||||||
var bitrate = txtBitrate ? txtBitrate.value : null;
|
|
||||||
|
|
||||||
if (bitrate) {
|
|
||||||
bitrate = parseFloat(bitrate) * 1000000;
|
|
||||||
}
|
|
||||||
job.Bitrate = bitrate;
|
|
||||||
|
|
||||||
var selectQuality = form.querySelector('#selectQuality');
|
|
||||||
if (selectQuality) {
|
|
||||||
job.Quality = selectQuality.value;
|
|
||||||
|
|
||||||
appSettings.set('sync-lastquality', job.Quality || '');
|
|
||||||
}
|
|
||||||
|
|
||||||
var selectProfile = form.querySelector('#selectProfile');
|
|
||||||
if (selectProfile) {
|
|
||||||
job.Profile = selectProfile.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
var txtItemLimit = form.querySelector('#txtItemLimit');
|
|
||||||
if (txtItemLimit) {
|
|
||||||
job.ItemLimit = txtItemLimit.value || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var chkSyncNewContent = form.querySelector('#chkSyncNewContent');
|
|
||||||
if (chkSyncNewContent) {
|
|
||||||
job.SyncNewContent = chkSyncNewContent.checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
var chkUnwatchedOnly = form.querySelector('#chkUnwatchedOnly');
|
|
||||||
if (chkUnwatchedOnly) {
|
|
||||||
job.UnwatchedOnly = chkUnwatchedOnly.checked;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderForm(options) {
|
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
|
|
||||||
require(['emby-checkbox', 'emby-input', 'emby-select'], function () {
|
|
||||||
|
|
||||||
renderFormInternal(options, connectionManager.deviceId(), resolve);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderFormInternal(options, defaultTargetId, resolve) {
|
|
||||||
|
|
||||||
var elem = options.elem;
|
|
||||||
var dialogOptions = options.dialogOptions;
|
|
||||||
|
|
||||||
var targets = dialogOptions.Targets;
|
|
||||||
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
var mode = options.mode;
|
|
||||||
var targetContainerClass = mode === 'download' ? ' hide' : '';
|
|
||||||
|
|
||||||
var syncTargetLabel = mode === 'convert' ? globalize.translate('LabelConvertTo') : globalize.translate('LabelSyncTo');
|
|
||||||
|
|
||||||
if (options.readOnlySyncTarget) {
|
|
||||||
html += '<div class="inputContainer' + targetContainerClass + '">';
|
|
||||||
html += '<input is="emby-input" type="text" id="selectSyncTarget" readonly label="' + syncTargetLabel + '"/>';
|
|
||||||
html += '</div>';
|
|
||||||
} else {
|
|
||||||
html += '<div class="selectContainer' + targetContainerClass + '">';
|
|
||||||
html += '<select is="emby-select" id="selectSyncTarget" required="required" label="' + syncTargetLabel + '">';
|
|
||||||
|
|
||||||
html += targets.map(function (t) {
|
|
||||||
|
|
||||||
var isSelected = defaultTargetId === t.Id;
|
|
||||||
var selectedHtml = isSelected ? ' selected="selected"' : '';
|
|
||||||
return '<option' + selectedHtml + ' value="' + t.Id + '">' + t.Name + '</option>';
|
|
||||||
|
|
||||||
}).join('');
|
|
||||||
html += '</select>';
|
|
||||||
if (!targets.length) {
|
|
||||||
html += '<div class="fieldDescription">' + globalize.translate('LabelSyncNoTargetsHelp') + '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (appHost.supports('externallinks')) {
|
|
||||||
html += '<div class="fieldDescription"><a is="emby-linkbutton" class="button-link lnkLearnMore" href="https://github.com/MediaBrowser/Wiki/wiki/Sync" target="_blank">' + globalize.translate('LearnMore') + '</a></div>';
|
|
||||||
}
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<div class="fldProfile selectContainer hide">';
|
|
||||||
html += '<select is="emby-select" id="selectProfile" label="' + globalize.translate('LabelProfile') + '">';
|
|
||||||
html += '</select>';
|
|
||||||
html += '<div class="fieldDescription profileDescription"></div>';
|
|
||||||
html += '</div>';
|
|
||||||
|
|
||||||
html += '<div class="fldQuality selectContainer hide">';
|
|
||||||
html += '<select is="emby-select" id="selectQuality" required="required" label="' + globalize.translate('LabelQuality') + '">';
|
|
||||||
html += '</select>';
|
|
||||||
html += '<div class="fieldDescription qualityDescription"></div>';
|
|
||||||
html += '</div>';
|
|
||||||
|
|
||||||
html += '<div class="fldBitrate inputContainer hide">';
|
|
||||||
html += '<input is="emby-input" type="number" step=".1" min=".1" id="txtBitrate" label="' + globalize.translate('LabelBitrateMbps') + '"/>';
|
|
||||||
html += '</div>';
|
|
||||||
|
|
||||||
if (dialogOptions.Options.indexOf('UnwatchedOnly') !== -1) {
|
|
||||||
html += '<div class="checkboxContainer checkboxContainer-withDescription">';
|
|
||||||
html += '<label>';
|
|
||||||
html += '<input is="emby-checkbox" type="checkbox" id="chkUnwatchedOnly"/>';
|
|
||||||
|
|
||||||
if (mode === 'convert') {
|
|
||||||
html += '<span>' + globalize.translate('ConvertUnwatchedVideosOnly') + '</span>';
|
|
||||||
} else {
|
|
||||||
html += '<span>' + globalize.translate('SyncUnwatchedVideosOnly') + '</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</label>';
|
|
||||||
|
|
||||||
if (mode === 'convert') {
|
|
||||||
html += '<div class="fieldDescription checkboxFieldDescription">' + globalize.translate('ConvertUnwatchedVideosOnlyHelp') + '</div>';
|
|
||||||
} else {
|
|
||||||
html += '<div class="fieldDescription checkboxFieldDescription">' + globalize.translate('SyncUnwatchedVideosOnlyHelp') + '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dialogOptions.Options.indexOf('SyncNewContent') !== -1) {
|
|
||||||
html += '<div class="checkboxContainer checkboxContainer-withDescription">';
|
|
||||||
html += '<label>';
|
|
||||||
html += '<input is="emby-checkbox" type="checkbox" id="chkSyncNewContent"/>';
|
|
||||||
|
|
||||||
if (mode === 'convert') {
|
|
||||||
html += '<span>' + globalize.translate('AutomaticallyConvertNewContent') + '</span>';
|
|
||||||
} else {
|
|
||||||
html += '<span>' + globalize.translate('AutomaticallySyncNewContent') + '</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</label>';
|
|
||||||
|
|
||||||
if (mode === 'convert') {
|
|
||||||
html += '<div class="fieldDescription checkboxFieldDescription">' + globalize.translate('AutomaticallyConvertNewContentHelp') + '</div>';
|
|
||||||
} else {
|
|
||||||
html += '<div class="fieldDescription checkboxFieldDescription">' + globalize.translate('AutomaticallySyncNewContentHelp') + '</div>';
|
|
||||||
}
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dialogOptions.Options.indexOf('ItemLimit') !== -1) {
|
|
||||||
html += '<div class="inputContainer">';
|
|
||||||
html += '<input is="emby-input" type="number" step="1" min="1" id="txtItemLimit" label="' + globalize.translate('LabelItemLimit') + '"/>';
|
|
||||||
|
|
||||||
if (mode === 'convert') {
|
|
||||||
html += '<div class="fieldDescription">' + globalize.translate('ConvertItemLimitHelp') + '</div>';
|
|
||||||
} else {
|
|
||||||
html += '<div class="fieldDescription">' + globalize.translate('DownloadItemLimitHelp') + '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
//html += '</div>';
|
|
||||||
//html += '</div>';
|
|
||||||
|
|
||||||
elem.innerHTML = html;
|
|
||||||
|
|
||||||
var selectSyncTarget = elem.querySelector('#selectSyncTarget');
|
|
||||||
if (selectSyncTarget) {
|
|
||||||
selectSyncTarget.addEventListener('change', function () {
|
|
||||||
loadQualityOptions(elem, this.value, options.dialogOptionsFn).then(resolve);
|
|
||||||
});
|
|
||||||
selectSyncTarget.dispatchEvent(new CustomEvent('change', {
|
|
||||||
bubbles: true
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
var selectProfile = elem.querySelector('#selectProfile');
|
|
||||||
if (selectProfile) {
|
|
||||||
selectProfile.addEventListener('change', function () {
|
|
||||||
onProfileChange(elem, this.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (dialogOptions.ProfileOptions.length) {
|
|
||||||
selectProfile.dispatchEvent(new CustomEvent('change', {
|
|
||||||
bubbles: true
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var selectQuality = elem.querySelector('#selectQuality');
|
|
||||||
if (selectQuality) {
|
|
||||||
selectQuality.addEventListener('change', function () {
|
|
||||||
onQualityChange(elem, this.value);
|
|
||||||
});
|
|
||||||
selectQuality.dispatchEvent(new CustomEvent('change', {
|
|
||||||
bubbles: true
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// This isn't ideal, but allow time for the change handlers above to run
|
|
||||||
setTimeout(function () {
|
|
||||||
focusManager.autoFocus(elem);
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
function showWifiMessage() {
|
|
||||||
|
|
||||||
require(['dialog', 'appRouter'], function (dialog, appRouter) {
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
|
|
||||||
title: globalize.translate('HeaderWaitingForWifi'),
|
|
||||||
text: globalize.translate('WifiRequiredToDownload')
|
|
||||||
};
|
|
||||||
|
|
||||||
var items = [];
|
|
||||||
|
|
||||||
items.push({
|
|
||||||
name: options.confirmText || globalize.translate('ButtonOk'),
|
|
||||||
id: 'ok',
|
|
||||||
type: 'submit'
|
|
||||||
});
|
|
||||||
|
|
||||||
items.push({
|
|
||||||
name: options.cancelText || globalize.translate('HeaderDownloadSettings'),
|
|
||||||
id: 'downloadsettings',
|
|
||||||
type: 'cancel'
|
|
||||||
});
|
|
||||||
|
|
||||||
options.buttons = items;
|
|
||||||
|
|
||||||
dialog(options).then(function (result) {
|
|
||||||
|
|
||||||
if (result === 'ok') {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
if (result === 'downloadsettings') {
|
|
||||||
appRouter.show(appRouter.getRouteUrl('downloadsettings'));
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.reject();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateNetwork() {
|
|
||||||
|
|
||||||
var network = navigator.connection ? navigator.connection.type : null;
|
|
||||||
|
|
||||||
switch (network) {
|
|
||||||
|
|
||||||
case 'cellular':
|
|
||||||
case 'bluetooth':
|
|
||||||
showWifiMessage();
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showSyncMenu(options) {
|
|
||||||
|
|
||||||
if (options.mode === 'download' && appSettings.syncOnlyOnWifi() && !validateNetwork()) {
|
|
||||||
return Promise.reject();
|
|
||||||
}
|
|
||||||
|
|
||||||
return registrationServices.validateFeature('sync').then(function () {
|
|
||||||
return showSyncMenuInternal(options);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function enableAutoSync(options) {
|
|
||||||
|
|
||||||
if (options.mode !== 'download') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var firstItem = (options.items || [])[0] || {};
|
|
||||||
|
|
||||||
if (firstItem.Type === 'Audio') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (firstItem.Type === 'MusicAlbum') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (firstItem.Type === 'MusicArtist') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (firstItem.Type === 'MusicGenre') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (firstItem.Type === 'Playlist' && firstItem.MediaType === 'Audio') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function showSyncMenuInternal(options) {
|
|
||||||
|
|
||||||
var apiClient = connectionManager.getApiClient(options.serverId);
|
|
||||||
var userId = apiClient.getCurrentUserId();
|
|
||||||
|
|
||||||
if (enableAutoSync(options)) {
|
|
||||||
|
|
||||||
return submitQuickSyncJob(apiClient, userId, apiClient.deviceId(), {
|
|
||||||
items: options.items,
|
|
||||||
Quality: 'custom',
|
|
||||||
Bitrate: appSettings.maxStaticMusicBitrate()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var dialogOptionsFn = getTargetDialogOptionsFn(apiClient, {
|
|
||||||
UserId: userId,
|
|
||||||
ItemIds: (options.items || []).map(function (i) {
|
|
||||||
return i.Id || i;
|
|
||||||
}).join(','),
|
|
||||||
|
|
||||||
ParentId: options.ParentId,
|
|
||||||
Category: options.Category,
|
|
||||||
IncludeProviders: options.mode === 'convert' ? 'ConvertSyncProvider' : null,
|
|
||||||
ExcludeProviders: options.mode === 'convert' ? null : 'ConvertSyncProvider'
|
|
||||||
});
|
|
||||||
|
|
||||||
return dialogOptionsFn().then(function (dialogOptions) {
|
|
||||||
|
|
||||||
currentDialogOptions = dialogOptions;
|
|
||||||
|
|
||||||
var dlgElementOptions = {
|
|
||||||
removeOnClose: true,
|
|
||||||
scrollY: false,
|
|
||||||
autoFocus: false
|
|
||||||
};
|
|
||||||
|
|
||||||
if (layoutManager.tv) {
|
|
||||||
dlgElementOptions.size = 'fullscreen';
|
|
||||||
} else {
|
|
||||||
dlgElementOptions.size = 'small';
|
|
||||||
}
|
|
||||||
|
|
||||||
var dlg = dialogHelper.createDialog(dlgElementOptions);
|
|
||||||
|
|
||||||
dlg.classList.add('formDialog');
|
|
||||||
|
|
||||||
var html = '';
|
|
||||||
html += '<div class="formDialogHeader">';
|
|
||||||
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon"></i></button>';
|
|
||||||
html += '<h3 class="formDialogHeaderTitle">';
|
|
||||||
|
|
||||||
var syncButtonLabel = options.mode === 'download' ?
|
|
||||||
globalize.translate('Download') :
|
|
||||||
(options.mode === 'convert' ? globalize.translate('Convert') : globalize.translate('Sync'));
|
|
||||||
|
|
||||||
html += syncButtonLabel;
|
|
||||||
html += '</h3>';
|
|
||||||
|
|
||||||
if (appHost.supports('externallinks')) {
|
|
||||||
html += '<a is="emby-linkbutton" href="https://github.com/MediaBrowser/Wiki/wiki/Sync" target="_blank" class="button-link lnkHelp" style="margin-top:0;display:inline-block;vertical-align:middle;margin-left:auto;"><i class="md-icon">info</i><span>' + globalize.translate('Help') + '</span></a>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</div>';
|
|
||||||
|
|
||||||
html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">';
|
|
||||||
html += '<div class="dialogContentInner dialog-content-centered">';
|
|
||||||
|
|
||||||
html += '<form class="formSubmitSyncRequest" style="margin: auto;">';
|
|
||||||
|
|
||||||
html += '<div class="formFields"></div>';
|
|
||||||
|
|
||||||
html += '<div class="formDialogFooter">';
|
|
||||||
|
|
||||||
html += '<button is="emby-button" type="submit" class="raised button-submit block formDialogFooterItem"><span>' + syncButtonLabel + '</span></button>';
|
|
||||||
html += '</div>';
|
|
||||||
|
|
||||||
html += '</form>';
|
|
||||||
|
|
||||||
html += '</div>';
|
|
||||||
html += '</div>';
|
|
||||||
|
|
||||||
dlg.innerHTML = html;
|
|
||||||
|
|
||||||
var submitted = false;
|
|
||||||
|
|
||||||
dlg.querySelector('form').addEventListener('submit', function (e) {
|
|
||||||
|
|
||||||
submitted = submitJob(dlg, apiClient, userId, options, this);
|
|
||||||
|
|
||||||
e.preventDefault();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
|
||||||
dialogHelper.close(dlg);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (layoutManager.tv) {
|
|
||||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var promise = dialogHelper.open(dlg);
|
|
||||||
|
|
||||||
renderForm({
|
|
||||||
elem: dlg.querySelector('.formFields'),
|
|
||||||
dialogOptions: dialogOptions,
|
|
||||||
dialogOptionsFn: dialogOptionsFn,
|
|
||||||
mode: options.mode
|
|
||||||
});
|
|
||||||
|
|
||||||
return promise.then(function () {
|
|
||||||
if (layoutManager.tv) {
|
|
||||||
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (submitted) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
return Promise.reject();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTargetDialogOptionsFn(apiClient, query) {
|
|
||||||
|
|
||||||
return function (targetId) {
|
|
||||||
|
|
||||||
query.TargetId = targetId;
|
|
||||||
return apiClient.getJSON(apiClient.getUrl('Sync/Options', query));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setQualityFieldVisible(form, visible) {
|
|
||||||
|
|
||||||
var fldQuality = form.querySelector('.fldQuality');
|
|
||||||
var selectQuality = form.querySelector('#selectQuality');
|
|
||||||
|
|
||||||
if (visible) {
|
|
||||||
if (fldQuality) {
|
|
||||||
fldQuality.classList.remove('hide');
|
|
||||||
}
|
|
||||||
if (selectQuality) {
|
|
||||||
//selectQuality.setAttribute('required', 'required');
|
|
||||||
|
|
||||||
// This is a hack due to what appears to be a edge bug but it shoudln't matter as the list always has selectable items
|
|
||||||
selectQuality.removeAttribute('required');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (fldQuality) {
|
|
||||||
fldQuality.classList.add('hide');
|
|
||||||
}
|
|
||||||
if (selectQuality) {
|
|
||||||
selectQuality.removeAttribute('required');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onProfileChange(form, profileId) {
|
|
||||||
|
|
||||||
var options = currentDialogOptions || {};
|
|
||||||
|
|
||||||
var profileOptions = options.ProfileOptions || [];
|
|
||||||
|
|
||||||
if (!profileOptions.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var option = profileOptions.filter(function (o) {
|
|
||||||
return o.Id === profileId;
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
var qualityOptions = options.QualityOptions || [];
|
|
||||||
|
|
||||||
if (option) {
|
|
||||||
form.querySelector('.profileDescription').innerHTML = option.Description || '';
|
|
||||||
setQualityFieldVisible(form, qualityOptions.length > 0 && option.EnableQualityOptions && options.Options.indexOf('Quality') !== -1);
|
|
||||||
} else {
|
|
||||||
form.querySelector('.profileDescription').innerHTML = '';
|
|
||||||
setQualityFieldVisible(form, qualityOptions.length > 0 && options.Options.indexOf('Quality') !== -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onQualityChange(form, qualityId) {
|
|
||||||
|
|
||||||
var options = currentDialogOptions || {};
|
|
||||||
var option = (options.QualityOptions || []).filter(function (o) {
|
|
||||||
return o.Id === qualityId;
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
var qualityDescription = form.querySelector('.qualityDescription');
|
|
||||||
|
|
||||||
if (option) {
|
|
||||||
qualityDescription.innerHTML = option.Description || '';
|
|
||||||
} else {
|
|
||||||
qualityDescription.innerHTML = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
var fldBitrate = form.querySelector('.fldBitrate');
|
|
||||||
var txtBitrate = form.querySelector('#txtBitrate');
|
|
||||||
|
|
||||||
if (qualityId === 'custom') {
|
|
||||||
|
|
||||||
if (fldBitrate) {
|
|
||||||
fldBitrate.classList.remove('hide');
|
|
||||||
}
|
|
||||||
if (txtBitrate) {
|
|
||||||
txtBitrate.setAttribute('required', 'required');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (fldBitrate) {
|
|
||||||
fldBitrate.classList.add('hide');
|
|
||||||
}
|
|
||||||
if (txtBitrate) {
|
|
||||||
txtBitrate.removeAttribute('required');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderTargetDialogOptions(form, options) {
|
|
||||||
|
|
||||||
currentDialogOptions = options;
|
|
||||||
|
|
||||||
var fldProfile = form.querySelector('.fldProfile');
|
|
||||||
var selectProfile = form.querySelector('#selectProfile');
|
|
||||||
|
|
||||||
if (options.ProfileOptions.length && options.Options.indexOf('Profile') !== -1) {
|
|
||||||
if (fldProfile) {
|
|
||||||
fldProfile.classList.remove('hide');
|
|
||||||
}
|
|
||||||
if (selectProfile) {
|
|
||||||
selectProfile.setAttribute('required', 'required');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (fldProfile) {
|
|
||||||
fldProfile.classList.add('hide');
|
|
||||||
}
|
|
||||||
if (selectProfile) {
|
|
||||||
selectProfile.removeAttribute('required');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setQualityFieldVisible(form, options.QualityOptions.length > 0);
|
|
||||||
|
|
||||||
if (selectProfile) {
|
|
||||||
selectProfile.innerHTML = options.ProfileOptions.map(function (o) {
|
|
||||||
|
|
||||||
var selectedAttribute = o.IsDefault ? ' selected="selected"' : '';
|
|
||||||
return '<option value="' + o.Id + '"' + selectedAttribute + '>' + o.Name + '</option>';
|
|
||||||
|
|
||||||
}).join('');
|
|
||||||
|
|
||||||
selectProfile.dispatchEvent(new CustomEvent('change', {
|
|
||||||
bubbles: true
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
var selectQuality = form.querySelector('#selectQuality');
|
|
||||||
if (selectQuality) {
|
|
||||||
selectQuality.innerHTML = options.QualityOptions.map(function (o) {
|
|
||||||
|
|
||||||
var selectedAttribute = o.IsDefault ? ' selected="selected"' : '';
|
|
||||||
return '<option value="' + o.Id + '"' + selectedAttribute + '>' + o.Name + '</option>';
|
|
||||||
|
|
||||||
}).join('');
|
|
||||||
|
|
||||||
var lastQuality = appSettings.get('sync-lastquality');
|
|
||||||
if (lastQuality && options.QualityOptions.filter(function (i) {
|
|
||||||
|
|
||||||
return i.Id === lastQuality;
|
|
||||||
|
|
||||||
}).length) {
|
|
||||||
selectQuality.value = lastQuality;
|
|
||||||
}
|
|
||||||
|
|
||||||
selectQuality.dispatchEvent(new CustomEvent('change', {
|
|
||||||
bubbles: true
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadQualityOptions(form, targetId, dialogOptionsFn) {
|
|
||||||
|
|
||||||
return dialogOptionsFn(targetId).then(function (options) {
|
|
||||||
|
|
||||||
return renderTargetDialogOptions(form, options);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
|
|
||||||
showMenu: showSyncMenu,
|
|
||||||
renderForm: renderForm,
|
|
||||||
setJobValues: setJobValues
|
|
||||||
};
|
|
||||||
});
|
|
Binary file not shown.
Before Width: | Height: | Size: 48 KiB |
Binary file not shown.
Before Width: | Height: | Size: 49 KiB |
@ -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
|
|
||||||
};
|
|
||||||
});
|
|
263
src/bower_components/fetch/fetch.js
vendored
263
src/bower_components/fetch/fetch.js
vendored
@ -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);
|
|
3
src/components/actionsheet/package.json
Normal file
3
src/components/actionsheet/package.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"main": "actionsheet.js"
|
||||||
|
}
|
40
src/components/alert.js
Normal file
40
src/components/alert.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return function (text, title) {
|
||||||
|
|
||||||
|
var options;
|
||||||
|
if (typeof text === 'string') {
|
||||||
|
options = {
|
||||||
|
title: title,
|
||||||
|
text: text
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
options = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (browser.tv && window.alert) {
|
||||||
|
alert(replaceAll(options.text || '', '<br/>', '\n'));
|
||||||
|
} else {
|
||||||
|
var items = [];
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
name: globalize.translate('ButtonGotIt'),
|
||||||
|
id: 'ok',
|
||||||
|
type: 'submit'
|
||||||
|
});
|
||||||
|
|
||||||
|
options.buttons = items;
|
||||||
|
|
||||||
|
return dialog(options).then(function (result) {
|
||||||
|
if (result === 'ok') {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
};
|
||||||
|
});
|
@ -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';
|
'use strict';
|
||||||
|
|
||||||
var appRouter = {
|
var appRouter = {
|
||||||
@ -14,31 +14,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||||||
},
|
},
|
||||||
showSettings: function () {
|
showSettings: function () {
|
||||||
show('/settings/settings.html');
|
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);
|
sendRouteToViewManager(ctx, next, route, controllerFactory);
|
||||||
};
|
};
|
||||||
|
|
||||||
require(route.dependencies || [], function () {
|
if (route.controller) {
|
||||||
if (route.controller) {
|
require(['controllers/' + route.controller], onInitComplete);
|
||||||
require([route.controller], onInitComplete);
|
} else {
|
||||||
} else {
|
onInitComplete();
|
||||||
onInitComplete();
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelCurrentLoadRequest() {
|
function cancelCurrentLoadRequest() {
|
||||||
@ -363,8 +336,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||||||
|
|
||||||
firstConnectionResult = result;
|
firstConnectionResult = result;
|
||||||
|
|
||||||
loading.hide();
|
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
page({
|
page({
|
||||||
@ -372,6 +343,8 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||||||
hashbang: options.hashbang !== false,
|
hashbang: options.hashbang !== false,
|
||||||
enableHistory: enableHistory()
|
enableHistory: enableHistory()
|
||||||
});
|
});
|
||||||
|
}).finally(function () {
|
||||||
|
loading.hide();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,11 +411,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||||||
|
|
||||||
console.log('appRouter - user is authenticated');
|
console.log('appRouter - user is authenticated');
|
||||||
|
|
||||||
if (ctx.isBack && (route.isDefaultRoute || route.startup) && !isCurrentRouteStartup) {
|
if (route.isDefaultRoute) {
|
||||||
handleBackToDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (route.isDefaultRoute) {
|
|
||||||
console.log('appRouter - loading skin home page');
|
console.log('appRouter - loading skin home page');
|
||||||
loadUserSkinWithOptions(ctx);
|
loadUserSkinWithOptions(ctx);
|
||||||
return;
|
return;
|
||||||
@ -501,30 +470,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||||||
var isHandlingBackToDefault;
|
var isHandlingBackToDefault;
|
||||||
var isDummyBackToHome;
|
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) {
|
function loadContent(ctx, route, html, request) {
|
||||||
|
|
||||||
html = globalize.translateDocument(html, route.dictionary);
|
html = globalize.translateDocument(html, route.dictionary);
|
||||||
@ -670,30 +615,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||||||
return currentRouteInfo ? currentRouteInfo.route : null;
|
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) {
|
function showItem(item, serverId, options) {
|
||||||
|
|
||||||
if (typeof (item) === 'string') {
|
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 = [];
|
var allRoutes = [];
|
||||||
|
|
||||||
function addRoute(path, newRoute) {
|
function addRoute(path, newRoute) {
|
||||||
@ -834,15 +741,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
|||||||
appRouter.canGoBack = canGoBack;
|
appRouter.canGoBack = canGoBack;
|
||||||
appRouter.current = current;
|
appRouter.current = current;
|
||||||
appRouter.beginConnectionWizard = beginConnectionWizard;
|
appRouter.beginConnectionWizard = beginConnectionWizard;
|
||||||
appRouter.goHome = goHome;
|
|
||||||
appRouter.showItem = showItem;
|
appRouter.showItem = showItem;
|
||||||
appRouter.setTitle = setTitle;
|
|
||||||
appRouter.setTransparency = setTransparency;
|
appRouter.setTransparency = setTransparency;
|
||||||
appRouter.getRoutes = getRoutes;
|
appRouter.getRoutes = getRoutes;
|
||||||
appRouter.getRouteUrl = getRouteUrl;
|
|
||||||
appRouter.pushState = pushState;
|
appRouter.pushState = pushState;
|
||||||
appRouter.enableNativeHistory = enableNativeHistory;
|
appRouter.enableNativeHistory = enableNativeHistory;
|
||||||
appRouter.showVideoOsd = showVideoOsd;
|
|
||||||
appRouter.handleAnchorClick = page.handleAnchorClick;
|
appRouter.handleAnchorClick = page.handleAnchorClick;
|
||||||
appRouter.TransparencyLevel = {
|
appRouter.TransparencyLevel = {
|
||||||
None: 0,
|
None: 0,
|
@ -1,109 +1,191 @@
|
|||||||
define(["appSettings", "browser", "events", "htmlMediaHelper"], function(appSettings, browser, events, htmlMediaHelper) {
|
define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSettings, browser, events, htmlMediaHelper) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function getBaseProfileOptions(item) {
|
function getBaseProfileOptions(item) {
|
||||||
var disableHlsVideoAudioCodecs = [];
|
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,
|
if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) {
|
||||||
disableHlsVideoAudioCodecs: disableHlsVideoAudioCodecs
|
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) {
|
function getDeviceProfileForWindowsUwp(item) {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
require(["browserdeviceprofile", "environments/windows-uwp/mediacaps"], function(profileBuilder, uwpMediaCaps) {
|
require(["browserdeviceprofile", "environments/windows-uwp/mediacaps"], function (profileBuilder, uwpMediaCaps) {
|
||||||
var profileOptions = getBaseProfileOptions(item);
|
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) {
|
function getDeviceProfile(item, options) {
|
||||||
return options = options || {}, self.Windows ? getDeviceProfileForWindowsUwp(item) : new Promise(function(resolve, reject) {
|
options = options || {};
|
||||||
require(["browserdeviceprofile"], function(profileBuilder) {
|
|
||||||
var profile = profileBuilder(getBaseProfileOptions(item));
|
if (self.Windows) {
|
||||||
item && !options.isRetry && "allcomplexformats" !== appSettings.get("subtitleburnin") && (browser.orsay || browser.tizen || (profile.SubtitleProfiles.push({
|
return getDeviceProfileForWindowsUwp(item);
|
||||||
Format: "ass",
|
}
|
||||||
Method: "External"
|
|
||||||
}), profile.SubtitleProfiles.push({
|
return new Promise(function (resolve) {
|
||||||
Format: "ssa",
|
require(["browserdeviceprofile"], function (profileBuilder) {
|
||||||
Method: "External"
|
var profile;
|
||||||
}))), resolve(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) {
|
function escapeRegExp(str) {
|
||||||
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1")
|
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
|
||||||
}
|
}
|
||||||
|
|
||||||
function replaceAll(originalString, strReplace, strWith) {
|
function replaceAll(originalString, strReplace, strWith) {
|
||||||
var strReplace2 = escapeRegExp(strReplace),
|
var strReplace2 = escapeRegExp(strReplace);
|
||||||
reg = new RegExp(strReplace2, "ig");
|
var reg = new RegExp(strReplace2, "ig");
|
||||||
return originalString.replace(reg, strWith)
|
return originalString.replace(reg, strWith);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateDeviceId() {
|
function generateDeviceId() {
|
||||||
var keys = [];
|
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");
|
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() {
|
function getDeviceId() {
|
||||||
var key = "_deviceId2",
|
var key = "_deviceId2";
|
||||||
deviceId = appSettings.get(key);
|
var deviceId = appSettings.get(key);
|
||||||
return deviceId ? Promise.resolve(deviceId) : generateDeviceId().then(function(deviceId) {
|
|
||||||
return appSettings.set(key, deviceId), deviceId
|
if (deviceId) {
|
||||||
})
|
return Promise.resolve(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateDeviceId().then(function (deviceId) {
|
||||||
|
appSettings.set(key, deviceId);
|
||||||
|
return deviceId;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDeviceName() {
|
function getDeviceName() {
|
||||||
var deviceName;
|
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() {
|
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() {
|
function supportsFullscreen() {
|
||||||
if (browser.tv) return !1;
|
if (browser.tv) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var element = document.documentElement;
|
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() {
|
function getSyncProfile() {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function (resolve) {
|
||||||
require(["browserdeviceprofile", "appSettings"], function(profileBuilder, appSettings) {
|
require(["browserdeviceprofile", "appSettings"], function (profileBuilder, appSettings) {
|
||||||
var profile = profileBuilder();
|
var profile;
|
||||||
profile.MaxStaticMusicBitrate = appSettings.maxStaticMusicBitrate(), resolve(profile)
|
|
||||||
})
|
if (window.NativeShell) {
|
||||||
})
|
profile = window.NativeShell.AppHost.getSyncProfile(profileBuilder, appSettings);
|
||||||
|
} else {
|
||||||
|
profile = profileBuilder();
|
||||||
|
profile.MaxStaticMusicBitrate = appSettings.maxStaticMusicBitrate();
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(profile);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDefaultLayout() {
|
function getDefaultLayout() {
|
||||||
return "desktop"
|
return "desktop";
|
||||||
}
|
}
|
||||||
|
|
||||||
function supportsHtmlMediaAutoplay() {
|
function supportsHtmlMediaAutoplay() {
|
||||||
if (browser.edgeUwp || browser.tizen || browser.web0s || browser.orsay || browser.operaTv || browser.ps4 || browser.xboxOne) return !0;
|
if (browser.edgeUwp || browser.tizen || browser.web0s || browser.orsay || browser.operaTv || browser.ps4 || browser.xboxOne) {
|
||||||
if (browser.mobile) return !1;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (browser.mobile) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var savedResult = appSettings.get(htmlMediaAutoplayAppStorageKey);
|
var savedResult = appSettings.get(htmlMediaAutoplayAppStorageKey);
|
||||||
return "true" === savedResult || "false" !== savedResult && null
|
return "true" === savedResult || "false" !== savedResult && null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cueSupported() {
|
function cueSupported() {
|
||||||
try {
|
try {
|
||||||
var video = document.createElement("video"),
|
var video = document.createElement("video");
|
||||||
style = document.createElement("style");
|
var style = document.createElement("style");
|
||||||
style.textContent = "video::cue {background: inherit}", document.body.appendChild(style), document.body.appendChild(video);
|
style.textContent = "video::cue {background: inherit}";
|
||||||
|
document.body.appendChild(style);
|
||||||
|
document.body.appendChild(video);
|
||||||
var cue = window.getComputedStyle(video, "::cue").background;
|
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) {
|
} 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 htmlMediaAutoplayAppStorageKey = "supportshtmlmediaautoplay0";
|
||||||
var supportedFeatures = function() {
|
|
||||||
|
var supportedFeatures = function () {
|
||||||
var features = [];
|
var features = [];
|
||||||
navigator.share && features.push("sharing");
|
|
||||||
browser.edgeUwp || browser.tv || browser.xboxOne || browser.ps4 || features.push("filedownload");
|
if (navigator.share) {
|
||||||
browser.operaTv || browser.tizen || browser.orsay || browser.web0s
|
features.push("sharing");
|
||||||
? 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"));
|
if (!browser.edgeUwp && !browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||||
browser.operaTv || features.push("externallinkdisplay");
|
features.push("filedownload");
|
||||||
supportsVoiceInput() && features.push("voiceinput");
|
}
|
||||||
!browser.tv && !browser.xboxOne && browser.ps4, supportsHtmlMediaAutoplay() && (features.push("htmlaudioautoplay"), features.push("htmlvideoautoplay"));
|
|
||||||
browser.edgeUwp && features.push("sync");
|
if (browser.operaTv || browser.tizen || browser.orsay || browser.web0s) {
|
||||||
supportsFullscreen() && features.push("fullscreenchange");
|
features.push("exit");
|
||||||
(browser.chrome || browser.edge && !browser.slow) && (browser.noAnimation || browser.edgeUwp || browser.xboxOne || features.push("imageanalysis"));
|
} else {
|
||||||
(browser.tv || browser.xboxOne || browser.ps4 || browser.mobile) && features.push("physicalvolumecontrol");
|
features.push("exitmenu");
|
||||||
browser.tv || browser.xboxOne || browser.ps4 || features.push("remotecontrol");
|
features.push("plugins");
|
||||||
browser.operaTv || browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp || features.push("remotevideo");
|
}
|
||||||
|
|
||||||
|
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("displaylanguage");
|
||||||
features.push("otherapppromotions");
|
features.push("otherapppromotions");
|
||||||
features.push("targetblank");
|
features.push("targetblank"); // allows users to connect to more than one server
|
||||||
features.push("multiserver");
|
//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");
|
if (!browser.orsay && !browser.tizen && !browser.msie && (browser.firefox || browser.ps4 || browser.edge || cueSupported())) {
|
||||||
browser.tv || browser.ps4 || browser.xboxOne || features.push("fileinput");
|
features.push("subtitleappearancesettings");
|
||||||
browser.chrome && features.push("chromecast");
|
}
|
||||||
|
|
||||||
|
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;
|
return features;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
if (supportedFeatures.indexOf("htmlvideoautoplay") === -1 && supportsHtmlMediaAutoplay() !== false) {
|
if (supportedFeatures.indexOf("htmlvideoautoplay") === -1 && supportsHtmlMediaAutoplay() !== false) {
|
||||||
require(["autoPlayDetect"], function(autoPlayDetect) {
|
require(["autoPlayDetect"], function (autoPlayDetect) {
|
||||||
autoPlayDetect.supportsHtmlMediaAutoplay().then(function() {
|
autoPlayDetect.supportsHtmlMediaAutoplay().then(function () {
|
||||||
appSettings.set(htmlMediaAutoplayAppStorageKey, "true");
|
appSettings.set(htmlMediaAutoplayAppStorageKey, "true");
|
||||||
supportedFeatures.push("htmlvideoautoplay");
|
supportedFeatures.push("htmlvideoautoplay");
|
||||||
supportedFeatures.push("htmlaudioautoplay");
|
supportedFeatures.push("htmlaudioautoplay");
|
||||||
}, function() {
|
}, function () {
|
||||||
appSettings.set(htmlMediaAutoplayAppStorageKey, "false");
|
appSettings.set(htmlMediaAutoplayAppStorageKey, "false");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -168,73 +314,169 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function(appSett
|
|||||||
var visibilityState;
|
var visibilityState;
|
||||||
var appVersion = window.dashboardVersion || "3.0";
|
var appVersion = window.dashboardVersion || "3.0";
|
||||||
var appHost = {
|
var appHost = {
|
||||||
getWindowState: function() {
|
getWindowState: function () {
|
||||||
return document.windowState || "Normal"
|
return document.windowState || "Normal";
|
||||||
},
|
},
|
||||||
setWindowState: function(state) {
|
setWindowState: function (state) {
|
||||||
alert("setWindowState is not supported and should not be called")
|
alert("setWindowState is not supported and should not be called");
|
||||||
},
|
},
|
||||||
exit: function() {
|
exit: function () {
|
||||||
if (browser.tizen) try {
|
if (window.NativeShell) {
|
||||||
tizen.application.getCurrentApplication().exit()
|
window.NativeShell.AppHost.exit();
|
||||||
} catch (err) {
|
} else if (browser.tizen) {
|
||||||
console.log("error closing application: " + err)
|
try {
|
||||||
} else window.close()
|
tizen.application.getCurrentApplication().exit();
|
||||||
|
} catch (err) {
|
||||||
|
console.log("error closing application: " + err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
supports: function(command) {
|
supports: function (command) {
|
||||||
return -1 !== supportedFeatures.indexOf(command.toLowerCase())
|
if (window.NativeShell) {
|
||||||
|
return window.NativeShell.AppHost.supports(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1 !== supportedFeatures.indexOf(command.toLowerCase());
|
||||||
},
|
},
|
||||||
preferVisualCards: browser.android || browser.chrome,
|
preferVisualCards: browser.android || browser.chrome,
|
||||||
moreIcon: browser.android ? "dots-vert" : "dots-horiz",
|
moreIcon: browser.android ? "dots-vert" : "dots-horiz",
|
||||||
getSyncProfile: getSyncProfile,
|
getSyncProfile: getSyncProfile,
|
||||||
getDefaultLayout: getDefaultLayout,
|
getDefaultLayout: function () {
|
||||||
|
if (window.NativeShell) {
|
||||||
|
return window.NativeShell.AppHost.getDefaultLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getDefaultLayout()
|
||||||
|
},
|
||||||
getDeviceProfile: getDeviceProfile,
|
getDeviceProfile: getDeviceProfile,
|
||||||
init: function() {
|
init: function () {
|
||||||
return deviceName = getDeviceName(), getDeviceId().then(function(resolvedDeviceId) {
|
if (window.NativeShell) {
|
||||||
deviceId = resolvedDeviceId
|
return window.NativeShell.AppHost.init();
|
||||||
})
|
}
|
||||||
|
|
||||||
|
deviceName = getDeviceName();
|
||||||
|
return getDeviceId().then(function (resolvedDeviceId) {
|
||||||
|
deviceId = resolvedDeviceId;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
deviceName: function() {
|
deviceName: function () {
|
||||||
return deviceName
|
return window.NativeShell ? window.NativeShell.AppHost.deviceName() : deviceName;
|
||||||
},
|
},
|
||||||
deviceId: function() {
|
deviceId: function () {
|
||||||
return deviceId
|
return window.NativeShell ? window.NativeShell.AppHost.deviceId() : deviceId;
|
||||||
},
|
},
|
||||||
appName: function() {
|
appName: function () {
|
||||||
return "Jellyfin Web"
|
return window.NativeShell ? window.NativeShell.AppHost.appName() : "Jellyfin Web";
|
||||||
},
|
},
|
||||||
appVersion: function() {
|
appVersion: function () {
|
||||||
return appVersion
|
return window.NativeShell ? window.NativeShell.AppHost.appVersion() : appVersion;
|
||||||
},
|
},
|
||||||
getPushTokenInfo: function() {
|
getPushTokenInfo: function () {
|
||||||
return {}
|
return {};
|
||||||
},
|
},
|
||||||
setThemeColor: function(color) {
|
setThemeColor: function (color) {
|
||||||
var metaThemeColor = document.querySelector("meta[name=theme-color]");
|
var metaThemeColor = document.querySelector("meta[name=theme-color]");
|
||||||
metaThemeColor && metaThemeColor.setAttribute("content", color)
|
|
||||||
},
|
if (metaThemeColor) {
|
||||||
setUserScalable: function(scalable) {
|
metaThemeColor.setAttribute("content", color);
|
||||||
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() {
|
setUserScalable: function (scalable) {
|
||||||
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"
|
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;
|
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) {
|
if (doc) {
|
||||||
doc.addEventListener(visibilityChange, function() {
|
if (void 0 !== doc.visibilityState) {
|
||||||
document[visibilityState] ? onAppHidden() : onAppVisible()
|
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) {
|
if (self.addEventListener) {
|
||||||
self.addEventListener("focus", onAppVisible);
|
self.addEventListener("focus", onAppVisible);
|
||||||
self.addEventListener("blur", onAppHidden);
|
self.addEventListener("blur", onAppHidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
return appHost;
|
return appHost;
|
||||||
});
|
});
|
||||||
|
3
src/components/backdrop/package.json
Normal file
3
src/components/backdrop/package.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"main": "backdrop.js"
|
||||||
|
}
|
@ -751,7 +751,7 @@ define(['browser'], function (browser) {
|
|||||||
Condition: 'Equals',
|
Condition: 'Equals',
|
||||||
Property: 'IsSecondaryAudio',
|
Property: 'IsSecondaryAudio',
|
||||||
Value: 'false',
|
Value: 'false',
|
||||||
IsRequired: 'false'
|
IsRequired: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -780,7 +780,7 @@ define(['browser'], function (browser) {
|
|||||||
Condition: 'Equals',
|
Condition: 'Equals',
|
||||||
Property: 'IsSecondaryAudio',
|
Property: 'IsSecondaryAudio',
|
||||||
Value: 'false',
|
Value: 'false',
|
||||||
IsRequired: 'false'
|
IsRequired: false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -913,4 +913,4 @@ define(['browser'], function (browser) {
|
|||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
};
|
};
|
||||||
});
|
});
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -187,8 +187,13 @@ define(['events'], function (events) {
|
|||||||
return apiClient.getEndpointInfo().then(function (endpoint) {
|
return apiClient.getEndpointInfo().then(function (endpoint) {
|
||||||
if (endpoint.IsInNetwork) {
|
if (endpoint.IsInNetwork) {
|
||||||
return apiClient.getPublicSystemInfo().then(function (info) {
|
return apiClient.getPublicSystemInfo().then(function (info) {
|
||||||
addToCache(serverAddress, info.LocalAddress);
|
var localAddress = info.LocalAddress
|
||||||
return info.LocalAddress;
|
if (!localAddress) {
|
||||||
|
console.log("No valid local address returned, defaulting to external one")
|
||||||
|
localAddress = serverAddress;
|
||||||
|
}
|
||||||
|
addToCache(serverAddress, localAddress);
|
||||||
|
return localAddress;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
addToCache(serverAddress, serverAddress);
|
addToCache(serverAddress, serverAddress);
|
@ -220,7 +220,9 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
|||||||
this.session = null;
|
this.session = null;
|
||||||
this.deviceState = DEVICE_STATE.IDLE;
|
this.deviceState = DEVICE_STATE.IDLE;
|
||||||
this.castPlayerState = PLAYER_STATE.IDLE;
|
this.castPlayerState = PLAYER_STATE.IDLE;
|
||||||
|
document.removeEventListener("volumeupbutton", onVolumeUpKeyDown, false);
|
||||||
|
document.removeEventListener("volumedownbutton", onVolumeDownKeyDown, false);
|
||||||
|
|
||||||
//console.log('sessionUpdateListener: setting currentMediaSession to null');
|
//console.log('sessionUpdateListener: setting currentMediaSession to null');
|
||||||
this.currentMediaSession = null;
|
this.currentMediaSession = null;
|
||||||
|
|
||||||
@ -258,6 +260,9 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
|||||||
this.session.addMediaListener(this.sessionMediaListener.bind(this));
|
this.session.addMediaListener(this.sessionMediaListener.bind(this));
|
||||||
this.session.addUpdateListener(this.sessionUpdateListener.bind(this));
|
this.session.addUpdateListener(this.sessionUpdateListener.bind(this));
|
||||||
|
|
||||||
|
document.addEventListener("volumeupbutton", onVolumeUpKeyDown, false);
|
||||||
|
document.addEventListener("volumedownbutton", onVolumeDownKeyDown, false);
|
||||||
|
|
||||||
events.trigger(this, 'connect');
|
events.trigger(this, 'connect');
|
||||||
|
|
||||||
this.sendMessage({
|
this.sendMessage({
|
||||||
@ -266,6 +271,14 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function onVolumeUpKeyDown() {
|
||||||
|
playbackManager.volumeUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onVolumeDownKeyDown() {
|
||||||
|
playbackManager.volumeDown();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* session update listener
|
* session update listener
|
||||||
*/
|
*/
|
||||||
@ -305,6 +318,8 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
|||||||
//console.log(message);
|
//console.log(message);
|
||||||
this.deviceState = DEVICE_STATE.IDLE;
|
this.deviceState = DEVICE_STATE.IDLE;
|
||||||
this.castPlayerState = PLAYER_STATE.IDLE;
|
this.castPlayerState = PLAYER_STATE.IDLE;
|
||||||
|
document.removeEventListener("volumeupbutton", onVolumeUpKeyDown, false);
|
||||||
|
document.removeEventListener("volumedownbutton", onVolumeDownKeyDown, false);
|
||||||
|
|
||||||
//console.log('onStopAppSuccess: setting currentMediaSession to null');
|
//console.log('onStopAppSuccess: setting currentMediaSession to null');
|
||||||
this.currentMediaSession = null;
|
this.currentMediaSession = null;
|
||||||
@ -574,8 +589,15 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
|||||||
|
|
||||||
events.trigger(instance, "playbackstop", [state]);
|
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.
|
// Reset this so the next query doesn't make it appear like content is playing.
|
||||||
instance.lastPlayerData = {};
|
instance.lastPlayerData = {};
|
||||||
|
instance.lastPlayerData.PlayState = {};
|
||||||
|
instance.lastPlayerData.PlayState.VolumeLevel = volume;
|
||||||
|
instance.lastPlayerData.PlayState.IsMuted = mute;
|
||||||
});
|
});
|
||||||
|
|
||||||
events.on(instance._castPlayer, "playbackprogress", function (e, data) {
|
events.on(instance._castPlayer, "playbackprogress", function (e, data) {
|
||||||
@ -780,11 +802,16 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
|||||||
};
|
};
|
||||||
|
|
||||||
ChromecastPlayer.prototype.volumeDown = function () {
|
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 () {
|
ChromecastPlayer.prototype.endSession = function () {
|
||||||
@ -799,24 +826,24 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
|||||||
};
|
};
|
||||||
|
|
||||||
ChromecastPlayer.prototype.volumeUp = function () {
|
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({
|
this._castPlayer.session.setReceiverVolumeLevel(vol);
|
||||||
options: {},
|
|
||||||
command: 'VolumeUp'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ChromecastPlayer.prototype.setVolume = function (vol) {
|
ChromecastPlayer.prototype.setVolume = function (vol) {
|
||||||
|
|
||||||
vol = Math.min(vol, 100);
|
vol = Math.min(vol, 100);
|
||||||
vol = Math.max(vol, 0);
|
vol = Math.max(vol, 0);
|
||||||
|
vol = vol / 100;
|
||||||
this._castPlayer.sendMessage({
|
|
||||||
options: {
|
this._castPlayer.session.setReceiverVolumeLevel(vol);
|
||||||
volume: vol
|
|
||||||
},
|
|
||||||
command: 'SetVolume'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ChromecastPlayer.prototype.unpause = function () {
|
ChromecastPlayer.prototype.unpause = function () {
|
@ -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';
|
'use strict';
|
||||||
|
|
||||||
var currentServerId;
|
var currentServerId;
|
3
src/components/dialog/package.json
Normal file
3
src/components/dialog/package.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"main": "dialog.js"
|
||||||
|
}
|
3
src/components/dialogHelper/package.json
Normal file
3
src/components/dialogHelper/package.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"main": "dialogHelper.js"
|
||||||
|
}
|
@ -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';
|
'use strict';
|
||||||
|
|
||||||
function getSystemInfo() {
|
function getSystemInfo() {
|
||||||
@ -18,18 +18,18 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'emby-b
|
|||||||
if (path && typeof path !== 'string') {
|
if (path && typeof path !== 'string') {
|
||||||
throw new Error("invalid path");
|
throw new Error("invalid path");
|
||||||
}
|
}
|
||||||
|
|
||||||
loading.show();
|
loading.show();
|
||||||
|
|
||||||
var promises = [];
|
var promises = [];
|
||||||
|
|
||||||
if ("Network" === path) {
|
if ("Network" === path) {
|
||||||
promises.push(ApiClient.getNetworkDevices())
|
promises.push(ApiClient.getNetworkDevices())
|
||||||
} else {
|
} else {
|
||||||
if (path) {
|
if (path) {
|
||||||
promises.push(ApiClient.getDirectoryContents(path, fileOptions));
|
promises.push(ApiClient.getDirectoryContents(path, fileOptions));
|
||||||
promises.push(ApiClient.getParentPath(path));
|
promises.push(ApiClient.getParentPath(path));
|
||||||
} else {
|
} else {
|
||||||
promises.push(ApiClient.getDrives());
|
promises.push(ApiClient.getDrives());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'emby-b
|
|||||||
|
|
||||||
page.querySelector(".results").scrollTop = 0;
|
page.querySelector(".results").scrollTop = 0;
|
||||||
page.querySelector("#txtDirectoryPickerPath").value = path || "";
|
page.querySelector("#txtDirectoryPickerPath").value = path || "";
|
||||||
|
|
||||||
if (path) {
|
if (path) {
|
||||||
html += getItem("lnkPath lnkDirectory", "", parentPath, "...");
|
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";
|
var cssClass = "File" === folder.Type ? "lnkPath lnkFile" : "lnkPath lnkDirectory";
|
||||||
html += getItem(cssClass, folder.Type, folder.Path, folder.Name);
|
html += getItem(cssClass, folder.Type, folder.Path, folder.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!path) {
|
if (!path) {
|
||||||
html += getItem("lnkPath lnkDirectory", "", "Network", Globalize.translate("ButtonNetwork"));
|
html += getItem("lnkPath lnkDirectory", "", "Network", Globalize.translate("ButtonNetwork"));
|
||||||
}
|
}
|
||||||
@ -128,7 +128,7 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'emby-b
|
|||||||
html += '<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="' + Globalize.translate("ButtonRefresh") + '"><i class="md-icon">search</i></button>';
|
html += '<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="' + Globalize.translate("ButtonRefresh") + '"><i class="md-icon">search</i></button>';
|
||||||
}
|
}
|
||||||
html += "</div>";
|
html += "</div>";
|
||||||
if (!readOnlyAttribute) {
|
if (!readOnlyAttribute) {
|
||||||
html += '<div class="results paperList" style="max-height: 200px; overflow-y: auto;"></div>';
|
html += '<div class="results paperList" style="max-height: 200px; overflow-y: auto;"></div>';
|
||||||
}
|
}
|
||||||
if (options.enableNetworkSharePath) {
|
if (options.enableNetworkSharePath) {
|
||||||
@ -222,11 +222,7 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'emby-b
|
|||||||
var networkSharePath = this.querySelector("#txtNetworkPath");
|
var networkSharePath = this.querySelector("#txtNetworkPath");
|
||||||
networkSharePath = networkSharePath ? networkSharePath.value : null;
|
networkSharePath = networkSharePath ? networkSharePath.value : null;
|
||||||
var path = this.querySelector("#txtDirectoryPickerPath").value;
|
var path = this.querySelector("#txtDirectoryPickerPath").value;
|
||||||
validatePath(path, options.validateWriteable, ApiClient).then(
|
validatePath(path, options.validateWriteable, ApiClient).then(options.callback(path, networkSharePath));
|
||||||
function() {
|
|
||||||
options.callback(path, networkSharePath);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
@ -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";
|
"use strict";
|
||||||
|
|
||||||
function fillThemes(select, isDashboard) {
|
function fillThemes(select, isDashboard) {
|
||||||
@ -225,32 +225,25 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
|||||||
userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked);
|
userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked);
|
||||||
|
|
||||||
if (user.Id === apiClient.getCurrentUserId()) {
|
if (user.Id === apiClient.getCurrentUserId()) {
|
||||||
|
|
||||||
skinManager.setTheme(userSettingsInstance.theme());
|
skinManager.setTheme(userSettingsInstance.theme());
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutManager.setLayout(context.querySelector('.selectLayout').value);
|
layoutManager.setLayout(context.querySelector('.selectLayout').value);
|
||||||
|
|
||||||
return apiClient.updateUserConfiguration(user.Id, user.Configuration);
|
return apiClient.updateUserConfiguration(user.Id, user.Configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
|
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
|
||||||
|
|
||||||
loading.show();
|
loading.show();
|
||||||
|
|
||||||
apiClient.getUser(userId).then(function (user) {
|
apiClient.getUser(userId).then(function (user) {
|
||||||
|
|
||||||
saveUser(context, user, userSettings, apiClient).then(function () {
|
saveUser(context, user, userSettings, apiClient).then(function () {
|
||||||
|
|
||||||
loading.hide();
|
loading.hide();
|
||||||
if (enableSaveConfirmation) {
|
if (enableSaveConfirmation) {
|
||||||
require(['toast'], function (toast) {
|
require(['toast'], function (toast) {
|
||||||
toast(globalize.translate('SettingsSaved'));
|
toast(globalize.translate('SettingsSaved'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
events.trigger(instance, 'saved');
|
events.trigger(instance, 'saved');
|
||||||
|
|
||||||
}, function () {
|
}, function () {
|
||||||
loading.hide();
|
loading.hide();
|
||||||
});
|
});
|
||||||
@ -258,14 +251,12 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onSubmit(e) {
|
function onSubmit(e) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var apiClient = connectionManager.getApiClient(self.options.serverId);
|
var apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||||
var userId = self.options.userId;
|
var userId = self.options.userId;
|
||||||
var userSettings = self.options.userSettings;
|
var userSettings = self.options.userSettings;
|
||||||
|
|
||||||
userSettings.setUserInfo(userId, apiClient).then(function () {
|
userSettings.setUserInfo(userId, apiClient).then(function () {
|
||||||
|
|
||||||
var enableSaveConfirmation = self.options.enableSaveConfirmation;
|
var enableSaveConfirmation = self.options.enableSaveConfirmation;
|
||||||
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
|
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
|
||||||
});
|
});
|
||||||
@ -278,30 +269,22 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
|||||||
}
|
}
|
||||||
|
|
||||||
function embed(options, self) {
|
function embed(options, self) {
|
||||||
|
|
||||||
require(['text!./displaysettings.template.html'], function (template) {
|
require(['text!./displaysettings.template.html'], function (template) {
|
||||||
|
|
||||||
options.element.innerHTML = globalize.translateDocument(template, 'core');
|
options.element.innerHTML = globalize.translateDocument(template, 'core');
|
||||||
|
|
||||||
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
|
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
|
||||||
|
|
||||||
if (options.enableSaveButton) {
|
if (options.enableSaveButton) {
|
||||||
options.element.querySelector('.btnSave').classList.remove('hide');
|
options.element.querySelector('.btnSave').classList.remove('hide');
|
||||||
}
|
}
|
||||||
|
|
||||||
self.loadData(options.autoFocus);
|
self.loadData(options.autoFocus);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function DisplaySettings(options) {
|
function DisplaySettings(options) {
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
|
||||||
embed(options, this);
|
embed(options, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplaySettings.prototype.loadData = function (autoFocus) {
|
DisplaySettings.prototype.loadData = function (autoFocus) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var context = self.options.element;
|
var context = self.options.element;
|
||||||
|
|
||||||
@ -312,13 +295,9 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
|||||||
var userSettings = self.options.userSettings;
|
var userSettings = self.options.userSettings;
|
||||||
|
|
||||||
return apiClient.getUser(userId).then(function (user) {
|
return apiClient.getUser(userId).then(function (user) {
|
||||||
|
|
||||||
return userSettings.setUserInfo(userId, apiClient).then(function () {
|
return userSettings.setUserInfo(userId, apiClient).then(function () {
|
||||||
|
|
||||||
self.dataLoaded = true;
|
self.dataLoaded = true;
|
||||||
|
|
||||||
loadForm(context, user, userSettings, apiClient);
|
loadForm(context, user, userSettings, apiClient);
|
||||||
|
|
||||||
if (autoFocus) {
|
if (autoFocus) {
|
||||||
focusManager.autoFocus(context);
|
focusManager.autoFocus(context);
|
||||||
}
|
}
|
||||||
@ -331,7 +310,6 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
|||||||
};
|
};
|
||||||
|
|
||||||
DisplaySettings.prototype.destroy = function () {
|
DisplaySettings.prototype.destroy = function () {
|
||||||
|
|
||||||
this.options = null;
|
this.options = null;
|
||||||
};
|
};
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user