mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge remote-tracking branch 'upstream/master' into quickconnect
This commit is contained in:
commit
9476edcbe2
431 changed files with 26974 additions and 36233 deletions
|
@ -59,7 +59,15 @@ jobs:
|
|||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
variables:
|
||||
- name: JellyfinVersion
|
||||
value: 0.0.0
|
||||
|
||||
steps:
|
||||
- script: echo "##vso[task.setvariable variable=JellyfinVersion]$( awk -F '/' '{ print $NF }' <<<'$(Build.SourceBranch)' | sed 's/^v//' )"
|
||||
displayName: Set release version (stable)
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
|
||||
|
||||
- task: Docker@2
|
||||
displayName: 'Push Unstable Image'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||
|
@ -84,7 +92,7 @@ jobs:
|
|||
containerRegistry: Docker Hub
|
||||
tags: |
|
||||
stable-$(Build.BuildNumber)
|
||||
stable
|
||||
$(JellyfinVersion)
|
||||
|
||||
- job: CollectArtifacts
|
||||
displayName: 'Collect Artifacts'
|
||||
|
|
|
@ -2,4 +2,4 @@ version: 1
|
|||
update_configs:
|
||||
- package_manager: "javascript"
|
||||
directory: "/"
|
||||
update_schedule: "live"
|
||||
update_schedule: "weekly"
|
||||
|
|
|
@ -8,5 +8,5 @@ trim_trailing_whitespace = true
|
|||
insert_final_newline = true
|
||||
end_of_line = lf
|
||||
|
||||
[json]
|
||||
[*.json]
|
||||
indent_size = 2
|
||||
|
|
|
@ -2,4 +2,3 @@ node_modules
|
|||
dist
|
||||
.idea
|
||||
.vscode
|
||||
src/libraries
|
||||
|
|
24
.eslintrc.js
24
.eslintrc.js
|
@ -1,6 +1,9 @@
|
|||
const restrictedGlobals = require('confusing-browser-globals');
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
plugins: [
|
||||
'@babel',
|
||||
'promise',
|
||||
'import',
|
||||
'eslint-comments'
|
||||
|
@ -28,7 +31,7 @@ module.exports = {
|
|||
],
|
||||
rules: {
|
||||
'block-spacing': ['error'],
|
||||
'brace-style': ['error'],
|
||||
'brace-style': ['error', '1tbs', { 'allowSingleLine': true }],
|
||||
'comma-dangle': ['error', 'never'],
|
||||
'comma-spacing': ['error'],
|
||||
'eol-last': ['error'],
|
||||
|
@ -38,19 +41,25 @@ module.exports = {
|
|||
'no-floating-decimal': ['error'],
|
||||
'no-multi-spaces': ['error'],
|
||||
'no-multiple-empty-lines': ['error', { 'max': 1 }],
|
||||
'no-restricted-globals': ['error'].concat(restrictedGlobals),
|
||||
'no-trailing-spaces': ['error'],
|
||||
'@babel/no-unused-expressions': ['error', { 'allowShortCircuit': true, 'allowTernary': true, 'allowTaggedTemplates': true }],
|
||||
//'no-unused-vars': ['error', { 'vars': 'all', 'args': 'none', 'ignoreRestSiblings': true }],
|
||||
'one-var': ['error', 'never'],
|
||||
'padded-blocks': ['error', 'never'],
|
||||
//'prefer-const': ['error', {'destructuring': 'all'}],
|
||||
'quotes': ['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': false }],
|
||||
'semi': ['error'],
|
||||
'@babel/semi': ['error'],
|
||||
'space-before-blocks': ['error'],
|
||||
'space-infix-ops': 'error'
|
||||
'space-infix-ops': 'error',
|
||||
'yoda': 'error'
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
'./src/**/*.js'
|
||||
],
|
||||
parser: 'babel-eslint',
|
||||
parser: '@babel/eslint-parser',
|
||||
env: {
|
||||
node: false,
|
||||
amd: true,
|
||||
|
@ -75,7 +84,6 @@ module.exports = {
|
|||
'ApiClient': 'writable',
|
||||
'AppInfo': 'writable',
|
||||
'chrome': 'writable',
|
||||
'ConnectionManager': 'writable',
|
||||
'DlnaProfilePage': 'writable',
|
||||
'Dashboard': 'writable',
|
||||
'DashboardPage': 'writable',
|
||||
|
@ -98,9 +106,9 @@ module.exports = {
|
|||
},
|
||||
rules: {
|
||||
// TODO: Fix warnings and remove these rules
|
||||
'no-redeclare': ['warn'],
|
||||
'no-unused-vars': ['warn'],
|
||||
'no-useless-escape': ['warn'],
|
||||
'no-redeclare': ['off'],
|
||||
'no-useless-escape': ['off'],
|
||||
'no-unused-vars': ['off'],
|
||||
// TODO: Remove after ES6 migration is complete
|
||||
'import/no-unresolved': ['off']
|
||||
},
|
||||
|
|
|
@ -36,7 +36,9 @@
|
|||
- [MrTimscampi](https://github.com/MrTimscampi)
|
||||
- [ConfusedPolarBear](https://github.com/ConfusedPolarBear)
|
||||
- [Sarab Singh](https://github.com/sarab97)
|
||||
- [GuilhermeHideki](https://github.com/GuilhermeHideki)
|
||||
- [Andrei Oanca](https://github.com/OancaAndrei)
|
||||
- [Cromefire_](https://github.com/cromefire)
|
||||
|
||||
# Emby Contributors
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ Jellyfin Web is the frontend used for most of the clients available for end user
|
|||
|
||||
### Dependencies
|
||||
|
||||
- [Node.js](https://nodejs.org/en/download/)
|
||||
- [Yarn 1.22.4](https://classic.yarnpkg.com/en/docs/install)
|
||||
- Gulp-cli
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
# We just wrap `build` so this is really it
|
||||
name: "jellyfin-web"
|
||||
version: "10.6.0"
|
||||
version: "10.7.0"
|
||||
packages:
|
||||
- debian.all
|
||||
- fedora.all
|
||||
|
|
23
bump_version
23
bump_version
|
@ -4,6 +4,7 @@
|
|||
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
set -o xtrace
|
||||
|
||||
usage() {
|
||||
echo -e "bump_version - increase the shared version and generate changelogs"
|
||||
|
@ -23,10 +24,7 @@ build_file="./build.yaml"
|
|||
new_version="$1"
|
||||
|
||||
# Parse the version from shared version file
|
||||
old_version="$(
|
||||
grep "appVersion" ${shared_version_file} | head -1 \
|
||||
| sed -E 's/var appVersion = "([0-9\.]+)";/\1/'
|
||||
)"
|
||||
old_version="$( grep "appVersion" ${shared_version_file} | head -1 | sed -E "s/var appVersion = '([0-9\.]+)';/\1/" | tr -d '[:space:]' )"
|
||||
echo "Old version in appHost is: $old_version"
|
||||
|
||||
# Set the shared version to the specified new_version
|
||||
|
@ -34,11 +32,8 @@ old_version_sed="$( sed 's/\./\\./g' <<<"${old_version}" )" # Escape the '.' cha
|
|||
new_version_sed="$( cut -f1 -d'-' <<<"${new_version}" )"
|
||||
sed -i "s/${old_version_sed}/${new_version_sed}/g" ${shared_version_file}
|
||||
|
||||
old_version="$(
|
||||
grep "version:" ${build_file} \
|
||||
| sed -E 's/version: "([0-9\.]+[-a-z0-9]*)"/\1/'
|
||||
)"
|
||||
echo "Old version in ${build_file}: $old_version`"
|
||||
old_version="$( grep "version:" ${build_file} | sed -E 's/version: "([0-9\.]+[-a-z0-9]*)"/\1/' )"
|
||||
echo "Old version in ${build_file}: ${old_version}"
|
||||
|
||||
# Set the build.yaml version to the specified new_version
|
||||
old_version_sed="$( sed 's/\./\\./g' <<<"${old_version}" )" # Escape the '.' chars
|
||||
|
@ -54,7 +49,7 @@ fi
|
|||
debian_changelog_file="debian/changelog"
|
||||
debian_changelog_temp="$( mktemp )"
|
||||
# Create new temp file with our changelog
|
||||
echo -e "jellyfin (${new_version_deb}) unstable; urgency=medium
|
||||
echo -e "jellyfin-web (${new_version_deb}) unstable; urgency=medium
|
||||
|
||||
* New upstream version ${new_version}; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v${new_version}
|
||||
|
||||
|
@ -65,15 +60,15 @@ cat ${debian_changelog_file} >> ${debian_changelog_temp}
|
|||
mv ${debian_changelog_temp} ${debian_changelog_file}
|
||||
|
||||
# Write out a temporary Yum changelog with our new stuff prepended and some templated formatting
|
||||
fedora_spec_file="fedora/jellyfin.spec"
|
||||
fedora_spec_file="fedora/jellyfin-web.spec"
|
||||
fedora_changelog_temp="$( mktemp )"
|
||||
fedora_spec_temp_dir="$( mktemp -d )"
|
||||
fedora_spec_temp="${fedora_spec_temp_dir}/jellyfin.spec.tmp"
|
||||
fedora_spec_temp="${fedora_spec_temp_dir}/jellyfin-web.spec.tmp"
|
||||
# Make a copy of our spec file for hacking
|
||||
cp ${fedora_spec_file} ${fedora_spec_temp_dir}/
|
||||
pushd ${fedora_spec_temp_dir}
|
||||
# Split out the stuff before and after changelog
|
||||
csplit jellyfin.spec "/^%changelog/" # produces xx00 xx01
|
||||
csplit jellyfin-web.spec "/^%changelog/" # produces xx00 xx01
|
||||
# Update the version in xx00
|
||||
sed -i "s/${old_version_sed}/${new_version_sed}/g" xx00
|
||||
# Remove the header from xx01
|
||||
|
@ -92,5 +87,5 @@ mv ${fedora_spec_temp} ${fedora_spec_file}
|
|||
rm -rf ${fedora_changelog_temp} ${fedora_spec_temp_dir}
|
||||
|
||||
# Stage the changed files for commit
|
||||
git add ${shared_version_file} ${build_file} ${debian_changelog_file} ${fedora_spec_file} Dockerfile*
|
||||
git add ${shared_version_file} ${build_file} ${debian_changelog_file} ${fedora_spec_file}
|
||||
git status
|
||||
|
|
6
debian/changelog
vendored
6
debian/changelog
vendored
|
@ -1,3 +1,9 @@
|
|||
jellyfin-web (10.7.0-1) unstable; urgency=medium
|
||||
|
||||
* Forthcoming stable release
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Mon, 27 Jul 2020 19:13:31 -0400
|
||||
|
||||
jellyfin-web (10.6.0-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.6.0; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
%global debug_package %{nil}
|
||||
|
||||
Name: jellyfin-web
|
||||
Version: 10.6.0
|
||||
Version: 10.7.0
|
||||
Release: 1%{?dist}
|
||||
Summary: The Free Software Media System web client
|
||||
License: GPLv3
|
||||
|
@ -11,6 +11,8 @@ Source0: jellyfin-web-%{version}.tar.gz
|
|||
|
||||
%if 0%{?centos}
|
||||
BuildRequires: yarn
|
||||
# sadly the yarn RPM at https://dl.yarnpkg.com/rpm/ uses git but doesn't Requires: it
|
||||
BuildRequires: git
|
||||
%else
|
||||
BuildRequires: nodejs-yarn
|
||||
%endif
|
||||
|
@ -39,5 +41,7 @@ mv dist %{buildroot}%{_datadir}/jellyfin-web
|
|||
%{_datadir}/licenses/jellyfin/LICENSE
|
||||
|
||||
%changelog
|
||||
* Mon Jul 27 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- Forthcoming stable release
|
||||
* Mon Mar 23 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- Forthcoming stable release
|
||||
|
|
157
package.json
157
package.json
|
@ -5,26 +5,28 @@
|
|||
"repository": "https://github.com/jellyfin/jellyfin-web",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.10.5",
|
||||
"@babel/core": "^7.11.5",
|
||||
"@babel/eslint-parser": "^7.11.5",
|
||||
"@babel/eslint-plugin": "^7.11.5",
|
||||
"@babel/plugin-proposal-class-properties": "^7.10.1",
|
||||
"@babel/plugin-proposal-private-methods": "^7.10.1",
|
||||
"@babel/plugin-transform-modules-amd": "^7.10.5",
|
||||
"@babel/polyfill": "^7.8.7",
|
||||
"@babel/preset-env": "^7.10.3",
|
||||
"autoprefixer": "^9.8.5",
|
||||
"babel-eslint": "^11.0.0-beta.2",
|
||||
"@babel/polyfill": "^7.11.5",
|
||||
"@babel/preset-env": "^7.11.5",
|
||||
"autoprefixer": "^9.8.6",
|
||||
"babel-loader": "^8.0.6",
|
||||
"browser-sync": "^2.26.10",
|
||||
"browser-sync": "^2.26.12",
|
||||
"confusing-browser-globals": "^1.0.9",
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"css-loader": "^4.0.0",
|
||||
"css-loader": "^4.2.2",
|
||||
"cssnano": "^4.1.10",
|
||||
"del": "^5.1.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint": "^7.8.1",
|
||||
"eslint-plugin-compat": "^3.5.1",
|
||||
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||
"eslint-plugin-import": "^2.21.2",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"file-loader": "^6.0.0",
|
||||
"file-loader": "^6.1.0",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-babel": "^8.0.0",
|
||||
"gulp-cli": "^2.3.0",
|
||||
|
@ -37,50 +39,51 @@
|
|||
"gulp-postcss": "^8.0.0",
|
||||
"gulp-sass": "^4.0.2",
|
||||
"gulp-sourcemaps": "^2.6.5",
|
||||
"gulp-terser": "^1.2.1",
|
||||
"html-webpack-plugin": "^4.3.0",
|
||||
"gulp-terser": "^1.4.0",
|
||||
"html-webpack-plugin": "^4.4.1",
|
||||
"lazypipe": "^1.0.2",
|
||||
"node-sass": "^4.13.1",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"postcss-preset-env": "^6.7.0",
|
||||
"style-loader": "^1.1.3",
|
||||
"stylelint": "^13.6.1",
|
||||
"stylelint": "^13.7.0",
|
||||
"stylelint-config-rational-order": "^0.1.2",
|
||||
"stylelint-no-browser-hacks": "^1.2.1",
|
||||
"stylelint-order": "^4.1.0",
|
||||
"webpack": "^4.44.0",
|
||||
"webpack": "^4.44.1",
|
||||
"webpack-merge": "^4.2.2",
|
||||
"webpack-stream": "^5.2.1"
|
||||
"webpack-stream": "^6.1.0",
|
||||
"worker-plugin": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"alameda": "^1.4.0",
|
||||
"blurhash": "^1.1.3",
|
||||
"classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
|
||||
"core-js": "^3.6.5",
|
||||
"date-fns": "^2.15.0",
|
||||
"date-fns": "^2.16.1",
|
||||
"epubjs": "^0.3.85",
|
||||
"fast-text-encoding": "^1.0.3",
|
||||
"flv.js": "^1.5.0",
|
||||
"headroom.js": "^0.11.0",
|
||||
"hls.js": "^0.14.5",
|
||||
"hls.js": "^0.14.11",
|
||||
"howler": "^2.2.0",
|
||||
"intersection-observer": "^0.11.0",
|
||||
"jellyfin-apiclient": "^1.4.1",
|
||||
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
|
||||
"jquery": "^3.5.1",
|
||||
"jstree": "^3.3.10",
|
||||
"libarchive.js": "^1.3.0",
|
||||
"libass-wasm": "https://github.com/jellyfin/JavascriptSubtitlesOctopus#4.0.0-jf-smarttv",
|
||||
"material-design-icons-iconfont": "^5.0.1",
|
||||
"material-design-icons-iconfont": "^6.0.1",
|
||||
"native-promise-only": "^0.8.0-a",
|
||||
"page": "^1.11.6",
|
||||
"query-string": "^6.13.1",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"screenfull": "^5.0.2",
|
||||
"shaka-player": "^2.5.13",
|
||||
"sortablejs": "^1.10.2",
|
||||
"swiper": "^5.4.5",
|
||||
"swiper": "^6.1.1",
|
||||
"webcomponents.js": "^0.7.24",
|
||||
"whatwg-fetch": "^3.2.0"
|
||||
"whatwg-fetch": "^3.4.0"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
|
@ -95,6 +98,8 @@
|
|||
"src/components/alert.js",
|
||||
"src/components/alphaPicker/alphaPicker.js",
|
||||
"src/components/appFooter/appFooter.js",
|
||||
"src/components/apphost.js",
|
||||
"src/components/appRouter.js",
|
||||
"src/components/autoFocuser.js",
|
||||
"src/components/backdrop/backdrop.js",
|
||||
"src/components/cardbuilder/cardBuilder.js",
|
||||
|
@ -107,22 +112,33 @@
|
|||
"src/components/dialogHelper/dialogHelper.js",
|
||||
"src/components/directorybrowser/directorybrowser.js",
|
||||
"src/components/displaySettings/displaySettings.js",
|
||||
"src/components/favoriteitems.js",
|
||||
"src/components/fetchhelper.js",
|
||||
"src/components/filterdialog/filterdialog.js",
|
||||
"src/components/filtermenu/filtermenu.js",
|
||||
"src/components/focusManager.js",
|
||||
"src/components/groupedcards.js",
|
||||
"src/components/guide/guide.js",
|
||||
"src/components/guide/guide-settings.js",
|
||||
"src/components/homeScreenSettings/homeScreenSettings.js",
|
||||
"src/components/homesections/homesections.js",
|
||||
"src/components/htmlMediaHelper.js",
|
||||
"src/components/imageOptionsEditor/imageOptionsEditor.js",
|
||||
"src/components/images/imageLoader.js",
|
||||
"src/components/imageDownloader/imageDownloader.js",
|
||||
"src/components/imageeditor/imageeditor.js",
|
||||
"src/components/imageUploader/imageUploader.js",
|
||||
"src/components/indicators/indicators.js",
|
||||
"src/components/itemContextMenu.js",
|
||||
"src/components/itemHelper.js",
|
||||
"src/components/itemidentifier/itemidentifier.js",
|
||||
"src/components/itemMediaInfo/itemMediaInfo.js",
|
||||
"src/components/itemsrefresher.js",
|
||||
"src/components/layoutManager.js",
|
||||
"src/components/lazyLoader/lazyLoaderIntersectionObserver.js",
|
||||
"src/components/libraryoptionseditor/libraryoptionseditor.js",
|
||||
"src/components/listview/listview.js",
|
||||
"src/components/loading/loading.js",
|
||||
"src/components/maintabsmanager.js",
|
||||
"src/components/mediainfo/mediainfo.js",
|
||||
"src/components/mediaLibraryCreator/mediaLibraryCreator.js",
|
||||
|
@ -130,39 +146,77 @@
|
|||
"src/components/metadataEditor/metadataEditor.js",
|
||||
"src/components/metadataEditor/personEditor.js",
|
||||
"src/components/multiSelect/multiSelect.js",
|
||||
"src/components/notifications/notifications.js",
|
||||
"src/components/nowPlayingBar/nowPlayingBar.js",
|
||||
"src/components/packageManager.js",
|
||||
"src/components/playback/brightnessosd.js",
|
||||
"src/components/playback/mediasession.js",
|
||||
"src/components/playback/nowplayinghelper.js",
|
||||
"src/components/playback/playbackorientation.js",
|
||||
"src/components/playback/playbackmanager.js",
|
||||
"src/components/playback/playerSelectionMenu.js",
|
||||
"src/components/playback/playersettingsmenu.js",
|
||||
"src/components/playback/playmethodhelper.js",
|
||||
"src/components/playback/playqueuemanager.js",
|
||||
"src/components/playback/remotecontrolautoplay.js",
|
||||
"src/components/playback/volumeosd.js",
|
||||
"src/components/playbackSettings/playbackSettings.js",
|
||||
"src/components/playerstats/playerstats.js",
|
||||
"src/components/playlisteditor/playlisteditor.js",
|
||||
"src/components/playmenu.js",
|
||||
"src/components/pluginManager.js",
|
||||
"src/components/prompt/prompt.js",
|
||||
"src/components/qualityOptions.js",
|
||||
"src/components/quickConnectSettings/quickConnectSettings.js",
|
||||
"src/components/recordingcreator/recordingbutton.js",
|
||||
"src/components/recordingcreator/recordingcreator.js",
|
||||
"src/components/recordingcreator/seriesrecordingeditor.js",
|
||||
"src/components/recordingcreator/recordinghelper.js",
|
||||
"src/components/refreshdialog/refreshdialog.js",
|
||||
"src/components/recordingcreator/recordingeditor.js",
|
||||
"src/components/recordingcreator/recordingfields.js",
|
||||
"src/components/remotecontrol/remotecontrol.js",
|
||||
"src/components/sanatizefilename.js",
|
||||
"src/components/scrollManager.js",
|
||||
"src/plugins/experimentalWarnings/plugin.js",
|
||||
"src/plugins/sessionPlayer/plugin.js",
|
||||
"src/plugins/htmlAudioPlayer/plugin.js",
|
||||
"src/plugins/comicsPlayer/plugin.js",
|
||||
"src/plugins/chromecastPlayer/plugin.js",
|
||||
"src/components/slideshow/slideshow.js",
|
||||
"src/components/sortmenu/sortmenu.js",
|
||||
"src/plugins/htmlVideoPlayer/plugin.js",
|
||||
"src/plugins/logoScreensaver/plugin.js",
|
||||
"src/plugins/playAccessValidation/plugin.js",
|
||||
"src/components/search/searchfields.js",
|
||||
"src/components/search/searchresults.js",
|
||||
"src/components/settingshelper.js",
|
||||
"src/components/shortcuts.js",
|
||||
"src/components/subtitleeditor/subtitleeditor.js",
|
||||
"src/components/subtitlesync/subtitlesync.js",
|
||||
"src/components/subtitlesettings/subtitleappearancehelper.js",
|
||||
"src/components/subtitlesettings/subtitlesettings.js",
|
||||
"src/components/syncPlay/groupSelectionMenu.js",
|
||||
"src/components/syncPlay/playbackPermissionManager.js",
|
||||
"src/components/syncPlay/syncPlayManager.js",
|
||||
"src/components/syncPlay/timeSyncManager.js",
|
||||
"src/components/themeMediaPlayer.js",
|
||||
"src/components/tabbedview/tabbedview.js",
|
||||
"src/components/viewManager/viewManager.js",
|
||||
"src/components/tvproviders/schedulesdirect.js",
|
||||
"src/components/tvproviders/xmltv.js",
|
||||
"src/components/toast/toast.js",
|
||||
"src/components/tunerPicker.js",
|
||||
"src/components/upnextdialog/upnextdialog.js",
|
||||
"src/components/userdatabuttons/userdatabuttons.js",
|
||||
"src/components/viewContainer.js",
|
||||
"src/components/viewSettings/viewSettings.js",
|
||||
"src/components/castSenderApi.js",
|
||||
"src/controllers/session/addServer/index.js",
|
||||
"src/controllers/session/forgotPassword/index.js",
|
||||
"src/controllers/session/redeemPassword/index.js",
|
||||
"src/controllers/session/login/index.js",
|
||||
"src/controllers/sessopm/selectServer/index.js",
|
||||
"src/controllers/session/selectServer/index.js",
|
||||
"src/controllers/dashboard/apikeys.js",
|
||||
"src/controllers/dashboard/dashboard.js",
|
||||
"src/controllers/dashboard/devices/device.js",
|
||||
|
@ -174,13 +228,24 @@
|
|||
"src/controllers/dashboard/general.js",
|
||||
"src/controllers/dashboard/librarydisplay.js",
|
||||
"src/controllers/dashboard/logs.js",
|
||||
"src/controllers/dashboard/mediaLibrary.js",
|
||||
"src/controllers/music/musicalbums.js",
|
||||
"src/controllers/music/musicartists.js",
|
||||
"src/controllers/music/musicgenres.js",
|
||||
"src/controllers/music/musicplaylists.js",
|
||||
"src/controllers/music/musicrecommended.js",
|
||||
"src/controllers/music/songs.js",
|
||||
"src/controllers/dashboard/library.js",
|
||||
"src/controllers/dashboard/metadataImages.js",
|
||||
"src/controllers/dashboard/metadatanfo.js",
|
||||
"src/controllers/dashboard/networking.js",
|
||||
"src/controllers/dashboard/notifications/notification/index.js",
|
||||
"src/controllers/dashboard/notifications/notifications/index.js",
|
||||
"src/controllers/dashboard/playback.js",
|
||||
"src/controllers/dashboard/quickconnect.js",
|
||||
"src/controllers/dashboard/plugins/add/index.js",
|
||||
"src/controllers/dashboard/plugins/installed/index.js",
|
||||
"src/controllers/dashboard/plugins/available/index.js",
|
||||
"src/controllers/dashboard/plugins/repositories/index.js",
|
||||
"src/controllers/dashboard/quickconnect.js",
|
||||
"src/controllers/dashboard/scheduledtasks/scheduledtask.js",
|
||||
"src/controllers/dashboard/scheduledtasks/scheduledtasks.js",
|
||||
"src/controllers/dashboard/serveractivity.js",
|
||||
|
@ -191,9 +256,32 @@
|
|||
"src/controllers/dashboard/users/userparentalcontrol.js",
|
||||
"src/controllers/dashboard/users/userpasswordpage.js",
|
||||
"src/controllers/dashboard/users/userprofilespage.js",
|
||||
"src/controllers/home.js",
|
||||
"src/controllers/list.js",
|
||||
"src/controllers/edititemmetadata.js",
|
||||
"src/controllers/favorites.js",
|
||||
"src/controllers/hometab.js",
|
||||
"src/controllers/movies/moviecollections.js",
|
||||
"src/controllers/movies/moviegenres.js",
|
||||
"src/controllers/movies/movies.js",
|
||||
"src/controllers/movies/moviesrecommended.js",
|
||||
"src/controllers/movies/movietrailers.js",
|
||||
"src/controllers/playback/nowplaying.js",
|
||||
"src/controllers/playback/videoosd.js",
|
||||
"src/controllers/itemDetails/index.js",
|
||||
"src/controllers/playback/queue/index.js",
|
||||
"src/controllers/playback/video/index.js",
|
||||
"src/controllers/searchpage.js",
|
||||
"src/controllers/livetv/livetvguide.js",
|
||||
"src/controllers/livetvtuner.js",
|
||||
"src/controllers/livetv/livetvsuggested.js",
|
||||
"src/controllers/livetvstatus.js",
|
||||
"src/controllers/livetvguideprovider.js",
|
||||
"src/controllers/livetvsettings.js",
|
||||
"src/controllers/livetv/livetvrecordings.js",
|
||||
"src/controllers/livetv/livetvschedule.js",
|
||||
"src/controllers/livetv/livetvseriestimers.js",
|
||||
"src/controllers/livetv/livetvchannels.js",
|
||||
"src/controllers/shows/episodes.js",
|
||||
"src/controllers/shows/tvgenres.js",
|
||||
"src/controllers/shows/tvlatest.js",
|
||||
|
@ -208,7 +296,6 @@
|
|||
"src/controllers/user/profile/index.js",
|
||||
"src/controllers/user/quickConnect/index.js",
|
||||
"src/controllers/user/subtitles/index.js",
|
||||
"src/controllers/user/subtitles/index.js",
|
||||
"src/controllers/wizard/finish/index.js",
|
||||
"src/controllers/wizard/remote/index.js",
|
||||
"src/controllers/wizard/settings/index.js",
|
||||
|
@ -234,13 +321,19 @@
|
|||
"src/elements/emby-tabs/emby-tabs.js",
|
||||
"src/elements/emby-textarea/emby-textarea.js",
|
||||
"src/elements/emby-toggle/emby-toggle.js",
|
||||
"src/libraries/screensavermanager.js",
|
||||
"src/libraries/navdrawer/navdrawer.js",
|
||||
"src/libraries/scroller.js",
|
||||
"src/plugins/backdropScreensaver/plugin.js",
|
||||
"src/plugins/bookPlayer/plugin.js",
|
||||
"src/plugins/bookPlayer/tableOfContents.js",
|
||||
"src/plugins/chromecastPlayer/chromecastHelper.js",
|
||||
"src/plugins/photoPlayer/plugin.js",
|
||||
"src/plugins/youtubePlayer/plugin.js",
|
||||
"src/scripts/alphanumericshortcuts.js",
|
||||
"src/scripts/autoBackdrops.js",
|
||||
"src/scripts/browser.js",
|
||||
"src/scripts/clientUtils.js",
|
||||
"src/scripts/datetime.js",
|
||||
"src/scripts/deleteHelper.js",
|
||||
"src/scripts/dfnshelper.js",
|
||||
|
@ -250,12 +343,24 @@
|
|||
"src/scripts/filesystem.js",
|
||||
"src/scripts/globalize.js",
|
||||
"src/scripts/imagehelper.js",
|
||||
"src/scripts/itembynamedetailpage.js",
|
||||
"src/scripts/inputManager.js",
|
||||
"src/scripts/autoThemes.js",
|
||||
"src/scripts/themeManager.js",
|
||||
"src/scripts/keyboardNavigation.js",
|
||||
"src/scripts/libraryMenu.js",
|
||||
"src/scripts/libraryBrowser.js",
|
||||
"src/scripts/livetvcomponents.js",
|
||||
"src/scripts/mouseManager.js",
|
||||
"src/scripts/multiDownload.js",
|
||||
"src/scripts/playlists.js",
|
||||
"src/scripts/scrollHelper.js",
|
||||
"src/scripts/serverNotifications.js",
|
||||
"src/scripts/routes.js",
|
||||
"src/scripts/settings/appSettings.js",
|
||||
"src/scripts/settings/userSettings.js",
|
||||
"src/scripts/settings/webSettings.js",
|
||||
"src/scripts/shell.js",
|
||||
"src/scripts/taskbutton.js",
|
||||
"src/scripts/themeLoader.js",
|
||||
"src/scripts/touchHelper.js"
|
||||
|
@ -273,7 +378,7 @@
|
|||
"last 2 Chrome versions",
|
||||
"last 2 ChromeAndroid versions",
|
||||
"last 2 Safari versions",
|
||||
"last 2 iOS versions",
|
||||
"iOS > 10",
|
||||
"last 2 Edge versions",
|
||||
"Chrome 27",
|
||||
"Chrome 38",
|
||||
|
@ -281,9 +386,11 @@
|
|||
"Chrome 53",
|
||||
"Chrome 56",
|
||||
"Chrome 63",
|
||||
"Edge 18",
|
||||
"Firefox ESR"
|
||||
],
|
||||
"scripts": {
|
||||
"start": "yarn serve",
|
||||
"serve": "gulp serve --development",
|
||||
"prepare": "gulp --production",
|
||||
"build:development": "gulp --development",
|
||||
|
|
33
scripts/duplicates.py
Normal file
33
scripts/duplicates.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
import sys
|
||||
import os
|
||||
import json
|
||||
|
||||
# load every string in the source language
|
||||
# print all duplicate values to a file
|
||||
|
||||
cwd = os.getcwd()
|
||||
source = cwd + '/../src/strings/en-us.json'
|
||||
|
||||
reverse = {}
|
||||
duplicates = {}
|
||||
|
||||
with open(source) as en:
|
||||
strings = json.load(en)
|
||||
for key, value in strings.items():
|
||||
if value not in reverse:
|
||||
reverse[value] = [key]
|
||||
else:
|
||||
reverse[value].append(key)
|
||||
|
||||
for key, value in reverse.items():
|
||||
if len(value) > 1:
|
||||
duplicates[key] = value
|
||||
|
||||
print('LENGTH: ' + str(len(duplicates)))
|
||||
with open('duplicates.txt', 'w') as out:
|
||||
for item in duplicates:
|
||||
out.write(json.dumps(item) + ': ')
|
||||
out.write(json.dumps(duplicates[item]) + '\n')
|
||||
out.close()
|
||||
|
||||
print('DONE')
|
|
@ -11,7 +11,7 @@ langlst = os.listdir(langdir)
|
|||
|
||||
keys = []
|
||||
|
||||
with open('scout.txt', 'r') as f:
|
||||
with open('unused.txt', 'r') as f:
|
||||
for line in f:
|
||||
keys.append(line.strip('\n'))
|
||||
|
|
@ -16,7 +16,7 @@ langlst.append('en-us.json')
|
|||
dep = []
|
||||
|
||||
def grep(key):
|
||||
command = 'grep -r -E "(\(\\\"|\(\'|\{)%s(\\\"|\'|\})" --include=\*.{js,html} --exclude-dir=../src/strings ../src' % key
|
||||
command = 'grep -r -E "(\\\"|\'|\{)%s(\\\"|\'|\})" --include=\*.{js,html} --exclude-dir=../src/strings ../src' % key
|
||||
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
output = p.stdout.readlines()
|
||||
if output:
|
|
@ -1,7 +1,5 @@
|
|||
html {
|
||||
font-family: "Noto Sans", sans-serif;
|
||||
font-size: 93%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
text-size-adjust: 100%;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
|
@ -29,7 +27,9 @@ h3 {
|
|||
}
|
||||
|
||||
.layout-tv {
|
||||
font-size: 130%;
|
||||
/* Per WebOS and Tizen guidelines, fonts must be 20px minimum.
|
||||
This takes the 16px baseline and multiplies it by 1.25 to get 20px. */
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
.layout-mobile {
|
||||
|
|
|
@ -28,6 +28,10 @@
|
|||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
.layout-tv .itemDetailPage {
|
||||
padding-top: 4.2em !important;
|
||||
}
|
||||
|
||||
.standalonePage {
|
||||
padding-top: 4.5em !important;
|
||||
}
|
||||
|
@ -163,6 +167,12 @@
|
|||
transition: background ease-in-out 0.5s;
|
||||
}
|
||||
|
||||
.layout-tv .skinHeader {
|
||||
/* In TV layout, it makes more sense to keep the top bar at the top of the page
|
||||
Having it follow the view only makes us lose vertical space, while not being focusable */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hiddenViewMenuBar .skinHeader {
|
||||
display: none;
|
||||
}
|
||||
|
@ -236,12 +246,6 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.layout-desktop .searchTabButton,
|
||||
.layout-mobile .searchTabButton,
|
||||
.layout-tv .headerSearchButton {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mainDrawer-scrollContainer {
|
||||
padding-bottom: 10vh;
|
||||
}
|
||||
|
@ -453,8 +457,7 @@
|
|||
height: 26.5vh;
|
||||
}
|
||||
|
||||
.layout-desktop .itemBackdrop::after,
|
||||
.layout-tv .itemBackdrop::after {
|
||||
.layout-desktop .itemBackdrop::after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -462,8 +465,8 @@
|
|||
display: block;
|
||||
}
|
||||
|
||||
.layout-desktop .noBackdrop .itemBackdrop,
|
||||
.layout-tv .noBackdrop .itemBackdrop {
|
||||
.layout-tv .itemBackdrop,
|
||||
.layout-desktop .noBackdrop .itemBackdrop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -630,6 +633,10 @@
|
|||
z-index: 2;
|
||||
}
|
||||
|
||||
.layout-tv .detailPagePrimaryContainer {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.layout-mobile .detailPagePrimaryContainer {
|
||||
display: block;
|
||||
position: relative;
|
||||
|
@ -643,10 +650,14 @@
|
|||
padding-left: 32.45vw;
|
||||
}
|
||||
|
||||
.layout-desktop .detailRibbon,
|
||||
.layout-tv .detailRibbon {
|
||||
.layout-desktop .detailRibbon {
|
||||
margin-top: -7.2em;
|
||||
height: 7.18em;
|
||||
height: 7.2em;
|
||||
}
|
||||
|
||||
.layout-tv .detailRibbon {
|
||||
margin-top: 0;
|
||||
height: inherit;
|
||||
}
|
||||
|
||||
.layout-desktop .noBackdrop .detailRibbon,
|
||||
|
@ -754,8 +765,7 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.layout-desktop .itemBackdrop,
|
||||
.layout-tv .itemBackdrop {
|
||||
.layout-desktop .itemBackdrop {
|
||||
height: 40vh;
|
||||
}
|
||||
|
||||
|
@ -781,13 +791,8 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
|||
}
|
||||
|
||||
.emby-button.detailFloatingButton {
|
||||
position: absolute;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 3;
|
||||
top: 100%;
|
||||
left: 90%;
|
||||
margin: -2.2em 0 0 -2.2em;
|
||||
padding: 0.4em;
|
||||
font-size: 1.4em;
|
||||
margin-right: 0.5em !important;
|
||||
color: rgba(255, 255, 255, 0.76);
|
||||
}
|
||||
|
||||
|
@ -850,7 +855,7 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
|||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
margin: 0 !important;
|
||||
padding: 0.5em 0.7em !important;
|
||||
padding: 0.7em 0.7em !important;
|
||||
}
|
||||
|
||||
@media all and (min-width: 29em) {
|
||||
|
@ -919,10 +924,6 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
|||
}
|
||||
|
||||
@media all and (min-width: 100em) {
|
||||
.detailFloatingButton {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.personBackdrop {
|
||||
display: none !important;
|
||||
}
|
||||
|
@ -931,6 +932,11 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
|||
font-size: 108%;
|
||||
margin: 1.25em 0;
|
||||
}
|
||||
|
||||
.layout-tv .mainDetailButtons {
|
||||
font-size: 108%;
|
||||
margin: 1em 0 1.25em;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 50em) {
|
||||
|
@ -1146,13 +1152,13 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards {
|
|||
}
|
||||
|
||||
.layout-tv .padded-top-focusscale {
|
||||
padding-top: 1em;
|
||||
margin-top: -1em;
|
||||
padding-top: 1.5em;
|
||||
margin-top: -1.5em;
|
||||
}
|
||||
|
||||
.layout-tv .padded-bottom-focusscale {
|
||||
padding-bottom: 1em;
|
||||
margin-bottom: -1em;
|
||||
padding-bottom: 1.5em;
|
||||
margin-bottom: -1.5em;
|
||||
}
|
||||
|
||||
@media all and (min-height: 31.25em) {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
}
|
||||
|
||||
.osdPoster img,
|
||||
.pageContainer,
|
||||
.videoOsdBottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
@ -248,14 +247,7 @@
|
|||
animation: spin 4s linear infinite;
|
||||
}
|
||||
|
||||
.pageContainer {
|
||||
top: 0;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
@media all and (max-width: 30em) {
|
||||
.btnFastForward,
|
||||
.btnRewind,
|
||||
.osdMediaInfo,
|
||||
.osdPoster {
|
||||
display: none !important;
|
||||
|
|
1
src/assets/img/devices/edgechromium.svg
Normal file
1
src/assets/img/devices/edgechromium.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24"><title>Microsoft Edge icon</title><path d="M21.86 17.86q.14 0 .25.12.1.13.1.25t-.11.33l-.32.46-.43.53-.44.5q-.21.25-.38.42l-.22.23q-.58.53-1.34 1.04-.76.51-1.6.91-.86.4-1.74.64t-1.67.24q-.9 0-1.69-.28-.8-.28-1.48-.78-.68-.5-1.22-1.17-.53-.66-.92-1.44-.38-.77-.58-1.6-.2-.83-.2-1.67 0-1 .32-1.96.33-.97.87-1.8.14.95.55 1.77.41.82 1.02 1.5.6.68 1.38 1.21.78.54 1.64.9.86.36 1.77.56.92.2 1.8.2 1.12 0 2.18-.24 1.06-.23 2.06-.72l.2-.1.2-.05zm-15.5-1.27q0 1.1.27 2.15.27 1.06.78 2.03.51.96 1.24 1.77.74.82 1.66 1.4-1.47-.2-2.8-.74-1.33-.55-2.48-1.37-1.15-.83-2.08-1.9-.92-1.07-1.58-2.33T.36 14.94Q0 13.54 0 12.06q0-.81.32-1.49.31-.68.83-1.23.53-.55 1.2-.96.66-.4 1.35-.66.74-.27 1.5-.39.78-.12 1.55-.12.7 0 1.42.1.72.12 1.4.35.68.23 1.32.57.63.35 1.16.83-.35 0-.7.07-.33.07-.65.23v-.02q-.63.28-1.2.74-.57.46-1.05 1.04-.48.58-.87 1.26-.38.67-.65 1.39-.27.71-.42 1.44-.15.72-.15 1.38zM11.96.06q1.7 0 3.33.39 1.63.38 3.07 1.15 1.43.77 2.62 1.93 1.18 1.16 1.98 2.7.49.94.76 1.96.28 1 .28 2.08 0 .89-.23 1.7-.24.8-.69 1.48-.45.68-1.1 1.22-.64.53-1.45.88-.54.24-1.11.36-.58.13-1.16.13-.42 0-.97-.03-.54-.03-1.1-.12-.55-.1-1.05-.28-.5-.19-.84-.5-.12-.09-.23-.24-.1-.16-.1-.33 0-.15.16-.35.16-.2.35-.5.2-.28.36-.68.16-.4.16-.95 0-1.06-.4-1.96-.4-.91-1.06-1.64-.66-.74-1.52-1.28-.86-.55-1.79-.89-.84-.3-1.72-.44-.87-.14-1.76-.14-1.55 0-3.06.45T.94 7.55q.71-1.74 1.81-3.13 1.1-1.38 2.52-2.35Q6.68 1.1 8.37.58q1.7-.52 3.58-.52Z" fill="#fff"/></svg>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -2,165 +2,159 @@
|
|||
* require.js module definitions bundled by webpack
|
||||
*/
|
||||
// Use define from require.js not webpack's define
|
||||
var _define = window.define;
|
||||
const _define = window.define;
|
||||
|
||||
// fetch
|
||||
var fetch = require('whatwg-fetch');
|
||||
const fetch = require('whatwg-fetch');
|
||||
_define('fetch', function() {
|
||||
return fetch;
|
||||
});
|
||||
|
||||
// Blurhash
|
||||
var blurhash = require('blurhash');
|
||||
const blurhash = require('blurhash');
|
||||
_define('blurhash', function() {
|
||||
return blurhash;
|
||||
});
|
||||
|
||||
// query-string
|
||||
var query = require('query-string');
|
||||
const query = require('query-string');
|
||||
_define('queryString', function() {
|
||||
return query;
|
||||
});
|
||||
|
||||
// flvjs
|
||||
var flvjs = require('flv.js/dist/flv').default;
|
||||
const flvjs = require('flv.js/dist/flv').default;
|
||||
_define('flvjs', function() {
|
||||
return flvjs;
|
||||
});
|
||||
|
||||
// jstree
|
||||
var jstree = require('jstree');
|
||||
const jstree = require('jstree');
|
||||
require('jstree/dist/themes/default/style.css');
|
||||
_define('jstree', function() {
|
||||
return jstree;
|
||||
});
|
||||
|
||||
// jquery
|
||||
var jquery = require('jquery');
|
||||
const jquery = require('jquery');
|
||||
_define('jQuery', function() {
|
||||
return jquery;
|
||||
});
|
||||
|
||||
// hlsjs
|
||||
var hlsjs = require('hls.js');
|
||||
const hlsjs = require('hls.js');
|
||||
_define('hlsjs', function() {
|
||||
return hlsjs;
|
||||
});
|
||||
|
||||
// howler
|
||||
var howler = require('howler');
|
||||
const howler = require('howler');
|
||||
_define('howler', function() {
|
||||
return howler;
|
||||
});
|
||||
|
||||
// resize-observer-polyfill
|
||||
var resize = require('resize-observer-polyfill').default;
|
||||
const resize = require('resize-observer-polyfill').default;
|
||||
_define('resize-observer-polyfill', function() {
|
||||
return resize;
|
||||
});
|
||||
|
||||
// swiper
|
||||
var swiper = require('swiper/js/swiper');
|
||||
require('swiper/css/swiper.min.css');
|
||||
const swiper = require('swiper/swiper-bundle');
|
||||
require('swiper/swiper-bundle.css');
|
||||
_define('swiper', function() {
|
||||
return swiper;
|
||||
});
|
||||
|
||||
// sortable
|
||||
var sortable = require('sortablejs').default;
|
||||
const sortable = require('sortablejs').default;
|
||||
_define('sortable', function() {
|
||||
return sortable;
|
||||
});
|
||||
|
||||
// webcomponents
|
||||
var webcomponents = require('webcomponents.js/webcomponents-lite');
|
||||
const webcomponents = require('webcomponents.js/webcomponents-lite');
|
||||
_define('webcomponents', function() {
|
||||
return webcomponents;
|
||||
});
|
||||
|
||||
// shaka
|
||||
var shaka = require('shaka-player');
|
||||
_define('shaka', function() {
|
||||
return shaka;
|
||||
});
|
||||
|
||||
// libass-wasm
|
||||
var libassWasm = require('libass-wasm');
|
||||
const libassWasm = require('libass-wasm');
|
||||
_define('JavascriptSubtitlesOctopus', function() {
|
||||
return libassWasm;
|
||||
});
|
||||
|
||||
// material-icons
|
||||
var materialIcons = require('material-design-icons-iconfont/dist/material-design-icons.css');
|
||||
const materialIcons = require('material-design-icons-iconfont/dist/material-design-icons.css');
|
||||
_define('material-icons', function() {
|
||||
return materialIcons;
|
||||
});
|
||||
|
||||
// noto font
|
||||
var noto = require('jellyfin-noto');
|
||||
const noto = require('jellyfin-noto');
|
||||
_define('jellyfin-noto', function () {
|
||||
return noto;
|
||||
});
|
||||
|
||||
var epubjs = require('epubjs');
|
||||
const epubjs = require('epubjs');
|
||||
_define('epubjs', function () {
|
||||
return epubjs;
|
||||
});
|
||||
|
||||
// page.js
|
||||
var page = require('page');
|
||||
const page = require('page');
|
||||
_define('page', function() {
|
||||
return page;
|
||||
});
|
||||
|
||||
// core-js
|
||||
var polyfill = require('@babel/polyfill/dist/polyfill');
|
||||
const polyfill = require('@babel/polyfill/dist/polyfill');
|
||||
_define('polyfill', function () {
|
||||
return polyfill;
|
||||
});
|
||||
|
||||
// domtokenlist-shim
|
||||
var classlist = require('classlist.js');
|
||||
const classlist = require('classlist.js');
|
||||
_define('classlist-polyfill', function () {
|
||||
return classlist;
|
||||
});
|
||||
|
||||
// Date-FNS
|
||||
var dateFns = require('date-fns');
|
||||
const dateFns = require('date-fns');
|
||||
_define('date-fns', function () {
|
||||
return dateFns;
|
||||
});
|
||||
|
||||
var dateFnsLocale = require('date-fns/locale');
|
||||
const dateFnsLocale = require('date-fns/locale');
|
||||
_define('date-fns/locale', function () {
|
||||
return dateFnsLocale;
|
||||
});
|
||||
|
||||
var fast_text_encoding = require('fast-text-encoding');
|
||||
const fast_text_encoding = require('fast-text-encoding');
|
||||
_define('fast-text-encoding', function () {
|
||||
return fast_text_encoding;
|
||||
});
|
||||
|
||||
// intersection-observer
|
||||
var intersection_observer = require('intersection-observer');
|
||||
const intersection_observer = require('intersection-observer');
|
||||
_define('intersection-observer', function () {
|
||||
return intersection_observer;
|
||||
});
|
||||
|
||||
// screenfull
|
||||
var screenfull = require('screenfull');
|
||||
const screenfull = require('screenfull');
|
||||
_define('screenfull', function () {
|
||||
return screenfull;
|
||||
});
|
||||
|
||||
// headroom.js
|
||||
var headroom = require('headroom.js/dist/headroom');
|
||||
const headroom = require('headroom.js/dist/headroom');
|
||||
_define('headroom', function () {
|
||||
return headroom;
|
||||
});
|
||||
|
||||
// apiclient
|
||||
var apiclient = require('jellyfin-apiclient');
|
||||
const apiclient = require('jellyfin-apiclient');
|
||||
|
||||
_define('apiclient', function () {
|
||||
return apiclient.ApiClient;
|
||||
|
@ -181,3 +175,9 @@ _define('connectionManagerFactory', function () {
|
|||
_define('appStorage', function () {
|
||||
return apiclient.AppStorage;
|
||||
});
|
||||
|
||||
// libarchive.js
|
||||
var libarchive = require('libarchive.js');
|
||||
_define('libarchive', function () {
|
||||
return libarchive;
|
||||
});
|
||||
|
|
|
@ -49,7 +49,7 @@ import 'formDialogStyle';
|
|||
};
|
||||
|
||||
if (parseFloat(updatedSchedule.StartHour) >= parseFloat(updatedSchedule.EndHour)) {
|
||||
return void alert(globalize.translate('ErrorMessageStartHourGreaterThanEnd'));
|
||||
return void alert(globalize.translate('ErrorStartHourGreaterThanEnd'));
|
||||
}
|
||||
|
||||
context.submitted = true;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="formDialogHeader">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${LabelPrevious}" tabindex="-1">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${Previous}" tabindex="-1">
|
||||
<span class="material-icons arrow_back" aria-hidden="true"></span>
|
||||
</button>
|
||||
<h3 class="formDialogHeaderTitle">
|
||||
|
@ -12,13 +12,13 @@
|
|||
|
||||
<div class="selectContainer">
|
||||
<select is="emby-select" id="selectDay" label="${LabelAccessDay}">
|
||||
<option value="Sunday">${OptionSunday}</option>
|
||||
<option value="Monday">${OptionMonday}</option>
|
||||
<option value="Tuesday">${OptionTuesday}</option>
|
||||
<option value="Wednesday">${OptionWednesday}</option>
|
||||
<option value="Thursday">${OptionThursday}</option>
|
||||
<option value="Friday">${OptionFriday}</option>
|
||||
<option value="Saturday">${OptionSaturday}</option>
|
||||
<option value="Sunday">${Sunday}</option>
|
||||
<option value="Monday">${Monday}</option>
|
||||
<option value="Tuesday">${Tuesday}</option>
|
||||
<option value="Wednesday">${Wednesday}</option>
|
||||
<option value="Thursday">${Thursday}</option>
|
||||
<option value="Friday">${Friday}</option>
|
||||
<option value="Saturday">${Saturday}</option>
|
||||
<option value="Everyday">${OptionEveryday}</option>
|
||||
<option value="Weekday">${OptionWeekdays}</option>
|
||||
<option value="Weekend">${OptionWeekends}</option>
|
||||
|
@ -33,7 +33,7 @@
|
|||
|
||||
<div class="formDialogFooter">
|
||||
<button is="emby-button" type="submit" class="raised button-submit block formDialogFooterItem">
|
||||
<span>${ButtonAdd}</span>
|
||||
<span>${Add}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -9,15 +9,14 @@ import 'scrollStyles';
|
|||
import 'listViewStyle';
|
||||
|
||||
function getOffsets(elems) {
|
||||
|
||||
let results = [];
|
||||
const results = [];
|
||||
|
||||
if (!document) {
|
||||
return results;
|
||||
}
|
||||
|
||||
for (const elem of elems) {
|
||||
let box = elem.getBoundingClientRect();
|
||||
const box = elem.getBoundingClientRect();
|
||||
|
||||
results.push({
|
||||
top: box.top,
|
||||
|
@ -31,12 +30,11 @@ function getOffsets(elems) {
|
|||
}
|
||||
|
||||
function getPosition(options, dlg) {
|
||||
|
||||
const windowSize = dom.getWindowSize();
|
||||
const windowHeight = windowSize.innerHeight;
|
||||
const windowWidth = windowSize.innerWidth;
|
||||
|
||||
let pos = getOffsets([options.positionTo])[0];
|
||||
const pos = getOffsets([options.positionTo])[0];
|
||||
|
||||
if (options.positionY !== 'top') {
|
||||
pos.top += (pos.height || 0) / 2;
|
||||
|
@ -80,12 +78,11 @@ function centerFocus(elem, horiz, on) {
|
|||
}
|
||||
|
||||
export function show(options) {
|
||||
|
||||
// items
|
||||
// positionTo
|
||||
// showCancel
|
||||
// title
|
||||
let dialogOptions = {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
enableHistory: options.enableHistory,
|
||||
scrollY: false
|
||||
|
@ -98,7 +95,6 @@ export function show(options) {
|
|||
isFullscreen = true;
|
||||
dialogOptions.autoFocus = true;
|
||||
} else {
|
||||
|
||||
dialogOptions.modal = false;
|
||||
dialogOptions.entryAnimation = options.entryAnimation;
|
||||
dialogOptions.exitAnimation = options.exitAnimation;
|
||||
|
@ -107,7 +103,7 @@ export function show(options) {
|
|||
dialogOptions.autoFocus = false;
|
||||
}
|
||||
|
||||
let dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
if (isFullscreen) {
|
||||
dlg.classList.add('actionsheet-fullscreen');
|
||||
|
@ -133,10 +129,9 @@ export function show(options) {
|
|||
}
|
||||
|
||||
let renderIcon = false;
|
||||
let icons = [];
|
||||
const icons = [];
|
||||
let itemIcon;
|
||||
for (const item of options.items) {
|
||||
|
||||
itemIcon = item.icon || (item.selected ? 'check' : null);
|
||||
|
||||
if (itemIcon) {
|
||||
|
@ -161,7 +156,6 @@ export function show(options) {
|
|||
}
|
||||
|
||||
if (options.title) {
|
||||
|
||||
html += '<h1 class="actionSheetTitle">' + options.title + '</h1>';
|
||||
}
|
||||
if (options.text) {
|
||||
|
@ -197,7 +191,6 @@ export function show(options) {
|
|||
const item = options.items[i];
|
||||
|
||||
if (item.divider) {
|
||||
|
||||
html += '<div class="actionsheetDivider"></div>';
|
||||
continue;
|
||||
}
|
||||
|
@ -248,15 +241,13 @@ export function show(options) {
|
|||
centerFocus(dlg.querySelector('.actionSheetScroller'), false, true);
|
||||
}
|
||||
|
||||
let btnCloseActionSheet = dlg.querySelector('.btnCloseActionSheet');
|
||||
const btnCloseActionSheet = dlg.querySelector('.btnCloseActionSheet');
|
||||
if (btnCloseActionSheet) {
|
||||
btnCloseActionSheet.addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
}
|
||||
|
||||
// Seeing an issue in some non-chrome browsers where this is requiring a double click
|
||||
//var eventName = browser.firefox ? 'mousedown' : 'click';
|
||||
let selectedId;
|
||||
|
||||
let timeout;
|
||||
|
@ -267,26 +258,20 @@ export function show(options) {
|
|||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
let isResolved;
|
||||
|
||||
dlg.addEventListener('click', function (e) {
|
||||
|
||||
const actionSheetMenuItem = dom.parentWithClass(e.target, 'actionSheetMenuItem');
|
||||
|
||||
if (actionSheetMenuItem) {
|
||||
selectedId = actionSheetMenuItem.getAttribute('data-id');
|
||||
|
||||
if (options.resolveOnClick) {
|
||||
|
||||
if (options.resolveOnClick.indexOf) {
|
||||
|
||||
if (options.resolveOnClick.indexOf(selectedId) !== -1) {
|
||||
|
||||
resolve(selectedId);
|
||||
isResolved = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
resolve(selectedId);
|
||||
isResolved = true;
|
||||
|
@ -295,11 +280,9 @@ export function show(options) {
|
|||
|
||||
dialogHelper.close(dlg);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.actionSheetScroller'), false, false);
|
||||
}
|
||||
|
|
|
@ -3,9 +3,7 @@ import globalize from 'globalize';
|
|||
import dom from 'dom';
|
||||
import * as datefns from 'date-fns';
|
||||
import dfnshelper from 'dfnshelper';
|
||||
import userSettings from 'userSettings';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import connectionManager from 'connectionManager';
|
||||
import 'emby-button';
|
||||
import 'listViewStyle';
|
||||
|
||||
|
@ -17,7 +15,7 @@ import 'listViewStyle';
|
|||
let color = '#00a4dc';
|
||||
let icon = 'notifications';
|
||||
|
||||
if ('Error' == entry.Severity || 'Fatal' == entry.Severity || 'Warn' == entry.Severity) {
|
||||
if (entry.Severity == 'Error' || entry.Severity == 'Fatal' || entry.Severity == 'Warn') {
|
||||
color = '#cc0000';
|
||||
icon = 'notification_important';
|
||||
}
|
||||
|
@ -61,14 +59,15 @@ import 'listViewStyle';
|
|||
}
|
||||
|
||||
function reloadData(instance, elem, apiClient, startIndex, limit) {
|
||||
if (null == startIndex) {
|
||||
if (startIndex == null) {
|
||||
startIndex = parseInt(elem.getAttribute('data-activitystartindex') || '0');
|
||||
}
|
||||
|
||||
limit = limit || parseInt(elem.getAttribute('data-activitylimit') || '7');
|
||||
const minDate = new Date();
|
||||
const hasUserId = 'false' !== elem.getAttribute('data-useractivity');
|
||||
const hasUserId = elem.getAttribute('data-useractivity') !== 'false';
|
||||
|
||||
// TODO: Use date-fns
|
||||
if (hasUserId) {
|
||||
minDate.setTime(minDate.getTime() - 24 * 60 * 60 * 1000); // one day back
|
||||
} else {
|
||||
|
@ -141,7 +140,7 @@ class ActivityLog {
|
|||
const element = options.element;
|
||||
element.classList.add('activityLogListWidget');
|
||||
element.addEventListener('click', onListClick.bind(this));
|
||||
const apiClient = connectionManager.getApiClient(options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(options.serverId);
|
||||
reloadData(this, element, apiClient);
|
||||
const onUpdate = onActivityLogUpdate.bind(this);
|
||||
this.updateFn = onUpdate;
|
||||
|
@ -153,7 +152,7 @@ class ActivityLog {
|
|||
|
||||
if (options) {
|
||||
options.element.classList.remove('activityLogListWidget');
|
||||
connectionManager.getApiClient(options.serverId).sendMessage('ActivityLogEntryStop', '0,1500');
|
||||
window.connectionManager.getApiClient(options.serverId).sendMessage('ActivityLogEntryStop', '0,1500');
|
||||
}
|
||||
|
||||
const onUpdate = this.updateFn;
|
||||
|
|
|
@ -10,7 +10,6 @@ import globalize from 'globalize';
|
|||
}
|
||||
|
||||
export default function (text, title) {
|
||||
|
||||
let options;
|
||||
if (typeof text === 'string') {
|
||||
options = {
|
||||
|
|
|
@ -26,7 +26,6 @@ import 'material-icons';
|
|||
}
|
||||
|
||||
function getAlphaPickerButtonClassName(vertical) {
|
||||
|
||||
let alphaPickerButtonClassName = 'alphaPickerButton';
|
||||
|
||||
if (layoutManager.tv) {
|
||||
|
@ -45,14 +44,12 @@ import 'material-icons';
|
|||
}
|
||||
|
||||
function mapLetters(letters, vertical) {
|
||||
|
||||
return letters.map(l => {
|
||||
return getLetterButton(l, vertical);
|
||||
});
|
||||
}
|
||||
|
||||
function render(element, options) {
|
||||
|
||||
element.classList.add('alphaPicker');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
|
@ -137,7 +134,6 @@ import 'material-icons';
|
|||
}
|
||||
|
||||
function onAlphaPickerInKeyboardModeClick(e) {
|
||||
|
||||
const alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
|
||||
|
||||
if (alphaPickerButton) {
|
||||
|
@ -153,7 +149,6 @@ import 'material-icons';
|
|||
}
|
||||
|
||||
function onAlphaPickerClick(e) {
|
||||
|
||||
const alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
|
||||
|
||||
if (alphaPickerButton) {
|
||||
|
@ -167,7 +162,6 @@ import 'material-icons';
|
|||
}
|
||||
|
||||
function onAlphaPickerFocusIn(e) {
|
||||
|
||||
if (alphaFocusTimeout) {
|
||||
clearTimeout(alphaFocusTimeout);
|
||||
alphaFocusTimeout = null;
|
||||
|
@ -182,13 +176,11 @@ import 'material-icons';
|
|||
}
|
||||
|
||||
function onItemsFocusIn(e) {
|
||||
|
||||
const item = dom.parentWithClass(e.target, itemClass);
|
||||
|
||||
if (item) {
|
||||
const prefix = item.getAttribute('data-prefix');
|
||||
if (prefix && prefix.length) {
|
||||
|
||||
itemFocusValue = prefix[0];
|
||||
if (itemFocusTimeout) {
|
||||
clearTimeout(itemFocusTimeout);
|
||||
|
@ -199,9 +191,7 @@ import 'material-icons';
|
|||
}
|
||||
|
||||
this.enabled = function (enabled) {
|
||||
|
||||
if (enabled) {
|
||||
|
||||
if (itemsContainer) {
|
||||
itemsContainer.addEventListener('focus', onItemsFocusIn, true);
|
||||
}
|
||||
|
@ -215,9 +205,7 @@ import 'material-icons';
|
|||
} else {
|
||||
element.addEventListener('click', onAlphaPickerClick.bind(this));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (itemsContainer) {
|
||||
itemsContainer.removeEventListener('focus', onItemsFocusIn, true);
|
||||
}
|
||||
|
@ -235,14 +223,12 @@ import 'material-icons';
|
|||
}
|
||||
|
||||
value(value, applyValue) {
|
||||
|
||||
const element = this.options.element;
|
||||
let btn;
|
||||
let selected;
|
||||
|
||||
if (value !== undefined) {
|
||||
if (value != null) {
|
||||
|
||||
value = value.toUpperCase();
|
||||
this._currentValue = value;
|
||||
|
||||
|
@ -295,33 +281,27 @@ import 'material-icons';
|
|||
}
|
||||
|
||||
visible(visible) {
|
||||
|
||||
const element = this.options.element;
|
||||
element.style.visibility = visible ? 'visible' : 'hidden';
|
||||
}
|
||||
|
||||
values() {
|
||||
|
||||
const element = this.options.element;
|
||||
const elems = element.querySelectorAll('.alphaPickerButton');
|
||||
const values = [];
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
values.push(elems[i].getAttribute('data-value'));
|
||||
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
focus() {
|
||||
|
||||
const element = this.options.element;
|
||||
focusManager.autoFocus(element, true);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
||||
const element = this.options.element;
|
||||
this.enabled(false);
|
||||
element.classList.remove('focuscontainer-x');
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import browser from 'browser';
|
||||
import 'css!./appFooter';
|
||||
|
||||
function render(options) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,12 @@
|
|||
define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'globalize'], function (appSettings, browser, events, htmlMediaHelper, webSettings, globalize) {
|
||||
'use strict';
|
||||
import appSettings from 'appSettings';
|
||||
import browser from 'browser';
|
||||
import events from 'events';
|
||||
import * as htmlMediaHelper from 'htmlMediaHelper';
|
||||
import * as webSettings from 'webSettings';
|
||||
import globalize from 'globalize';
|
||||
|
||||
function getBaseProfileOptions(item) {
|
||||
var disableHlsVideoAudioCodecs = [];
|
||||
function getBaseProfileOptions(item) {
|
||||
const disableHlsVideoAudioCodecs = [];
|
||||
|
||||
if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) {
|
||||
if (browser.edge) {
|
||||
|
@ -18,68 +22,50 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
enableMkvProgressive: false,
|
||||
disableHlsVideoAudioCodecs: disableHlsVideoAudioCodecs
|
||||
};
|
||||
}
|
||||
|
||||
function getDeviceProfileForWindowsUwp(item) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(['browserdeviceprofile', 'environments/windows-uwp/mediacaps'], function (profileBuilder, uwpMediaCaps) {
|
||||
var profileOptions = getBaseProfileOptions(item);
|
||||
profileOptions.supportsDts = uwpMediaCaps.supportsDTS();
|
||||
profileOptions.supportsTrueHd = uwpMediaCaps.supportsDolby();
|
||||
profileOptions.audioChannels = uwpMediaCaps.getAudioChannels();
|
||||
resolve(profileBuilder(profileOptions));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getDeviceProfile(item, options) {
|
||||
options = options || {};
|
||||
|
||||
if (self.Windows) {
|
||||
return getDeviceProfileForWindowsUwp(item);
|
||||
}
|
||||
}
|
||||
|
||||
function getDeviceProfile(item, options = {}) {
|
||||
return new Promise(function (resolve) {
|
||||
require(['browserdeviceprofile'], function (profileBuilder) {
|
||||
var profile;
|
||||
import('browserdeviceprofile').then(({default: profileBuilder}) => {
|
||||
let profile;
|
||||
|
||||
if (window.NativeShell) {
|
||||
profile = window.NativeShell.AppHost.getDeviceProfile(profileBuilder);
|
||||
} else {
|
||||
var builderOpts = getBaseProfileOptions(item);
|
||||
builderOpts.enableSsaRender = (item && !options.isRetry && 'allcomplexformats' !== appSettings.get('subtitleburnin'));
|
||||
const builderOpts = getBaseProfileOptions(item);
|
||||
builderOpts.enableSsaRender = (item && !options.isRetry && appSettings.get('subtitleburnin') !== 'allcomplexformats');
|
||||
profile = profileBuilder(builderOpts);
|
||||
}
|
||||
|
||||
resolve(profile);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
|
||||
}
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1');
|
||||
}
|
||||
|
||||
function replaceAll(originalString, strReplace, strWith) {
|
||||
var strReplace2 = escapeRegExp(strReplace);
|
||||
var reg = new RegExp(strReplace2, 'ig');
|
||||
function replaceAll(originalString, strReplace, strWith) {
|
||||
const strReplace2 = escapeRegExp(strReplace);
|
||||
const reg = new RegExp(strReplace2, 'ig');
|
||||
return originalString.replace(reg, strWith);
|
||||
}
|
||||
}
|
||||
|
||||
function generateDeviceId() {
|
||||
var keys = [];
|
||||
function generateDeviceId() {
|
||||
const keys = [];
|
||||
|
||||
if (keys.push(navigator.userAgent), keys.push(new Date().getTime()), self.btoa) {
|
||||
var result = replaceAll(btoa(keys.join('|')), '=', '1');
|
||||
if (keys.push(navigator.userAgent), keys.push(new Date().getTime()), window.btoa) {
|
||||
const result = replaceAll(btoa(keys.join('|')), '=', '1');
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
return Promise.resolve(new Date().getTime());
|
||||
}
|
||||
}
|
||||
|
||||
function getDeviceId() {
|
||||
var key = '_deviceId2';
|
||||
var deviceId = appSettings.get(key);
|
||||
function getDeviceId() {
|
||||
const key = '_deviceId2';
|
||||
const deviceId = appSettings.get(key);
|
||||
|
||||
if (deviceId) {
|
||||
return Promise.resolve(deviceId);
|
||||
|
@ -89,9 +75,9 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
appSettings.set(key, deviceId);
|
||||
return deviceId;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getDeviceName() {
|
||||
function getDeviceName() {
|
||||
var deviceName;
|
||||
if (browser.tizen) {
|
||||
deviceName = 'Samsung Smart TV';
|
||||
|
@ -105,6 +91,8 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
deviceName = 'Sony PS4';
|
||||
} else if (browser.chrome) {
|
||||
deviceName = 'Chrome';
|
||||
} else if (browser.edgeChromium) {
|
||||
deviceName = 'Edge Chromium';
|
||||
} else if (browser.edge) {
|
||||
deviceName = 'Edge';
|
||||
} else if (browser.firefox) {
|
||||
|
@ -126,47 +114,30 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
}
|
||||
|
||||
return deviceName;
|
||||
}
|
||||
}
|
||||
|
||||
function supportsVoiceInput() {
|
||||
function supportsVoiceInput() {
|
||||
if (!browser.tv) {
|
||||
return window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.oSpeechRecognition || window.msSpeechRecognition;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function supportsFullscreen() {
|
||||
function supportsFullscreen() {
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var element = document.documentElement;
|
||||
const element = document.documentElement;
|
||||
return (element.requestFullscreen || element.mozRequestFullScreen || element.webkitRequestFullscreen || element.msRequestFullscreen) || document.createElement('video').webkitEnterFullscreen;
|
||||
}
|
||||
}
|
||||
|
||||
function getSyncProfile() {
|
||||
return new Promise(function (resolve) {
|
||||
require(['browserdeviceprofile', 'appSettings'], function (profileBuilder, appSettings) {
|
||||
var profile;
|
||||
|
||||
if (window.NativeShell) {
|
||||
profile = window.NativeShell.AppHost.getSyncProfile(profileBuilder, appSettings);
|
||||
} else {
|
||||
profile = profileBuilder();
|
||||
profile.MaxStaticMusicBitrate = appSettings.maxStaticMusicBitrate();
|
||||
}
|
||||
|
||||
resolve(profile);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getDefaultLayout() {
|
||||
function getDefaultLayout() {
|
||||
return 'desktop';
|
||||
}
|
||||
}
|
||||
|
||||
function supportsHtmlMediaAutoplay() {
|
||||
function supportsHtmlMediaAutoplay() {
|
||||
if (browser.edgeUwp || browser.tizen || browser.web0s || browser.orsay || browser.operaTv || browser.ps4 || browser.xboxOne) {
|
||||
return true;
|
||||
}
|
||||
|
@ -176,18 +147,18 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function supportsCue() {
|
||||
function supportsCue() {
|
||||
try {
|
||||
var video = document.createElement('video');
|
||||
var style = document.createElement('style');
|
||||
const video = document.createElement('video');
|
||||
const style = document.createElement('style');
|
||||
|
||||
style.textContent = 'video::cue {background: inherit}';
|
||||
document.body.appendChild(style);
|
||||
document.body.appendChild(video);
|
||||
|
||||
var cue = window.getComputedStyle(video, '::cue').background;
|
||||
const cue = window.getComputedStyle(video, '::cue').background;
|
||||
document.body.removeChild(style);
|
||||
document.body.removeChild(video);
|
||||
|
||||
|
@ -196,25 +167,25 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
console.error('error detecting cue support: ' + err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onAppVisible() {
|
||||
function onAppVisible() {
|
||||
if (isHidden) {
|
||||
isHidden = false;
|
||||
console.debug('triggering app resume event');
|
||||
events.trigger(appHost, 'resume');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onAppHidden() {
|
||||
function onAppHidden() {
|
||||
if (!isHidden) {
|
||||
isHidden = true;
|
||||
console.debug('app is hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var supportedFeatures = function () {
|
||||
var features = [];
|
||||
const supportedFeatures = function () {
|
||||
const features = [];
|
||||
|
||||
if (navigator.share) {
|
||||
features.push('sharing');
|
||||
|
@ -257,12 +228,6 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
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');
|
||||
}
|
||||
|
@ -281,7 +246,7 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
features.push('targetblank');
|
||||
features.push('screensaver');
|
||||
|
||||
webSettings.enableMultiServer().then(enabled => {
|
||||
webSettings.getMultiServer().then(enabled => {
|
||||
if (enabled) features.push('multiserver');
|
||||
});
|
||||
|
||||
|
@ -297,17 +262,17 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
features.push('fileinput');
|
||||
}
|
||||
|
||||
if (browser.chrome) {
|
||||
if (browser.chrome || browser.edgeChromium) {
|
||||
features.push('chromecast');
|
||||
}
|
||||
|
||||
return features;
|
||||
}();
|
||||
}();
|
||||
|
||||
/**
|
||||
/**
|
||||
* Do exit according to platform
|
||||
*/
|
||||
function doExit() {
|
||||
function doExit() {
|
||||
try {
|
||||
if (window.NativeShell) {
|
||||
window.NativeShell.AppHost.exit();
|
||||
|
@ -321,19 +286,19 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
} catch (err) {
|
||||
console.error('error closing application: ' + err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var exitPromise;
|
||||
let exitPromise;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Ask user for exit
|
||||
*/
|
||||
function askForExit() {
|
||||
function askForExit() {
|
||||
if (exitPromise) {
|
||||
return;
|
||||
}
|
||||
|
||||
require(['actionsheet'], function (actionsheet) {
|
||||
import('actionsheet').then(({default: actionsheet}) => {
|
||||
exitPromise = actionsheet.show({
|
||||
title: globalize.translate('MessageConfirmAppExit'),
|
||||
items: [
|
||||
|
@ -348,18 +313,18 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
exitPromise = null;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var deviceId;
|
||||
var deviceName;
|
||||
var appName = 'Jellyfin Web';
|
||||
var appVersion = '10.6.0';
|
||||
let deviceId;
|
||||
let deviceName;
|
||||
const appName = 'Jellyfin Web';
|
||||
const appVersion = '10.7.0';
|
||||
|
||||
var appHost = {
|
||||
const appHost = {
|
||||
getWindowState: function () {
|
||||
return document.windowState || 'Normal';
|
||||
},
|
||||
setWindowState: function (state) {
|
||||
setWindowState: function () {
|
||||
alert('setWindowState is not supported and should not be called');
|
||||
},
|
||||
exit: function () {
|
||||
|
@ -374,10 +339,9 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
return window.NativeShell.AppHost.supports(command);
|
||||
}
|
||||
|
||||
return -1 !== supportedFeatures.indexOf(command.toLowerCase());
|
||||
return supportedFeatures.indexOf(command.toLowerCase()) !== -1;
|
||||
},
|
||||
preferVisualCards: browser.android || browser.chrome,
|
||||
getSyncProfile: getSyncProfile,
|
||||
getDefaultLayout: function () {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.getDefaultLayout();
|
||||
|
@ -411,46 +375,38 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
|||
getPushTokenInfo: function () {
|
||||
return {};
|
||||
},
|
||||
setThemeColor: function (color) {
|
||||
var metaThemeColor = document.querySelector('meta[name=theme-color]');
|
||||
|
||||
if (metaThemeColor) {
|
||||
metaThemeColor.setAttribute('content', color);
|
||||
}
|
||||
},
|
||||
setUserScalable: function (scalable) {
|
||||
if (!browser.tv) {
|
||||
var att = scalable ? 'width=device-width, initial-scale=1, minimum-scale=1, user-scalable=yes' : 'width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no';
|
||||
const 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var isHidden = false;
|
||||
var hidden;
|
||||
var visibilityChange;
|
||||
let isHidden = false;
|
||||
let hidden;
|
||||
let visibilityChange;
|
||||
|
||||
if (typeof document.hidden !== 'undefined') { /* eslint-disable-line compat/compat */
|
||||
if (typeof document.hidden !== 'undefined') { /* eslint-disable-line compat/compat */
|
||||
hidden = 'hidden';
|
||||
visibilityChange = 'visibilitychange';
|
||||
} else if (typeof document.webkitHidden !== 'undefined') {
|
||||
} else if (typeof document.webkitHidden !== 'undefined') {
|
||||
hidden = 'webkitHidden';
|
||||
visibilityChange = 'webkitvisibilitychange';
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener(visibilityChange, function () {
|
||||
document.addEventListener(visibilityChange, function () {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (document[hidden]) {
|
||||
onAppHidden();
|
||||
} else {
|
||||
onAppVisible();
|
||||
}
|
||||
}, false);
|
||||
}, false);
|
||||
|
||||
if (self.addEventListener) {
|
||||
self.addEventListener('focus', onAppVisible);
|
||||
self.addEventListener('blur', onAppHidden);
|
||||
}
|
||||
if (window.addEventListener) {
|
||||
window.addEventListener('focus', onAppVisible);
|
||||
window.addEventListener('blur', onAppHidden);
|
||||
}
|
||||
|
||||
return appHost;
|
||||
});
|
||||
export default appHost;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import browser from 'browser';
|
||||
import connectionManager from 'connectionManager';
|
||||
import playbackManager from 'playbackManager';
|
||||
import dom from 'dom';
|
||||
import * as userSettings from 'userSettings';
|
||||
|
@ -177,7 +176,7 @@ import 'css!./backdrop';
|
|||
function getItemImageUrls(item, imageOptions) {
|
||||
imageOptions = imageOptions || {};
|
||||
|
||||
const apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
if (item.BackdropImageTags && item.BackdropImageTags.length > 0) {
|
||||
return item.BackdropImageTags.map((imgTag, index) => {
|
||||
return apiClient.getScaledImageUrl(item.BackdropItemId || item.Id, Object.assign(imageOptions, {
|
||||
|
|
|
@ -209,6 +209,10 @@ button::-moz-focus-inner {
|
|||
contain: strict;
|
||||
}
|
||||
|
||||
.defaultCardBackground {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.cardContent:not(.defaultCardBackground) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
@ -239,33 +243,13 @@ button::-moz-focus-inner {
|
|||
border: none;
|
||||
}
|
||||
|
||||
.cardImage-img {
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
|
||||
/* This is simply for lazy image purposes, to ensure the image is visible sooner when scrolling */
|
||||
min-height: 70%;
|
||||
min-width: 70%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.coveredImage-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.coveredImage-noscale-img {
|
||||
max-height: none;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.coveredImage {
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
.coveredImage-noScale {
|
||||
background-size: cover;
|
||||
.coveredImage.coveredImage-contain {
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.cardFooter {
|
||||
|
@ -372,6 +356,8 @@ button::-moz-focus-inner {
|
|||
.cardDefaultText {
|
||||
white-space: normal;
|
||||
text-align: center;
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cardImageContainer .cardImageIcon {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
import datetime from 'datetime';
|
||||
import imageLoader from 'imageLoader';
|
||||
import connectionManager from 'connectionManager';
|
||||
import itemHelper from 'itemHelper';
|
||||
import focusManager from 'focusManager';
|
||||
import indicators from 'indicators';
|
||||
|
@ -277,7 +276,7 @@ import 'programStyles';
|
|||
*/
|
||||
function getImageWidth(shape, screenWidth, isOrientationLandscape) {
|
||||
const imagesPerRow = getPostersPerRow(shape, screenWidth, isOrientationLandscape);
|
||||
return Math.round(screenWidth / imagesPerRow) * 2;
|
||||
return Math.round(screenWidth / imagesPerRow);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -291,12 +290,10 @@ import 'programStyles';
|
|||
const primaryImageAspectRatio = imageLoader.getPrimaryImageAspectRatio(items);
|
||||
|
||||
if (['auto', 'autohome', 'autooverflow', 'autoVertical'].includes(options.shape)) {
|
||||
|
||||
const requestedShape = options.shape;
|
||||
options.shape = null;
|
||||
|
||||
if (primaryImageAspectRatio) {
|
||||
|
||||
if (primaryImageAspectRatio >= 3) {
|
||||
options.shape = 'banner';
|
||||
options.coverImage = true;
|
||||
|
@ -364,16 +361,16 @@ import 'programStyles';
|
|||
let hasOpenRow;
|
||||
let hasOpenSection;
|
||||
|
||||
let sectionTitleTagName = options.sectionTitleTagName || 'div';
|
||||
const sectionTitleTagName = options.sectionTitleTagName || 'div';
|
||||
let apiClient;
|
||||
let lastServerId;
|
||||
|
||||
for (const [i, item] of items.entries()) {
|
||||
let serverId = item.ServerId || options.serverId;
|
||||
const serverId = item.ServerId || options.serverId;
|
||||
|
||||
if (serverId !== lastServerId) {
|
||||
lastServerId = serverId;
|
||||
apiClient = connectionManager.getApiClient(lastServerId);
|
||||
apiClient = window.connectionManager.getApiClient(lastServerId);
|
||||
}
|
||||
|
||||
if (options.indexBy) {
|
||||
|
@ -394,7 +391,6 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
if (newIndexValue !== currentIndexValue) {
|
||||
|
||||
if (hasOpenRow) {
|
||||
html += '</div>';
|
||||
hasOpenRow = false;
|
||||
|
@ -402,7 +398,6 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
if (hasOpenSection) {
|
||||
|
||||
html += '</div>';
|
||||
|
||||
if (isVertical) {
|
||||
|
@ -426,7 +421,6 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
if (options.rows && itemsInRow === 0) {
|
||||
|
||||
if (hasOpenRow) {
|
||||
html += '</div>';
|
||||
hasOpenRow = false;
|
||||
|
@ -626,7 +620,7 @@ import 'programStyles';
|
|||
});
|
||||
}
|
||||
|
||||
let blurHashes = options.imageBlurhashes || item.ImageBlurHashes || {};
|
||||
const blurHashes = options.imageBlurhashes || item.ImageBlurHashes || {};
|
||||
|
||||
return {
|
||||
imgUrl: imgUrl,
|
||||
|
@ -661,7 +655,7 @@ import 'programStyles';
|
|||
for (let i = 0; i < character.length; i++) {
|
||||
sum += parseInt(character.charAt(i));
|
||||
}
|
||||
let index = String(sum).substr(-1);
|
||||
const index = String(sum).substr(-1);
|
||||
|
||||
return (index % numRandomColors) + 1;
|
||||
} else {
|
||||
|
@ -686,9 +680,8 @@ import 'programStyles';
|
|||
let valid = 0;
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
|
||||
let currentCssClass = cssClass;
|
||||
let text = lines[i];
|
||||
const text = lines[i];
|
||||
|
||||
if (valid > 0 && isOuterFooter) {
|
||||
currentCssClass += ' cardText-secondary';
|
||||
|
@ -713,8 +706,7 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
if (forceLines) {
|
||||
|
||||
let linesLength = maxLines || Math.min(lines.length, maxLines || lines.length);
|
||||
const linesLength = maxLines || Math.min(lines.length, maxLines || lines.length);
|
||||
|
||||
while (valid < linesLength) {
|
||||
html += "<div class='" + cssClass + "'> </div>";
|
||||
|
@ -745,7 +737,6 @@ import 'programStyles';
|
|||
let airTimeText = '';
|
||||
|
||||
if (item.StartDate) {
|
||||
|
||||
try {
|
||||
let date = datetime.parseISO8601Date(item.StartDate);
|
||||
|
||||
|
@ -792,7 +783,6 @@ import 'programStyles';
|
|||
const showOtherText = isOuterFooter ? !overlayText : overlayText;
|
||||
|
||||
if (isOuterFooter && options.cardLayout && layoutManager.mobile) {
|
||||
|
||||
if (options.cardFooterAside !== 'none') {
|
||||
html += '<button is="paper-icon-button-light" class="itemAction btnCardOptions cardText-secondary" data-action="menu"><span class="material-icons more_vert"></span></button>';
|
||||
}
|
||||
|
@ -807,9 +797,7 @@ import 'programStyles';
|
|||
|
||||
if (showOtherText) {
|
||||
if ((options.showParentTitle || options.showParentTitleOrTitle) && !parentTitleUnderneath) {
|
||||
|
||||
if (isOuterFooter && item.Type === 'Episode' && item.SeriesName) {
|
||||
|
||||
if (item.SeriesId) {
|
||||
lines.push(getTextActionButton({
|
||||
Id: item.SeriesId,
|
||||
|
@ -822,15 +810,12 @@ import 'programStyles';
|
|||
lines.push(item.SeriesName);
|
||||
}
|
||||
} else {
|
||||
|
||||
if (isUsingLiveTvNaming(item)) {
|
||||
|
||||
lines.push(item.Name);
|
||||
|
||||
if (!item.EpisodeTitle) {
|
||||
titleAdded = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
const parentTitle = item.SeriesName || item.Series || item.Album || item.AlbumArtist || '';
|
||||
|
||||
|
@ -848,7 +833,6 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
if (showMediaTitle) {
|
||||
|
||||
const name = options.showTitle === 'auto' && !item.IsFolder && item.MediaType === 'Photo' ? '' : itemHelper.getDisplayName(item, {
|
||||
includeParentInfo: options.includeParentInfoInTitle
|
||||
});
|
||||
|
@ -865,7 +849,6 @@ import 'programStyles';
|
|||
|
||||
if (showOtherText) {
|
||||
if (options.showParentTitle && parentTitleUnderneath) {
|
||||
|
||||
if (isOuterFooter && item.AlbumArtists && item.AlbumArtists.length) {
|
||||
item.AlbumArtists[0].Type = 'MusicArtist';
|
||||
item.AlbumArtists[0].IsFolder = true;
|
||||
|
@ -899,7 +882,6 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
if (options.showPremiereDate) {
|
||||
|
||||
if (item.PremiereDate) {
|
||||
try {
|
||||
lines.push(datetime.toLocaleDateString(
|
||||
|
@ -908,7 +890,6 @@ import 'programStyles';
|
|||
));
|
||||
} catch (err) {
|
||||
lines.push('');
|
||||
|
||||
}
|
||||
} else {
|
||||
lines.push('');
|
||||
|
@ -916,14 +897,10 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
if (options.showYear || options.showSeriesYear) {
|
||||
|
||||
if (item.Type === 'Series') {
|
||||
if (item.Status === 'Continuing') {
|
||||
|
||||
lines.push(globalize.translate('SeriesYearToPresent', item.ProductionYear || ''));
|
||||
|
||||
} else {
|
||||
|
||||
if (item.EndDate && item.ProductionYear) {
|
||||
const endYear = datetime.parseISO8601Date(item.EndDate).getFullYear();
|
||||
lines.push(item.ProductionYear + ((endYear === item.ProductionYear) ? '' : (' - ' + endYear)));
|
||||
|
@ -937,9 +914,7 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
if (options.showRuntime) {
|
||||
|
||||
if (item.RunTimeTicks) {
|
||||
|
||||
lines.push(datetime.getDisplayRunningTime(item.RunTimeTicks));
|
||||
} else {
|
||||
lines.push('');
|
||||
|
@ -947,14 +922,11 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
if (options.showAirTime) {
|
||||
|
||||
lines.push(getAirTimeText(item, options.showAirDateTime, options.showAirEndTime) || '');
|
||||
}
|
||||
|
||||
if (options.showChannelName) {
|
||||
|
||||
if (item.ChannelId) {
|
||||
|
||||
lines.push(getTextActionButton({
|
||||
|
||||
Id: item.ChannelId,
|
||||
|
@ -971,7 +943,6 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
if (options.showCurrentProgram && item.Type === 'TvChannel') {
|
||||
|
||||
if (item.CurrentProgram) {
|
||||
lines.push(item.CurrentProgram.Name);
|
||||
} else {
|
||||
|
@ -980,7 +951,6 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
if (options.showCurrentProgramTime && item.Type === 'TvChannel') {
|
||||
|
||||
if (item.CurrentProgram) {
|
||||
lines.push(getAirTimeText(item.CurrentProgram, false, true) || '');
|
||||
} else {
|
||||
|
@ -990,7 +960,6 @@ import 'programStyles';
|
|||
|
||||
if (options.showSeriesTimerTime) {
|
||||
if (item.RecordAnyTime) {
|
||||
|
||||
lines.push(globalize.translate('Anytime'));
|
||||
} else {
|
||||
lines.push(datetime.getDisplayTime(item.StartDate));
|
||||
|
@ -1016,6 +985,10 @@ import 'programStyles';
|
|||
lines = [];
|
||||
}
|
||||
|
||||
if (overlayText && showTitle) {
|
||||
lines = [item.Name];
|
||||
}
|
||||
|
||||
const addRightTextMargin = isOuterFooter && options.cardLayout && !options.centerText && options.cardFooterAside !== 'none' && layoutManager.mobile;
|
||||
|
||||
html += getCardTextLines(lines, cssClass, !options.overlayText, isOuterFooter, options.cardLayout, addRightTextMargin, options.lines);
|
||||
|
@ -1025,7 +998,6 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
if (html) {
|
||||
|
||||
if (!isOuterFooter || logoUrl || options.cardLayout) {
|
||||
html = '<div class="' + footerClass + '">' + html;
|
||||
|
||||
|
@ -1067,31 +1039,25 @@ import 'programStyles';
|
|||
* @returns {string} HTML markup for the item count indicator.
|
||||
*/
|
||||
function getItemCountsHtml(options, item) {
|
||||
let counts = [];
|
||||
const counts = [];
|
||||
let childText;
|
||||
|
||||
if (item.Type === 'Playlist') {
|
||||
|
||||
childText = '';
|
||||
|
||||
if (item.RunTimeTicks) {
|
||||
|
||||
let minutes = item.RunTimeTicks / 600000000;
|
||||
|
||||
minutes = minutes || 1;
|
||||
|
||||
childText += globalize.translate('ValueMinutes', Math.round(minutes));
|
||||
|
||||
} else {
|
||||
childText += globalize.translate('ValueMinutes', 0);
|
||||
}
|
||||
|
||||
counts.push(childText);
|
||||
|
||||
} else if (item.Type === 'Genre' || item.Type === 'Studio') {
|
||||
|
||||
if (item.MovieCount) {
|
||||
|
||||
childText = item.MovieCount === 1 ?
|
||||
globalize.translate('ValueOneMovie') :
|
||||
globalize.translate('ValueMovieCount', item.MovieCount);
|
||||
|
@ -1100,7 +1066,6 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
if (item.SeriesCount) {
|
||||
|
||||
childText = item.SeriesCount === 1 ?
|
||||
globalize.translate('ValueOneSeries') :
|
||||
globalize.translate('ValueSeriesCount', item.SeriesCount);
|
||||
|
@ -1108,18 +1073,14 @@ import 'programStyles';
|
|||
counts.push(childText);
|
||||
}
|
||||
if (item.EpisodeCount) {
|
||||
|
||||
childText = item.EpisodeCount === 1 ?
|
||||
globalize.translate('ValueOneEpisode') :
|
||||
globalize.translate('ValueEpisodeCount', item.EpisodeCount);
|
||||
|
||||
counts.push(childText);
|
||||
}
|
||||
|
||||
} else if (item.Type === 'MusicGenre' || options.context === 'MusicArtist') {
|
||||
|
||||
if (item.AlbumCount) {
|
||||
|
||||
childText = item.AlbumCount === 1 ?
|
||||
globalize.translate('ValueOneAlbum') :
|
||||
globalize.translate('ValueAlbumCount', item.AlbumCount);
|
||||
|
@ -1127,7 +1088,6 @@ import 'programStyles';
|
|||
counts.push(childText);
|
||||
}
|
||||
if (item.SongCount) {
|
||||
|
||||
childText = item.SongCount === 1 ?
|
||||
globalize.translate('ValueOneSong') :
|
||||
globalize.translate('ValueSongCount', item.SongCount);
|
||||
|
@ -1135,16 +1095,13 @@ import 'programStyles';
|
|||
counts.push(childText);
|
||||
}
|
||||
if (item.MusicVideoCount) {
|
||||
|
||||
childText = item.MusicVideoCount === 1 ?
|
||||
globalize.translate('ValueOneMusicVideo') :
|
||||
globalize.translate('ValueMusicVideoCount', item.MusicVideoCount);
|
||||
|
||||
counts.push(childText);
|
||||
}
|
||||
|
||||
} else if (item.Type === 'Series') {
|
||||
|
||||
childText = item.RecursiveItemCount === 1 ?
|
||||
globalize.translate('ValueOneEpisode') :
|
||||
globalize.translate('ValueEpisodeCount', item.RecursiveItemCount);
|
||||
|
@ -1163,6 +1120,7 @@ import 'programStyles';
|
|||
function importRefreshIndicator() {
|
||||
if (!refreshIndicatorLoaded) {
|
||||
refreshIndicatorLoaded = true;
|
||||
/* eslint-disable-next-line @babel/no-unused-expressions */
|
||||
import('emby-itemrefreshindicator');
|
||||
}
|
||||
}
|
||||
|
@ -1197,13 +1155,11 @@ import 'programStyles';
|
|||
let shape = options.shape;
|
||||
|
||||
if (shape === 'mixed') {
|
||||
|
||||
shape = null;
|
||||
|
||||
const primaryImageAspectRatio = item.PrimaryImageAspectRatio;
|
||||
|
||||
if (primaryImageAspectRatio) {
|
||||
|
||||
if (primaryImageAspectRatio >= 1.33) {
|
||||
shape = 'mixedBackdrop';
|
||||
} else if (primaryImageAspectRatio > 0.71) {
|
||||
|
@ -1259,8 +1215,8 @@ import 'programStyles';
|
|||
if (coveredImage) {
|
||||
cardImageContainerClass += ' coveredImage';
|
||||
|
||||
if (item.MediaType === 'Photo' || item.Type === 'PhotoAlbum' || item.Type === 'Folder' || item.ProgramInfo || item.Type === 'Program' || item.Type === 'Recording') {
|
||||
cardImageContainerClass += ' coveredImage-noScale';
|
||||
if (item.Type === 'TvChannel') {
|
||||
cardImageContainerClass += ' coveredImage-contain';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1295,7 +1251,6 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
if (overlayText) {
|
||||
|
||||
logoUrl = null;
|
||||
|
||||
footerCssClass = progressHtml ? 'innerCardFooter fullInnerCardFooter' : 'innerCardFooter';
|
||||
|
@ -1366,7 +1321,7 @@ import 'programStyles';
|
|||
let cardBoxClose = '';
|
||||
let cardScalableClose = '';
|
||||
|
||||
let cardContentClass = 'cardContent';
|
||||
const cardContentClass = 'cardContent';
|
||||
|
||||
let blurhashAttrib = '';
|
||||
if (blurhash && blurhash.length > 0) {
|
||||
|
@ -1385,7 +1340,7 @@ import 'programStyles';
|
|||
cardImageContainerClose = '</button>';
|
||||
}
|
||||
|
||||
let cardScalableClass = 'cardScalable';
|
||||
const cardScalableClass = 'cardScalable';
|
||||
|
||||
cardImageContainerOpen = '<div class="' + cardBoxClass + '"><div class="' + cardScalableClass + '"><div class="cardPadder cardPadder-' + shape + '"></div>' + cardImageContainerOpen;
|
||||
cardBoxClose = '</div>';
|
||||
|
@ -1404,7 +1359,6 @@ import 'programStyles';
|
|||
indicatorsHtml += indicators.getTypeIndicator(item);
|
||||
|
||||
if (options.showGroupCount) {
|
||||
|
||||
indicatorsHtml += indicators.getChildCountIndicatorHtml(item, {
|
||||
minCount: 1
|
||||
});
|
||||
|
@ -1498,14 +1452,15 @@ import 'programStyles';
|
|||
const userData = item.UserData || {};
|
||||
|
||||
if (itemHelper.canMarkPlayed(item)) {
|
||||
/* eslint-disable-next-line @babel/no-unused-expressions */
|
||||
import('emby-playstatebutton');
|
||||
html += '<button is="emby-playstatebutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-played="' + (userData.Played) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover check"></span></button>';
|
||||
}
|
||||
|
||||
if (itemHelper.canRate(item)) {
|
||||
|
||||
const likes = userData.Likes == null ? '' : userData.Likes;
|
||||
|
||||
/* eslint-disable-next-line @babel/no-unused-expressions */
|
||||
import('emby-ratingbutton');
|
||||
html += '<button is="emby-ratingbutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-likes="' + likes + '" data-isfavorite="' + (userData.IsFavorite) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover favorite"></span></button>';
|
||||
}
|
||||
|
@ -1583,7 +1538,6 @@ import 'programStyles';
|
|||
const html = buildCardsHtmlInternal(items, options);
|
||||
|
||||
if (html) {
|
||||
|
||||
if (options.itemsContainer.cardBuilderHtml !== html) {
|
||||
options.itemsContainer.innerHTML = html;
|
||||
|
||||
|
@ -1596,7 +1550,6 @@ import 'programStyles';
|
|||
|
||||
imageLoader.lazyChildren(options.itemsContainer);
|
||||
} else {
|
||||
|
||||
options.itemsContainer.innerHTML = html;
|
||||
options.itemsContainer.cardBuilderHtml = null;
|
||||
}
|
||||
|
@ -1620,7 +1573,6 @@ import 'programStyles';
|
|||
indicatorsElem = card.querySelector('.cardIndicators');
|
||||
|
||||
if (!indicatorsElem) {
|
||||
|
||||
const cardImageContainer = card.querySelector('.cardImageContainer');
|
||||
indicatorsElem = document.createElement('div');
|
||||
indicatorsElem.classList.add('cardIndicators');
|
||||
|
@ -1644,11 +1596,9 @@ import 'programStyles';
|
|||
let itemProgressBar = null;
|
||||
|
||||
if (userData.Played) {
|
||||
|
||||
playedIndicator = card.querySelector('.playedIndicator');
|
||||
|
||||
if (!playedIndicator) {
|
||||
|
||||
playedIndicator = document.createElement('div');
|
||||
playedIndicator.classList.add('playedIndicator');
|
||||
playedIndicator.classList.add('indicator');
|
||||
|
@ -1657,10 +1607,8 @@ import 'programStyles';
|
|||
}
|
||||
playedIndicator.innerHTML = '<span class="material-icons indicatorIcon check"></span>';
|
||||
} else {
|
||||
|
||||
playedIndicator = card.querySelector('.playedIndicator');
|
||||
if (playedIndicator) {
|
||||
|
||||
playedIndicator.parentNode.removeChild(playedIndicator);
|
||||
}
|
||||
}
|
||||
|
@ -1668,7 +1616,6 @@ import 'programStyles';
|
|||
countIndicator = card.querySelector('.countIndicator');
|
||||
|
||||
if (!countIndicator) {
|
||||
|
||||
countIndicator = document.createElement('div');
|
||||
countIndicator.classList.add('countIndicator');
|
||||
indicatorsElem = ensureIndicators(card, indicatorsElem);
|
||||
|
@ -1676,10 +1623,8 @@ import 'programStyles';
|
|||
}
|
||||
countIndicator.innerHTML = userData.UnplayedItemCount;
|
||||
} else if (enableCountIndicator) {
|
||||
|
||||
countIndicator = card.querySelector('.countIndicator');
|
||||
if (countIndicator) {
|
||||
|
||||
countIndicator.parentNode.removeChild(countIndicator);
|
||||
}
|
||||
}
|
||||
|
@ -1691,7 +1636,6 @@ import 'programStyles';
|
|||
});
|
||||
|
||||
if (progressHtml) {
|
||||
|
||||
itemProgressBar = card.querySelector('.itemProgressBar');
|
||||
|
||||
if (!itemProgressBar) {
|
||||
|
@ -1710,7 +1654,6 @@ import 'programStyles';
|
|||
|
||||
itemProgressBar.innerHTML = progressHtml;
|
||||
} else {
|
||||
|
||||
itemProgressBar = card.querySelector('.itemProgressBar');
|
||||
if (itemProgressBar) {
|
||||
itemProgressBar.parentNode.removeChild(itemProgressBar);
|
||||
|
@ -1741,7 +1684,7 @@ import 'programStyles';
|
|||
const cells = itemsContainer.querySelectorAll('.card[data-id="' + programId + '"]');
|
||||
|
||||
for (let i = 0, length = cells.length; i < length; i++) {
|
||||
let cell = cells[i];
|
||||
const cell = cells[i];
|
||||
const icon = cell.querySelector('.timerIndicator');
|
||||
if (!icon) {
|
||||
const indicatorsElem = ensureIndicators(cell);
|
||||
|
@ -1760,8 +1703,8 @@ import 'programStyles';
|
|||
const cells = itemsContainer.querySelectorAll('.card[data-timerid="' + timerId + '"]');
|
||||
|
||||
for (let i = 0; i < cells.length; i++) {
|
||||
let cell = cells[i];
|
||||
let icon = cell.querySelector('.timerIndicator');
|
||||
const cell = cells[i];
|
||||
const icon = cell.querySelector('.timerIndicator');
|
||||
if (icon) {
|
||||
icon.parentNode.removeChild(icon);
|
||||
}
|
||||
|
@ -1778,8 +1721,8 @@ import 'programStyles';
|
|||
const cells = itemsContainer.querySelectorAll('.card[data-seriestimerid="' + cancelledTimerId + '"]');
|
||||
|
||||
for (let i = 0; i < cells.length; i++) {
|
||||
let cell = cells[i];
|
||||
let icon = cell.querySelector('.timerIndicator');
|
||||
const cell = cells[i];
|
||||
const icon = cell.querySelector('.timerIndicator');
|
||||
if (icon) {
|
||||
icon.parentNode.removeChild(icon);
|
||||
}
|
||||
|
|
|
@ -7,14 +7,12 @@
|
|||
|
||||
import datetime from 'datetime';
|
||||
import imageLoader from 'imageLoader';
|
||||
import connectionManager from 'connectionManager';
|
||||
import layoutManager from 'layoutManager';
|
||||
import browser from 'browser';
|
||||
|
||||
const enableFocusTransform = !browser.slow && !browser.edge;
|
||||
|
||||
function buildChapterCardsHtml(item, chapters, options) {
|
||||
|
||||
// TODO move card creation code to Card component
|
||||
|
||||
let className = 'card itemAction chapterCard';
|
||||
|
@ -35,7 +33,6 @@ import browser from 'browser';
|
|||
let shape = (options.backdropShape || 'backdrop');
|
||||
|
||||
if (videoStream.Width && videoStream.Height) {
|
||||
|
||||
if ((videoStream.Width / videoStream.Height) <= 1.2) {
|
||||
shape = (options.squareShape || 'square');
|
||||
}
|
||||
|
@ -50,10 +47,9 @@ import browser from 'browser';
|
|||
let html = '';
|
||||
let itemsInRow = 0;
|
||||
|
||||
const apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
for (let i = 0, length = chapters.length; i < length; i++) {
|
||||
|
||||
if (options.rows && itemsInRow === 0) {
|
||||
html += '<div class="cardColumn">';
|
||||
}
|
||||
|
@ -73,12 +69,10 @@ import browser from 'browser';
|
|||
}
|
||||
|
||||
function getImgUrl({Id}, {ImageTag}, index, maxWidth, apiClient) {
|
||||
|
||||
if (ImageTag) {
|
||||
|
||||
return apiClient.getScaledImageUrl(Id, {
|
||||
|
||||
maxWidth: maxWidth * 2,
|
||||
maxWidth: maxWidth,
|
||||
tag: ImageTag,
|
||||
type: 'Chapter',
|
||||
index
|
||||
|
@ -89,7 +83,6 @@ import browser from 'browser';
|
|||
}
|
||||
|
||||
function buildChapterCard(item, apiClient, chapter, index, {width, coverImage}, className, shape) {
|
||||
|
||||
const imgUrl = getImgUrl(item, chapter, index, width || 400, apiClient);
|
||||
|
||||
let cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer';
|
||||
|
@ -110,13 +103,10 @@ import browser from 'browser';
|
|||
const cardBoxCssClass = 'cardBox';
|
||||
const cardScalableClass = 'cardScalable';
|
||||
|
||||
const html = `<button type="button" class="${className}"${dataAttributes}><div class="${cardBoxCssClass}"><div class="${cardScalableClass}"><div class="cardPadder-${shape}"></div>${cardImageContainer}</div><div class="innerCardFooter">${nameHtml}</div></div></div></button>`;
|
||||
|
||||
return html;
|
||||
return `<button type="button" class="${className}"${dataAttributes}><div class="${cardBoxCssClass}"><div class="${cardScalableClass}"><div class="cardPadder-${shape}"></div>${cardImageContainer}</div><div class="innerCardFooter">${nameHtml}</div></div></div></button>`;
|
||||
}
|
||||
|
||||
export function buildChapterCards(item, chapters, options) {
|
||||
|
||||
if (options.parentContainer) {
|
||||
// Abort if the container has been disposed
|
||||
if (!document.body.contains(options.parentContainer)) {
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
import cardBuilder from 'cardBuilder';
|
||||
|
||||
export function buildPeopleCards(items, options) {
|
||||
|
||||
options = Object.assign(options || {}, {
|
||||
cardLayout: false,
|
||||
centerText: true,
|
||||
|
|
|
@ -1,23 +1,16 @@
|
|||
define([], function() {
|
||||
'use strict';
|
||||
|
||||
class CastSenderApi {
|
||||
load() {
|
||||
if (window.appMode === 'cordova' || window.appMode === 'android') {
|
||||
return {
|
||||
load: function () {
|
||||
window.chrome = window.chrome || {};
|
||||
return Promise.resolve();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
var ccLoaded = false;
|
||||
return {
|
||||
load: function () {
|
||||
let ccLoaded = false;
|
||||
if (ccLoaded) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
var fileref = document.createElement('script');
|
||||
return new Promise(function (resolve) {
|
||||
const fileref = document.createElement('script');
|
||||
fileref.setAttribute('type', 'text/javascript');
|
||||
|
||||
fileref.onload = function () {
|
||||
|
@ -29,6 +22,7 @@ define([], function() {
|
|||
document.querySelector('head').appendChild(fileref);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default CastSenderApi;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import dom from 'dom';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import loading from 'loading';
|
||||
import connectionManager from 'connectionManager';
|
||||
import globalize from 'globalize';
|
||||
import actionsheet from 'actionsheet';
|
||||
import 'emby-input';
|
||||
|
@ -16,14 +15,15 @@ export default class channelMapper {
|
|||
function mapChannel(button, channelId, providerChannelId) {
|
||||
loading.show();
|
||||
const providerId = options.providerId;
|
||||
connectionManager.getApiClient(options.serverId).ajax({
|
||||
window.connectionManager.getApiClient(options.serverId).ajax({
|
||||
type: 'POST',
|
||||
url: ApiClient.getUrl('LiveTv/ChannelMappings'),
|
||||
data: {
|
||||
data: JSON.stringify({
|
||||
providerId: providerId,
|
||||
tunerChannelId: channelId,
|
||||
providerChannelId: providerChannelId
|
||||
},
|
||||
}),
|
||||
contentType: 'application/json',
|
||||
dataType: 'json'
|
||||
}).then(mapping => {
|
||||
const listItem = dom.parentWithClass(button, 'listItem');
|
||||
|
@ -58,7 +58,7 @@ export default class channelMapper {
|
|||
}
|
||||
|
||||
function getChannelMappingOptions(serverId, providerId) {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getJSON(apiClient.getUrl('LiveTv/ChannelMappingOptions', {
|
||||
providerId: providerId
|
||||
}));
|
||||
|
@ -93,7 +93,7 @@ export default class channelMapper {
|
|||
html += '<div class="formDialogContent smoothScrollY">';
|
||||
html += '<div class="dialogContentInner dialog-content-centered">';
|
||||
html += '<form style="margin:auto;">';
|
||||
html += `<h1>${globalize.translate('HeaderChannels')}</h1>`;
|
||||
html += `<h1>${globalize.translate('Channels')}</h1>`;
|
||||
html += '<div class="channels paperList">';
|
||||
html += '</div>';
|
||||
html += '</form>';
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import dom from 'dom';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import loading from 'loading';
|
||||
import appHost from 'apphost';
|
||||
import layoutManager from 'layoutManager';
|
||||
import connectionManager from 'connectionManager';
|
||||
import appRouter from 'appRouter';
|
||||
import globalize from 'globalize';
|
||||
import 'emby-checkbox';
|
||||
|
@ -26,7 +24,7 @@ import 'flexStyles';
|
|||
|
||||
const collectionId = panel.querySelector('#selectCollectionToAddTo').value;
|
||||
|
||||
const apiClient = connectionManager.getApiClient(currentServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(currentServerId);
|
||||
|
||||
if (collectionId) {
|
||||
addToCollection(apiClient, panel, collectionId);
|
||||
|
@ -39,7 +37,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function createCollection(apiClient, dlg) {
|
||||
|
||||
const url = apiClient.getUrl('Collections', {
|
||||
|
||||
Name: dlg.querySelector('#txtNewCollectionName').value,
|
||||
|
@ -53,7 +50,6 @@ import 'flexStyles';
|
|||
dataType: 'json'
|
||||
|
||||
}).then(result => {
|
||||
|
||||
loading.hide();
|
||||
|
||||
const id = result.Id;
|
||||
|
@ -61,17 +57,14 @@ import 'flexStyles';
|
|||
dlg.submitted = true;
|
||||
dialogHelper.close(dlg);
|
||||
redirectToCollection(apiClient, id);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function redirectToCollection(apiClient, id) {
|
||||
|
||||
appRouter.showItem(id, apiClient.serverId());
|
||||
}
|
||||
|
||||
function addToCollection(apiClient, dlg, id) {
|
||||
|
||||
const url = apiClient.getUrl(`Collections/${id}/Items`, {
|
||||
|
||||
Ids: dlg.querySelector('.fldSelectedItemIds').value || ''
|
||||
|
@ -82,7 +75,6 @@ import 'flexStyles';
|
|||
url: url
|
||||
|
||||
}).then(() => {
|
||||
|
||||
loading.hide();
|
||||
|
||||
dlg.submitted = true;
|
||||
|
@ -99,7 +91,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function populateCollections(panel) {
|
||||
|
||||
loading.show();
|
||||
|
||||
const select = panel.querySelector('#selectCollectionToAddTo');
|
||||
|
@ -114,15 +105,13 @@ import 'flexStyles';
|
|||
EnableTotalRecordCount: false
|
||||
};
|
||||
|
||||
const apiClient = connectionManager.getApiClient(currentServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(currentServerId);
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), options).then(result => {
|
||||
|
||||
let html = '';
|
||||
|
||||
html += `<option value="">${globalize.translate('OptionNew')}</option>`;
|
||||
|
||||
html += result.Items.map(i => {
|
||||
|
||||
return `<option value="${i.Id}">${i.Name}</option>`;
|
||||
});
|
||||
|
||||
|
@ -135,7 +124,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function getEditorHtml() {
|
||||
|
||||
let html = '';
|
||||
|
||||
html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">';
|
||||
|
@ -183,7 +171,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function initEditor(content, items) {
|
||||
|
||||
content.querySelector('#selectCollectionToAddTo').addEventListener('change', function () {
|
||||
if (this.value) {
|
||||
content.querySelector('.newCollectionInfo').classList.add('hide');
|
||||
|
@ -212,7 +199,7 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
import('scrollHelper').then(scrollHelper => {
|
||||
import('scrollHelper').then((scrollHelper) => {
|
||||
const fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
|
@ -220,7 +207,6 @@ import 'flexStyles';
|
|||
|
||||
export class showEditor {
|
||||
constructor(options) {
|
||||
|
||||
const items = options.items || {};
|
||||
currentServerId = options.serverId;
|
||||
|
||||
|
@ -248,10 +234,6 @@ import 'flexStyles';
|
|||
html += title;
|
||||
html += '</h3>';
|
||||
|
||||
if (appHost.supports('externallinks')) {
|
||||
html += `<a is="emby-linkbutton" class="button-link btnHelp flex align-items-center" href="https://web.archive.org/web/20181216120305/https://github.com/MediaBrowser/Wiki/wiki/Collections" target="_blank" style="margin-left:auto;margin-right:.5em;padding:.25em;" title="${globalize.translate('Help')}"><span class="material-icons info"></span><span style="margin-left:.25em;">${globalize.translate('Help')}</span></a>`;
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
html += getEditorHtml();
|
||||
|
@ -261,7 +243,6 @@ import 'flexStyles';
|
|||
initEditor(dlg, items);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
|
@ -270,7 +251,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
return dialogHelper.open(dlg).then(() => {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import globalize from 'globalize';
|
|||
|
||||
/* eslint-disable indent */
|
||||
export default (() => {
|
||||
|
||||
function replaceAll(str, find, replace) {
|
||||
return str.split(find).join(replace);
|
||||
}
|
||||
|
@ -20,7 +19,7 @@ export default (() => {
|
|||
}
|
||||
|
||||
const text = replaceAll(options.text || '', '<br/>', '\n');
|
||||
const result = confirm(text);
|
||||
const result = window.confirm(text);
|
||||
|
||||
if (result) {
|
||||
return Promise.resolve();
|
||||
|
|
|
@ -13,7 +13,6 @@ import 'flexStyles';
|
|||
/* eslint-disable indent */
|
||||
|
||||
function showDialog(options, template) {
|
||||
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
|
@ -45,10 +44,6 @@ import 'flexStyles';
|
|||
dlg.classList.add('dialog-fullscreen-lowres');
|
||||
}
|
||||
|
||||
//dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
|
||||
// dialogHelper.close(dlg);
|
||||
//});
|
||||
|
||||
if (options.title) {
|
||||
dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.title || '';
|
||||
} else {
|
||||
|
@ -68,7 +63,6 @@ import 'flexStyles';
|
|||
let hasDescriptions = false;
|
||||
|
||||
for (i = 0, length = options.buttons.length; i < length; i++) {
|
||||
|
||||
const item = options.buttons[i];
|
||||
const autoFocus = i === 0 ? ' autofocus' : '';
|
||||
|
||||
|
@ -111,7 +105,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
return dialogHelper.open(dlg).then(() => {
|
||||
|
||||
if (enableTvLayout) {
|
||||
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
@ -125,7 +118,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
export async function show(text, title) {
|
||||
|
||||
let options;
|
||||
if (typeof text === 'string') {
|
||||
options = {
|
||||
|
|
|
@ -12,7 +12,6 @@ import 'scrollStyles';
|
|||
let globalOnOpenCallback;
|
||||
|
||||
function enableAnimation() {
|
||||
|
||||
// too slow
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
|
@ -22,7 +21,6 @@ import 'scrollStyles';
|
|||
}
|
||||
|
||||
function removeCenterFocus(dlg) {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
if (dlg.classList.contains('scrollX')) {
|
||||
centerFocus(dlg, true, false);
|
||||
|
@ -35,7 +33,6 @@ import 'scrollStyles';
|
|||
function tryRemoveElement(elem) {
|
||||
const parentNode = elem.parentNode;
|
||||
if (parentNode) {
|
||||
|
||||
// Seeing crashes in edge webview
|
||||
try {
|
||||
parentNode.removeChild(elem);
|
||||
|
@ -46,14 +43,12 @@ import 'scrollStyles';
|
|||
}
|
||||
|
||||
function DialogHashHandler(dlg, hash, resolve) {
|
||||
|
||||
const self = this;
|
||||
self.originalUrl = window.location.href;
|
||||
const activeElement = document.activeElement;
|
||||
let removeScrollLockOnClose = false;
|
||||
|
||||
function onHashChange(e) {
|
||||
|
||||
const isBack = self.originalUrl === window.location.href;
|
||||
|
||||
if (isBack || !isOpened(dlg)) {
|
||||
|
@ -67,7 +62,6 @@ import 'scrollStyles';
|
|||
}
|
||||
|
||||
function onBackCommand(e) {
|
||||
|
||||
if (e.detail.command === 'back') {
|
||||
self.closedByBack = true;
|
||||
e.preventDefault();
|
||||
|
@ -77,7 +71,6 @@ import 'scrollStyles';
|
|||
}
|
||||
|
||||
function onDialogClosed() {
|
||||
|
||||
if (!isHistoryEnabled(dlg)) {
|
||||
inputManager.off(dlg, onBackCommand);
|
||||
}
|
||||
|
@ -92,9 +85,9 @@ import 'scrollStyles';
|
|||
}
|
||||
|
||||
if (!self.closedByBack && isHistoryEnabled(dlg)) {
|
||||
const state = history.state || {};
|
||||
const state = window.history.state || {};
|
||||
if (state.dialogId === hash) {
|
||||
history.back();
|
||||
window.history.back();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,7 +151,6 @@ import 'scrollStyles';
|
|||
}
|
||||
|
||||
function addBackdropOverlay(dlg) {
|
||||
|
||||
const backdrop = document.createElement('div');
|
||||
backdrop.classList.add('dialogBackdrop');
|
||||
|
||||
|
@ -193,7 +185,6 @@ import 'scrollStyles';
|
|||
}
|
||||
|
||||
export function open(dlg) {
|
||||
|
||||
if (globalOnOpenCallback) {
|
||||
globalOnOpenCallback(dlg);
|
||||
}
|
||||
|
@ -210,22 +201,19 @@ import 'scrollStyles';
|
|||
document.body.appendChild(dialogContainer);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
new DialogHashHandler(dlg, `dlg${new Date().getTime()}`, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function isOpened(dlg) {
|
||||
|
||||
//return dlg.opened;
|
||||
return !dlg.classList.contains('hide');
|
||||
}
|
||||
|
||||
export function close(dlg) {
|
||||
|
||||
if (isOpened(dlg)) {
|
||||
if (isHistoryEnabled(dlg)) {
|
||||
history.back();
|
||||
window.history.back();
|
||||
} else {
|
||||
closeDialog(dlg);
|
||||
}
|
||||
|
@ -233,9 +221,7 @@ import 'scrollStyles';
|
|||
}
|
||||
|
||||
function closeDialog(dlg) {
|
||||
|
||||
if (!dlg.classList.contains('hide')) {
|
||||
|
||||
dlg.dispatchEvent(new CustomEvent('closing', {
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
|
@ -256,7 +242,6 @@ import 'scrollStyles';
|
|||
}
|
||||
|
||||
function animateDialogOpen(dlg) {
|
||||
|
||||
const onAnimationFinish = () => {
|
||||
focusManager.pushScope(dlg);
|
||||
|
||||
|
@ -271,7 +256,6 @@ import 'scrollStyles';
|
|||
};
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
const onFinish = () => {
|
||||
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
|
||||
once: true
|
||||
|
@ -288,13 +272,10 @@ import 'scrollStyles';
|
|||
}
|
||||
|
||||
function animateDialogClose(dlg, onAnimationFinish) {
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
let animated = true;
|
||||
|
||||
switch (dlg.animationConfig.exit.name) {
|
||||
|
||||
case 'fadeout':
|
||||
dlg.style.animation = `fadeout ${dlg.animationConfig.exit.timing.duration}ms ease-out normal both`;
|
||||
break;
|
||||
|
@ -329,7 +310,6 @@ import 'scrollStyles';
|
|||
const supportsOverscrollBehavior = 'overscroll-behavior-y' in document.body.style;
|
||||
|
||||
function shouldLockDocumentScroll(options) {
|
||||
|
||||
if (supportsOverscrollBehavior && (options.size || !browser.touch)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -350,7 +330,6 @@ import 'scrollStyles';
|
|||
}
|
||||
|
||||
function removeBackdrop(dlg) {
|
||||
|
||||
const backdrop = dlg.backdrop;
|
||||
|
||||
if (!backdrop) {
|
||||
|
@ -364,7 +343,6 @@ import 'scrollStyles';
|
|||
};
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
backdrop.classList.remove('dialogBackdropOpened');
|
||||
|
||||
// this is not firing animatonend
|
||||
|
@ -376,14 +354,13 @@ import 'scrollStyles';
|
|||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
import('scrollHelper').then(scrollHelper => {
|
||||
import('scrollHelper').then((scrollHelper) => {
|
||||
const fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
export function createDialog(options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
// If there's no native dialog support, use a plain div
|
||||
|
@ -398,7 +375,7 @@ import 'scrollStyles';
|
|||
dlg.setAttribute('data-lockscroll', 'true');
|
||||
}
|
||||
|
||||
if (options.enableHistory !== false && appRouter.enableNativeHistory()) {
|
||||
if (options.enableHistory === true) {
|
||||
dlg.setAttribute('data-history', 'true');
|
||||
}
|
||||
|
||||
|
@ -414,11 +391,8 @@ import 'scrollStyles';
|
|||
dlg.setAttribute('data-autofocus', 'true');
|
||||
}
|
||||
|
||||
let defaultEntryAnimation;
|
||||
let defaultExitAnimation;
|
||||
|
||||
defaultEntryAnimation = 'scaleup';
|
||||
defaultExitAnimation = 'scaledown';
|
||||
const defaultEntryAnimation = 'scaleup';
|
||||
const defaultExitAnimation = 'scaledown';
|
||||
const entryAnimation = options.entryAnimation || defaultEntryAnimation;
|
||||
const exitAnimation = options.exitAnimation || defaultExitAnimation;
|
||||
|
||||
|
@ -473,9 +447,7 @@ import 'scrollStyles';
|
|||
}
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
switch (dlg.animationConfig.entry.name) {
|
||||
|
||||
case 'fadein':
|
||||
dlg.style.animation = `fadein ${entryAnimationDuration}ms ease-out normal`;
|
||||
break;
|
||||
|
|
|
@ -125,7 +125,7 @@ import 'emby-button';
|
|||
html += `<input is="emby-input" id="txtDirectoryPickerPath" type="text" required="required" ${readOnlyAttribute} label="${globalize.translate(labelKey)}"/>`;
|
||||
html += '</div>';
|
||||
if (!readOnlyAttribute) {
|
||||
html += `<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="${globalize.translate('ButtonRefresh')}"><span class="material-icons search"></span></button>`;
|
||||
html += `<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="${globalize.translate('Refresh')}"><span class="material-icons search"></span></button>`;
|
||||
}
|
||||
html += '</div>';
|
||||
if (!readOnlyAttribute) {
|
||||
|
@ -166,10 +166,11 @@ import 'emby-button';
|
|||
return apiClient.ajax({
|
||||
type: 'POST',
|
||||
url: apiClient.getUrl('Environment/ValidatePath'),
|
||||
data: {
|
||||
data: JSON.stringify({
|
||||
ValidateWriteable: validateWriteable,
|
||||
Path: path
|
||||
}
|
||||
}),
|
||||
contentType: 'application/json'
|
||||
}).catch(response => {
|
||||
if (response) {
|
||||
if (response.status === 404) {
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
import browser from 'browser';
|
||||
import layoutManager from 'layoutManager';
|
||||
import appSettings from 'appSettings';
|
||||
import pluginManager from 'pluginManager';
|
||||
import appHost from 'apphost';
|
||||
import focusManager from 'focusManager';
|
||||
import datetime from 'datetime';
|
||||
import globalize from 'globalize';
|
||||
import loading from 'loading';
|
||||
import connectionManager from 'connectionManager';
|
||||
import skinManager from 'skinManager';
|
||||
import events from 'events';
|
||||
import 'emby-select';
|
||||
|
@ -16,17 +14,22 @@ import 'emby-button';
|
|||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function fillThemes(select, isDashboard) {
|
||||
select.innerHTML = skinManager.getThemes().map(t => {
|
||||
let value = t.id;
|
||||
if (t.isDefault && !isDashboard) {
|
||||
value = '';
|
||||
} else if (t.isDefaultServerDashboard && isDashboard) {
|
||||
value = '';
|
||||
}
|
||||
function fillThemes(context, userSettings) {
|
||||
const select = context.querySelector('#selectTheme');
|
||||
|
||||
return `<option value="${value}">${t.name}</option>`;
|
||||
skinManager.getThemes().then(themes => {
|
||||
select.innerHTML = themes.map(t => {
|
||||
return `<option value="${t.id}">${t.name}</option>`;
|
||||
}).join('');
|
||||
|
||||
// get default theme
|
||||
var defaultTheme = themes.find(theme => {
|
||||
return theme.default;
|
||||
});
|
||||
|
||||
// set the current theme
|
||||
select.value = userSettings.theme() || defaultTheme.id;
|
||||
});
|
||||
}
|
||||
|
||||
function loadScreensavers(context, userSettings) {
|
||||
|
@ -46,6 +49,7 @@ import 'emby-button';
|
|||
selectScreensaver.innerHTML = options.map(o => {
|
||||
return `<option value="${o.value}">${o.name}</option>`;
|
||||
}).join('');
|
||||
|
||||
selectScreensaver.value = userSettings.screensaver();
|
||||
|
||||
if (!selectScreensaver.value) {
|
||||
|
@ -54,61 +58,7 @@ import 'emby-button';
|
|||
}
|
||||
}
|
||||
|
||||
function loadSoundEffects(context, userSettings) {
|
||||
|
||||
const selectSoundEffects = context.querySelector('.selectSoundEffects');
|
||||
const options = pluginManager.ofType('soundeffects').map(plugin => {
|
||||
return {
|
||||
name: plugin.name,
|
||||
value: plugin.id
|
||||
};
|
||||
});
|
||||
|
||||
options.unshift({
|
||||
name: globalize.translate('None'),
|
||||
value: 'none'
|
||||
});
|
||||
|
||||
selectSoundEffects.innerHTML = options.map(o => {
|
||||
return `<option value="${o.value}">${o.name}</option>`;
|
||||
}).join('');
|
||||
selectSoundEffects.value = userSettings.soundEffects();
|
||||
|
||||
if (!selectSoundEffects.value) {
|
||||
// TODO: set the default instead of none
|
||||
selectSoundEffects.value = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function loadSkins(context, userSettings) {
|
||||
|
||||
const selectSkin = context.querySelector('.selectSkin');
|
||||
|
||||
const options = pluginManager.ofType('skin').map(plugin => {
|
||||
return {
|
||||
name: plugin.name,
|
||||
value: plugin.id
|
||||
};
|
||||
});
|
||||
|
||||
selectSkin.innerHTML = options.map(o => {
|
||||
return `<option value="${o.value}">${o.name}</option>`;
|
||||
}).join('');
|
||||
selectSkin.value = userSettings.skin();
|
||||
|
||||
if (!selectSkin.value && options.length) {
|
||||
selectSkin.value = options[0].value;
|
||||
}
|
||||
|
||||
if (options.length > 1 && appHost.supports('skins')) {
|
||||
context.querySelector('.selectSkinContainer').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.selectSkinContainer').classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function showOrHideMissingEpisodesField(context) {
|
||||
|
||||
if (browser.tizen || browser.web0s) {
|
||||
context.querySelector('.fldDisplayMissingEpisodes').classList.add('hide');
|
||||
return;
|
||||
|
@ -118,13 +68,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
function loadForm(context, user, userSettings) {
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
context.querySelector('.selectDashboardThemeContainer').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.selectDashboardThemeContainer').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('displaylanguage')) {
|
||||
context.querySelector('.languageSection').classList.remove('hide');
|
||||
} else {
|
||||
|
@ -143,18 +86,6 @@ import 'emby-button';
|
|||
context.querySelector('.learnHowToContributeContainer').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('runatstartup')) {
|
||||
context.querySelector('.fldAutorun').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.fldAutorun').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('soundeffects')) {
|
||||
context.querySelector('.fldSoundEffects').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.fldSoundEffects').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('screensaver')) {
|
||||
context.querySelector('.selectScreensaverContainer').classList.remove('hide');
|
||||
} else {
|
||||
|
@ -177,16 +108,8 @@ import 'emby-button';
|
|||
context.querySelector('.fldThemeVideo').classList.add('hide');
|
||||
}
|
||||
|
||||
context.querySelector('.chkRunAtStartup').checked = appSettings.runAtStartup();
|
||||
|
||||
const selectTheme = context.querySelector('#selectTheme');
|
||||
const selectDashboardTheme = context.querySelector('#selectDashboardTheme');
|
||||
|
||||
fillThemes(selectTheme);
|
||||
fillThemes(selectDashboardTheme, true);
|
||||
fillThemes(context, userSettings);
|
||||
loadScreensavers(context, userSettings);
|
||||
loadSoundEffects(context, userSettings);
|
||||
loadSkins(context, userSettings);
|
||||
|
||||
context.querySelector('.chkDisplayMissingEpisodes').checked = user.Configuration.DisplayMissingEpisodes || false;
|
||||
|
||||
|
@ -202,9 +125,6 @@ import 'emby-button';
|
|||
|
||||
context.querySelector('#txtLibraryPageSize').value = userSettings.libraryPageSize();
|
||||
|
||||
selectDashboardTheme.value = userSettings.dashboardTheme() || '';
|
||||
selectTheme.value = userSettings.theme() || '';
|
||||
|
||||
context.querySelector('.selectLayout').value = layoutManager.getSavedLayout() || '';
|
||||
|
||||
showOrHideMissingEpisodesField(context);
|
||||
|
@ -213,9 +133,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
function saveUser(context, user, userSettingsInstance, apiClient) {
|
||||
|
||||
appSettings.runAtStartup(context.querySelector('.chkRunAtStartup').checked);
|
||||
|
||||
user.Configuration.DisplayMissingEpisodes = context.querySelector('.chkDisplayMissingEpisodes').checked;
|
||||
|
||||
if (appHost.supports('displaylanguage')) {
|
||||
|
@ -226,15 +143,11 @@ import 'emby-button';
|
|||
|
||||
userSettingsInstance.enableThemeSongs(context.querySelector('#chkThemeSong').checked);
|
||||
userSettingsInstance.enableThemeVideos(context.querySelector('#chkThemeVideo').checked);
|
||||
userSettingsInstance.dashboardTheme(context.querySelector('#selectDashboardTheme').value);
|
||||
userSettingsInstance.theme(context.querySelector('#selectTheme').value);
|
||||
userSettingsInstance.soundEffects(context.querySelector('.selectSoundEffects').value);
|
||||
userSettingsInstance.screensaver(context.querySelector('.selectScreensaver').value);
|
||||
|
||||
userSettingsInstance.libraryPageSize(context.querySelector('#txtLibraryPageSize').value);
|
||||
|
||||
userSettingsInstance.skin(context.querySelector('.selectSkin').value);
|
||||
|
||||
userSettingsInstance.enableFastFadein(context.querySelector('#chkFadein').checked);
|
||||
userSettingsInstance.enableBlurhash(context.querySelector('#chkBlurhash').checked);
|
||||
userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked);
|
||||
|
@ -268,7 +181,7 @@ import 'emby-button';
|
|||
|
||||
function onSubmit(e) {
|
||||
const self = this;
|
||||
const apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userId = self.options.userId;
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
|
@ -307,7 +220,7 @@ import 'emby-button';
|
|||
loading.show();
|
||||
|
||||
const userId = self.options.userId;
|
||||
const apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
return apiClient.getUser(userId).then(user => {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<form style="margin: 0 auto;">
|
||||
|
||||
<h2 class="sectionTitle">
|
||||
${Display}
|
||||
</h2>
|
||||
|
@ -123,26 +122,14 @@
|
|||
<div class="fieldDescription">${LabelPleaseRestart}</div>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer hide selectSkinContainer">
|
||||
<select is="emby-select" class="selectSkin" label="${LabelSkin}"></select>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer">
|
||||
<select id="selectTheme" is="emby-select" label="${LabelTheme}"></select>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer selectDashboardThemeContainer hide">
|
||||
<select id="selectDashboardTheme" is="emby-select" label="${LabelDashboardTheme}"></select>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer hide selectScreensaverContainer">
|
||||
<select is="emby-select" class="selectScreensaver" label="${LabelScreensaver}"></select>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer fldSoundEffects hide">
|
||||
<select is="emby-select" class="selectSoundEffects" label="${LabelSoundEffects}"></select>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer inputContainer-withDescription">
|
||||
<input is="emby-input" type="number" id="txtLibraryPageSize" pattern="[0-9]*" required="required" min="0" max="1000" step="1" label="${LabelLibraryPageSize}" />
|
||||
<div class="fieldDescription">${LabelLibraryPageSizeHelp}</div>
|
||||
|
@ -159,9 +146,9 @@
|
|||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkBlurhash" />
|
||||
<span>${EnableBlurhash}</span>
|
||||
<span>${EnableBlurHash}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableBlurhashHelp}</div>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableBlurHashHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
|
@ -175,7 +162,7 @@
|
|||
<div class="checkboxContainer checkboxContainer-withDescription fldBackdrops hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkBackdrops" />
|
||||
<span>${EnableBackdrops}</span>
|
||||
<span>${Backdrops}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableBackdropsHelp}</div>
|
||||
</div>
|
||||
|
@ -183,7 +170,7 @@
|
|||
<div class="checkboxContainer checkboxContainer-withDescription fldThemeSong hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkThemeSong" />
|
||||
<span>${EnableThemeSongs}</span>
|
||||
<span>${ThemeSongs}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableThemeSongsHelp}</div>
|
||||
</div>
|
||||
|
@ -191,18 +178,11 @@
|
|||
<div class="checkboxContainer checkboxContainer-withDescription fldThemeVideo hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkThemeVideo" />
|
||||
<span>${EnableThemeVideos}</span>
|
||||
<span>${ThemeVideos}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableThemeVideosHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer hide fldAutorun">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkRunAtStartup" />
|
||||
<span>${RunAtStartup}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldDisplayMissingEpisodes hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkDisplayMissingEpisodes" />
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoader', 'globalize', 'layoutManager', 'scrollStyles', 'emby-itemscontainer'], function (loading, libraryBrowser, cardBuilder, dom, appHost, imageLoader, globalize, layoutManager) {
|
||||
'use strict';
|
||||
import loading from 'loading';
|
||||
import cardBuilder from 'cardBuilder';
|
||||
import dom from 'dom';
|
||||
import appHost from 'apphost';
|
||||
import imageLoader from 'imageLoader';
|
||||
import globalize from 'globalize';
|
||||
import layoutManager from 'layoutManager';
|
||||
import 'scrollStyles';
|
||||
import 'emby-itemscontainer';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function enableScrollX() {
|
||||
return !layoutManager.desktop;
|
||||
|
@ -19,21 +28,21 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
|||
|
||||
function getSections() {
|
||||
return [{
|
||||
name: 'HeaderFavoriteMovies',
|
||||
name: 'Movies',
|
||||
types: 'Movie',
|
||||
id: 'favoriteMovies',
|
||||
shape: getPosterShape(),
|
||||
showTitle: false,
|
||||
overlayPlayButton: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteShows',
|
||||
name: 'Shows',
|
||||
types: 'Series',
|
||||
id: 'favoriteShows',
|
||||
shape: getPosterShape(),
|
||||
showTitle: false,
|
||||
overlayPlayButton: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteEpisodes',
|
||||
name: 'Episodes',
|
||||
types: 'Episode',
|
||||
id: 'favoriteEpisode',
|
||||
shape: getThumbShape(),
|
||||
|
@ -44,7 +53,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
|||
overlayText: false,
|
||||
centerText: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteVideos',
|
||||
name: 'Videos',
|
||||
types: 'Video,MusicVideo',
|
||||
id: 'favoriteVideos',
|
||||
shape: getThumbShape(),
|
||||
|
@ -54,7 +63,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
|||
overlayText: false,
|
||||
centerText: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteArtists',
|
||||
name: 'Artists',
|
||||
types: 'MusicArtist',
|
||||
id: 'favoriteArtists',
|
||||
shape: getSquareShape(),
|
||||
|
@ -66,7 +75,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
|||
overlayPlayButton: true,
|
||||
coverImage: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteAlbums',
|
||||
name: 'Albums',
|
||||
types: 'MusicAlbum',
|
||||
id: 'favoriteAlbums',
|
||||
shape: getSquareShape(),
|
||||
|
@ -78,7 +87,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
|||
overlayPlayButton: true,
|
||||
coverImage: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteSongs',
|
||||
name: 'Songs',
|
||||
types: 'Audio',
|
||||
id: 'favoriteSongs',
|
||||
shape: getSquareShape(),
|
||||
|
@ -94,8 +103,8 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
|||
}
|
||||
|
||||
function loadSection(elem, userId, topParentId, section, isSingleSection) {
|
||||
var screenWidth = dom.getWindowSize().innerWidth;
|
||||
var options = {
|
||||
const screenWidth = dom.getWindowSize().innerWidth;
|
||||
const options = {
|
||||
SortBy: 'SortName',
|
||||
SortOrder: 'Ascending',
|
||||
Filters: 'IsFavorite',
|
||||
|
@ -118,9 +127,9 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
|||
}
|
||||
}
|
||||
|
||||
var promise;
|
||||
let promise;
|
||||
|
||||
if ('MusicArtist' === section.types) {
|
||||
if (section.types === 'MusicArtist') {
|
||||
promise = ApiClient.getArtists(userId, options);
|
||||
} else {
|
||||
options.IncludeItemTypes = section.types;
|
||||
|
@ -128,7 +137,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
|||
}
|
||||
|
||||
return promise.then(function (result) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
if (result.Items.length) {
|
||||
if (html += '<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">', !layoutManager.tv && options.Limit && result.Items.length >= options.Limit) {
|
||||
|
@ -144,7 +153,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
|||
|
||||
html += '</div>';
|
||||
if (enableScrollX()) {
|
||||
var scrollXClass = 'scrollX hiddenScrollX';
|
||||
let scrollXClass = 'scrollX hiddenScrollX';
|
||||
if (layoutManager.tv) {
|
||||
scrollXClass += ' smoothScrollX';
|
||||
}
|
||||
|
@ -154,14 +163,13 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
|||
html += '<div is="emby-itemscontainer" class="itemsContainer vertical-wrap padded-left padded-right">';
|
||||
}
|
||||
|
||||
var supportsImageAnalysis = appHost.supports('imageanalysis');
|
||||
var cardLayout = (appHost.preferVisualCards || supportsImageAnalysis) && section.autoCardLayout && section.showTitle;
|
||||
let cardLayout = appHost.preferVisualCards && section.autoCardLayout && section.showTitle;
|
||||
cardLayout = false;
|
||||
html += cardBuilder.getCardsHtml(result.Items, {
|
||||
preferThumb: section.preferThumb,
|
||||
shape: section.shape,
|
||||
centerText: section.centerText && !cardLayout,
|
||||
overlayText: false !== section.overlayText,
|
||||
overlayText: section.overlayText !== false,
|
||||
showTitle: section.showTitle,
|
||||
showParentTitle: section.showParentTitle,
|
||||
scalable: true,
|
||||
|
@ -180,10 +188,10 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
|||
});
|
||||
}
|
||||
|
||||
function loadSections(page, userId, topParentId, types) {
|
||||
export function loadSections(page, userId, topParentId, types) {
|
||||
loading.show();
|
||||
var sections = getSections();
|
||||
var sectionid = getParameterByName('sectionid');
|
||||
let sections = getSections();
|
||||
const sectionid = getParameterByName('sectionid');
|
||||
|
||||
if (sectionid) {
|
||||
sections = sections.filter(function (s) {
|
||||
|
@ -193,30 +201,28 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
|||
|
||||
if (types) {
|
||||
sections = sections.filter(function (s) {
|
||||
return -1 !== types.indexOf(s.id);
|
||||
return types.indexOf(s.id) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
var i;
|
||||
var length;
|
||||
var elem = page.querySelector('.favoriteSections');
|
||||
let elem = page.querySelector('.favoriteSections');
|
||||
|
||||
if (!elem.innerHTML) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
for (i = 0, length = sections.length; i < length; i++) {
|
||||
for (let i = 0, length = sections.length; i < length; i++) {
|
||||
html += '<div class="verticalSection section' + sections[i].id + '"></div>';
|
||||
}
|
||||
|
||||
elem.innerHTML = html;
|
||||
}
|
||||
|
||||
var promises = [];
|
||||
const promises = [];
|
||||
|
||||
for (i = 0, length = sections.length; i < length; i++) {
|
||||
var section = sections[i];
|
||||
for (let i = 0, length = sections.length; i < length; i++) {
|
||||
const section = sections[i];
|
||||
elem = page.querySelector('.section' + section.id);
|
||||
promises.push(loadSection(elem, userId, topParentId, section, 1 === sections.length));
|
||||
promises.push(loadSection(elem, userId, topParentId, section, sections.length === 1));
|
||||
}
|
||||
|
||||
Promise.all(promises).then(function () {
|
||||
|
@ -224,7 +230,8 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
|||
});
|
||||
}
|
||||
|
||||
return {
|
||||
export default {
|
||||
render: loadSections
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* eslint-disable indent */
|
||||
export function getFetchPromise(request) {
|
||||
|
||||
const headers = request.headers || {};
|
||||
|
||||
if (request.dataType === 'json') {
|
||||
|
@ -16,7 +15,6 @@
|
|||
let contentType = request.contentType;
|
||||
|
||||
if (request.data) {
|
||||
|
||||
if (typeof request.data === 'string') {
|
||||
fetchRequest.body = request.data;
|
||||
} else {
|
||||
|
@ -27,7 +25,6 @@
|
|||
}
|
||||
|
||||
if (contentType) {
|
||||
|
||||
headers['Content-Type'] = contentType;
|
||||
}
|
||||
|
||||
|
@ -48,11 +45,9 @@
|
|||
}
|
||||
|
||||
function fetchWithTimeout(url, options, timeoutMs) {
|
||||
|
||||
console.debug(`fetchWithTimeout: timeoutMs: ${timeoutMs}, url: ${url}`);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
const timeout = setTimeout(reject, timeoutMs);
|
||||
|
||||
options = options || {};
|
||||
|
@ -65,7 +60,6 @@
|
|||
|
||||
resolve(response);
|
||||
}, function (error) {
|
||||
|
||||
clearTimeout(timeout);
|
||||
|
||||
console.debug(`fetchWithTimeout: timed out connecting to url: ${url}`);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import dom from 'dom';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import globalize from 'globalize';
|
||||
import connectionManager from 'connectionManager';
|
||||
import events from 'events';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-collapse';
|
||||
|
@ -420,7 +419,7 @@ import 'css!./style.css';
|
|||
this.bindEvents(dlg);
|
||||
if (enableDynamicFilters(this.options.mode)) {
|
||||
dlg.classList.add('dynamicFilterDialog');
|
||||
const apiClient = connectionManager.getApiClient(this.options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(this.options.serverId);
|
||||
loadDynamicFilters(dlg, apiClient, apiClient.getCurrentUserId(), this.options.query);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<div style="margin: 0;padding:1.5em 2em;" class="filterDialogContent">
|
||||
|
||||
<div is="emby-collapse" title="${HeaderFilters}">
|
||||
<div is="emby-collapse" title="${Filters}">
|
||||
<div class="collapseContent">
|
||||
<div class="checkboxList">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter videoStandard"
|
||||
data-filter="IsPlayed" />
|
||||
<span>${OptionPlayed}</span>
|
||||
<span>${Played}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter videoStandard"
|
||||
data-filter="IsUnPlayed" />
|
||||
<span>${OptionUnplayed}</span>
|
||||
<span>${Unplayed}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter videoStandard"
|
||||
|
@ -21,7 +21,7 @@
|
|||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter chkFavorite"
|
||||
data-filter="IsFavorite" />
|
||||
<span>${OptionFavorite}</span>
|
||||
<span>${Favorites}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter chkLikes" data-filter="Likes" />
|
||||
|
@ -53,30 +53,30 @@
|
|||
<div class="checkboxList">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStatus" data-filter="Continuing" />
|
||||
<span>${OptionContinuing}</span>
|
||||
<span>${Continuing}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStatus" data-filter="Ended" />
|
||||
<span>${OptionEnded}</span>
|
||||
<span>${Ended}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div is="emby-collapse" title="${HeaderFeatures}" class="features hide">
|
||||
<div is="emby-collapse" title="${Features}" class="features hide">
|
||||
<div class="collapseContent">
|
||||
<div class="checkboxList">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkFeatureFilter" id="chkSubtitle" />
|
||||
<span>${OptionHasSubtitles}</span>
|
||||
<span>${Subtitles}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkFeatureFilter" id="chkTrailer" />
|
||||
<span>${OptionHasTrailer}</span>
|
||||
<span>${ButtonTrailer}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkFeatureFilter" id="chkSpecialFeature" />
|
||||
<span>${OptionHasSpecialFeatures}</span>
|
||||
<span>${SpecialFeatures}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkFeatureFilter" id="chkThemeSong" />
|
||||
|
@ -90,7 +90,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div is="emby-collapse" title="${HeaderGenres}" class="genreFilters hide">
|
||||
<div is="emby-collapse" title="${Genres}" class="genreFilters hide">
|
||||
<div class="collapseContent filterOptions">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -100,7 +100,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div is="emby-collapse" title="${HeaderTags}" class="tagFilters hide">
|
||||
<div is="emby-collapse" title="${Tags}" class="tagFilters hide">
|
||||
<div class="collapseContent filterOptions">
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,20 +1,28 @@
|
|||
define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost', 'inputManager', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'userSettings', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (require, dom, focusManager, dialogHelper, loading, appHost, inputManager, layoutManager, connectionManager, appRouter, globalize, userSettings) {
|
||||
'use strict';
|
||||
|
||||
function onSubmit(e) {
|
||||
import dom from 'dom';
|
||||
import focusManager from 'focusManager';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import inputManager from 'inputManager';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import * as userSettings from 'userSettings';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-input';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-select';
|
||||
import 'material-icons';
|
||||
import 'css!./../formdialog';
|
||||
import 'emby-button';
|
||||
import 'flexStyles';
|
||||
|
||||
function onSubmit(e) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
function renderOptions(context, selector, cssClass, items, isCheckedFn) {
|
||||
|
||||
}
|
||||
function renderOptions(context, selector, cssClass, items, isCheckedFn) {
|
||||
var elem = context.querySelector(selector);
|
||||
|
||||
if (items.length) {
|
||||
|
||||
elem.classList.remove('hide');
|
||||
|
||||
} else {
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
|
@ -22,7 +30,6 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
|||
var html = '';
|
||||
|
||||
html += items.map(function (filter) {
|
||||
|
||||
var itemHtml = '';
|
||||
|
||||
var checkedHtml = isCheckedFn(filter) ? ' checked' : '';
|
||||
|
@ -32,180 +39,30 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
|||
itemHtml += '</label>';
|
||||
|
||||
return itemHtml;
|
||||
|
||||
}).join('');
|
||||
|
||||
elem.querySelector('.filterOptions').innerHTML = html;
|
||||
}
|
||||
|
||||
function renderDynamicFilters(context, result, options) {
|
||||
|
||||
// If there's a huge number of these they will be really show to render
|
||||
//if (result.Tags) {
|
||||
// result.Tags.length = Math.min(result.Tags.length, 50);
|
||||
//}
|
||||
}
|
||||
|
||||
function renderDynamicFilters(context, result, options) {
|
||||
renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) {
|
||||
|
||||
// Switching from | to ,
|
||||
var delimeter = (options.settings.GenreIds || '').indexOf('|') === -1 ? ',' : '|';
|
||||
return (delimeter + (options.settings.GenreIds || '') + delimeter).indexOf(delimeter + i.Id + delimeter) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
//renderOptions(context, '.officialRatingFilters', 'chkOfficialRatingFilter', result.OfficialRatings, function (i) {
|
||||
// var delimeter = '|';
|
||||
// return (delimeter + (query.OfficialRatings || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
//});
|
||||
|
||||
//renderOptions(context, '.tagFilters', 'chkTagFilter', result.Tags, function (i) {
|
||||
// var delimeter = '|';
|
||||
// return (delimeter + (query.Tags || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
//});
|
||||
|
||||
//renderOptions(context, '.yearFilters', 'chkYearFilter', result.Years, function (i) {
|
||||
|
||||
// var delimeter = ',';
|
||||
// return (delimeter + (query.Years || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
//});
|
||||
}
|
||||
|
||||
function loadDynamicFilters(context, options) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(options.serverId);
|
||||
|
||||
var filterMenuOptions = Object.assign(options.filterMenuOptions, {
|
||||
|
||||
UserId: apiClient.getCurrentUserId(),
|
||||
ParentId: options.parentId,
|
||||
IncludeItemTypes: options.itemTypes.join(',')
|
||||
});
|
||||
|
||||
apiClient.getFilters(filterMenuOptions).then(function (result) {
|
||||
|
||||
renderDynamicFilters(context, result, options);
|
||||
}, function () {
|
||||
|
||||
// older server
|
||||
});
|
||||
}
|
||||
|
||||
function initEditor(context, settings) {
|
||||
|
||||
context.querySelector('form').addEventListener('submit', onSubmit);
|
||||
|
||||
var elems = context.querySelectorAll('.simpleFilter');
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].tagName === 'INPUT') {
|
||||
elems[i].checked = settings[elems[i].getAttribute('data-settingname')] || false;
|
||||
} else {
|
||||
elems[i].querySelector('input').checked = settings[elems[i].getAttribute('data-settingname')] || false;
|
||||
}
|
||||
}
|
||||
|
||||
var videoTypes = settings.VideoTypes ? settings.VideoTypes.split(',') : [];
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
elems[i].checked = videoTypes.indexOf(elems[i].getAttribute('data-filter')) !== -1;
|
||||
}
|
||||
|
||||
var seriesStatuses = settings.SeriesStatus ? settings.SeriesStatus.split(',') : [];
|
||||
elems = context.querySelectorAll('.chkSeriesStatus');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
elems[i].checked = seriesStatuses.indexOf(elems[i].getAttribute('data-filter')) !== -1;
|
||||
}
|
||||
|
||||
if (context.querySelector('.basicFilterSection .viewSetting:not(.hide)')) {
|
||||
context.querySelector('.basicFilterSection').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.basicFilterSection').classList.add('hide');
|
||||
}
|
||||
|
||||
if (context.querySelector('.featureSection .viewSetting:not(.hide)')) {
|
||||
context.querySelector('.featureSection').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.featureSection').classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function saveValues(context, settings, settingsKey) {
|
||||
|
||||
var elems = context.querySelectorAll('.simpleFilter');
|
||||
var i;
|
||||
var length;
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].tagName === 'INPUT') {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i]);
|
||||
} else {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i].querySelector('input'));
|
||||
}
|
||||
}
|
||||
|
||||
// Video type
|
||||
var videoTypes = [];
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].checked) {
|
||||
videoTypes.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
userSettings.setFilter(settingsKey + '-filter-VideoTypes', videoTypes.join(','));
|
||||
|
||||
// Series status
|
||||
var seriesStatuses = [];
|
||||
elems = context.querySelectorAll('.chkSeriesStatus');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].checked) {
|
||||
seriesStatuses.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
|
||||
// Genres
|
||||
var genres = [];
|
||||
elems = context.querySelectorAll('.chkGenreFilter');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].checked) {
|
||||
genres.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
userSettings.setFilter(settingsKey + '-filter-GenreIds', genres.join(','));
|
||||
}
|
||||
|
||||
function setBasicFilter(context, key, elem) {
|
||||
|
||||
function setBasicFilter(context, key, elem) {
|
||||
var value = elem.checked;
|
||||
value = value ? value : null;
|
||||
userSettings.setFilter(key, value);
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
var fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
function moveCheckboxFocus(elem, offset) {
|
||||
|
||||
}
|
||||
function moveCheckboxFocus(elem, offset) {
|
||||
var parent = dom.parentWithClass(elem, 'checkboxList-verticalwrap');
|
||||
var elems = focusManager.getFocusableElements(parent);
|
||||
|
||||
var index = -1;
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i] === elem) {
|
||||
index = i;
|
||||
break;
|
||||
|
@ -221,11 +78,15 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
|||
if (newElem) {
|
||||
focusManager.focus(newElem);
|
||||
}
|
||||
}
|
||||
|
||||
function onInputCommand(e) {
|
||||
}
|
||||
function centerFocus(elem, horiz, on) {
|
||||
import('scrollHelper').then(({ default: scrollHelper }) => {
|
||||
var fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
function onInputCommand(e) {
|
||||
switch (e.detail.command) {
|
||||
|
||||
case 'left':
|
||||
moveCheckboxFocus(e.target, -1);
|
||||
e.preventDefault();
|
||||
|
@ -237,35 +98,122 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
|||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
function saveValues(context, settings, settingsKey) {
|
||||
var elems = context.querySelectorAll('.simpleFilter');
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].tagName === 'INPUT') {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i]);
|
||||
} else {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i].querySelector('input'));
|
||||
}
|
||||
}
|
||||
|
||||
function FilterMenu() {
|
||||
// Video type
|
||||
var videoTypes = [];
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].checked) {
|
||||
videoTypes.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
userSettings.setFilter(settingsKey + '-filter-VideoTypes', videoTypes.join(','));
|
||||
|
||||
// Series status
|
||||
var seriesStatuses = [];
|
||||
elems = context.querySelectorAll('.chkSeriesStatus');
|
||||
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].checked) {
|
||||
seriesStatuses.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
|
||||
function bindCheckboxInput(context, on) {
|
||||
// Genres
|
||||
var genres = [];
|
||||
elems = context.querySelectorAll('.chkGenreFilter');
|
||||
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].checked) {
|
||||
genres.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
userSettings.setFilter(settingsKey + '-filter-GenreIds', genres.join(','));
|
||||
}
|
||||
function bindCheckboxInput(context, on) {
|
||||
var elems = context.querySelectorAll('.checkboxList-verticalwrap');
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (on) {
|
||||
inputManager.on(elems[i], onInputCommand);
|
||||
} else {
|
||||
inputManager.off(elems[i], onInputCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
function initEditor(context, settings) {
|
||||
context.querySelector('form').addEventListener('submit', onSubmit);
|
||||
|
||||
var elems = context.querySelectorAll('.simpleFilter');
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].tagName === 'INPUT') {
|
||||
elems[i].checked = settings[elems[i].getAttribute('data-settingname')] || false;
|
||||
} else {
|
||||
elems[i].querySelector('input').checked = settings[elems[i].getAttribute('data-settingname')] || false;
|
||||
}
|
||||
}
|
||||
|
||||
FilterMenu.prototype.show = function (options) {
|
||||
var videoTypes = settings.VideoTypes ? settings.VideoTypes.split(',') : [];
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].checked = videoTypes.indexOf(elems[i].getAttribute('data-filter')) !== -1;
|
||||
}
|
||||
|
||||
require(['text!./filtermenu.template.html'], function (template) {
|
||||
var seriesStatuses = settings.SeriesStatus ? settings.SeriesStatus.split(',') : [];
|
||||
elems = context.querySelectorAll('.chkSeriesStatus');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].checked = seriesStatuses.indexOf(elems[i].getAttribute('data-filter')) !== -1;
|
||||
}
|
||||
|
||||
if (context.querySelector('.basicFilterSection .viewSetting:not(.hide)')) {
|
||||
context.querySelector('.basicFilterSection').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.basicFilterSection').classList.add('hide');
|
||||
}
|
||||
|
||||
if (context.querySelector('.featureSection .viewSetting:not(.hide)')) {
|
||||
context.querySelector('.featureSection').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.featureSection').classList.add('hide');
|
||||
}
|
||||
}
|
||||
function loadDynamicFilters(context, options) {
|
||||
var apiClient = window.connectionManager.getApiClient(options.serverId);
|
||||
|
||||
var filterMenuOptions = Object.assign(options.filterMenuOptions, {
|
||||
|
||||
UserId: apiClient.getCurrentUserId(),
|
||||
ParentId: options.parentId,
|
||||
IncludeItemTypes: options.itemTypes.join(',')
|
||||
});
|
||||
|
||||
apiClient.getFilters(filterMenuOptions).then((result) => {
|
||||
renderDynamicFilters(context, result, options);
|
||||
});
|
||||
}
|
||||
class FilterMenu {
|
||||
show(options) {
|
||||
return new Promise( (resolve, reject) => {
|
||||
import('text!./filtermenu.template.html').then(({ default: template }) => {
|
||||
var dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
|
@ -289,7 +237,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
|||
dlg.innerHTML = globalize.translateHtml(html, 'core');
|
||||
|
||||
var settingElements = dlg.querySelectorAll('.viewSetting');
|
||||
for (var i = 0, length = settingElements.length; i < length; i++) {
|
||||
for (let i = 0, length = settingElements.length; i < length; i++) {
|
||||
if (options.visibleSettings.indexOf(settingElements[i].getAttribute('data-settingname')) === -1) {
|
||||
settingElements[i].classList.add('hide');
|
||||
} else {
|
||||
|
@ -301,9 +249,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
|||
loadDynamicFilters(dlg, options);
|
||||
|
||||
bindCheckboxInput(dlg, true);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
|
@ -314,17 +260,10 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
|||
var submitted;
|
||||
|
||||
dlg.querySelector('form').addEventListener('change', function () {
|
||||
|
||||
submitted = true;
|
||||
//if (options.onChange) {
|
||||
// saveValues(dlg, options.settings, options.settingsKey);
|
||||
// options.onChange();
|
||||
//}
|
||||
|
||||
}, true);
|
||||
|
||||
dialogHelper.open(dlg).then(function () {
|
||||
|
||||
dialogHelper.open(dlg).then( function() {
|
||||
bindCheckboxInput(dlg, false);
|
||||
|
||||
if (layoutManager.tv) {
|
||||
|
@ -332,19 +271,16 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
|||
}
|
||||
|
||||
if (submitted) {
|
||||
|
||||
//if (!options.onChange) {
|
||||
saveValues(dlg, options.settings, options.settingsKey);
|
||||
resolve();
|
||||
return resolve();
|
||||
//}
|
||||
return;
|
||||
}
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
reject();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return FilterMenu;
|
||||
});
|
||||
export default FilterMenu;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
import dom from 'dom';
|
||||
import scrollManager from 'scrollManager';
|
||||
|
||||
var scopes = [];
|
||||
function pushScope(elem) {
|
||||
|
@ -7,14 +9,12 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
}
|
||||
|
||||
function popScope(elem) {
|
||||
|
||||
if (scopes.length) {
|
||||
scopes.length -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
function autoFocus(view, defaultToFirst, findAutoFocusElement) {
|
||||
|
||||
var element;
|
||||
if (findAutoFocusElement !== false) {
|
||||
element = view.querySelector('*[autofocus]');
|
||||
|
@ -37,7 +37,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
}
|
||||
|
||||
function focus(element) {
|
||||
|
||||
try {
|
||||
element.focus({
|
||||
preventScroll: scrollManager.isEnabled()
|
||||
|
@ -50,16 +49,13 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
var focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A'];
|
||||
var focusableContainerTagNames = ['BODY', 'DIALOG'];
|
||||
var focusableQuery = focusableTagNames.map(function (t) {
|
||||
|
||||
if (t === 'INPUT') {
|
||||
t += ':not([type="range"]):not([type="file"])';
|
||||
}
|
||||
return t + ':not([tabindex="-1"]):not(:disabled)';
|
||||
|
||||
}).join(',') + ',.focusable';
|
||||
|
||||
function isFocusable(elem) {
|
||||
|
||||
if (focusableTagNames.indexOf(elem.tagName) !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
@ -83,7 +79,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
}
|
||||
|
||||
function focusableParent(elem) {
|
||||
|
||||
var originalElement = elem;
|
||||
|
||||
while (!isFocusable(elem)) {
|
||||
|
@ -101,7 +96,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
|
||||
// Determines if a focusable element can be focused at a given point in time
|
||||
function isCurrentlyFocusableInternal(elem) {
|
||||
|
||||
// http://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom
|
||||
if (elem.offsetParent === null) {
|
||||
return false;
|
||||
|
@ -112,7 +106,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
|
||||
// Determines if a focusable element can be focused at a given point in time
|
||||
function isCurrentlyFocusable(elem) {
|
||||
|
||||
if (elem.disabled) {
|
||||
return false;
|
||||
}
|
||||
|
@ -143,7 +136,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
var focusableElements = [];
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elem = elems[i];
|
||||
|
||||
if (excludeClass && elem.classList.contains(excludeClass)) {
|
||||
|
@ -163,7 +155,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
}
|
||||
|
||||
function isFocusContainer(elem, direction) {
|
||||
|
||||
if (focusableContainerTagNames.indexOf(elem.tagName) !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
@ -217,7 +208,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
}
|
||||
|
||||
function getOffset(elem) {
|
||||
|
||||
var box;
|
||||
|
||||
// Support: BlackBerry 5, iOS 3 (original iPhone)
|
||||
|
@ -234,7 +224,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
}
|
||||
|
||||
if (box.right === null) {
|
||||
|
||||
// Create a new object because some browsers will throw an error when trying to set data onto the Rect object
|
||||
var newBox = {
|
||||
top: box.top,
|
||||
|
@ -253,7 +242,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
}
|
||||
|
||||
function nav(activeElement, direction, container, focusableElements) {
|
||||
|
||||
activeElement = activeElement || document.activeElement;
|
||||
|
||||
if (activeElement) {
|
||||
|
@ -272,14 +260,10 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
var rect = getOffset(activeElement);
|
||||
|
||||
// Get elements and work out x/y points
|
||||
var cache = [];
|
||||
var point1x = parseFloat(rect.left) || 0;
|
||||
var point1y = parseFloat(rect.top) || 0;
|
||||
var point2x = parseFloat(point1x + rect.width - 1) || point1x;
|
||||
var point2y = parseFloat(point1y + rect.height - 1) || point1y;
|
||||
// Shortcuts to help with compression
|
||||
var min = Math.min;
|
||||
var max = Math.max;
|
||||
|
||||
var sourceMidX = rect.left + (rect.width / 2);
|
||||
var sourceMidY = rect.top + (rect.height / 2);
|
||||
|
@ -301,10 +285,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
continue;
|
||||
}
|
||||
|
||||
//if (!isCurrentlyFocusableInternal(curr)) {
|
||||
// continue;
|
||||
//}
|
||||
|
||||
var elementRect = getOffset(curr);
|
||||
|
||||
// not currently visible
|
||||
|
@ -313,7 +293,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
}
|
||||
|
||||
switch (direction) {
|
||||
|
||||
case 0:
|
||||
// left
|
||||
if (elementRect.left >= rect.left) {
|
||||
|
@ -369,7 +348,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
var distY;
|
||||
|
||||
switch (direction) {
|
||||
|
||||
case 0:
|
||||
// left
|
||||
distX = Math.abs(point1x - Math.min(point1x, x2));
|
||||
|
@ -403,7 +381,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
}
|
||||
|
||||
if (nearestElement) {
|
||||
|
||||
// See if there's a focusable container, and if so, send the focus command to that
|
||||
if (activeElement) {
|
||||
var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable');
|
||||
|
@ -418,12 +395,10 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
}
|
||||
|
||||
function intersectsInternal(a1, a2, b1, b2) {
|
||||
|
||||
return (b1 >= a1 && b1 <= a2) || (b2 >= a1 && b2 <= a2);
|
||||
}
|
||||
|
||||
function intersects(a1, a2, b1, b2) {
|
||||
|
||||
return intersectsInternal(a1, a2, b1, b2) || intersectsInternal(b1, b2, a1, a2);
|
||||
}
|
||||
|
||||
|
@ -434,11 +409,9 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
}
|
||||
|
||||
function focusFirst(container, focusableSelector) {
|
||||
|
||||
var elems = container.querySelectorAll(focusableSelector);
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elem = elems[i];
|
||||
|
||||
if (isCurrentlyFocusableInternal(elem)) {
|
||||
|
@ -449,11 +422,9 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
}
|
||||
|
||||
function focusLast(container, focusableSelector) {
|
||||
|
||||
var elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse();
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elem = elems[i];
|
||||
|
||||
if (isCurrentlyFocusableInternal(elem)) {
|
||||
|
@ -464,7 +435,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
}
|
||||
|
||||
function moveFocus(sourceElement, container, focusableSelector, offset) {
|
||||
|
||||
var elems = container.querySelectorAll(focusableSelector);
|
||||
var list = [];
|
||||
var i;
|
||||
|
@ -472,7 +442,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
var elem;
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
elem = elems[i];
|
||||
|
||||
if (isCurrentlyFocusableInternal(elem)) {
|
||||
|
@ -483,7 +452,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
var currentIndex = -1;
|
||||
|
||||
for (i = 0, length = list.length; i < length; i++) {
|
||||
|
||||
elem = list[i];
|
||||
|
||||
if (sourceElement === elem || elem.contains(sourceElement)) {
|
||||
|
@ -506,7 +474,9 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
}
|
||||
}
|
||||
|
||||
return {
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
autoFocus: autoFocus,
|
||||
focus: focus,
|
||||
focusableParent: focusableParent,
|
||||
|
@ -538,5 +508,4 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
|||
focusFirst: focusFirst,
|
||||
focusLast: focusLast,
|
||||
moveFocus: moveFocus
|
||||
};
|
||||
});
|
||||
};
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
|
||||
import dom from 'dom';
|
||||
import appRouter from 'appRouter';
|
||||
import connectionManager from 'connectionManager';
|
||||
|
||||
function onGroupedCardClick(e, card) {
|
||||
var itemId = card.getAttribute('data-id');
|
||||
var serverId = card.getAttribute('data-serverid');
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
var apiClient = window.connectionManager.getApiClient(serverId);
|
||||
var userId = apiClient.getCurrentUserId();
|
||||
var playedIndicator = card.querySelector('.playedIndicator');
|
||||
var playedIndicatorHtml = playedIndicator ? playedIndicator.innerHTML : null;
|
||||
|
@ -21,7 +20,7 @@ import connectionManager from 'connectionManager';
|
|||
|
||||
if (!actionableParent || actionableParent.classList.contains('cardContent')) {
|
||||
apiClient.getJSON(apiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) {
|
||||
if (1 === items.length) {
|
||||
if (items.length === 1) {
|
||||
return void appRouter.showItem(items[0]);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectionManager', 'require', 'loading', 'scrollHelper', 'emby-checkbox', 'emby-radio', 'css!./../formdialog', 'material-icons'], function (dialogHelper, globalize, userSettings, layoutManager, connectionManager, require, loading, scrollHelper) {
|
||||
'use strict';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import globalize from 'globalize';
|
||||
import * as userSettings from 'userSettings';
|
||||
import layoutManager from 'layoutManager';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-radio';
|
||||
import 'css!./../formdialog';
|
||||
import 'material-icons';
|
||||
|
||||
function saveCategories(context, options) {
|
||||
function saveCategories(context, options) {
|
||||
const categories = [];
|
||||
|
||||
var categories = [];
|
||||
const chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (const chkCategory of chkCategorys) {
|
||||
const type = chkCategory.getAttribute('data-type');
|
||||
|
||||
var chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (var i = 0, length = chkCategorys.length; i < length; i++) {
|
||||
|
||||
var type = chkCategorys[i].getAttribute('data-type');
|
||||
|
||||
if (chkCategorys[i].checked) {
|
||||
if (chkCategory.checked) {
|
||||
categories.push(type);
|
||||
}
|
||||
}
|
||||
|
@ -22,82 +27,69 @@ define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectio
|
|||
// differentiate between none and all
|
||||
categories.push('all');
|
||||
options.categories = categories;
|
||||
}
|
||||
|
||||
function loadCategories(context, options) {
|
||||
const selectedCategories = options.categories || [];
|
||||
|
||||
const chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (const chkCategory of chkCategorys) {
|
||||
const type = chkCategory.getAttribute('data-type');
|
||||
|
||||
chkCategory.checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1;
|
||||
}
|
||||
}
|
||||
|
||||
function loadCategories(context, options) {
|
||||
function save(context) {
|
||||
const chkIndicators = context.querySelectorAll('.chkIndicator');
|
||||
|
||||
var selectedCategories = options.categories || [];
|
||||
|
||||
var chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (var i = 0, length = chkCategorys.length; i < length; i++) {
|
||||
|
||||
var type = chkCategorys[i].getAttribute('data-type');
|
||||
|
||||
chkCategorys[i].checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1;
|
||||
}
|
||||
}
|
||||
|
||||
function save(context) {
|
||||
|
||||
var i;
|
||||
var length;
|
||||
|
||||
var chkIndicators = context.querySelectorAll('.chkIndicator');
|
||||
for (i = 0, length = chkIndicators.length; i < length; i++) {
|
||||
|
||||
var type = chkIndicators[i].getAttribute('data-type');
|
||||
userSettings.set('guide-indicator-' + type, chkIndicators[i].checked);
|
||||
for (const chkIndicator of chkIndicators) {
|
||||
const type = chkIndicator.getAttribute('data-type');
|
||||
userSettings.set('guide-indicator-' + type, chkIndicator.checked);
|
||||
}
|
||||
|
||||
userSettings.set('guide-colorcodedbackgrounds', context.querySelector('.chkColorCodedBackgrounds').checked);
|
||||
userSettings.set('livetv-favoritechannelsattop', context.querySelector('.chkFavoriteChannelsAtTop').checked);
|
||||
|
||||
var sortBys = context.querySelectorAll('.chkSortOrder');
|
||||
for (i = 0, length = sortBys.length; i < length; i++) {
|
||||
if (sortBys[i].checked) {
|
||||
userSettings.set('livetv-channelorder', sortBys[i].value);
|
||||
const sortBys = context.querySelectorAll('.chkSortOrder');
|
||||
for (const sortBy of sortBys) {
|
||||
if (sortBy.checked) {
|
||||
userSettings.set('livetv-channelorder', sortBy.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function load(context) {
|
||||
function load(context) {
|
||||
const chkIndicators = context.querySelectorAll('.chkIndicator');
|
||||
|
||||
var i;
|
||||
var length;
|
||||
for (const chkIndicator of chkIndicators) {
|
||||
const type = chkIndicator.getAttribute('data-type');
|
||||
|
||||
var chkIndicators = context.querySelectorAll('.chkIndicator');
|
||||
for (i = 0, length = chkIndicators.length; i < length; i++) {
|
||||
|
||||
var type = chkIndicators[i].getAttribute('data-type');
|
||||
|
||||
if (chkIndicators[i].getAttribute('data-default') === 'true') {
|
||||
chkIndicators[i].checked = userSettings.get('guide-indicator-' + type) !== 'false';
|
||||
if (chkIndicator.getAttribute('data-default') === 'true') {
|
||||
chkIndicator.checked = userSettings.get('guide-indicator-' + type) !== 'false';
|
||||
} else {
|
||||
chkIndicators[i].checked = userSettings.get('guide-indicator-' + type) === 'true';
|
||||
chkIndicator.checked = userSettings.get('guide-indicator-' + type) === 'true';
|
||||
}
|
||||
}
|
||||
|
||||
context.querySelector('.chkColorCodedBackgrounds').checked = userSettings.get('guide-colorcodedbackgrounds') === 'true';
|
||||
context.querySelector('.chkFavoriteChannelsAtTop').checked = userSettings.get('livetv-favoritechannelsattop') !== 'false';
|
||||
|
||||
var sortByValue = userSettings.get('livetv-channelorder') || 'Number';
|
||||
const sortByValue = userSettings.get('livetv-channelorder') || 'Number';
|
||||
|
||||
var sortBys = context.querySelectorAll('.chkSortOrder');
|
||||
for (i = 0, length = sortBys.length; i < length; i++) {
|
||||
sortBys[i].checked = sortBys[i].value === sortByValue;
|
||||
}
|
||||
const sortBys = context.querySelectorAll('.chkSortOrder');
|
||||
for (const sortBy of sortBys) {
|
||||
sortBy.checked = sortBy.value === sortByValue;
|
||||
}
|
||||
}
|
||||
|
||||
function showEditor(options) {
|
||||
|
||||
function showEditor(options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
let settingsChanged = false;
|
||||
|
||||
var settingsChanged = false;
|
||||
|
||||
require(['text!./guide-settings.template.html'], function (template) {
|
||||
|
||||
var dialogOptions = {
|
||||
import('text!./guide-settings.template.html').then(({ default: template }) => {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
@ -108,23 +100,21 @@ define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectio
|
|||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
dlg.addEventListener('change', function () {
|
||||
|
||||
settingsChanged = true;
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
@ -152,9 +142,8 @@ define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectio
|
|||
dialogHelper.open(dlg);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
export default {
|
||||
show: showEditor
|
||||
};
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="formDialogHeader">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${LabelPrevious}" tabindex="-1">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${Previous}" tabindex="-1">
|
||||
<span class="material-icons arrow_back" aria-hidden="true"></span>
|
||||
</button>
|
||||
<h3 class="formDialogHeaderTitle">
|
||||
|
|
|
@ -70,6 +70,10 @@
|
|||
contain: strict;
|
||||
}
|
||||
|
||||
.programContainer.emby-scroller {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.channelPrograms {
|
||||
height: 4.42em;
|
||||
contain: strict;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -29,10 +29,10 @@
|
|||
</div>
|
||||
|
||||
<div class="guideOptions hide">
|
||||
<button is="paper-icon-button-light" type="button" class="btnPreviousPage" title="${LabelPrevious}">
|
||||
<button is="paper-icon-button-light" type="button" class="btnPreviousPage" title="${Previous}">
|
||||
<span class="material-icons arrow_back" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" type="button" class="btnNextPage" title="${LabelNext}">
|
||||
<button is="paper-icon-button-light" type="button" class="btnNextPage" title="${Next}">
|
||||
<span class="material-icons arrow_forward" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,6 @@ import layoutManager from 'layoutManager';
|
|||
import focusManager from 'focusManager';
|
||||
import globalize from 'globalize';
|
||||
import loading from 'loading';
|
||||
import connectionManager from 'connectionManager';
|
||||
import homeSections from 'homeSections';
|
||||
import dom from 'dom';
|
||||
import events from 'events';
|
||||
|
@ -15,12 +14,10 @@ import 'emby-checkbox';
|
|||
const numConfigurableSections = 7;
|
||||
|
||||
function renderViews(page, user, result) {
|
||||
|
||||
let folderHtml = '';
|
||||
|
||||
folderHtml += '<div class="checkboxList">';
|
||||
folderHtml += result.map(i => {
|
||||
|
||||
let currentHtml = '';
|
||||
|
||||
const id = `chkGroupFolder${i.Id}`;
|
||||
|
@ -35,7 +32,6 @@ import 'emby-checkbox';
|
|||
currentHtml += '</label>';
|
||||
|
||||
return currentHtml;
|
||||
|
||||
}).join('');
|
||||
|
||||
folderHtml += '</div>';
|
||||
|
@ -44,7 +40,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function getLandingScreenOptions(type) {
|
||||
|
||||
const list = [];
|
||||
|
||||
if (type === 'movies') {
|
||||
|
@ -133,9 +128,7 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function getLandingScreenOptionsHtml(type, userValue) {
|
||||
|
||||
return getLandingScreenOptions(type).map(o => {
|
||||
|
||||
const selected = userValue === o.value || (o.isDefault && !userValue);
|
||||
const selectedHtml = selected ? ' selected' : '';
|
||||
const optionValue = o.isDefault ? '' : o.value;
|
||||
|
@ -145,13 +138,9 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function renderViewOrder(context, user, result) {
|
||||
|
||||
let html = '';
|
||||
|
||||
let index = 0;
|
||||
|
||||
html += result.Items.map(view => {
|
||||
|
||||
html += result.Items.map((view) => {
|
||||
let currentHtml = '';
|
||||
|
||||
currentHtml += `<div class="listItem viewItem" data-viewid="${view.Id}">`;
|
||||
|
@ -171,18 +160,14 @@ import 'emby-checkbox';
|
|||
|
||||
currentHtml += '</div>';
|
||||
|
||||
index++;
|
||||
return currentHtml;
|
||||
|
||||
}).join('');
|
||||
|
||||
context.querySelector('.viewOrderList').innerHTML = html;
|
||||
}
|
||||
|
||||
function updateHomeSectionValues(context, userSettings) {
|
||||
|
||||
for (let i = 1; i <= 7; i++) {
|
||||
|
||||
const select = context.querySelector(`#selectHomeSection${i}`);
|
||||
const defaultValue = homeSections.getDefaultSection(i - 1);
|
||||
|
||||
|
@ -203,7 +188,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function getPerLibrarySettingsHtml(item, user, userSettings, apiClient) {
|
||||
|
||||
let html = '';
|
||||
|
||||
let isChecked;
|
||||
|
@ -220,7 +204,6 @@ import 'emby-checkbox';
|
|||
|
||||
const excludeFromLatest = ['playlists', 'livetv', 'boxsets', 'channels'];
|
||||
if (!excludeFromLatest.includes(item.CollectionType || '')) {
|
||||
|
||||
isChecked = !user.Configuration.LatestItemsExcludes.includes(item.Id);
|
||||
html += '<label class="fldIncludeInLatest">';
|
||||
html += `<input type="checkbox" is="emby-checkbox" class="chkIncludeInLatest" data-folderid="${item.Id}"${isChecked ? ' checked="checked"' : ''}/>`;
|
||||
|
@ -229,12 +212,10 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
if (html) {
|
||||
|
||||
html = `<div class="checkboxListContainer">${html}</div>`;
|
||||
}
|
||||
|
||||
if (item.CollectionType === 'movies' || item.CollectionType === 'tvshows' || item.CollectionType === 'music' || item.CollectionType === 'livetv') {
|
||||
|
||||
const idForLanding = item.CollectionType === 'livetv' ? item.CollectionType : item.Id;
|
||||
html += '<div class="selectContainer">';
|
||||
html += `<select is="emby-select" class="selectLanding" data-folderid="${idForLanding}" label="${globalize.translate('LabelDefaultScreen')}">`;
|
||||
|
@ -248,7 +229,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
if (html) {
|
||||
|
||||
let prefix = '';
|
||||
prefix += '<div class="verticalSection">';
|
||||
|
||||
|
@ -264,12 +244,10 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function renderPerLibrarySettings(context, user, userViews, userSettings, apiClient) {
|
||||
|
||||
const elem = context.querySelector('.perLibrarySettings');
|
||||
let html = '';
|
||||
|
||||
for (let i = 0, length = userViews.length; i < length; i++) {
|
||||
|
||||
html += getPerLibrarySettingsHtml(userViews[i], user, userSettings, apiClient);
|
||||
}
|
||||
|
||||
|
@ -277,7 +255,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function loadForm(context, user, userSettings, apiClient) {
|
||||
|
||||
context.querySelector('.chkHidePlayedFromLatest').checked = user.Configuration.HidePlayedInLatest || false;
|
||||
|
||||
updateHomeSectionValues(context, userSettings);
|
||||
|
@ -286,7 +263,6 @@ import 'emby-checkbox';
|
|||
const promise2 = apiClient.getJSON(apiClient.getUrl(`Users/${user.Id}/GroupingOptions`));
|
||||
|
||||
Promise.all([promise1, promise2]).then(responses => {
|
||||
|
||||
renderViewOrder(context, user, responses[0]);
|
||||
|
||||
renderPerLibrarySettings(context, user, responses[0].Items, userSettings, apiClient);
|
||||
|
@ -298,17 +274,13 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function onSectionOrderListClick(e) {
|
||||
|
||||
const target = dom.parentWithClass(e.target, 'btnViewItemMove');
|
||||
|
||||
if (target) {
|
||||
const viewItem = dom.parentWithClass(target, 'viewItem');
|
||||
|
||||
if (viewItem) {
|
||||
const ul = dom.parentWithClass(viewItem, 'paperList');
|
||||
|
||||
if (target.classList.contains('btnViewItemDown')) {
|
||||
|
||||
const next = viewItem.nextSibling;
|
||||
|
||||
if (next) {
|
||||
|
@ -316,9 +288,7 @@ import 'emby-checkbox';
|
|||
next.parentNode.insertBefore(viewItem, next.nextSibling);
|
||||
focusManager.focus(e.target);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
const prev = viewItem.previousSibling;
|
||||
|
||||
if (prev) {
|
||||
|
@ -332,37 +302,30 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function getCheckboxItems(selector, context, isChecked) {
|
||||
|
||||
const inputs = context.querySelectorAll(selector);
|
||||
const list = [];
|
||||
|
||||
for (let i = 0, length = inputs.length; i < length; i++) {
|
||||
|
||||
if (inputs[i].checked === isChecked) {
|
||||
list.push(inputs[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
function saveUser(context, user, userSettingsInstance, apiClient) {
|
||||
|
||||
user.Configuration.HidePlayedInLatest = context.querySelector('.chkHidePlayedFromLatest').checked;
|
||||
|
||||
user.Configuration.LatestItemsExcludes = getCheckboxItems('.chkIncludeInLatest', context, false).map(i => {
|
||||
|
||||
return i.getAttribute('data-folderid');
|
||||
});
|
||||
|
||||
user.Configuration.MyMediaExcludes = getCheckboxItems('.chkIncludeInMyMedia', context, false).map(i => {
|
||||
|
||||
return i.getAttribute('data-folderid');
|
||||
});
|
||||
|
||||
user.Configuration.GroupedFolders = getCheckboxItems('.chkGroupFolder', context, true).map(i => {
|
||||
|
||||
return i.getAttribute('data-folderid');
|
||||
});
|
||||
|
||||
|
@ -396,13 +359,10 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
|
||||
|
||||
loading.show();
|
||||
|
||||
apiClient.getUser(userId).then(user => {
|
||||
|
||||
saveUser(context, user, userSettings, apiClient).then(() => {
|
||||
|
||||
loading.hide();
|
||||
if (enableSaveConfirmation) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
|
@ -411,7 +371,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
events.trigger(instance, 'saved');
|
||||
|
||||
}, () => {
|
||||
loading.hide();
|
||||
});
|
||||
|
@ -419,14 +378,12 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
|
||||
const self = this;
|
||||
const apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userId = self.options.userId;
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(() => {
|
||||
|
||||
const enableSaveConfirmation = self.options.enableSaveConfirmation;
|
||||
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
|
||||
});
|
||||
|
@ -439,7 +396,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function onChange(e) {
|
||||
|
||||
const chkIncludeInMyMedia = dom.parentWithClass(e.target, 'chkIncludeInMyMedia');
|
||||
if (!chkIncludeInMyMedia) {
|
||||
return;
|
||||
|
@ -457,9 +413,7 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function embed(options, self) {
|
||||
|
||||
return import('text!./homeScreenSettings.template.html').then(({default: template}) => {
|
||||
|
||||
for (let i = 1; i <= numConfigurableSections; i++) {
|
||||
template = template.replace(`{section${i}label}`, globalize.translate('LabelHomeScreenSectionValue', i));
|
||||
}
|
||||
|
@ -491,20 +445,17 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
loadData(autoFocus) {
|
||||
|
||||
const self = this;
|
||||
const context = self.options.element;
|
||||
|
||||
loading.show();
|
||||
|
||||
const userId = self.options.userId;
|
||||
const apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
apiClient.getUser(userId).then(user => {
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(() => {
|
||||
|
||||
self.dataLoaded = true;
|
||||
|
||||
loadForm(context, user, userSettings, apiClient);
|
||||
|
@ -521,7 +472,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
destroy() {
|
||||
|
||||
this.options = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<form style="margin:0 auto;">
|
||||
<div class="verticalSection verticalSection-extrabottompadding">
|
||||
<h2 class="sectionTitle">${HeaderHome}</h2>
|
||||
<h2 class="sectionTitle">${Home}</h2>
|
||||
|
||||
<div class="selectContainer hide selectTVHomeScreenContainer">
|
||||
<select is="emby-select" class="selectTVHomeScreen" label="${LabelTVHomeScreen}">
|
||||
|
@ -25,7 +25,7 @@
|
|||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
|
@ -38,7 +38,7 @@
|
|||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
|
@ -51,7 +51,7 @@
|
|||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
|
@ -64,7 +64,7 @@
|
|||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
|
@ -77,7 +77,7 @@
|
|||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
|
@ -90,7 +90,7 @@
|
|||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
|
@ -103,7 +103,7 @@
|
|||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
import connectionManager from 'connectionManager';
|
||||
import cardBuilder from 'cardBuilder';
|
||||
import appSettings from 'appSettings';
|
||||
import dom from 'dom';
|
||||
import appHost from 'apphost';
|
||||
import layoutManager from 'layoutManager';
|
||||
import imageLoader from 'imageLoader';
|
||||
import globalize from 'globalize';
|
||||
import itemShortcuts from 'itemShortcuts';
|
||||
import itemHelper from 'itemHelper';
|
||||
import appRouter from 'appRouter';
|
||||
import imageHelper from 'scripts/imagehelper';
|
||||
import 'paper-icon-button-light';
|
||||
|
@ -135,7 +130,6 @@ import 'css!./homesections';
|
|||
}
|
||||
|
||||
function loadSection(page, apiClient, user, userSettings, userViews, allSections, index) {
|
||||
|
||||
const section = allSections[index];
|
||||
const userId = user.Id;
|
||||
|
||||
|
@ -215,17 +209,9 @@ import 'css!./homesections';
|
|||
imageLoader.lazyChildren(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random integer between min (inclusive) and max (inclusive)
|
||||
* Using Math.round() will give you a non-uniform distribution!
|
||||
*/
|
||||
function getRandomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function getFetchLatestItemsFn(serverId, parentId, collectionType) {
|
||||
return function () {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
let limit = 16;
|
||||
|
||||
if (enableScrollX()) {
|
||||
|
@ -347,14 +333,6 @@ import 'css!./homesections';
|
|||
}
|
||||
}
|
||||
|
||||
function getRequirePromise(deps) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
import(deps).then(() => {
|
||||
return resolve;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function loadLibraryTiles(elem, apiClient, user, userSettings, shape, userViews, allSections) {
|
||||
let html = '';
|
||||
if (userViews.length) {
|
||||
|
@ -389,7 +367,7 @@ import 'css!./homesections';
|
|||
|
||||
function getContinueWatchingFetchFn(serverId) {
|
||||
return function () {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
const screenWidth = dom.getWindowSize().innerWidth;
|
||||
|
||||
let limit;
|
||||
|
@ -462,7 +440,7 @@ import 'css!./homesections';
|
|||
|
||||
function getContinueListeningFetchFn(serverId) {
|
||||
return function () {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
const screenWidth = dom.getWindowSize().innerWidth;
|
||||
|
||||
let limit;
|
||||
|
@ -535,7 +513,7 @@ import 'css!./homesections';
|
|||
|
||||
function getOnNowFetchFn(serverId) {
|
||||
return function () {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getLiveTvRecommendedPrograms({
|
||||
userId: apiClient.getCurrentUserId(),
|
||||
IsAiring: true,
|
||||
|
@ -549,7 +527,6 @@ import 'css!./homesections';
|
|||
}
|
||||
|
||||
function getOnNowItemsHtml(items) {
|
||||
const cardLayout = false;
|
||||
return cardBuilder.getCardsHtml({
|
||||
items: items,
|
||||
preferThumb: 'auto',
|
||||
|
@ -576,7 +553,6 @@ import 'css!./homesections';
|
|||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const userId = user.Id;
|
||||
return apiClient.getLiveTvRecommendedPrograms({
|
||||
userId: apiClient.getCurrentUserId(),
|
||||
IsAiring: true,
|
||||
|
@ -649,7 +625,6 @@ import 'css!./homesections';
|
|||
html += '</h2>';
|
||||
html += '<span class="material-icons chevron_right"></span>';
|
||||
html += '</a>';
|
||||
|
||||
} else {
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards">' + globalize.translate('HeaderOnNow') + '</h2>';
|
||||
}
|
||||
|
@ -681,7 +656,7 @@ import 'css!./homesections';
|
|||
|
||||
function getNextUpFetchFn(serverId) {
|
||||
return function () {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getNextUpEpisodes({
|
||||
Limit: enableScrollX() ? 24 : 15,
|
||||
Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo,Path',
|
||||
|
@ -720,12 +695,12 @@ import 'css!./homesections';
|
|||
serverId: apiClient.serverId()
|
||||
}) + '" class="button-flat button-flat-mini sectionTitleTextButton">';
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards">';
|
||||
html += globalize.translate('HeaderNextUp');
|
||||
html += globalize.translate('NextUp');
|
||||
html += '</h2>';
|
||||
html += '<span class="material-icons chevron_right"></span>';
|
||||
html += '</a>';
|
||||
} else {
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards">' + globalize.translate('HeaderNextUp') + '</h2>';
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards">' + globalize.translate('NextUp') + '</h2>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
|
@ -752,7 +727,7 @@ import 'css!./homesections';
|
|||
|
||||
function getLatestRecordingsFetchFn(serverId, activeRecordingsOnly) {
|
||||
return function () {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getLiveTvRecordings({
|
||||
userId: apiClient.getCurrentUserId(),
|
||||
Limit: enableScrollX() ? 12 : 5,
|
||||
|
@ -766,7 +741,6 @@ import 'css!./homesections';
|
|||
|
||||
function getLatestRecordingItemsHtml(activeRecordingsOnly) {
|
||||
return function (items) {
|
||||
const cardLayout = false;
|
||||
return cardBuilder.getCardsHtml({
|
||||
items: items,
|
||||
shape: enableScrollX() ? 'autooverflow' : 'auto',
|
||||
|
|
|
@ -33,34 +33,7 @@ import events from 'events';
|
|||
return false;
|
||||
}
|
||||
|
||||
export function enableHlsShakaPlayer(item, mediaSource, mediaType) {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (!!window.MediaSource && !!MediaSource.isTypeSupported) {
|
||||
|
||||
if (canPlayNativeHls()) {
|
||||
|
||||
if (browser.edge && mediaType === 'Video') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// simple playback should use the native support
|
||||
if (mediaSource.RunTimeTicks) {
|
||||
//if (!browser.edge) {
|
||||
//return false;
|
||||
//}
|
||||
}
|
||||
|
||||
//return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function enableHlsJsPlayer(runTimeTicks, mediaType) {
|
||||
|
||||
if (window.MediaSource == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -76,7 +49,6 @@ import events from 'events';
|
|||
}
|
||||
|
||||
if (canPlayNativeHls()) {
|
||||
|
||||
// Having trouble with chrome's native support and transcoded music
|
||||
if (browser.android && mediaType === 'Audio') {
|
||||
return true;
|
||||
|
@ -102,7 +74,6 @@ import events from 'events';
|
|||
var recoverDecodingErrorDate;
|
||||
var recoverSwapAudioCodecDate;
|
||||
export function handleHlsJsMediaError(instance, reject) {
|
||||
|
||||
var hlsPlayer = instance._hlsPlayer;
|
||||
|
||||
if (!hlsPlayer) {
|
||||
|
@ -138,7 +109,6 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function onErrorInternal(instance, type) {
|
||||
|
||||
// Needed for video
|
||||
if (instance.destroyCustomTrack) {
|
||||
instance.destroyCustomTrack(instance._mediaElement);
|
||||
|
@ -166,12 +136,9 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function seekOnPlaybackStart(instance, element, ticks, onMediaReady) {
|
||||
|
||||
var seconds = (ticks || 0) / 10000000;
|
||||
|
||||
if (seconds) {
|
||||
var src = (instance.currentSrc() || '').toLowerCase();
|
||||
|
||||
// Appending #t=xxx to the query string doesn't seem to work with HLS
|
||||
// For plain video files, not all browsers support it either
|
||||
|
||||
|
@ -204,11 +171,8 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function applySrc(elem, src, options) {
|
||||
|
||||
if (window.Windows && options.mediaSource && options.mediaSource.IsLocal) {
|
||||
|
||||
return Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function (file) {
|
||||
|
||||
var playlist = new Windows.Media.Playback.MediaPlaybackList();
|
||||
|
||||
var source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file);
|
||||
|
@ -217,9 +181,7 @@ import events from 'events';
|
|||
elem.src = URL.createObjectURL(playlist, { oneTimeOnly: true });
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
elem.src = src;
|
||||
}
|
||||
|
||||
|
@ -227,18 +189,15 @@ import events from 'events';
|
|||
}
|
||||
|
||||
function onSuccessfulPlay(elem, onErrorFn) {
|
||||
|
||||
elem.addEventListener('error', onErrorFn);
|
||||
}
|
||||
|
||||
export function playWithPromise(elem, onErrorFn) {
|
||||
|
||||
try {
|
||||
var promise = elem.play();
|
||||
if (promise && promise.then) {
|
||||
// Chrome now returns a promise
|
||||
return promise.catch(function (e) {
|
||||
|
||||
var errorName = (e.name || '').toLowerCase();
|
||||
// safari uses aborterror
|
||||
if (errorName === 'notallowederror' ||
|
||||
|
@ -260,7 +219,6 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function destroyCastPlayer(instance) {
|
||||
|
||||
var player = instance._castPlayer;
|
||||
if (player) {
|
||||
try {
|
||||
|
@ -273,19 +231,6 @@ import events from 'events';
|
|||
}
|
||||
}
|
||||
|
||||
export function destroyShakaPlayer(instance) {
|
||||
var player = instance._shakaPlayer;
|
||||
if (player) {
|
||||
try {
|
||||
player.destroy();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
instance._shakaPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
export function destroyHlsPlayer(instance) {
|
||||
var player = instance._hlsPlayer;
|
||||
if (player) {
|
||||
|
@ -315,10 +260,8 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function bindEventsToHlsPlayer(instance, hls, elem, onErrorFn, resolve, reject) {
|
||||
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, function () {
|
||||
playWithPromise(elem, onErrorFn).then(resolve, function () {
|
||||
|
||||
if (reject) {
|
||||
reject();
|
||||
reject = null;
|
||||
|
@ -327,14 +270,12 @@ import events from 'events';
|
|||
});
|
||||
|
||||
hls.on(Hls.Events.ERROR, function (event, data) {
|
||||
|
||||
console.error('HLS Error: Type: ' + data.type + ' Details: ' + (data.details || '') + ' Fatal: ' + (data.fatal || false));
|
||||
|
||||
switch (data.type) {
|
||||
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||
// try to recover network error
|
||||
if (data.response && data.response.code && data.response.code >= 400) {
|
||||
|
||||
console.debug('hls.js response error code: ' + data.response.code);
|
||||
|
||||
// Trigger failure differently depending on whether this is prior to start of playback, or after
|
||||
|
@ -348,7 +289,6 @@ import events from 'events';
|
|||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -361,7 +301,6 @@ import events from 'events';
|
|||
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||
|
||||
if (data.response && data.response.code === 0) {
|
||||
|
||||
// This could be a CORS error related to access control response headers
|
||||
|
||||
console.debug('hls.js response error code: ' + data.response.code);
|
||||
|
@ -407,7 +346,6 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function onEndedInternal(instance, elem, onErrorFn) {
|
||||
|
||||
elem.removeEventListener('error', onErrorFn);
|
||||
|
||||
elem.src = '';
|
||||
|
@ -416,7 +354,6 @@ import events from 'events';
|
|||
|
||||
destroyHlsPlayer(instance);
|
||||
destroyFlvPlayer(instance);
|
||||
destroyShakaPlayer(instance);
|
||||
destroyCastPlayer(instance);
|
||||
|
||||
var stopInfo = {
|
||||
|
@ -431,7 +368,6 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function getBufferedRanges(instance, elem) {
|
||||
|
||||
var ranges = [];
|
||||
var seekable = elem.buffered || [];
|
||||
|
||||
|
@ -444,7 +380,6 @@ import events from 'events';
|
|||
offset = offset || 0;
|
||||
|
||||
for (var i = 0, length = seekable.length; i < length; i++) {
|
||||
|
||||
var start = seekable.start(i);
|
||||
var end = seekable.end(i);
|
||||
|
||||
|
|
|
@ -1,24 +1,37 @@
|
|||
define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'imageLoader', 'browser', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'emby-checkbox', 'paper-icon-button-light', 'emby-button', 'formDialogStyle', 'cardStyle'], function (dom, loading, appHost, dialogHelper, connectionManager, imageLoader, browser, layoutManager, scrollHelper, globalize, require) {
|
||||
'use strict';
|
||||
import dom from 'dom';
|
||||
import loading from 'loading';
|
||||
import appHost from 'apphost';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import imageLoader from 'imageLoader';
|
||||
import browser from 'browser';
|
||||
import layoutManager from 'layoutManager';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import globalize from 'globalize';
|
||||
import 'emby-checkbox';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-button';
|
||||
import 'formDialogStyle';
|
||||
import 'cardStyle';
|
||||
|
||||
var enableFocusTransform = !browser.slow && !browser.edge;
|
||||
/* eslint-disable indent */
|
||||
|
||||
var currentItemId;
|
||||
var currentItemType;
|
||||
var currentResolve;
|
||||
var currentReject;
|
||||
var hasChanges = false;
|
||||
const enableFocusTransform = !browser.slow && !browser.edge;
|
||||
|
||||
let currentItemId;
|
||||
let currentItemType;
|
||||
let currentResolve;
|
||||
let currentReject;
|
||||
let hasChanges = false;
|
||||
|
||||
// These images can be large and we're seeing memory problems in safari
|
||||
var browsableImagePageSize = browser.slow ? 6 : 30;
|
||||
const browsableImagePageSize = browser.slow ? 6 : 30;
|
||||
|
||||
var browsableImageStartIndex = 0;
|
||||
var browsableImageType = 'Primary';
|
||||
var selectedProvider;
|
||||
let browsableImageStartIndex = 0;
|
||||
let browsableImageType = 'Primary';
|
||||
let selectedProvider;
|
||||
|
||||
function getBaseRemoteOptions() {
|
||||
|
||||
var options = {};
|
||||
const options = {};
|
||||
|
||||
options.itemId = currentItemId;
|
||||
|
||||
|
@ -26,58 +39,53 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
}
|
||||
|
||||
function reloadBrowsableImages(page, apiClient) {
|
||||
|
||||
loading.show();
|
||||
|
||||
var options = getBaseRemoteOptions();
|
||||
const options = getBaseRemoteOptions();
|
||||
|
||||
options.type = browsableImageType;
|
||||
options.startIndex = browsableImageStartIndex;
|
||||
options.limit = browsableImagePageSize;
|
||||
options.IncludeAllLanguages = page.querySelector('#chkAllLanguages').checked;
|
||||
|
||||
var provider = selectedProvider || '';
|
||||
const provider = selectedProvider || '';
|
||||
|
||||
if (provider) {
|
||||
options.ProviderName = provider;
|
||||
}
|
||||
|
||||
apiClient.getAvailableRemoteImages(options).then(function (result) {
|
||||
|
||||
renderRemoteImages(page, apiClient, result, browsableImageType, options.startIndex, options.limit);
|
||||
|
||||
page.querySelector('#selectBrowsableImageType').value = browsableImageType;
|
||||
|
||||
var providersHtml = result.Providers.map(function (p) {
|
||||
const providersHtml = result.Providers.map(function (p) {
|
||||
return '<option value="' + p + '">' + p + '</option>';
|
||||
});
|
||||
|
||||
var selectImageProvider = page.querySelector('#selectImageProvider');
|
||||
const selectImageProvider = page.querySelector('#selectImageProvider');
|
||||
selectImageProvider.innerHTML = '<option value="">' + globalize.translate('All') + '</option>' + providersHtml;
|
||||
selectImageProvider.value = provider;
|
||||
|
||||
loading.hide();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function renderRemoteImages(page, apiClient, imagesResult, imageType, startIndex, limit) {
|
||||
|
||||
page.querySelector('.availableImagesPaging').innerHTML = getPagingHtml(startIndex, limit, imagesResult.TotalRecordCount);
|
||||
|
||||
var html = '';
|
||||
|
||||
for (var i = 0, length = imagesResult.Images.length; i < length; i++) {
|
||||
let html = '';
|
||||
|
||||
for (let i = 0, length = imagesResult.Images.length; i < length; i++) {
|
||||
html += getRemoteImageHtml(imagesResult.Images[i], imageType, apiClient);
|
||||
}
|
||||
|
||||
var availableImagesList = page.querySelector('.availableImagesList');
|
||||
const availableImagesList = page.querySelector('.availableImagesList');
|
||||
availableImagesList.innerHTML = html;
|
||||
imageLoader.lazyChildren(availableImagesList);
|
||||
|
||||
var btnNextPage = page.querySelector('.btnNextPage');
|
||||
var btnPreviousPage = page.querySelector('.btnPreviousPage');
|
||||
const btnNextPage = page.querySelector('.btnNextPage');
|
||||
const btnPreviousPage = page.querySelector('.btnPreviousPage');
|
||||
|
||||
if (btnNextPage) {
|
||||
btnNextPage.addEventListener('click', function () {
|
||||
|
@ -92,23 +100,21 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
reloadBrowsableImages(page, apiClient);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getPagingHtml(startIndex, limit, totalRecordCount) {
|
||||
let html = '';
|
||||
|
||||
var html = '';
|
||||
|
||||
var recordsEnd = Math.min(startIndex + limit, totalRecordCount);
|
||||
const recordsEnd = Math.min(startIndex + limit, totalRecordCount);
|
||||
|
||||
// 20 is the minimum page size
|
||||
var showControls = totalRecordCount > limit;
|
||||
const showControls = totalRecordCount > limit;
|
||||
|
||||
html += '<div class="listPaging">';
|
||||
|
||||
html += '<span style="margin-right: 10px;">';
|
||||
|
||||
var startAtDisplay = totalRecordCount ? startIndex + 1 : 0;
|
||||
const startAtDisplay = totalRecordCount ? startIndex + 1 : 0;
|
||||
html += globalize.translate('ListPaging', startAtDisplay, recordsEnd, totalRecordCount);
|
||||
|
||||
html += '</span>';
|
||||
|
@ -127,7 +133,7 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
}
|
||||
|
||||
function downloadRemoteImage(page, apiClient, url, type, provider) {
|
||||
var options = getBaseRemoteOptions();
|
||||
const options = getBaseRemoteOptions();
|
||||
|
||||
options.Type = type;
|
||||
options.ImageUrl = url;
|
||||
|
@ -136,9 +142,8 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
loading.show();
|
||||
|
||||
apiClient.downloadRemoteImage(options).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
var dlg = dom.parentWithClass(page, 'dialog');
|
||||
const dlg = dom.parentWithClass(page, 'dialog');
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
}
|
||||
|
@ -148,17 +153,17 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
}
|
||||
|
||||
function getRemoteImageHtml(image, imageType, apiClient) {
|
||||
var tagName = layoutManager.tv ? 'button' : 'div';
|
||||
var enableFooterButtons = !layoutManager.tv;
|
||||
const tagName = layoutManager.tv ? 'button' : 'div';
|
||||
const enableFooterButtons = !layoutManager.tv;
|
||||
|
||||
// TODO move card creation code to Card component
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
var cssClass = 'card scalableCard imageEditorCard';
|
||||
var cardBoxCssClass = 'cardBox visualCardBox';
|
||||
let cssClass = 'card scalableCard imageEditorCard';
|
||||
const cardBoxCssClass = 'cardBox visualCardBox';
|
||||
|
||||
var shape = 'backdrop';
|
||||
let shape;
|
||||
if (imageType === 'Backdrop' || imageType === 'Art' || imageType === 'Thumb' || imageType === 'Logo') {
|
||||
shape = 'backdrop';
|
||||
} else if (imageType === 'Banner') {
|
||||
|
@ -166,7 +171,6 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
} else if (imageType === 'Disc') {
|
||||
shape = 'square';
|
||||
} else {
|
||||
|
||||
if (currentItemType === 'Episode') {
|
||||
shape = 'backdrop';
|
||||
} else if (currentItemType === 'MusicAlbum' || currentItemType === 'MusicArtist') {
|
||||
|
@ -217,19 +221,16 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
html += '<div class="cardText cardTextCentered">' + image.ProviderName + '</div>';
|
||||
|
||||
if (image.Width || image.Height || image.Language) {
|
||||
|
||||
html += '<div class="cardText cardText-secondary cardTextCentered">';
|
||||
|
||||
if (image.Width && image.Height) {
|
||||
html += image.Width + ' x ' + image.Height;
|
||||
|
||||
if (image.Language) {
|
||||
|
||||
html += ' • ' + image.Language;
|
||||
}
|
||||
} else {
|
||||
if (image.Language) {
|
||||
|
||||
html += image.Language;
|
||||
}
|
||||
}
|
||||
|
@ -238,13 +239,11 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
}
|
||||
|
||||
if (image.CommunityRating != null) {
|
||||
|
||||
html += '<div class="cardText cardText-secondary cardTextCentered">';
|
||||
|
||||
if (image.RatingType === 'Likes') {
|
||||
html += image.CommunityRating + (image.CommunityRating === 1 ? ' like' : ' likes');
|
||||
} else {
|
||||
|
||||
if (image.CommunityRating) {
|
||||
html += image.CommunityRating.toFixed(1);
|
||||
|
||||
|
@ -270,7 +269,6 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
// end footer
|
||||
|
||||
html += '</div>';
|
||||
//html += '</div>';
|
||||
|
||||
html += '</' + tagName + '>';
|
||||
|
||||
|
@ -287,7 +285,6 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
});
|
||||
|
||||
page.querySelector('#selectImageProvider').addEventListener('change', function () {
|
||||
|
||||
browsableImageStartIndex = 0;
|
||||
selectedProvider = this.value;
|
||||
|
||||
|
@ -295,22 +292,20 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
});
|
||||
|
||||
page.querySelector('#chkAllLanguages').addEventListener('change', function () {
|
||||
|
||||
browsableImageStartIndex = 0;
|
||||
|
||||
reloadBrowsableImages(page, apiClient);
|
||||
});
|
||||
|
||||
page.addEventListener('click', function (e) {
|
||||
|
||||
var btnDownloadRemoteImage = dom.parentWithClass(e.target, 'btnDownloadRemoteImage');
|
||||
const btnDownloadRemoteImage = dom.parentWithClass(e.target, 'btnDownloadRemoteImage');
|
||||
if (btnDownloadRemoteImage) {
|
||||
var card = dom.parentWithClass(btnDownloadRemoteImage, 'card');
|
||||
const card = dom.parentWithClass(btnDownloadRemoteImage, 'card');
|
||||
downloadRemoteImage(page, apiClient, card.getAttribute('data-imageurl'), card.getAttribute('data-imagetype'), card.getAttribute('data-imageprovider'));
|
||||
return;
|
||||
}
|
||||
|
||||
var btnImageCard = dom.parentWithClass(e.target, 'btnImageCard');
|
||||
const btnImageCard = dom.parentWithClass(e.target, 'btnImageCard');
|
||||
if (btnImageCard) {
|
||||
downloadRemoteImage(page, apiClient, btnImageCard.getAttribute('data-imageurl'), btnImageCard.getAttribute('data-imagetype'), btnImageCard.getAttribute('data-imageprovider'));
|
||||
}
|
||||
|
@ -320,14 +315,13 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
function showEditor(itemId, serverId, itemType) {
|
||||
loading.show();
|
||||
|
||||
require(['text!./imageDownloader.template.html'], function (template) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
import('text!./imageDownloader.template.html').then(({default: template}) => {
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
currentItemId = itemId;
|
||||
currentItemType = itemType;
|
||||
|
||||
var dialogOptions = {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true
|
||||
};
|
||||
|
||||
|
@ -337,7 +331,7 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.innerHTML = globalize.translateHtml(template, 'core');
|
||||
|
||||
|
@ -350,11 +344,10 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
var editorContent = dlg.querySelector('.formDialogContent');
|
||||
const editorContent = dlg.querySelector('.formDialogContent');
|
||||
initEditor(editorContent, apiClient);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
|
@ -363,7 +356,7 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
}
|
||||
|
||||
function onDialogClosed() {
|
||||
var dlg = this;
|
||||
const dlg = this;
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg, false);
|
||||
|
@ -377,8 +370,7 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
}
|
||||
}
|
||||
|
||||
return {
|
||||
show: function (itemId, serverId, itemType, imageType) {
|
||||
export function show(itemId, serverId, itemType, imageType) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
currentResolve = resolve;
|
||||
currentReject = reject;
|
||||
|
@ -386,9 +378,12 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
browsableImageStartIndex = 0;
|
||||
browsableImageType = imageType || 'Primary';
|
||||
selectedProvider = null;
|
||||
|
||||
showEditor(itemId, serverId, itemType);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -16,7 +16,7 @@ import 'emby-input';
|
|||
return {
|
||||
Type: type,
|
||||
MinWidth: 0,
|
||||
Limit: 'Primary' === type ? 1 : 0
|
||||
Limit: type === 'Primary' ? 1 : 0
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -15,41 +15,41 @@
|
|||
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Primary" />
|
||||
<span>${OptionDownloadPrimaryImage}</span>
|
||||
<span>${Primary}</span>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Art" />
|
||||
<span>${OptionDownloadArtImage}</span>
|
||||
<span>${Art}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="BoxRear" />
|
||||
<span>${OptionDownloadBackImage}</span>
|
||||
<span>${Back}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Banner" />
|
||||
<span>${OptionDownloadBannerImage}</span>
|
||||
<span>${Banner}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Box" />
|
||||
<span>${OptionDownloadBoxImage}</span>
|
||||
<span>${Box}</span>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Disc" />
|
||||
<span>${OptionDownloadDiscImage}</span>
|
||||
<span>${Disc}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Logo" />
|
||||
<span>${OptionDownloadLogoImage}</span>
|
||||
<span>${Logo}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Menu" />
|
||||
<span>${OptionDownloadMenuImage}</span>
|
||||
<span>${Menu}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Thumb" />
|
||||
<span>${OptionDownloadThumbImage}</span>
|
||||
<span>${Thumb}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import connectionManager from 'connectionManager';
|
||||
import dom from 'dom';
|
||||
import loading from 'loading';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
|
@ -23,7 +22,6 @@ import 'css!./style';
|
|||
let hasChanges = false;
|
||||
|
||||
function onFileReaderError(evt) {
|
||||
|
||||
loading.hide();
|
||||
|
||||
switch (evt.target.error.code) {
|
||||
|
@ -43,7 +41,6 @@ import 'css!./style';
|
|||
}
|
||||
|
||||
function setFiles(page, files) {
|
||||
|
||||
const file = files[0];
|
||||
|
||||
if (!file || !file.type.match('image.*')) {
|
||||
|
@ -69,7 +66,6 @@ import 'css!./style';
|
|||
// Closure to capture the file information.
|
||||
reader.onload = (theFile => {
|
||||
return e => {
|
||||
|
||||
// Render thumbnail.
|
||||
const html = ['<img style="max-width:100%;max-height:100%;" src="', e.target.result, '" title="', escape(theFile.name), '"/>'].join('');
|
||||
|
||||
|
@ -84,7 +80,6 @@ import 'css!./style';
|
|||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
|
||||
const file = currentFile;
|
||||
|
||||
if (!file) {
|
||||
|
@ -112,8 +107,7 @@ import 'css!./style';
|
|||
return false;
|
||||
}
|
||||
|
||||
connectionManager.getApiClient(currentServerId).uploadItemImage(currentItemId, imageType, file).then(() => {
|
||||
|
||||
window.connectionManager.getApiClient(currentServerId).uploadItemImage(currentItemId, imageType, file).then(() => {
|
||||
dlg.querySelector('#uploadImage').value = '';
|
||||
|
||||
loading.hide();
|
||||
|
@ -126,7 +120,6 @@ import 'css!./style';
|
|||
}
|
||||
|
||||
function initEditor(page) {
|
||||
|
||||
page.querySelector('form').addEventListener('submit', onSubmit);
|
||||
|
||||
page.querySelector('#uploadImage').addEventListener('change', function () {
|
||||
|
@ -139,11 +132,9 @@ import 'css!./style';
|
|||
}
|
||||
|
||||
function showEditor(options, resolve) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
return import('text!./imageUploader.template.html').then(({default: template}) => {
|
||||
|
||||
currentItemId = options.itemId;
|
||||
currentServerId = options.serverId;
|
||||
|
||||
|
@ -169,7 +160,6 @@ import 'css!./style';
|
|||
|
||||
// Has to be assigned a z-index after the call to .open()
|
||||
dlg.addEventListener('close', () => {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg, false);
|
||||
}
|
||||
|
@ -185,16 +175,13 @@ import 'css!./style';
|
|||
dlg.querySelector('#selectImageType').value = options.imageType || 'Primary';
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function show(options) {
|
||||
|
||||
return new Promise(resolve => {
|
||||
|
||||
hasChanges = false;
|
||||
|
||||
showEditor(options, resolve);
|
||||
|
|
|
@ -1,14 +1,28 @@
|
|||
define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager', 'focusManager', 'globalize', 'scrollHelper', 'imageLoader', 'require', 'browser', 'apphost', 'cardStyle', 'formDialogStyle', 'emby-button', 'paper-icon-button-light', 'css!./imageeditor'], function (dialogHelper, connectionManager, loading, dom, layoutManager, focusManager, globalize, scrollHelper, imageLoader, require, browser, appHost) {
|
||||
'use strict';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import loading from 'loading';
|
||||
import dom from 'dom';
|
||||
import layoutManager from 'layoutManager';
|
||||
import focusManager from 'focusManager';
|
||||
import globalize from 'globalize';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import imageLoader from 'imageLoader';
|
||||
import browser from 'browser';
|
||||
import appHost from 'apphost';
|
||||
import 'cardStyle';
|
||||
import 'formDialogStyle';
|
||||
import 'emby-button';
|
||||
import 'paper-icon-button-light';
|
||||
import 'css!./imageeditor';
|
||||
|
||||
var enableFocusTransform = !browser.slow && !browser.edge;
|
||||
/* eslint-disable indent */
|
||||
|
||||
var currentItem;
|
||||
var hasChanges = false;
|
||||
const enableFocusTransform = !browser.slow && !browser.edge;
|
||||
|
||||
let currentItem;
|
||||
let hasChanges = false;
|
||||
|
||||
function getBaseRemoteOptions() {
|
||||
|
||||
var options = {};
|
||||
const options = {};
|
||||
|
||||
options.itemId = currentItem.Id;
|
||||
|
||||
|
@ -16,17 +30,15 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
}
|
||||
|
||||
function reload(page, item, focusContext) {
|
||||
|
||||
loading.show();
|
||||
|
||||
var apiClient;
|
||||
let apiClient;
|
||||
|
||||
if (item) {
|
||||
apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
reloadItem(page, item, apiClient, focusContext);
|
||||
} else {
|
||||
|
||||
apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
apiClient = window.connectionManager.getApiClient(currentItem.ServerId);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), currentItem.Id).then(function (item) {
|
||||
reloadItem(page, item, apiClient, focusContext);
|
||||
});
|
||||
|
@ -34,9 +46,8 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
}
|
||||
|
||||
function addListeners(container, className, eventName, fn) {
|
||||
|
||||
container.addEventListener(eventName, function (e) {
|
||||
var elem = dom.parentWithClass(e.target, className);
|
||||
const elem = dom.parentWithClass(e.target, className);
|
||||
if (elem) {
|
||||
fn.call(elem, e);
|
||||
}
|
||||
|
@ -44,14 +55,11 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
}
|
||||
|
||||
function reloadItem(page, item, apiClient, focusContext) {
|
||||
|
||||
currentItem = item;
|
||||
|
||||
apiClient.getRemoteImageProviders(getBaseRemoteOptions()).then(function (providers) {
|
||||
|
||||
var btnBrowseAllImages = page.querySelectorAll('.btnBrowseAllImages');
|
||||
for (var i = 0, length = btnBrowseAllImages.length; i < length; i++) {
|
||||
|
||||
if (providers.length) {
|
||||
btnBrowseAllImages[i].classList.remove('hide');
|
||||
} else {
|
||||
|
@ -60,7 +68,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
}
|
||||
|
||||
apiClient.getItemImageInfos(currentItem.Id).then(function (imageInfos) {
|
||||
|
||||
renderStandardImages(page, apiClient, item, imageInfos, providers);
|
||||
renderBackdrops(page, apiClient, item, imageInfos, providers);
|
||||
renderScreenshots(page, apiClient, item, imageInfos, providers);
|
||||
|
@ -74,7 +81,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
}
|
||||
|
||||
function getImageUrl(item, apiClient, type, index, options) {
|
||||
|
||||
options = options || {};
|
||||
options.type = type;
|
||||
options.index = index;
|
||||
|
@ -94,13 +100,12 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
}
|
||||
|
||||
function getCardHtml(image, index, numImages, apiClient, imageProviders, imageSize, tagName, enableFooterButtons) {
|
||||
|
||||
// TODO move card creation code to Card component
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
var cssClass = 'card scalableCard imageEditorCard';
|
||||
var cardBoxCssClass = 'cardBox visualCardBox';
|
||||
let cssClass = 'card scalableCard imageEditorCard';
|
||||
const cardBoxCssClass = 'cardBox visualCardBox';
|
||||
|
||||
cssClass += ' backdropCard backdropCard-scalable';
|
||||
|
||||
|
@ -130,7 +135,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
|
||||
html += '<div class="cardContent">';
|
||||
|
||||
var imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: imageSize });
|
||||
const imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: imageSize });
|
||||
|
||||
html += '<div class="cardImageContainer" style="background-image:url(\'' + imageUrl + '\');background-position:center center;background-size:contain;"></div>';
|
||||
|
||||
|
@ -153,7 +158,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
html += '<div class="cardText cardTextCentered">';
|
||||
|
||||
if (image.ImageType === 'Backdrop' || image.ImageType === 'Screenshot') {
|
||||
|
||||
if (index > 0) {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex - 1) + '" title="' + globalize.translate('MoveLeft') + '"><span class="material-icons chevron_left"></span></button>';
|
||||
} else {
|
||||
|
@ -183,13 +187,10 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
}
|
||||
|
||||
function deleteImage(context, itemId, type, index, apiClient, enableConfirmation) {
|
||||
|
||||
var afterConfirm = function () {
|
||||
const afterConfirm = function () {
|
||||
apiClient.deleteItemImage(itemId, type, index).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
reload(context);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -198,9 +199,8 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
return;
|
||||
}
|
||||
|
||||
require(['confirm'], function (confirm) {
|
||||
|
||||
confirm.default({
|
||||
import('confirm').then(({default: confirm}) => {
|
||||
confirm({
|
||||
|
||||
text: globalize.translate('ConfirmDeleteImage'),
|
||||
confirmText: globalize.translate('Delete'),
|
||||
|
@ -211,36 +211,30 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
}
|
||||
|
||||
function moveImage(context, apiClient, itemId, type, index, newIndex, focusContext) {
|
||||
|
||||
apiClient.updateItemImageIndex(itemId, type, index, newIndex).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
reload(context, null, focusContext);
|
||||
}, function () {
|
||||
|
||||
require(['alert'], function (alert) {
|
||||
alert(globalize.translate('DefaultErrorMessage'));
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert(globalize.translate('ErrorDefault'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderImages(page, item, apiClient, images, imageProviders, elem) {
|
||||
let html = '';
|
||||
|
||||
var html = '';
|
||||
|
||||
var imageSize = 300;
|
||||
var windowSize = dom.getWindowSize();
|
||||
let imageSize = 300;
|
||||
const windowSize = dom.getWindowSize();
|
||||
if (windowSize.innerWidth >= 1280) {
|
||||
imageSize = Math.round(windowSize.innerWidth / 4);
|
||||
}
|
||||
|
||||
var tagName = layoutManager.tv ? 'button' : 'div';
|
||||
var enableFooterButtons = !layoutManager.tv;
|
||||
|
||||
for (var i = 0, length = images.length; i < length; i++) {
|
||||
|
||||
var image = images[i];
|
||||
const tagName = layoutManager.tv ? 'button' : 'div';
|
||||
const enableFooterButtons = !layoutManager.tv;
|
||||
|
||||
for (let i = 0, length = images.length; i < length; i++) {
|
||||
const image = images[i];
|
||||
html += getCardHtml(image, i, length, apiClient, imageProviders, imageSize, tagName, enableFooterButtons);
|
||||
}
|
||||
|
||||
|
@ -249,8 +243,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
}
|
||||
|
||||
function renderStandardImages(page, apiClient, item, imageInfos, imageProviders) {
|
||||
|
||||
var images = imageInfos.filter(function (i) {
|
||||
const images = imageInfos.filter(function (i) {
|
||||
return i.ImageType !== 'Screenshot' && i.ImageType !== 'Backdrop' && i.ImageType !== 'Chapter';
|
||||
});
|
||||
|
||||
|
@ -258,10 +251,8 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
}
|
||||
|
||||
function renderBackdrops(page, apiClient, item, imageInfos, imageProviders) {
|
||||
|
||||
var images = imageInfos.filter(function (i) {
|
||||
const images = imageInfos.filter(function (i) {
|
||||
return i.ImageType === 'Backdrop';
|
||||
|
||||
}).sort(function (a, b) {
|
||||
return a.ImageIndex - b.ImageIndex;
|
||||
});
|
||||
|
@ -275,10 +266,8 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
}
|
||||
|
||||
function renderScreenshots(page, apiClient, item, imageInfos, imageProviders) {
|
||||
|
||||
var images = imageInfos.filter(function (i) {
|
||||
const images = imageInfos.filter(function (i) {
|
||||
return i.ImageType === 'Screenshot';
|
||||
|
||||
}).sort(function (a, b) {
|
||||
return a.ImageIndex - b.ImageIndex;
|
||||
});
|
||||
|
@ -292,32 +281,26 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
}
|
||||
|
||||
function showImageDownloader(page, imageType) {
|
||||
|
||||
require(['imageDownloader'], function (ImageDownloader) {
|
||||
|
||||
import('imageDownloader').then(({default: ImageDownloader}) => {
|
||||
ImageDownloader.show(currentItem.Id, currentItem.ServerId, currentItem.Type, imageType).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
reload(page);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function showActionSheet(context, imageCard) {
|
||||
const itemId = imageCard.getAttribute('data-id');
|
||||
const serverId = imageCard.getAttribute('data-serverid');
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
var itemId = imageCard.getAttribute('data-id');
|
||||
var serverId = imageCard.getAttribute('data-serverid');
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
const type = imageCard.getAttribute('data-imagetype');
|
||||
const index = parseInt(imageCard.getAttribute('data-index'));
|
||||
const providerCount = parseInt(imageCard.getAttribute('data-providers'));
|
||||
const numImages = parseInt(imageCard.getAttribute('data-numimages'));
|
||||
|
||||
var type = imageCard.getAttribute('data-imagetype');
|
||||
var index = parseInt(imageCard.getAttribute('data-index'));
|
||||
var providerCount = parseInt(imageCard.getAttribute('data-providers'));
|
||||
var numImages = parseInt(imageCard.getAttribute('data-numimages'));
|
||||
|
||||
require(['actionsheet'], function (actionSheet) {
|
||||
|
||||
var commands = [];
|
||||
import('actionsheet').then(({default: actionSheet}) => {
|
||||
const commands = [];
|
||||
|
||||
commands.push({
|
||||
name: globalize.translate('Delete'),
|
||||
|
@ -353,9 +336,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
positionTo: imageCard
|
||||
|
||||
}).then(function (id) {
|
||||
|
||||
switch (id) {
|
||||
|
||||
case 'delete':
|
||||
deleteImage(context, itemId, type, index, apiClient, false);
|
||||
break;
|
||||
|
@ -371,16 +352,14 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initEditor(context, options) {
|
||||
|
||||
var uploadButtons = context.querySelectorAll('.btnOpenUploadMenu');
|
||||
var isFileInputSupported = appHost.supports('fileinput');
|
||||
for (var i = 0, length = uploadButtons.length; i < length; i++) {
|
||||
const uploadButtons = context.querySelectorAll('.btnOpenUploadMenu');
|
||||
const isFileInputSupported = appHost.supports('fileinput');
|
||||
for (let i = 0, length = uploadButtons.length; i < length; i++) {
|
||||
if (isFileInputSupported) {
|
||||
uploadButtons[i].classList.remove('hide');
|
||||
} else {
|
||||
|
@ -389,10 +368,9 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
}
|
||||
|
||||
addListeners(context, 'btnOpenUploadMenu', 'click', function () {
|
||||
var imageType = this.getAttribute('data-imagetype');
|
||||
|
||||
require(['imageUploader'], function (imageUploader) {
|
||||
const imageType = this.getAttribute('data-imagetype');
|
||||
|
||||
import('imageUploader').then(({default: imageUploader}) => {
|
||||
imageUploader.show({
|
||||
|
||||
theme: options.theme,
|
||||
|
@ -401,7 +379,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
serverId: currentItem.ServerId
|
||||
|
||||
}).then(function (hasChanged) {
|
||||
|
||||
if (hasChanged) {
|
||||
hasChanges = true;
|
||||
reload(context);
|
||||
|
@ -423,34 +400,32 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
});
|
||||
|
||||
addListeners(context, 'btnDeleteImage', 'click', function () {
|
||||
var type = this.getAttribute('data-imagetype');
|
||||
var index = this.getAttribute('data-index');
|
||||
const type = this.getAttribute('data-imagetype');
|
||||
let index = this.getAttribute('data-index');
|
||||
index = index === 'null' ? null : parseInt(index);
|
||||
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(currentItem.ServerId);
|
||||
deleteImage(context, currentItem.Id, type, index, apiClient, true);
|
||||
});
|
||||
|
||||
addListeners(context, 'btnMoveImage', 'click', function () {
|
||||
var type = this.getAttribute('data-imagetype');
|
||||
var index = this.getAttribute('data-index');
|
||||
var newIndex = this.getAttribute('data-newindex');
|
||||
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
const type = this.getAttribute('data-imagetype');
|
||||
const index = this.getAttribute('data-index');
|
||||
const newIndex = this.getAttribute('data-newindex');
|
||||
const apiClient = window.connectionManager.getApiClient(currentItem.ServerId);
|
||||
moveImage(context, apiClient, currentItem.Id, type, index, newIndex, dom.parentWithClass(this, 'itemsContainer'));
|
||||
});
|
||||
}
|
||||
|
||||
function showEditor(options, resolve, reject) {
|
||||
|
||||
var itemId = options.itemId;
|
||||
var serverId = options.serverId;
|
||||
const itemId = options.itemId;
|
||||
const serverId = options.serverId;
|
||||
|
||||
loading.show();
|
||||
|
||||
require(['text!./imageeditor.template.html'], function (template) {
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
import('text!./imageeditor.template.html').then(({default: template}) => {
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
|
||||
|
||||
var dialogOptions = {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true
|
||||
};
|
||||
|
||||
|
@ -460,7 +435,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
|
@ -474,7 +449,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
|
||||
// Has to be assigned a z-index after the call to .open()
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg, false);
|
||||
}
|
||||
|
@ -493,22 +467,21 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
reload(dlg, item);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: function (options) {
|
||||
|
||||
export function show (options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
hasChanges = false;
|
||||
|
||||
showEditor(options, resolve, reject);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
show
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -17,8 +17,8 @@ import 'css!./style';
|
|||
// Although the default values recommended by Blurhash developers is 32x32, a size of 18x18 seems to be the sweet spot for us,
|
||||
// improving the performance and reducing the memory usage, while retaining almost full blur quality.
|
||||
// Lower values had more visible pixelation
|
||||
let width = 18;
|
||||
let height = 18;
|
||||
const width = 18;
|
||||
const height = 18;
|
||||
let pixels;
|
||||
try {
|
||||
pixels = blurhash.decode(blurhashstr, width, height);
|
||||
|
@ -27,11 +27,11 @@ import 'css!./style';
|
|||
target.classList.add('non-blurhashable');
|
||||
return;
|
||||
}
|
||||
let canvas = document.createElement('canvas');
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
let ctx = canvas.getContext('2d');
|
||||
let imgData = ctx.createImageData(width, height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
const imgData = ctx.createImageData(width, height);
|
||||
|
||||
imgData.data.set(pixels);
|
||||
ctx.putImageData(imgData, 0, 0);
|
||||
|
@ -55,7 +55,7 @@ import 'css!./style';
|
|||
if (!entry) {
|
||||
throw new Error('entry cannot be null');
|
||||
}
|
||||
let target = entry.target;
|
||||
const target = entry.target;
|
||||
var source = undefined;
|
||||
|
||||
if (target) {
|
||||
|
@ -78,7 +78,7 @@ import 'css!./style';
|
|||
throw new TypeError('url cannot be undefined');
|
||||
}
|
||||
|
||||
let preloaderImg = new Image();
|
||||
const preloaderImg = new Image();
|
||||
preloaderImg.src = url;
|
||||
|
||||
elem.classList.add('lazy-hidden');
|
||||
|
@ -87,6 +87,9 @@ import 'css!./style';
|
|||
requestAnimationFrame(() => {
|
||||
if (elem.tagName !== 'IMG') {
|
||||
elem.style.backgroundImage = "url('" + url + "')";
|
||||
if (elem.classList.contains('blurhashed')) {
|
||||
elem.style.backgroundColor = '#fff';
|
||||
}
|
||||
} else {
|
||||
elem.setAttribute('src', url);
|
||||
}
|
||||
|
@ -108,6 +111,7 @@ import 'css!./style';
|
|||
if (elem.tagName !== 'IMG') {
|
||||
url = elem.style.backgroundImage.slice(4, -1).replace(/"/g, '');
|
||||
elem.style.backgroundImage = 'none';
|
||||
elem.style.backgroundColor = null;
|
||||
} else {
|
||||
url = elem.getAttribute('src');
|
||||
elem.setAttribute('src', '');
|
||||
|
@ -133,11 +137,9 @@ import 'css!./style';
|
|||
}
|
||||
|
||||
export function getPrimaryImageAspectRatio(items) {
|
||||
|
||||
var values = [];
|
||||
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
var ratio = items[i].PrimaryImageAspectRatio || 0;
|
||||
|
||||
if (!ratio) {
|
||||
|
@ -193,7 +195,6 @@ import 'css!./style';
|
|||
}
|
||||
|
||||
export function fillImages(elems) {
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
var elem = elems[0];
|
||||
fillImage(elem);
|
||||
|
@ -208,7 +209,7 @@ import 'css!./style';
|
|||
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
serLazyImage: setLazyImage,
|
||||
setLazyImage: setLazyImage,
|
||||
fillImages: fillImages,
|
||||
fillImage: fillImage,
|
||||
lazyImage: lazyImage,
|
||||
|
|
|
@ -82,7 +82,7 @@ export function enablePlayedIndicator(item) {
|
|||
|
||||
export function getPlayedIndicatorHtml(item) {
|
||||
if (enablePlayedIndicator(item)) {
|
||||
let userData = item.UserData || {};
|
||||
const userData = item.UserData || {};
|
||||
if (userData.UnplayedItemCount) {
|
||||
return '<div class="countIndicator indicator">' + userData.UnplayedItemCount + '</div>';
|
||||
}
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
import appHost from 'apphost';
|
||||
import globalize from 'globalize';
|
||||
import connectionManager from 'connectionManager';
|
||||
import itemHelper from 'itemHelper';
|
||||
import appRouter from 'appRouter';
|
||||
import playbackManager from 'playbackManager';
|
||||
import loading from 'loading';
|
||||
import appSettings from 'appSettings';
|
||||
import browser from 'browser';
|
||||
import actionsheet from 'actionsheet';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
export function getCommands(options) {
|
||||
const item = options.item;
|
||||
const user = options.user;
|
||||
|
@ -18,7 +14,7 @@ import actionsheet from 'actionsheet';
|
|||
const canPlay = playbackManager.canPlay(item);
|
||||
const restrictOptions = (browser.operaTv || browser.web0s) && !user.Policy.IsAdministrator;
|
||||
|
||||
let commands = [];
|
||||
const commands = [];
|
||||
|
||||
if (canPlay && item.MediaType !== 'Photo') {
|
||||
if (options.play !== false) {
|
||||
|
@ -144,7 +140,6 @@ import actionsheet from 'actionsheet';
|
|||
}
|
||||
|
||||
if (item.CanDelete && options.deleteItem !== false) {
|
||||
|
||||
if (item.Type === 'Playlist' || item.Type === 'BoxSet') {
|
||||
commands.push({
|
||||
name: globalize.translate('Delete'),
|
||||
|
@ -334,7 +329,7 @@ import actionsheet from 'actionsheet';
|
|||
function executeCommand(item, id, options) {
|
||||
const itemId = item.Id;
|
||||
const serverId = item.ServerId;
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
switch (id) {
|
||||
|
@ -355,7 +350,7 @@ import actionsheet from 'actionsheet';
|
|||
});
|
||||
break;
|
||||
case 'download':
|
||||
import('fileDownloader').then(({default: fileDownloader}) => {
|
||||
import('fileDownloader').then((fileDownloader) => {
|
||||
const downloadHref = apiClient.getItemDownloadUrl(itemId);
|
||||
fileDownloader.download([{
|
||||
url: downloadHref,
|
||||
|
@ -370,7 +365,7 @@ import actionsheet from 'actionsheet';
|
|||
case 'copy-stream': {
|
||||
const downloadHref = apiClient.getItemDownloadUrl(itemId);
|
||||
const textAreaCopy = function () {
|
||||
let textArea = document.createElement('textarea');
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = downloadHref;
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
define(['apphost', 'globalize'], function (appHost, globalize) {
|
||||
'use strict';
|
||||
|
||||
function getDisplayName(item, options = {}) {
|
||||
import appHost from 'apphost';
|
||||
import globalize from 'globalize';
|
||||
|
||||
export function getDisplayName(item, options = {}) {
|
||||
if (!item) {
|
||||
throw new Error('null item passed into getDisplayName');
|
||||
}
|
||||
|
@ -11,7 +10,7 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
item = item.ProgramInfo || item;
|
||||
}
|
||||
|
||||
var name = ((item.Type === 'Program' || item.Type === 'Recording') && (item.IsSeries || item.EpisodeTitle) ? item.EpisodeTitle : item.Name) || '';
|
||||
let name = ((item.Type === 'Program' || item.Type === 'Recording') && (item.IsSeries || item.EpisodeTitle) ? item.EpisodeTitle : item.Name) || '';
|
||||
|
||||
if (item.Type === 'TvChannel') {
|
||||
if (item.ChannelNumber) {
|
||||
|
@ -22,11 +21,10 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
if (item.Type === 'Episode' && item.ParentIndexNumber === 0) {
|
||||
name = globalize.translate('ValueSpecialEpisodeName', name);
|
||||
} else if ((item.Type === 'Episode' || item.Type === 'Program') && item.IndexNumber != null && item.ParentIndexNumber != null && options.includeIndexNumber !== false) {
|
||||
let displayIndexNumber = item.IndexNumber;
|
||||
|
||||
var displayIndexNumber = item.IndexNumber;
|
||||
|
||||
var number = displayIndexNumber;
|
||||
var nameSeparator = ' - ';
|
||||
let number = displayIndexNumber;
|
||||
let nameSeparator = ' - ';
|
||||
|
||||
if (options.includeParentInfo !== false) {
|
||||
number = 'S' + item.ParentIndexNumber + ':E' + number;
|
||||
|
@ -35,7 +33,6 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
}
|
||||
|
||||
if (item.IndexNumberEnd) {
|
||||
|
||||
displayIndexNumber = item.IndexNumberEnd;
|
||||
number += '-' + displayIndexNumber;
|
||||
}
|
||||
|
@ -46,11 +43,10 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
function supportsAddingToCollection(item) {
|
||||
|
||||
var invalidTypes = ['Genre', 'MusicGenre', 'Studio', 'UserView', 'CollectionFolder', 'Audio', 'Program', 'Timer', 'SeriesTimer'];
|
||||
export function supportsAddingToCollection(item) {
|
||||
const invalidTypes = ['Genre', 'MusicGenre', 'Studio', 'UserView', 'CollectionFolder', 'Audio', 'Program', 'Timer', 'SeriesTimer'];
|
||||
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
|
@ -59,10 +55,9 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
}
|
||||
|
||||
return !item.CollectionType && invalidTypes.indexOf(item.Type) === -1 && item.MediaType !== 'Photo' && !isLocalItem(item);
|
||||
}
|
||||
|
||||
function supportsAddingToPlaylist(item) {
|
||||
}
|
||||
|
||||
export function supportsAddingToPlaylist(item) {
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
|
@ -93,11 +88,10 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
}
|
||||
|
||||
return item.MediaType || item.IsFolder || item.Type === 'Genre' || item.Type === 'MusicGenre' || item.Type === 'MusicArtist';
|
||||
}
|
||||
}
|
||||
|
||||
function canEdit(user, item) {
|
||||
|
||||
var itemType = item.Type;
|
||||
export function canEdit(user, item) {
|
||||
const itemType = item.Type;
|
||||
|
||||
if (itemType === 'UserRootFolder' || itemType === 'UserView') {
|
||||
return false;
|
||||
|
@ -126,26 +120,18 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
}
|
||||
|
||||
return user.Policy.IsAdministrator;
|
||||
}
|
||||
|
||||
function isLocalItem(item) {
|
||||
}
|
||||
|
||||
export function isLocalItem(item) {
|
||||
if (item && item.Id && item.Id.indexOf('local') === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
getDisplayName: getDisplayName,
|
||||
supportsAddingToCollection: supportsAddingToCollection,
|
||||
supportsAddingToPlaylist: supportsAddingToPlaylist,
|
||||
isLocalItem: isLocalItem,
|
||||
|
||||
canIdentify: function (user, item) {
|
||||
|
||||
var itemType = item.Type;
|
||||
export function canIdentify (user, item) {
|
||||
const itemType = item.Type;
|
||||
|
||||
if (itemType === 'Movie' ||
|
||||
itemType === 'Trailer' ||
|
||||
|
@ -156,9 +142,7 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
itemType === 'MusicAlbum' ||
|
||||
itemType === 'MusicArtist' ||
|
||||
itemType === 'MusicVideo') {
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
|
||||
if (!isLocalItem(item)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -166,13 +150,10 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
canEdit: canEdit,
|
||||
|
||||
canEditImages: function (user, item) {
|
||||
|
||||
var itemType = item.Type;
|
||||
export function canEditImages (user, item) {
|
||||
const itemType = item.Type;
|
||||
|
||||
if (item.MediaType === 'Photo') {
|
||||
return false;
|
||||
|
@ -180,7 +161,6 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
|
||||
if (itemType === 'UserView') {
|
||||
if (user.Policy.IsAdministrator) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -194,10 +174,9 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
}
|
||||
|
||||
return itemType !== 'Timer' && itemType !== 'SeriesTimer' && canEdit(user, item) && !isLocalItem(item);
|
||||
},
|
||||
|
||||
canSync: function (user, item) {
|
||||
}
|
||||
|
||||
export function canSync (user, item) {
|
||||
if (user && !user.Policy.EnableContentDownloading) {
|
||||
return false;
|
||||
}
|
||||
|
@ -207,10 +186,9 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
}
|
||||
|
||||
return item.SupportsSync;
|
||||
},
|
||||
|
||||
canShare: function (item, user) {
|
||||
}
|
||||
|
||||
export function canShare (item, user) {
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
|
@ -232,14 +210,13 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
return false;
|
||||
}
|
||||
return user.Policy.EnablePublicSharing && appHost.supports('sharing');
|
||||
},
|
||||
}
|
||||
|
||||
enableDateAddedDisplay: function (item) {
|
||||
export function enableDateAddedDisplay (item) {
|
||||
return !item.IsFolder && item.MediaType && item.Type !== 'Program' && item.Type !== 'TvChannel' && item.Type !== 'Trailer';
|
||||
},
|
||||
|
||||
canMarkPlayed: function (item) {
|
||||
}
|
||||
|
||||
export function canMarkPlayed (item) {
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
|
@ -266,10 +243,9 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
canRate: function (item) {
|
||||
}
|
||||
|
||||
export function canRate (item) {
|
||||
if (item.Type === 'Program'
|
||||
|| item.Type === 'Timer'
|
||||
|| item.Type === 'SeriesTimer'
|
||||
|
@ -281,10 +257,9 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
canConvert: function (item, user) {
|
||||
}
|
||||
|
||||
export function canConvert (item, user) {
|
||||
if (!user.Policy.EnableMediaConversion) {
|
||||
return false;
|
||||
}
|
||||
|
@ -293,17 +268,17 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
return false;
|
||||
}
|
||||
|
||||
var mediaType = item.MediaType;
|
||||
const mediaType = item.MediaType;
|
||||
if (mediaType === 'Book' || mediaType === 'Photo' || mediaType === 'Audio') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var collectionType = item.CollectionType;
|
||||
const collectionType = item.CollectionType;
|
||||
if (collectionType === 'livetv') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var type = item.Type;
|
||||
const type = item.Type;
|
||||
if (type === 'Channel' || type === 'Person' || type === 'Year' || type === 'Program' || type === 'Timer' || type === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
|
@ -317,19 +292,16 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
canRefreshMetadata: function (item, user) {
|
||||
}
|
||||
|
||||
export function canRefreshMetadata (item, user) {
|
||||
if (user.Policy.IsAdministrator) {
|
||||
|
||||
var collectionType = item.CollectionType;
|
||||
const collectionType = item.CollectionType;
|
||||
if (collectionType === 'livetv') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.Type !== 'Timer' && item.Type !== 'SeriesTimer' && item.Type !== 'Program' && item.Type !== 'TvChannel' && !(item.Type === 'Recording' && item.Status !== 'Completed')) {
|
||||
|
||||
if (!isLocalItem(item)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -337,10 +309,9 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
supportsMediaSourceSelection: function (item) {
|
||||
}
|
||||
|
||||
export function supportsMediaSourceSelection (item) {
|
||||
if (item.MediaType !== 'Video') {
|
||||
return false;
|
||||
}
|
||||
|
@ -358,6 +329,22 @@ define(['apphost', 'globalize'], function (appHost, globalize) {
|
|||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
getDisplayName: getDisplayName,
|
||||
supportsAddingToCollection: supportsAddingToCollection,
|
||||
supportsAddingToPlaylist: supportsAddingToPlaylist,
|
||||
isLocalItem: isLocalItem,
|
||||
canIdentify: canIdentify,
|
||||
canEdit: canEdit,
|
||||
canEditImages: canEditImages,
|
||||
canSync: canSync,
|
||||
canShare: canShare,
|
||||
enableDateAddedDisplay: enableDateAddedDisplay,
|
||||
canMarkPlayed: canMarkPlayed,
|
||||
canRate: canRate,
|
||||
canConvert: canConvert,
|
||||
canRefreshMetadata: canRefreshMetadata,
|
||||
supportsMediaSourceSelection: supportsMediaSourceSelection
|
||||
};
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
import dialogHelper from 'dialogHelper';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import connectionManager from 'connectionManager';
|
||||
import loading from 'loading';
|
||||
import 'emby-select';
|
||||
import 'listViewStyle';
|
||||
|
@ -52,8 +51,22 @@ import 'flexStyles';
|
|||
if (stream.Type === 'Data') {
|
||||
continue;
|
||||
}
|
||||
|
||||
html += '<div class="mediaInfoStream">';
|
||||
const displayType = globalize.translate(`MediaInfoStreamType${stream.Type}`);
|
||||
let translateString;
|
||||
switch (stream.Type) {
|
||||
case 'Audio':
|
||||
case 'Data':
|
||||
case 'Subtitle':
|
||||
case 'Video':
|
||||
translateString = stream.Type;
|
||||
break;
|
||||
case 'EmbeddedImage':
|
||||
translateString = 'Image';
|
||||
break;
|
||||
}
|
||||
|
||||
const displayType = globalize.translate(translateString);
|
||||
html += `<h2 class="mediaInfoStreamType">${displayType}</h2>`;
|
||||
const attributes = [];
|
||||
if (stream.DisplayTitle) {
|
||||
|
@ -137,7 +150,7 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function loadMediaInfo(itemId, serverId, template) {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(item => {
|
||||
const dialogOptions = {
|
||||
size: 'small',
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1">
|
||||
<span class="material-icons arrow_back"></span>
|
||||
</button>
|
||||
<h3 class="formDialogHeaderTitle">${HeaderMediaInfo}</h3>
|
||||
<h3 class="formDialogHeaderTitle">${MoreMediaInfo}</h3>
|
||||
</div>
|
||||
|
||||
<div class="formDialogContent smoothScrollY">
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import loading from 'loading';
|
||||
import connectionManager from 'connectionManager';
|
||||
import globalize from 'globalize';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import layoutManager from 'layoutManager';
|
||||
|
@ -31,11 +30,10 @@ import 'cardStyle';
|
|||
let currentSearchResult;
|
||||
|
||||
function getApiClient() {
|
||||
return connectionManager.getApiClient(currentServerId);
|
||||
return window.connectionManager.getApiClient(currentServerId);
|
||||
}
|
||||
|
||||
function searchForIdentificationResults(page) {
|
||||
|
||||
let lookupInfo = {
|
||||
ProviderIds: {}
|
||||
};
|
||||
|
@ -45,11 +43,9 @@ import 'cardStyle';
|
|||
const identifyField = page.querySelectorAll('.identifyField');
|
||||
let value;
|
||||
for (i = 0, length = identifyField.length; i < length; i++) {
|
||||
|
||||
value = identifyField[i].value;
|
||||
|
||||
if (value) {
|
||||
|
||||
if (identifyField[i].type === 'number') {
|
||||
value = parseInt(value);
|
||||
}
|
||||
|
@ -62,7 +58,6 @@ import 'cardStyle';
|
|||
|
||||
const txtLookupId = page.querySelectorAll('.txtLookupId');
|
||||
for (i = 0, length = txtLookupId.length; i < length; i++) {
|
||||
|
||||
value = txtLookupId[i].value;
|
||||
|
||||
if (value) {
|
||||
|
@ -100,14 +95,12 @@ import 'cardStyle';
|
|||
dataType: 'json'
|
||||
|
||||
}).then(results => {
|
||||
|
||||
loading.hide();
|
||||
showIdentificationSearchResults(page, results);
|
||||
});
|
||||
}
|
||||
|
||||
function showIdentificationSearchResults(page, results) {
|
||||
|
||||
const identificationSearchResults = page.querySelector('.identificationSearchResults');
|
||||
|
||||
page.querySelector('.popupIdentifyForm').classList.add('hide');
|
||||
|
@ -119,7 +112,6 @@ import 'cardStyle';
|
|||
let i;
|
||||
let length;
|
||||
for (i = 0, length = results.length; i < length; i++) {
|
||||
|
||||
const result = results[i];
|
||||
html += getSearchResultHtml(result, i);
|
||||
}
|
||||
|
@ -133,17 +125,14 @@ import 'cardStyle';
|
|||
const currentResult = results[index];
|
||||
|
||||
if (currentItem != null) {
|
||||
|
||||
showIdentifyOptions(page, currentResult);
|
||||
} else {
|
||||
|
||||
finishFindNewDialog(page, currentResult);
|
||||
}
|
||||
}
|
||||
|
||||
const searchImages = elem.querySelectorAll('.card');
|
||||
for (i = 0, length = searchImages.length; i < length; i++) {
|
||||
|
||||
searchImages[i].addEventListener('click', onSearchImageClick);
|
||||
}
|
||||
|
||||
|
@ -161,7 +150,6 @@ import 'cardStyle';
|
|||
}
|
||||
|
||||
function showIdentifyOptions(page, identifyResult) {
|
||||
|
||||
const identifyOptionsForm = page.querySelector('.identifyOptionsForm');
|
||||
|
||||
page.querySelector('.popupIdentifyForm').classList.add('hide');
|
||||
|
@ -193,7 +181,6 @@ import 'cardStyle';
|
|||
}
|
||||
|
||||
function getSearchResultHtml(result, index) {
|
||||
|
||||
// TODO move card creation code to Card component
|
||||
|
||||
let html = '';
|
||||
|
@ -234,7 +221,6 @@ import 'cardStyle';
|
|||
|
||||
html += `<div class="cardImageContainer coveredImage" style="background-image:url('${displayUrl}');"></div>`;
|
||||
} else {
|
||||
|
||||
html += `<div class="cardImageContainer coveredImage defaultCardBackground defaultCardBackground1"><div class="cardText cardCenteredText">${result.Name}</div></div>`;
|
||||
}
|
||||
html += '</div>';
|
||||
|
@ -257,7 +243,6 @@ import 'cardStyle';
|
|||
}
|
||||
|
||||
for (let i = 0; i < numLines; i++) {
|
||||
|
||||
if (i === 0) {
|
||||
html += '<div class="cardText cardText-first cardTextCentered">';
|
||||
} else {
|
||||
|
@ -279,7 +264,6 @@ import 'cardStyle';
|
|||
}
|
||||
|
||||
function submitIdentficationResult(page) {
|
||||
|
||||
loading.show();
|
||||
|
||||
const options = {
|
||||
|
@ -295,14 +279,11 @@ import 'cardStyle';
|
|||
contentType: 'application/json'
|
||||
|
||||
}).then(() => {
|
||||
|
||||
hasChanges = true;
|
||||
loading.hide();
|
||||
|
||||
dialogHelper.close(page);
|
||||
|
||||
}, () => {
|
||||
|
||||
loading.hide();
|
||||
|
||||
dialogHelper.close(page);
|
||||
|
@ -310,15 +291,12 @@ import 'cardStyle';
|
|||
}
|
||||
|
||||
function showIdentificationForm(page, item) {
|
||||
|
||||
const apiClient = getApiClient();
|
||||
|
||||
apiClient.getJSON(apiClient.getUrl(`Items/${item.Id}/ExternalIdInfos`)).then(idList => {
|
||||
|
||||
let html = '';
|
||||
|
||||
for (let i = 0, length = idList.length; i < length; i++) {
|
||||
|
||||
const idInfo = idList[i];
|
||||
|
||||
const id = `txtLookup${idInfo.Key}`;
|
||||
|
@ -340,11 +318,9 @@ import 'cardStyle';
|
|||
page.querySelector('#txtLookupName').value = '';
|
||||
|
||||
if (item.Type === 'Person' || item.Type === 'BoxSet') {
|
||||
|
||||
page.querySelector('.fldLookupYear').classList.add('hide');
|
||||
page.querySelector('#txtLookupYear').value = '';
|
||||
} else {
|
||||
|
||||
page.querySelector('.fldLookupYear').classList.remove('hide');
|
||||
page.querySelector('#txtLookupYear').value = '';
|
||||
}
|
||||
|
@ -356,15 +332,12 @@ import 'cardStyle';
|
|||
}
|
||||
|
||||
function showEditor(itemId) {
|
||||
|
||||
loading.show();
|
||||
|
||||
return import('text!./itemidentifier.template.html').then(({default: template}) => {
|
||||
|
||||
const apiClient = getApiClient();
|
||||
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(item => {
|
||||
|
||||
currentItem = item;
|
||||
currentItemType = currentItem.Type;
|
||||
|
||||
|
@ -406,21 +379,18 @@ import 'cardStyle';
|
|||
dialogHelper.open(dlg);
|
||||
|
||||
dlg.querySelector('.popupIdentifyForm').addEventListener('submit', e => {
|
||||
|
||||
e.preventDefault();
|
||||
searchForIdentificationResults(dlg);
|
||||
return false;
|
||||
});
|
||||
|
||||
dlg.querySelector('.identifyOptionsForm').addEventListener('submit', e => {
|
||||
|
||||
e.preventDefault();
|
||||
submitIdentficationResult(dlg);
|
||||
return false;
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
|
@ -433,7 +403,6 @@ import 'cardStyle';
|
|||
}
|
||||
|
||||
function onDialogClosed() {
|
||||
|
||||
loading.hide();
|
||||
if (hasChanges) {
|
||||
currentResolve();
|
||||
|
@ -444,12 +413,10 @@ import 'cardStyle';
|
|||
|
||||
// TODO investigate where this was used
|
||||
function showEditorFindNew(itemName, itemYear, itemType, resolveFunc) {
|
||||
|
||||
currentItem = null;
|
||||
currentItemType = itemType;
|
||||
|
||||
return import('text!./itemidentifier.template.html').then(({default: template}) => {
|
||||
|
||||
const dialogOptions = {
|
||||
size: 'small',
|
||||
removeOnClose: true,
|
||||
|
@ -477,19 +444,16 @@ import 'cardStyle';
|
|||
dialogHelper.open(dlg);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
dlg.querySelector('.popupIdentifyForm').addEventListener('submit', e => {
|
||||
|
||||
e.preventDefault();
|
||||
searchForIdentificationResults(dlg);
|
||||
return false;
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', () => {
|
||||
|
||||
loading.hide();
|
||||
const foundItem = hasChanges ? currentSearchResult : null;
|
||||
|
||||
|
@ -503,16 +467,12 @@ import 'cardStyle';
|
|||
}
|
||||
|
||||
function showIdentificationFormFindNew(dlg, itemName, itemYear, itemType) {
|
||||
|
||||
dlg.querySelector('#txtLookupName').value = itemName;
|
||||
|
||||
if (itemType === 'Person' || itemType === 'BoxSet') {
|
||||
|
||||
dlg.querySelector('.fldLookupYear').classList.add('hide');
|
||||
dlg.querySelector('#txtLookupYear').value = '';
|
||||
|
||||
} else {
|
||||
|
||||
dlg.querySelector('.fldLookupYear').classList.remove('hide');
|
||||
dlg.querySelector('#txtLookupYear').value = itemYear;
|
||||
}
|
||||
|
@ -521,9 +481,7 @@ import 'cardStyle';
|
|||
}
|
||||
|
||||
export function show(itemId, serverId) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
currentResolve = resolve;
|
||||
currentReject = reject;
|
||||
currentServerId = serverId;
|
||||
|
@ -534,9 +492,7 @@ import 'cardStyle';
|
|||
}
|
||||
|
||||
export function showFindNew(itemName, itemYear, itemType, serverId) {
|
||||
|
||||
return new Promise((resolve) => {
|
||||
|
||||
currentServerId = serverId;
|
||||
|
||||
hasChanges = false;
|
||||
|
|
|
@ -1,96 +1,84 @@
|
|||
define(['playbackManager', 'serverNotifications', 'events'], function (playbackManager, serverNotifications, events) {
|
||||
'use strict';
|
||||
import playbackManager from 'playbackManager';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import events from 'events';
|
||||
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
const instance = this;
|
||||
|
||||
var instance = this;
|
||||
|
||||
var eventsToMonitor = getEventsToMonitor(instance);
|
||||
const eventsToMonitor = getEventsToMonitor(instance);
|
||||
|
||||
// TODO: Check user data change reason?
|
||||
if (eventsToMonitor.indexOf('markfavorite') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
} else if (eventsToMonitor.indexOf('markplayed') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getEventsToMonitor(instance) {
|
||||
|
||||
var options = instance.options;
|
||||
var monitor = options ? options.monitorEvents : null;
|
||||
function getEventsToMonitor(instance) {
|
||||
const options = instance.options;
|
||||
const monitor = options ? options.monitorEvents : null;
|
||||
if (monitor) {
|
||||
return monitor.split(',');
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function onTimerCreated(e, apiClient, data) {
|
||||
|
||||
var instance = this;
|
||||
function onTimerCreated(e, apiClient, data) {
|
||||
const instance = this;
|
||||
|
||||
if (getEventsToMonitor(instance).indexOf('timers') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onSeriesTimerCreated(e, apiClient, data) {
|
||||
|
||||
var instance = this;
|
||||
function onSeriesTimerCreated(e, apiClient, data) {
|
||||
const instance = this;
|
||||
if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onTimerCancelled(e, apiClient, data) {
|
||||
var instance = this;
|
||||
function onTimerCancelled(e, apiClient, data) {
|
||||
const instance = this;
|
||||
|
||||
if (getEventsToMonitor(instance).indexOf('timers') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onSeriesTimerCancelled(e, apiClient, data) {
|
||||
|
||||
var instance = this;
|
||||
function onSeriesTimerCancelled(e, apiClient, data) {
|
||||
const instance = this;
|
||||
if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onLibraryChanged(e, apiClient, data) {
|
||||
|
||||
var instance = this;
|
||||
var eventsToMonitor = getEventsToMonitor(instance);
|
||||
function onLibraryChanged(e, apiClient, data) {
|
||||
const instance = this;
|
||||
const eventsToMonitor = getEventsToMonitor(instance);
|
||||
if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) {
|
||||
|
||||
// yes this is an assumption
|
||||
return;
|
||||
}
|
||||
|
||||
var itemsAdded = data.ItemsAdded || [];
|
||||
var itemsRemoved = data.ItemsRemoved || [];
|
||||
const itemsAdded = data.ItemsAdded || [];
|
||||
const itemsRemoved = data.ItemsRemoved || [];
|
||||
if (!itemsAdded.length && !itemsRemoved.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var options = instance.options || {};
|
||||
var parentId = options.parentId;
|
||||
const options = instance.options || {};
|
||||
const parentId = options.parentId;
|
||||
if (parentId) {
|
||||
var foldersAddedTo = data.FoldersAddedTo || [];
|
||||
var foldersRemovedFrom = data.FoldersRemovedFrom || [];
|
||||
var collectionFolders = data.CollectionFolders || [];
|
||||
const foldersAddedTo = data.FoldersAddedTo || [];
|
||||
const foldersRemovedFrom = data.FoldersRemovedFrom || [];
|
||||
const collectionFolders = data.CollectionFolders || [];
|
||||
|
||||
if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) {
|
||||
return;
|
||||
|
@ -98,52 +86,45 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
|||
}
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
function onPlaybackStopped(e, stopInfo) {
|
||||
function onPlaybackStopped(e, stopInfo) {
|
||||
const instance = this;
|
||||
|
||||
var instance = this;
|
||||
const state = stopInfo.state;
|
||||
|
||||
var state = stopInfo.state;
|
||||
|
||||
var eventsToMonitor = getEventsToMonitor(instance);
|
||||
const eventsToMonitor = getEventsToMonitor(instance);
|
||||
if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') {
|
||||
|
||||
if (eventsToMonitor.indexOf('videoplayback') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
} else if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Audio') {
|
||||
|
||||
if (eventsToMonitor.indexOf('audioplayback') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addNotificationEvent(instance, name, handler, owner) {
|
||||
|
||||
var localHandler = handler.bind(instance);
|
||||
function addNotificationEvent(instance, name, handler, owner) {
|
||||
const localHandler = handler.bind(instance);
|
||||
owner = owner || serverNotifications;
|
||||
events.on(owner, name, localHandler);
|
||||
instance['event_' + name] = localHandler;
|
||||
}
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name, owner) {
|
||||
|
||||
var handler = instance['event_' + name];
|
||||
function removeNotificationEvent(instance, name, owner) {
|
||||
const handler = instance['event_' + name];
|
||||
if (handler) {
|
||||
owner = owner || serverNotifications;
|
||||
events.off(owner, name, handler);
|
||||
instance['event_' + name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
function ItemsRefresher(options) {
|
||||
}
|
||||
|
||||
class ItemsRefresher {
|
||||
constructor(options) {
|
||||
this.options = options || {};
|
||||
|
||||
addNotificationEvent(this, 'UserDataChanged', onUserDataChanged);
|
||||
|
@ -155,25 +136,20 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
|||
addNotificationEvent(this, 'playbackstop', onPlaybackStopped, playbackManager);
|
||||
}
|
||||
|
||||
ItemsRefresher.prototype.pause = function () {
|
||||
|
||||
pause() {
|
||||
clearRefreshInterval(this, true);
|
||||
|
||||
this.paused = true;
|
||||
};
|
||||
|
||||
ItemsRefresher.prototype.resume = function (options) {
|
||||
}
|
||||
|
||||
resume(options) {
|
||||
this.paused = false;
|
||||
|
||||
var refreshIntervalEndTime = this.refreshIntervalEndTime;
|
||||
const refreshIntervalEndTime = this.refreshIntervalEndTime;
|
||||
if (refreshIntervalEndTime) {
|
||||
|
||||
var remainingMs = refreshIntervalEndTime - new Date().getTime();
|
||||
const remainingMs = refreshIntervalEndTime - new Date().getTime();
|
||||
if (remainingMs > 0 && !this.needsRefresh) {
|
||||
|
||||
resetRefreshInterval(this, remainingMs);
|
||||
|
||||
} else {
|
||||
this.needsRefresh = true;
|
||||
this.refreshIntervalEndTime = null;
|
||||
|
@ -185,10 +161,9 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
|||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
ItemsRefresher.prototype.refreshItems = function () {
|
||||
}
|
||||
|
||||
refreshItems() {
|
||||
if (!this.fetchData) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
@ -201,16 +176,15 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
|||
this.needsRefresh = false;
|
||||
|
||||
return this.fetchData().then(onDataFetched.bind(this));
|
||||
};
|
||||
|
||||
ItemsRefresher.prototype.notifyRefreshNeeded = function (isInForeground) {
|
||||
}
|
||||
|
||||
notifyRefreshNeeded(isInForeground) {
|
||||
if (this.paused) {
|
||||
this.needsRefresh = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var timeout = this.refreshTimeout;
|
||||
const timeout = this.refreshTimeout;
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
|
@ -220,49 +194,9 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
|||
} else {
|
||||
this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 10000);
|
||||
}
|
||||
};
|
||||
|
||||
function clearRefreshInterval(instance, isPausing) {
|
||||
|
||||
if (instance.refreshInterval) {
|
||||
|
||||
clearInterval(instance.refreshInterval);
|
||||
instance.refreshInterval = null;
|
||||
|
||||
if (!isPausing) {
|
||||
instance.refreshIntervalEndTime = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetRefreshInterval(instance, intervalMs) {
|
||||
|
||||
clearRefreshInterval(instance);
|
||||
|
||||
if (!intervalMs) {
|
||||
var options = instance.options;
|
||||
if (options) {
|
||||
intervalMs = options.refreshIntervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
if (intervalMs) {
|
||||
instance.refreshInterval = setInterval(instance.notifyRefreshNeeded.bind(instance), intervalMs);
|
||||
instance.refreshIntervalEndTime = new Date().getTime() + intervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
function onDataFetched(result) {
|
||||
|
||||
resetRefreshInterval(this);
|
||||
|
||||
if (this.afterRefresh) {
|
||||
this.afterRefresh(result);
|
||||
}
|
||||
}
|
||||
|
||||
ItemsRefresher.prototype.destroy = function () {
|
||||
|
||||
destroy() {
|
||||
clearRefreshInterval(this);
|
||||
|
||||
removeNotificationEvent(this, 'UserDataChanged');
|
||||
|
@ -275,7 +209,42 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
|||
|
||||
this.fetchData = null;
|
||||
this.options = null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return ItemsRefresher;
|
||||
});
|
||||
function clearRefreshInterval(instance, isPausing) {
|
||||
if (instance.refreshInterval) {
|
||||
clearInterval(instance.refreshInterval);
|
||||
instance.refreshInterval = null;
|
||||
|
||||
if (!isPausing) {
|
||||
instance.refreshIntervalEndTime = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetRefreshInterval(instance, intervalMs) {
|
||||
clearRefreshInterval(instance);
|
||||
|
||||
if (!intervalMs) {
|
||||
const options = instance.options;
|
||||
if (options) {
|
||||
intervalMs = options.refreshIntervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
if (intervalMs) {
|
||||
instance.refreshInterval = setInterval(instance.notifyRefreshNeeded.bind(instance), intervalMs);
|
||||
instance.refreshIntervalEndTime = new Date().getTime() + intervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
function onDataFetched(result) {
|
||||
resetRefreshInterval(this);
|
||||
|
||||
if (this.afterRefresh) {
|
||||
this.afterRefresh(result);
|
||||
}
|
||||
}
|
||||
|
||||
export default ItemsRefresher;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
define(['browser', 'appSettings', 'events'], function (browser, appSettings, events) {
|
||||
'use strict';
|
||||
import browser from 'browser';
|
||||
import appSettings from 'appSettings';
|
||||
import events from 'events';
|
||||
|
||||
function setLayout(instance, layout, selectedLayout) {
|
||||
function setLayout(instance, layout, selectedLayout) {
|
||||
if (layout === selectedLayout) {
|
||||
instance[layout] = true;
|
||||
document.documentElement.classList.add('layout-' + layout);
|
||||
|
@ -9,14 +10,10 @@ define(['browser', 'appSettings', 'events'], function (browser, appSettings, eve
|
|||
instance[layout] = false;
|
||||
document.documentElement.classList.remove('layout-' + layout);
|
||||
}
|
||||
}
|
||||
|
||||
function LayoutManager() {
|
||||
|
||||
}
|
||||
|
||||
LayoutManager.prototype.setLayout = function (layout, save) {
|
||||
}
|
||||
|
||||
class LayoutManager {
|
||||
setLayout(layout, save) {
|
||||
if (!layout || layout === 'auto') {
|
||||
this.autoLayout();
|
||||
|
||||
|
@ -34,14 +31,13 @@ define(['browser', 'appSettings', 'events'], function (browser, appSettings, eve
|
|||
}
|
||||
|
||||
events.trigger(this, 'modechange');
|
||||
};
|
||||
}
|
||||
|
||||
LayoutManager.prototype.getSavedLayout = function (layout) {
|
||||
getSavedLayout(layout) {
|
||||
return appSettings.get('layout');
|
||||
};
|
||||
|
||||
LayoutManager.prototype.autoLayout = function () {
|
||||
}
|
||||
|
||||
autoLayout() {
|
||||
// Take a guess at initial layout. The consuming app can override
|
||||
if (browser.mobile) {
|
||||
this.setLayout('mobile', false);
|
||||
|
@ -50,16 +46,16 @@ define(['browser', 'appSettings', 'events'], function (browser, appSettings, eve
|
|||
} else {
|
||||
this.setLayout(this.defaultLayout || 'tv', false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
LayoutManager.prototype.init = function () {
|
||||
var saved = this.getSavedLayout();
|
||||
init() {
|
||||
const saved = this.getSavedLayout();
|
||||
if (saved) {
|
||||
this.setLayout(saved, false);
|
||||
} else {
|
||||
this.autoLayout();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return new LayoutManager();
|
||||
});
|
||||
export default new LayoutManager();
|
||||
|
|
|
@ -75,9 +75,9 @@ import 'emby-input';
|
|||
html += '</h3>';
|
||||
html += '</div>';
|
||||
if (i > 0) {
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('ButtonUp')}" class="btnSortableMoveUp btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_up"></span></button>`;
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Up')}" class="btnSortableMoveUp btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_up"></span></button>`;
|
||||
} else if (plugins.length > 1) {
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('ButtonDown')}" class="btnSortableMoveDown btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_down"></span></button>`;
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Down')}" class="btnSortableMoveDown btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_down"></span></button>`;
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
|
@ -131,9 +131,9 @@ import 'emby-input';
|
|||
html += '</h3>';
|
||||
html += '</div>';
|
||||
if (index > 0) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonUp') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Up') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
} else if (plugins.length > 1) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonDown') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Down') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
}
|
||||
html += '</div>';
|
||||
});
|
||||
|
@ -197,9 +197,9 @@ import 'emby-input';
|
|||
html += '</h3>';
|
||||
html += '</div>';
|
||||
if (i > 0) {
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('ButtonUp')}" class="btnSortableMoveUp btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_up"></span></button>`;
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Up')}" class="btnSortableMoveUp btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_up"></span></button>`;
|
||||
} else if (plugins.length > 1) {
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('ButtonDown')}" class="btnSortableMoveDown btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_down"></span></button>`;
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Down')}" class="btnSortableMoveDown btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_down"></span></button>`;
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ import 'emby-input';
|
|||
html += '<div class="flex align-items-center" style="margin:1.5em 0 .5em;">';
|
||||
html += '<h3 class="checkboxListLabel" style="margin:0;">' + globalize.translate('HeaderTypeImageFetchers', availableTypeOptions.Type) + '</h3>';
|
||||
const supportedImageTypes = availableTypeOptions.SupportedImageTypes || [];
|
||||
if (supportedImageTypes.length > 1 || 1 === supportedImageTypes.length && 'Primary' !== supportedImageTypes[0]) {
|
||||
if (supportedImageTypes.length > 1 || supportedImageTypes.length === 1 && supportedImageTypes[0] !== 'Primary') {
|
||||
html += '<button is="emby-button" class="raised btnImageOptionsForType" type="button" style="margin-left:1.5em;font-size:90%;"><span>' + globalize.translate('HeaderFetcherSettings') + '</span></button>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
@ -236,9 +236,9 @@ import 'emby-input';
|
|||
html += '</h3>';
|
||||
html += '</div>';
|
||||
if (i > 0) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonUp') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Up') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
} else if (plugins.length > 1) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonDown') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Down') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
|
@ -291,13 +291,13 @@ import 'emby-input';
|
|||
const btnSortable = elem.querySelector('.btnSortable');
|
||||
const inner = btnSortable.querySelector('.material-icons');
|
||||
if (elem.previousSibling) {
|
||||
btnSortable.title = globalize.translate('ButtonUp');
|
||||
btnSortable.title = globalize.translate('Up');
|
||||
btnSortable.classList.add('btnSortableMoveUp');
|
||||
btnSortable.classList.remove('btnSortableMoveDown');
|
||||
inner.classList.remove('keyboard_arrow_down');
|
||||
inner.classList.add('keyboard_arrow_up');
|
||||
} else {
|
||||
btnSortable.title = globalize.translate('ButtonDown');
|
||||
btnSortable.title = globalize.translate('Down');
|
||||
btnSortable.classList.remove('btnSortableMoveUp');
|
||||
btnSortable.classList.add('btnSortableMoveDown');
|
||||
inner.classList.remove('keyboard_arrow_up');
|
||||
|
@ -362,7 +362,7 @@ import 'emby-input';
|
|||
TypeOptions: []
|
||||
};
|
||||
currentAvailableOptions = null;
|
||||
const isNewLibrary = null === libraryOptions;
|
||||
const isNewLibrary = libraryOptions === null;
|
||||
isNewLibrary && parent.classList.add('newlibrary');
|
||||
const response = await fetch('components/libraryoptionseditor/libraryoptionseditor.template.html');
|
||||
const template = await response.text();
|
||||
|
@ -578,7 +578,7 @@ import 'emby-input';
|
|||
parent.querySelector('#chkSkipIfAudioTrackPresent').checked = options.SkipSubtitlesIfAudioTrackMatches;
|
||||
parent.querySelector('#chkRequirePerfectMatch').checked = options.RequirePerfectSubtitleMatch;
|
||||
Array.prototype.forEach.call(parent.querySelectorAll('.chkMetadataSaver'), elem => {
|
||||
elem.checked = options.MetadataSavers ? options.MetadataSavers.includes(elem.getAttribute('data-pluginname')) : 'true' === elem.getAttribute('data-defaultenabled');
|
||||
elem.checked = options.MetadataSavers ? options.MetadataSavers.includes(elem.getAttribute('data-pluginname')) : elem.getAttribute('data-defaultenabled') === 'true';
|
||||
});
|
||||
Array.prototype.forEach.call(parent.querySelectorAll('.chkSubtitleLanguage'), elem => {
|
||||
elem.checked = !!options.SubtitleDownloadLanguages && options.SubtitleDownloadLanguages.includes(elem.getAttribute('data-lang'));
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
<div class="checkboxContainer checkboxContainer-withDescription hide chkImportMissingEpisodesContainer advanced">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="chkImportMissingEpisodes" />
|
||||
<span>${LabelDisplayMissingEpisodesWithinSeasons}</span>
|
||||
<span>${DisplayMissingEpisodesWithinSeasons}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${ImportMissingEpisodesHelp}</div>
|
||||
</div>
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
import itemHelper from 'itemHelper';
|
||||
import mediaInfo from 'mediaInfo';
|
||||
import indicators from 'indicators';
|
||||
import connectionManager from 'connectionManager';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import datetime from 'datetime';
|
||||
|
@ -18,9 +17,7 @@ import 'emby-ratingbutton';
|
|||
import 'emby-playstatebutton';
|
||||
|
||||
function getIndex(item, options) {
|
||||
|
||||
if (options.index === 'disc') {
|
||||
|
||||
return item.ParentIndexNumber == null ? '' : globalize.translate('ValueDiscNumber', item.ParentIndexNumber);
|
||||
}
|
||||
|
||||
|
@ -29,7 +26,6 @@ import 'emby-playstatebutton';
|
|||
let name;
|
||||
|
||||
if (sortBy.indexOf('sortname') === 0) {
|
||||
|
||||
if (item.Type === 'Episode') {
|
||||
return '';
|
||||
}
|
||||
|
@ -45,11 +41,9 @@ import 'emby-playstatebutton';
|
|||
return name.toUpperCase();
|
||||
}
|
||||
if (sortBy.indexOf('officialrating') === 0) {
|
||||
|
||||
return item.OfficialRating || globalize.translate('Unrated');
|
||||
}
|
||||
if (sortBy.indexOf('communityrating') === 0) {
|
||||
|
||||
if (item.CommunityRating == null) {
|
||||
return globalize.translate('Unrated');
|
||||
}
|
||||
|
@ -57,7 +51,6 @@ import 'emby-playstatebutton';
|
|||
return Math.floor(item.CommunityRating);
|
||||
}
|
||||
if (sortBy.indexOf('criticrating') === 0) {
|
||||
|
||||
if (item.CriticRating == null) {
|
||||
return globalize.translate('Unrated');
|
||||
}
|
||||
|
@ -65,7 +58,6 @@ import 'emby-playstatebutton';
|
|||
return Math.floor(item.CriticRating);
|
||||
}
|
||||
if (sortBy.indexOf('albumartist') === 0) {
|
||||
|
||||
// SortName
|
||||
if (!item.AlbumArtist) {
|
||||
return '';
|
||||
|
@ -84,12 +76,11 @@ import 'emby-playstatebutton';
|
|||
}
|
||||
|
||||
function getImageUrl(item, width) {
|
||||
|
||||
const apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
let itemId;
|
||||
|
||||
const options = {
|
||||
maxWidth: width * 2,
|
||||
maxWidth: width,
|
||||
type: 'Primary'
|
||||
};
|
||||
|
||||
|
@ -114,10 +105,9 @@ import 'emby-playstatebutton';
|
|||
}
|
||||
|
||||
function getChannelImageUrl(item, width) {
|
||||
|
||||
const apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
const options = {
|
||||
maxWidth: width * 2,
|
||||
maxWidth: width,
|
||||
type: 'Primary'
|
||||
};
|
||||
|
||||
|
@ -161,11 +151,9 @@ import 'emby-playstatebutton';
|
|||
}
|
||||
|
||||
function getRightButtonsHtml(options) {
|
||||
|
||||
let html = '';
|
||||
|
||||
for (let i = 0, length = options.rightButtons.length; i < length; i++) {
|
||||
|
||||
const button = options.rightButtons[i];
|
||||
|
||||
html += `<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="custom" data-customaction="${button.id}" title="${button.title}"><span class="material-icons ${button.icon}"></span></button>`;
|
||||
|
@ -179,7 +167,6 @@ import 'emby-playstatebutton';
|
|||
}
|
||||
|
||||
export function getListViewHtml(options) {
|
||||
|
||||
const items = options.items;
|
||||
|
||||
let groupTitle = '';
|
||||
|
@ -198,17 +185,14 @@ import 'emby-playstatebutton';
|
|||
const containerAlbumArtistIds = (options.containerAlbumArtists || []).map(getId);
|
||||
|
||||
for (let i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
const item = items[i];
|
||||
|
||||
let html = '';
|
||||
|
||||
if (options.showIndex) {
|
||||
|
||||
const itemGroupTitle = getIndex(item, options);
|
||||
|
||||
if (itemGroupTitle !== groupTitle) {
|
||||
|
||||
if (html) {
|
||||
html += '</div>';
|
||||
}
|
||||
|
@ -258,20 +242,16 @@ import 'emby-playstatebutton';
|
|||
const channelIdData = item.ChannelId ? (` data-channelid="${item.ChannelId}"`) : '';
|
||||
|
||||
if (enableContentWrapper) {
|
||||
|
||||
cssClass += ' listItem-withContentWrapper';
|
||||
}
|
||||
|
||||
html += `<${outerTagName} class="${cssClass}"${playlistItemId} data-action="${action}" data-isfolder="${item.IsFolder}" data-id="${item.Id}" data-serverid="${item.ServerId}" data-type="${item.Type}"${mediaTypeData}${collectionTypeData}${channelIdData}${positionTicksData}${collectionIdData}${playlistIdData}>`;
|
||||
|
||||
if (enableContentWrapper) {
|
||||
|
||||
html += '<div class="listItem-content">';
|
||||
}
|
||||
|
||||
if (!clickEntireItem && options.dragHandle) {
|
||||
//html += '<button is="paper-icon-button-light" class="listViewDragHandle listItemButton"><span class="material-icons drag_handle"></span></button>';
|
||||
// Firefox and Edge are not allowing the button to be draggable
|
||||
html += '<span class="listViewDragHandle material-icons listItemIcon listItemIcon-transparent drag_handle"></span>';
|
||||
}
|
||||
|
||||
|
@ -319,7 +299,6 @@ import 'emby-playstatebutton';
|
|||
}
|
||||
|
||||
if (options.showIndexNumberLeft) {
|
||||
|
||||
html += '<div class="listItem-indexnumberleft">';
|
||||
html += (item.IndexNumber || ' ');
|
||||
html += '</div>';
|
||||
|
@ -367,9 +346,7 @@ import 'emby-playstatebutton';
|
|||
}
|
||||
|
||||
if (options.showParentTitle && options.parentTitleWithTitle) {
|
||||
|
||||
if (displayName) {
|
||||
|
||||
if (parentTitle) {
|
||||
parentTitle += ' - ';
|
||||
}
|
||||
|
@ -387,27 +364,13 @@ import 'emby-playstatebutton';
|
|||
|
||||
if (item.IsFolder) {
|
||||
if (options.artist !== false) {
|
||||
|
||||
if (item.AlbumArtist && item.Type === 'MusicAlbum') {
|
||||
textlines.push(item.AlbumArtist);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
let showArtist = options.artist === true;
|
||||
if (options.artist) {
|
||||
const artistItems = item.ArtistItems;
|
||||
|
||||
if (!showArtist && options.artist !== false) {
|
||||
|
||||
if (!artistItems || !artistItems.length) {
|
||||
showArtist = true;
|
||||
} else if (artistItems.length > 1 || !containerAlbumArtistIds.includes(artistItems[0].Id)) {
|
||||
showArtist = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (showArtist) {
|
||||
|
||||
if (artistItems && item.Type !== 'MusicAlbum') {
|
||||
textlines.push(artistItems.map(a => {
|
||||
return a.Name;
|
||||
|
@ -417,7 +380,6 @@ import 'emby-playstatebutton';
|
|||
}
|
||||
|
||||
if (item.Type === 'TvChannel') {
|
||||
|
||||
if (item.CurrentProgram) {
|
||||
textlines.push(itemHelper.getDisplayName(item.CurrentProgram));
|
||||
}
|
||||
|
@ -438,7 +400,6 @@ import 'emby-playstatebutton';
|
|||
|
||||
if (options.mediaInfo !== false) {
|
||||
if (!enableSideMediaInfo) {
|
||||
|
||||
const mediaInfoClass = 'secondary listItemMediaInfo listItemBodyText';
|
||||
|
||||
html += `<div class="${mediaInfoClass}">`;
|
||||
|
@ -483,7 +444,6 @@ import 'emby-playstatebutton';
|
|||
html += '<div class="listViewUserDataButtons">';
|
||||
|
||||
if (!clickEntireItem) {
|
||||
|
||||
if (options.addToListButton) {
|
||||
html += '<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="addtoplaylist"><span class="material-icons playlist_add"></span></button>';
|
||||
}
|
||||
|
@ -497,7 +457,6 @@ import 'emby-playstatebutton';
|
|||
}
|
||||
|
||||
if (options.enableUserDataButtons !== false) {
|
||||
|
||||
const userData = item.UserData || {};
|
||||
const likes = userData.Likes == null ? '' : userData.Likes;
|
||||
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
define(['css!./loading'], function () {
|
||||
'use strict';
|
||||
import 'css!./loading';
|
||||
|
||||
var loadingElem;
|
||||
var layer1;
|
||||
var layer2;
|
||||
var layer3;
|
||||
var layer4;
|
||||
var circleLefts;
|
||||
var circleRights;
|
||||
let loadingElem;
|
||||
let layer1;
|
||||
let layer2;
|
||||
let layer3;
|
||||
let layer4;
|
||||
let circleLefts;
|
||||
let circleRights;
|
||||
|
||||
return {
|
||||
show: function () {
|
||||
var elem = loadingElem;
|
||||
export function show() {
|
||||
let elem = loadingElem;
|
||||
|
||||
if (!elem) {
|
||||
|
||||
elem = document.createElement('div');
|
||||
loadingElem = elem;
|
||||
|
||||
|
@ -41,22 +38,19 @@ define(['css!./loading'], function () {
|
|||
layer3.classList.add('mdl-spinner__layer-3-active');
|
||||
layer4.classList.add('mdl-spinner__layer-4-active');
|
||||
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = circleLefts.length; i < length; i++) {
|
||||
for (let i = 0, length = circleLefts.length; i < length; i++) {
|
||||
circleLefts[i].classList.add('mdl-spinner__circleLeft-active');
|
||||
}
|
||||
|
||||
for (i = 0, length = circleRights.length; i < length; i++) {
|
||||
for (let i = 0, length = circleRights.length; i < length; i++) {
|
||||
circleRights[i].classList.add('mdl-spinner__circleRight-active');
|
||||
}
|
||||
},
|
||||
hide: function () {
|
||||
var elem = loadingElem;
|
||||
}
|
||||
|
||||
export function hide() {
|
||||
const elem = loadingElem;
|
||||
|
||||
if (elem) {
|
||||
|
||||
elem.classList.remove('mdlSpinnerActive');
|
||||
|
||||
elem.classList.remove('mdl-spinner__layer-1-active');
|
||||
|
@ -64,17 +58,17 @@ define(['css!./loading'], function () {
|
|||
elem.classList.remove('mdl-spinner__layer-3-active');
|
||||
elem.classList.remove('mdl-spinner__layer-4-active');
|
||||
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = circleLefts.length; i < length; i++) {
|
||||
for (let i = 0, length = circleLefts.length; i < length; i++) {
|
||||
circleLefts[i].classList.remove('mdl-spinner__circleLeft-active');
|
||||
}
|
||||
|
||||
for (i = 0, length = circleRights.length; i < length; i++) {
|
||||
for (let i = 0, length = circleRights.length; i < length; i++) {
|
||||
circleRights[i].classList.remove('mdl-spinner__circleRight-active');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
show: show,
|
||||
hide: hide
|
||||
};
|
||||
|
|
|
@ -8,29 +8,10 @@ import 'emby-button';
|
|||
|
||||
let tabOwnerView;
|
||||
const queryScope = document.querySelector('.skinHeader');
|
||||
let footerTabsContainer;
|
||||
let headerTabsContainer;
|
||||
let tabsElem;
|
||||
|
||||
function enableTabsInFooter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getTabsContainerElem() {
|
||||
}
|
||||
|
||||
function ensureElements(enableInFooter) {
|
||||
|
||||
if (enableInFooter) {
|
||||
if (!footerTabsContainer) {
|
||||
footerTabsContainer = document.createElement('div');
|
||||
footerTabsContainer.classList.add('footerTabs');
|
||||
footerTabsContainer.classList.add('sectionTabs');
|
||||
footerTabsContainer.classList.add('hide');
|
||||
//appFooter.add(footerTabsContainer);
|
||||
}
|
||||
}
|
||||
|
||||
function ensureElements() {
|
||||
if (!headerTabsContainer) {
|
||||
headerTabsContainer = queryScope.querySelector('.headerTabs');
|
||||
}
|
||||
|
@ -42,9 +23,7 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
function allowSwipe(target) {
|
||||
|
||||
function allowSwipeOn(elem) {
|
||||
|
||||
if (dom.parentWithTag(elem, 'input')) {
|
||||
return false;
|
||||
}
|
||||
|
@ -69,13 +48,11 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
function configureSwipeTabs(view, tabsElem, getTabContainersFn) {
|
||||
|
||||
if (!browser.touch) {
|
||||
return;
|
||||
}
|
||||
|
||||
// implement without hammer
|
||||
const pageCount = getTabContainersFn().length;
|
||||
const onSwipeLeft = function (e, target) {
|
||||
if (allowSwipe(target) && view.contains(target)) {
|
||||
tabsElem.selectNext();
|
||||
|
@ -89,7 +66,6 @@ import 'emby-button';
|
|||
};
|
||||
|
||||
import('touchHelper').then(({default: TouchHelper}) => {
|
||||
|
||||
const touchHelper = new TouchHelper(view.parentNode.parentNode);
|
||||
|
||||
events.on(touchHelper, 'swipeleft', onSwipeLeft);
|
||||
|
@ -102,28 +78,19 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
export function setTabs(view, selectedIndex, getTabsFn, getTabContainersFn, onBeforeTabChange, onTabChange, setSelectedIndex) {
|
||||
|
||||
const enableInFooter = enableTabsInFooter();
|
||||
|
||||
if (!view) {
|
||||
if (tabOwnerView) {
|
||||
|
||||
if (!headerTabsContainer) {
|
||||
headerTabsContainer = queryScope.querySelector('.headerTabs');
|
||||
}
|
||||
|
||||
ensureElements(enableInFooter);
|
||||
ensureElements();
|
||||
|
||||
document.body.classList.remove('withSectionTabs');
|
||||
|
||||
headerTabsContainer.innerHTML = '';
|
||||
headerTabsContainer.classList.add('hide');
|
||||
|
||||
if (footerTabsContainer) {
|
||||
footerTabsContainer.innerHTML = '';
|
||||
footerTabsContainer.classList.add('hide');
|
||||
}
|
||||
|
||||
tabOwnerView = null;
|
||||
}
|
||||
return {
|
||||
|
@ -132,21 +99,19 @@ import 'emby-button';
|
|||
};
|
||||
}
|
||||
|
||||
ensureElements(enableInFooter);
|
||||
ensureElements();
|
||||
|
||||
const tabsContainerElem = enableInFooter ? footerTabsContainer : headerTabsContainer;
|
||||
const tabsContainerElem = headerTabsContainer;
|
||||
|
||||
if (!tabOwnerView) {
|
||||
tabsContainerElem.classList.remove('hide');
|
||||
}
|
||||
|
||||
if (tabOwnerView !== view) {
|
||||
|
||||
let index = 0;
|
||||
|
||||
const indexAttribute = selectedIndex == null ? '' : (' data-index="' + selectedIndex + '"');
|
||||
const tabsHtml = '<div is="emby-tabs"' + indexAttribute + ' class="tabs-viewmenubar"><div class="emby-tabs-slider" style="white-space:nowrap;">' + getTabsFn().map(function (t) {
|
||||
|
||||
let tabClass = 'emby-tab-button';
|
||||
|
||||
if (t.enabled === false) {
|
||||
|
@ -167,7 +132,6 @@ import 'emby-button';
|
|||
|
||||
index++;
|
||||
return tabHtml;
|
||||
|
||||
}).join('') + '</div></div>';
|
||||
|
||||
tabsContainerElem.innerHTML = tabsHtml;
|
||||
|
@ -181,10 +145,8 @@ import 'emby-button';
|
|||
configureSwipeTabs(view, tabsElem, getTabContainersFn);
|
||||
|
||||
tabsElem.addEventListener('beforetabchange', function (e) {
|
||||
|
||||
const tabContainers = getTabContainersFn();
|
||||
if (e.detail.previousIndex != null) {
|
||||
|
||||
const previousPanel = tabContainers[e.detail.previousIndex];
|
||||
if (previousPanel) {
|
||||
previousPanel.classList.remove('is-active');
|
||||
|
@ -193,12 +155,6 @@ import 'emby-button';
|
|||
|
||||
const newPanel = tabContainers[e.detail.selectedTabIndex];
|
||||
|
||||
//if (e.detail.previousIndex != null && e.detail.previousIndex != e.detail.selectedTabIndex) {
|
||||
// if (newPanel.animate && (animateTabs || []).indexOf(e.detail.selectedTabIndex) != -1) {
|
||||
// fadeInRight(newPanel);
|
||||
// }
|
||||
//}
|
||||
|
||||
if (newPanel) {
|
||||
newPanel.classList.add('is-active');
|
||||
}
|
||||
|
@ -215,16 +171,11 @@ import 'emby-button';
|
|||
if (tabsElem.selectedIndex) {
|
||||
tabsElem.selectedIndex(selectedIndex);
|
||||
} else {
|
||||
|
||||
tabsElem.readySelectedIndex = selectedIndex;
|
||||
tabsElem.addEventListener('ready', onViewTabsReady);
|
||||
}
|
||||
}
|
||||
|
||||
//if (enableSwipe !== false) {
|
||||
// libraryBrowser.configureSwipeTabs(ownerpage, tabs);
|
||||
//}
|
||||
|
||||
return {
|
||||
tabsContainer: tabsContainerElem,
|
||||
tabs: tabsContainerElem.querySelector('[is="emby-tabs"]'),
|
||||
|
@ -247,7 +198,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
export function selectedTabIndex(index) {
|
||||
|
||||
const tabsContainerElem = headerTabsContainer;
|
||||
|
||||
if (!tabsElem) {
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
|
||||
<div class="folders">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<h1 style="margin: .5em 0;">${HeadersFolders}</h1>
|
||||
<button is="emby-button" type="button" class="fab btnAddFolder submit" style="margin-left:1em;" title="${ButtonAdd}">
|
||||
<h1 style="margin: .5em 0;">${Folders}</h1>
|
||||
<button is="emby-button" type="button" class="fab btnAddFolder submit" style="margin-left:1em;" title="${Add}">
|
||||
<span class="material-icons add"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -76,7 +76,7 @@ import 'flexStyles';
|
|||
confirm({
|
||||
title: globalize.translate('HeaderRemoveMediaLocation'),
|
||||
text: globalize.translate('MessageConfirmRemoveMediaLocation'),
|
||||
confirmText: globalize.translate('ButtonDelete'),
|
||||
confirmText: globalize.translate('Delete'),
|
||||
primary: 'delete'
|
||||
}).then(() => {
|
||||
const refreshAfterChange = currentOptions.refresh;
|
||||
|
@ -85,7 +85,7 @@ import 'flexStyles';
|
|||
refreshLibraryFromServer(dom.parentWithClass(button, 'dlg-libraryeditor'));
|
||||
}, () => {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('DefaultErrorMessage'));
|
||||
toast(globalize.translate('ErrorDefault'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -98,8 +98,8 @@ import 'flexStyles';
|
|||
if (listItem) {
|
||||
const index = parseInt(listItem.getAttribute('data-index'));
|
||||
const pathInfos = (currentOptions.library.LibraryOptions || {}).PathInfos || [];
|
||||
const pathInfo = null == index ? {} : pathInfos[index] || {};
|
||||
const originalPath = pathInfo.Path || (null == index ? null : currentOptions.library.Locations[index]);
|
||||
const pathInfo = index == null ? {} : pathInfos[index] || {};
|
||||
const originalPath = pathInfo.Path || (index == null ? null : currentOptions.library.Locations[index]);
|
||||
const btnRemovePath = dom.parentWithClass(e.target, 'btnRemovePath');
|
||||
|
||||
if (btnRemovePath) {
|
||||
|
@ -171,7 +171,7 @@ import 'flexStyles';
|
|||
const picker = new directoryBrowser();
|
||||
picker.show({
|
||||
enableNetworkSharePath: true,
|
||||
pathReadOnly: null != originalPath,
|
||||
pathReadOnly: originalPath != null,
|
||||
path: originalPath,
|
||||
networkSharePath: networkPath,
|
||||
callback: function (path, networkSharePath) {
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
|
||||
<div class="folders hide">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<h1 style="margin: .5em 0;">${HeadersFolders}</h1>
|
||||
<button is="emby-button" type="button" class="fab btnAddFolder submit" style="margin-left:1em;" title="${ButtonAdd}">
|
||||
<h1 style="margin: .5em 0;">${Folders}</h1>
|
||||
<button is="emby-button" type="button" class="fab btnAddFolder submit" style="margin-left:1em;" title="${Add}">
|
||||
<span class="material-icons add"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -9,25 +9,20 @@ import 'programStyles';
|
|||
import 'emby-button';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function getTimerIndicator(item) {
|
||||
|
||||
let status;
|
||||
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
return '<span class="material-icons mediaInfoItem mediaInfoIconItem mediaInfoTimerIcon fiber_smart_record"></span>';
|
||||
} else if (item.TimerId || item.SeriesTimerId) {
|
||||
|
||||
status = item.Status || 'Cancelled';
|
||||
} else if (item.Type === 'Timer') {
|
||||
|
||||
status = item.Status;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (item.SeriesTimerId) {
|
||||
|
||||
if (status !== 'Cancelled') {
|
||||
return '<span class="material-icons mediaInfoItem mediaInfoIconItem mediaInfoTimerIcon fiber_smart_record"></span>';
|
||||
}
|
||||
|
@ -46,9 +41,7 @@ import 'emby-button';
|
|||
let date;
|
||||
|
||||
if (item.StartDate && options.programTime !== false) {
|
||||
|
||||
try {
|
||||
|
||||
text = '';
|
||||
|
||||
date = datetime.parseISO8601Date(item.StartDate);
|
||||
|
@ -75,7 +68,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
if (item.ChannelName) {
|
||||
|
||||
if (options.interactive && item.ChannelId) {
|
||||
miscInfo.push({
|
||||
html: `<a is="emby-linkbutton" class="button-flat mediaInfoItem" href="${appRouter.getRouteUrl({
|
||||
|
@ -121,11 +113,9 @@ import 'emby-button';
|
|||
const showFolderRuntime = item.Type === 'MusicAlbum' || item.MediaType === 'MusicArtist' || item.MediaType === 'Playlist' || item.MediaType === 'MusicGenre';
|
||||
|
||||
if (showFolderRuntime) {
|
||||
|
||||
count = item.SongCount || item.ChildCount;
|
||||
|
||||
if (count) {
|
||||
|
||||
miscInfo.push(globalize.translate('TrackCount', count));
|
||||
}
|
||||
|
||||
|
@ -133,19 +123,15 @@ import 'emby-button';
|
|||
miscInfo.push(datetime.getDisplayRunningTime(item.RunTimeTicks));
|
||||
}
|
||||
} else if (item.Type === 'PhotoAlbum' || item.Type === 'BoxSet') {
|
||||
|
||||
count = item.ChildCount;
|
||||
|
||||
if (count) {
|
||||
|
||||
miscInfo.push(globalize.translate('ItemCount', count));
|
||||
}
|
||||
}
|
||||
|
||||
if ((item.Type === 'Episode' || item.MediaType === 'Photo') && options.originalAirDate !== false) {
|
||||
|
||||
if (item.PremiereDate) {
|
||||
|
||||
try {
|
||||
date = datetime.parseISO8601Date(item.PremiereDate);
|
||||
|
||||
|
@ -159,7 +145,6 @@ import 'emby-button';
|
|||
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
if (item.RecordAnyTime) {
|
||||
|
||||
miscInfo.push(globalize.translate('Anytime'));
|
||||
} else {
|
||||
miscInfo.push(datetime.getDisplayTime(item.StartDate));
|
||||
|
@ -173,7 +158,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
if (item.StartDate && item.Type !== 'Program' && item.Type !== 'SeriesTimer') {
|
||||
|
||||
try {
|
||||
date = datetime.parseISO8601Date(item.StartDate);
|
||||
|
||||
|
@ -190,24 +174,18 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
if (options.year !== false && item.ProductionYear && item.Type === 'Series') {
|
||||
|
||||
if (item.Status === 'Continuing') {
|
||||
miscInfo.push(globalize.translate('SeriesYearToPresent', item.ProductionYear));
|
||||
|
||||
} else if (item.ProductionYear) {
|
||||
|
||||
text = item.ProductionYear;
|
||||
|
||||
if (item.EndDate) {
|
||||
|
||||
try {
|
||||
|
||||
const endYear = datetime.parseISO8601Date(item.EndDate).getFullYear();
|
||||
|
||||
if (endYear !== item.ProductionYear) {
|
||||
text += `-${datetime.parseISO8601Date(item.EndDate).getFullYear()}`;
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error('error parsing date:', item.EndDate);
|
||||
}
|
||||
|
@ -218,7 +196,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
if (item.Type === 'Program') {
|
||||
|
||||
if (options.programIndicator !== false) {
|
||||
if (item.IsLive) {
|
||||
miscInfo.push({
|
||||
|
@ -230,7 +207,7 @@ import 'emby-button';
|
|||
});
|
||||
} else if (item.IsSeries && !item.IsRepeat) {
|
||||
miscInfo.push({
|
||||
html: `<div class="mediaInfoProgramAttribute mediaInfoItem newTvProgram">${globalize.translate('AttributeNew')}</div>`
|
||||
html: `<div class="mediaInfoProgramAttribute mediaInfoItem newTvProgram">${globalize.translate('New')}</div>`
|
||||
});
|
||||
} else if (item.IsSeries && item.IsRepeat) {
|
||||
miscInfo.push({
|
||||
|
@ -240,7 +217,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
if ((item.IsSeries || item.EpisodeTitle) && options.episodeTitle !== false) {
|
||||
|
||||
text = itemHelper.getDisplayName(item, {
|
||||
includeIndexNumber: options.episodeTitleIndexNumber
|
||||
});
|
||||
|
@ -251,7 +227,6 @@ import 'emby-button';
|
|||
} else if (item.IsMovie && item.ProductionYear && options.originalAirDate !== false) {
|
||||
miscInfo.push(item.ProductionYear);
|
||||
} else if (item.PremiereDate && options.originalAirDate !== false) {
|
||||
|
||||
try {
|
||||
date = datetime.parseISO8601Date(item.PremiereDate);
|
||||
text = globalize.translate('OriginalAirDateValue', datetime.toLocaleDateString(date));
|
||||
|
@ -266,12 +241,9 @@ import 'emby-button';
|
|||
|
||||
if (options.year !== false) {
|
||||
if (item.Type !== 'Series' && item.Type !== 'Episode' && item.Type !== 'Person' && item.MediaType !== 'Photo' && item.Type !== 'Program' && item.Type !== 'Season') {
|
||||
|
||||
if (item.ProductionYear) {
|
||||
|
||||
miscInfo.push(item.ProductionYear);
|
||||
} else if (item.PremiereDate) {
|
||||
|
||||
try {
|
||||
text = datetime.parseISO8601Date(item.PremiereDate).getFullYear();
|
||||
miscInfo.push(text);
|
||||
|
@ -283,11 +255,8 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
if (item.RunTimeTicks && item.Type !== 'Series' && item.Type !== 'Program' && item.Type !== 'Book' && !showFolderRuntime && options.runtime !== false) {
|
||||
|
||||
if (item.Type === 'Audio') {
|
||||
|
||||
miscInfo.push(datetime.getDisplayRunningTime(item.RunTimeTicks));
|
||||
|
||||
} else {
|
||||
minutes = item.RunTimeTicks / 600000000;
|
||||
|
||||
|
@ -327,7 +296,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
if (item.CriticRating && options.criticRating !== false) {
|
||||
|
||||
if (item.CriticRating >= 60) {
|
||||
html += `<div class="mediaInfoItem mediaInfoCriticRating mediaInfoCriticRatingFresh">${item.CriticRating}</div>`;
|
||||
} else {
|
||||
|
@ -336,7 +304,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
if (options.endsAt !== false) {
|
||||
|
||||
const endsAt = getEndsAt(item);
|
||||
if (endsAt) {
|
||||
html += getMediaInfoItem(endsAt, 'endsAt');
|
||||
|
@ -349,9 +316,7 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
export function getEndsAt(item) {
|
||||
|
||||
if (item.MediaType === 'Video' && item.RunTimeTicks) {
|
||||
|
||||
if (!item.StartDate) {
|
||||
let endDate = new Date().getTime() + (item.RunTimeTicks / 10000);
|
||||
endDate = new Date(endDate);
|
||||
|
@ -365,7 +330,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
export function getEndsAtFromPosition(runtimeTicks, positionTicks, includeText) {
|
||||
|
||||
let endDate = new Date().getTime() + ((runtimeTicks - (positionTicks || 0)) / 10000);
|
||||
endDate = new Date(endDate);
|
||||
|
||||
|
@ -378,12 +342,10 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
function getMediaInfoItem(m, cssClass) {
|
||||
|
||||
cssClass = cssClass ? (`${cssClass} mediaInfoItem`) : 'mediaInfoItem';
|
||||
let mediaInfoText = m;
|
||||
|
||||
if (typeof (m) !== 'string' && typeof (m) !== 'number') {
|
||||
|
||||
if (m.html) {
|
||||
return m.html;
|
||||
}
|
||||
|
@ -408,17 +370,13 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
function dynamicEndTime(elem, item) {
|
||||
|
||||
const interval = setInterval(() => {
|
||||
|
||||
if (!document.body.contains(elem)) {
|
||||
|
||||
clearInterval(interval);
|
||||
return;
|
||||
}
|
||||
|
||||
elem.innerHTML = getEndsAt(item);
|
||||
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
|
@ -437,7 +395,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
function afterFill(elem, item, options) {
|
||||
|
||||
if (options.endsAt !== false) {
|
||||
const endsAtElem = elem.querySelector('.endsAt');
|
||||
if (endsAtElem) {
|
||||
|
@ -452,7 +409,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
function onChannelLinkClick(e) {
|
||||
|
||||
const channelId = this.getAttribute('data-id');
|
||||
const serverId = this.getAttribute('data-serverid');
|
||||
|
||||
|
@ -463,7 +419,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
export function getPrimaryMediaInfoHtml(item, options) {
|
||||
|
||||
options = options || {};
|
||||
if (options.interactive == null) {
|
||||
options.interactive = false;
|
||||
|
@ -473,7 +428,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
export function getSecondaryMediaInfoHtml(item, options) {
|
||||
|
||||
options = options || {};
|
||||
if (options.interactive == null) {
|
||||
options.interactive = false;
|
||||
|
@ -486,12 +440,10 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
export function getResolutionText(i) {
|
||||
|
||||
const width = i.Width;
|
||||
const height = i.Height;
|
||||
|
||||
if (width && height) {
|
||||
|
||||
if (width >= 3800 || height >= 2000) {
|
||||
return '4K';
|
||||
}
|
||||
|
@ -514,19 +466,16 @@ import 'emby-button';
|
|||
return '720p';
|
||||
}
|
||||
if (width >= 700 || height >= 400) {
|
||||
|
||||
if (i.IsInterlaced) {
|
||||
return '480i';
|
||||
}
|
||||
return '480p';
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getAudioStreamForDisplay(item) {
|
||||
|
||||
if (!item.MediaSources) {
|
||||
return null;
|
||||
}
|
||||
|
@ -542,7 +491,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
export function getMediaInfoStats(item, options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
const list = [];
|
||||
|
@ -568,10 +516,6 @@ import 'emby-button';
|
|||
});
|
||||
}
|
||||
|
||||
//if (mediaSource.Container) {
|
||||
// html += '<div class="mediaInfoIcon mediaInfoText">' + mediaSource.Container + '</div>';
|
||||
//}
|
||||
|
||||
const resolutionText = getResolutionText(videoStream);
|
||||
if (resolutionText) {
|
||||
list.push({
|
||||
|
@ -591,19 +535,12 @@ import 'emby-button';
|
|||
let channelText;
|
||||
|
||||
if (channels === 8) {
|
||||
|
||||
channelText = '7.1';
|
||||
|
||||
} else if (channels === 7) {
|
||||
|
||||
channelText = '6.1';
|
||||
|
||||
} else if (channels === 6) {
|
||||
|
||||
channelText = '5.1';
|
||||
|
||||
} else if (channels === 2) {
|
||||
|
||||
channelText = '2.0';
|
||||
}
|
||||
|
||||
|
@ -629,7 +566,6 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
if (item.DateCreated && itemHelper.enableDateAddedDisplay(item)) {
|
||||
|
||||
const dateCreated = datetime.parseISO8601Date(item.DateCreated);
|
||||
|
||||
list.push({
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
import itemHelper from 'itemHelper';
|
||||
import dom from 'dom';
|
||||
import layoutManager from 'layoutManager';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import datetime from 'datetime';
|
||||
import loading from 'loading';
|
||||
import focusManager from 'focusManager';
|
||||
import connectionManager from 'connectionManager';
|
||||
import globalize from 'globalize';
|
||||
import require from 'require';
|
||||
import shell from 'shell';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-input';
|
||||
|
@ -31,17 +28,14 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function closeDialog(isSubmitted) {
|
||||
|
||||
if (isDialog()) {
|
||||
dialogHelper.close(currentContext);
|
||||
}
|
||||
}
|
||||
|
||||
function submitUpdatedItem(form, item) {
|
||||
|
||||
function afterContentTypeUpdated() {
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('MessageItemSaved'));
|
||||
});
|
||||
|
||||
|
@ -52,11 +46,9 @@ import 'flexStyles';
|
|||
const apiClient = getApiClient();
|
||||
|
||||
apiClient.updateItem(item).then(function () {
|
||||
|
||||
const newContentType = form.querySelector('#selectContentType').value || '';
|
||||
|
||||
if ((metadataEditorInfo.ContentType || '') !== newContentType) {
|
||||
|
||||
apiClient.ajax({
|
||||
|
||||
url: apiClient.getUrl('Items/' + item.Id + '/ContentType', {
|
||||
|
@ -68,11 +60,9 @@ import 'flexStyles';
|
|||
}).then(function () {
|
||||
afterContentTypeUpdated();
|
||||
});
|
||||
|
||||
} else {
|
||||
afterContentTypeUpdated();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -84,13 +74,9 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function getAlbumArtists(form) {
|
||||
|
||||
return form.querySelector('#txtAlbumArtist').value.trim().split(';').filter(function (s) {
|
||||
|
||||
return s.length > 0;
|
||||
|
||||
}).map(function (a) {
|
||||
|
||||
return {
|
||||
Name: a
|
||||
};
|
||||
|
@ -98,13 +84,9 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function getArtists(form) {
|
||||
|
||||
return form.querySelector('#txtArtist').value.trim().split(';').filter(function (s) {
|
||||
|
||||
return s.length > 0;
|
||||
|
||||
}).map(function (a) {
|
||||
|
||||
return {
|
||||
Name: a
|
||||
};
|
||||
|
@ -112,7 +94,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function getDateValue(form, element, property) {
|
||||
|
||||
let val = form.querySelector(element).value;
|
||||
|
||||
if (!val) {
|
||||
|
@ -120,14 +101,12 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
if (currentItem[property]) {
|
||||
|
||||
const date = datetime.parseISO8601Date(currentItem[property], true);
|
||||
|
||||
const parts = date.toISOString().split('T');
|
||||
|
||||
// If the date is the same, preserve the time
|
||||
if (parts[0].indexOf(val) === 0) {
|
||||
|
||||
const iso = parts[1];
|
||||
|
||||
val += 'T' + iso;
|
||||
|
@ -138,7 +117,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
|
||||
loading.show();
|
||||
|
||||
const form = this;
|
||||
|
@ -199,14 +177,12 @@ import 'flexStyles';
|
|||
item.PreferredMetadataCountryCode = form.querySelector('#selectCountry').value;
|
||||
|
||||
if (currentItem.Type === 'Person') {
|
||||
|
||||
const placeOfBirth = form.querySelector('#txtPlaceOfBirth').value;
|
||||
|
||||
item.ProductionLocations = placeOfBirth ? [placeOfBirth] : [];
|
||||
}
|
||||
|
||||
if (currentItem.Type === 'Series') {
|
||||
|
||||
// 600000000
|
||||
const seriesRuntime = form.querySelector('#txtSeriesRuntime').value;
|
||||
item.RunTimeTicks = seriesRuntime ? (seriesRuntime * 600000000) : null;
|
||||
|
@ -249,11 +225,8 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function editPerson(context, person, index) {
|
||||
|
||||
require(['personEditor'], function (personEditor) {
|
||||
|
||||
import('personEditor').then(({default: personEditor}) => {
|
||||
personEditor.show(person).then(function (updatedPerson) {
|
||||
|
||||
const isNew = index === -1;
|
||||
|
||||
if (isNew) {
|
||||
|
@ -271,14 +244,14 @@ import 'flexStyles';
|
|||
if (parentId) {
|
||||
reload(context, parentId, item.ServerId);
|
||||
} else {
|
||||
require(['appRouter'], function (appRouter) {
|
||||
import('appRouter').then(({default: appRouter}) => {
|
||||
appRouter.goHome();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showMoreMenu(context, button, user) {
|
||||
require(['itemContextMenu'], function (itemContextMenu) {
|
||||
import('itemContextMenu').then(({default: itemContextMenu}) => {
|
||||
var item = currentItem;
|
||||
|
||||
itemContextMenu.show({
|
||||
|
@ -303,7 +276,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function onEditorClick(e) {
|
||||
|
||||
const btnRemoveFromEditorList = dom.parentWithClass(e.target, 'btnRemoveFromEditorList');
|
||||
if (btnRemoveFromEditorList) {
|
||||
removeElementFromList(btnRemoveFromEditorList);
|
||||
|
@ -317,7 +289,7 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function getApiClient() {
|
||||
return connectionManager.getApiClient(currentItem.ServerId);
|
||||
return window.connectionManager.getApiClient(currentItem.ServerId);
|
||||
}
|
||||
|
||||
function bindAll(elems, eventName, fn) {
|
||||
|
@ -376,12 +348,10 @@ import 'flexStyles';
|
|||
form.addEventListener('submit', onSubmit);
|
||||
|
||||
context.querySelector('#btnAddPerson').addEventListener('click', function (event, data) {
|
||||
|
||||
editPerson(context, {}, -1);
|
||||
});
|
||||
|
||||
context.querySelector('#peopleList').addEventListener('click', function (e) {
|
||||
|
||||
let index;
|
||||
const btnDeletePerson = dom.parentWithClass(e.target, 'btnDeletePerson');
|
||||
if (btnDeletePerson) {
|
||||
|
@ -399,8 +369,7 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function getItem(itemId, serverId) {
|
||||
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
if (itemId) {
|
||||
return apiClient.getItem(apiClient.getCurrentUserId(), itemId);
|
||||
|
@ -410,8 +379,7 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function getEditorConfig(itemId, serverId) {
|
||||
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
if (itemId) {
|
||||
return apiClient.getJSON(apiClient.getUrl('Items/' + itemId + '/MetadataEditor'));
|
||||
|
@ -421,13 +389,11 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function populateCountries(select, allCountries) {
|
||||
|
||||
let html = '';
|
||||
|
||||
html += "<option value=''></option>";
|
||||
|
||||
for (let i = 0, length = allCountries.length; i < length; i++) {
|
||||
|
||||
const culture = allCountries[i];
|
||||
|
||||
html += "<option value='" + culture.TwoLetterISORegionName + "'>" + culture.DisplayName + '</option>';
|
||||
|
@ -437,13 +403,11 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function populateLanguages(select, languages) {
|
||||
|
||||
let html = '';
|
||||
|
||||
html += "<option value=''></option>";
|
||||
|
||||
for (let i = 0, length = languages.length; i < length; i++) {
|
||||
|
||||
const culture = languages[i];
|
||||
|
||||
html += "<option value='" + culture.TwoLetterISOLanguageName + "'>" + culture.DisplayName + '</option>';
|
||||
|
@ -453,7 +417,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function renderContentTypeOptions(context, metadataInfo) {
|
||||
|
||||
if (!metadataInfo.ContentTypeOptions.length) {
|
||||
hideElement('#fldContentType', context);
|
||||
} else {
|
||||
|
@ -461,9 +424,7 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
const html = metadataInfo.ContentTypeOptions.map(function (i) {
|
||||
|
||||
return '<option value="' + i.Value + '">' + i.Name + '</option>';
|
||||
|
||||
}).join('');
|
||||
|
||||
const selectEl = context.querySelector('#selectContentType');
|
||||
|
@ -472,13 +433,11 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function loadExternalIds(context, item, externalIds) {
|
||||
|
||||
let html = '';
|
||||
|
||||
const providerIds = item.ProviderIds || {};
|
||||
|
||||
for (let i = 0, length = externalIds.length; i < length; i++) {
|
||||
|
||||
const idInfo = externalIds[i];
|
||||
|
||||
const id = 'txt1' + idInfo.Key;
|
||||
|
@ -524,7 +483,6 @@ import 'flexStyles';
|
|||
function hideElement(selector, context, multiple) {
|
||||
context = context || document;
|
||||
if (typeof selector === 'string') {
|
||||
|
||||
const elements = multiple ? context.querySelectorAll(selector) : [context.querySelector(selector)];
|
||||
|
||||
Array.prototype.forEach.call(elements, function (el) {
|
||||
|
@ -543,7 +501,6 @@ import 'flexStyles';
|
|||
function showElement(selector, context, multiple) {
|
||||
context = context || document;
|
||||
if (typeof selector === 'string') {
|
||||
|
||||
const elements = multiple ? context.querySelectorAll(selector) : [context.querySelector(selector)];
|
||||
|
||||
Array.prototype.forEach.call(elements, function (el) {
|
||||
|
@ -745,7 +702,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function fillItemInfo(context, item, parentalRatingOptions) {
|
||||
|
||||
let select = context.querySelector('#selectOfficialRating');
|
||||
|
||||
populateRatings(parentalRatingOptions, select, item.OfficialRating);
|
||||
|
@ -867,7 +823,6 @@ import 'flexStyles';
|
|||
context.querySelector('#selectCountry').value = item.PreferredMetadataCountryCode || '';
|
||||
|
||||
if (item.RunTimeTicks) {
|
||||
|
||||
const minutes = item.RunTimeTicks / 600000000;
|
||||
|
||||
context.querySelector('#txtSeriesRuntime').value = Math.round(minutes);
|
||||
|
@ -877,7 +832,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function populateRatings(allParentalRatings, select, currentValue) {
|
||||
|
||||
let html = '';
|
||||
|
||||
html += "<option value=''></option>";
|
||||
|
@ -888,7 +842,6 @@ import 'flexStyles';
|
|||
let currentValueFound = false;
|
||||
|
||||
for (let i = 0, length = allParentalRatings.length; i < length; i++) {
|
||||
|
||||
rating = allParentalRatings[i];
|
||||
|
||||
ratings.push({ Name: rating.Name, Value: rating.Name });
|
||||
|
@ -903,7 +856,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
for (let i = 0, length = ratings.length; i < length; i++) {
|
||||
|
||||
rating = ratings[i];
|
||||
|
||||
html += "<option value='" + rating.Value + "'>" + rating.Name + '</option>';
|
||||
|
@ -922,7 +874,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function populateListView(list, items, sortCallback) {
|
||||
|
||||
items = items || [];
|
||||
if (typeof (sortCallback) === 'undefined') {
|
||||
items.sort(function (a, b) {
|
||||
|
@ -954,14 +905,12 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function populatePeople(context, people) {
|
||||
|
||||
let lastType = '';
|
||||
const lastType = '';
|
||||
let html = '';
|
||||
|
||||
const elem = context.querySelector('#peopleList');
|
||||
|
||||
for (let i = 0, length = people.length; i < length; i++) {
|
||||
|
||||
const person = people[i];
|
||||
|
||||
html += '<div class="listItem">';
|
||||
|
@ -991,10 +940,8 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function getLockedFieldsHtml(fields, currentFields) {
|
||||
|
||||
let html = '';
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
|
||||
const field = fields[i];
|
||||
const name = field.name;
|
||||
const value = field.value || field.name;
|
||||
|
@ -1041,11 +988,9 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function reload(context, itemId, serverId) {
|
||||
|
||||
loading.show();
|
||||
|
||||
Promise.all([getItem(itemId, serverId), getEditorConfig(itemId, serverId)]).then(function (responses) {
|
||||
|
||||
const item = responses[0];
|
||||
metadataEditorInfo = responses[1];
|
||||
|
||||
|
@ -1122,7 +1067,7 @@ import 'flexStyles';
|
|||
|
||||
currentContext = dlg;
|
||||
|
||||
init(dlg, connectionManager.getApiClient(serverId));
|
||||
init(dlg, window.connectionManager.getApiClient(serverId));
|
||||
|
||||
reload(dlg, itemId, serverId);
|
||||
});
|
||||
|
@ -1137,7 +1082,6 @@ import 'flexStyles';
|
|||
|
||||
embed: function (elem, itemId, serverId) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
loading.show();
|
||||
|
||||
import('text!./metadataEditor.template.html').then(({default: template}) => {
|
||||
|
@ -1150,7 +1094,7 @@ import 'flexStyles';
|
|||
|
||||
currentContext = elem;
|
||||
|
||||
init(elem, connectionManager.getApiClient(serverId));
|
||||
init(elem, window.connectionManager.getApiClient(serverId));
|
||||
reload(elem, itemId, serverId);
|
||||
|
||||
focusManager.autoFocus(elem);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import dialogHelper from 'dialogHelper';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import require from 'require';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-input';
|
||||
import 'emby-select';
|
||||
|
@ -18,9 +17,7 @@ import 'css!./../formdialog';
|
|||
|
||||
function show(person) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
import('text!./personEditor.template.html').then(({default: template}) => {
|
||||
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
|
@ -54,7 +51,6 @@ import 'css!./../formdialog';
|
|||
dialogHelper.open(dlg);
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
|
||||
}
|
||||
|
@ -67,7 +63,6 @@ import 'css!./../formdialog';
|
|||
});
|
||||
|
||||
dlg.querySelector('.selectPersonType').addEventListener('change', function (e) {
|
||||
|
||||
if (this.value === 'Actor') {
|
||||
dlg.querySelector('.fldRole').classList.remove('hide');
|
||||
} else {
|
||||
|
@ -76,12 +71,10 @@ import 'css!./../formdialog';
|
|||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
dlg.querySelector('form').addEventListener('submit', function (e) {
|
||||
|
||||
submitted = true;
|
||||
|
||||
person.Name = dlg.querySelector('.txtPersonName', dlg).value;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import browser from 'browser';
|
||||
import appHost from 'apphost';
|
||||
import loading from 'loading';
|
||||
import connectionManager from 'connectionManager';
|
||||
import globalize from 'globalize';
|
||||
import dom from 'dom';
|
||||
import 'css!./multiSelect';
|
||||
|
@ -13,10 +12,8 @@ import 'css!./multiSelect';
|
|||
let currentSelectionCommandsPanel;
|
||||
|
||||
function hideSelections() {
|
||||
|
||||
const selectionCommandsPanel = currentSelectionCommandsPanel;
|
||||
if (selectionCommandsPanel) {
|
||||
|
||||
selectionCommandsPanel.parentNode.removeChild(selectionCommandsPanel);
|
||||
currentSelectionCommandsPanel = null;
|
||||
|
||||
|
@ -24,7 +21,6 @@ import 'css!./multiSelect';
|
|||
selectedElements = [];
|
||||
const elems = document.querySelectorAll('.itemSelectionPanel');
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
const parent = elems[i].parentNode;
|
||||
parent.removeChild(elems[i]);
|
||||
parent.classList.remove('withMultiSelect');
|
||||
|
@ -33,13 +29,11 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
function onItemSelectionPanelClick(e, itemSelectionPanel) {
|
||||
|
||||
// toggle the checkbox, if it wasn't clicked on
|
||||
if (!dom.parentWithClass(e.target, 'chkItemSelect')) {
|
||||
const chkItemSelect = itemSelectionPanel.querySelector('.chkItemSelect');
|
||||
|
||||
if (chkItemSelect) {
|
||||
|
||||
if (chkItemSelect.classList.contains('checkedInitial')) {
|
||||
chkItemSelect.classList.remove('checkedInitial');
|
||||
} else {
|
||||
|
@ -56,11 +50,9 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
function updateItemSelection(chkItemSelect, selected) {
|
||||
|
||||
const id = dom.parentWithAttribute(chkItemSelect, 'data-id').getAttribute('data-id');
|
||||
|
||||
if (selected) {
|
||||
|
||||
const current = selectedItems.filter(i => {
|
||||
return i === id;
|
||||
});
|
||||
|
@ -69,7 +61,6 @@ import 'css!./multiSelect';
|
|||
selectedItems.push(id);
|
||||
selectedElements.push(chkItemSelect);
|
||||
}
|
||||
|
||||
} else {
|
||||
selectedItems = selectedItems.filter(i => {
|
||||
return i !== id;
|
||||
|
@ -94,11 +85,9 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
function showSelection(item, isChecked) {
|
||||
|
||||
let itemSelectionPanel = item.querySelector('.itemSelectionPanel');
|
||||
|
||||
if (!itemSelectionPanel) {
|
||||
|
||||
itemSelectionPanel = document.createElement('div');
|
||||
itemSelectionPanel.classList.add('itemSelectionPanel');
|
||||
|
||||
|
@ -120,11 +109,9 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
function showSelectionCommands() {
|
||||
|
||||
let selectionCommandsPanel = currentSelectionCommandsPanel;
|
||||
|
||||
if (!selectionCommandsPanel) {
|
||||
|
||||
selectionCommandsPanel = document.createElement('div');
|
||||
selectionCommandsPanel.classList.add('selectionCommandsPanel');
|
||||
|
||||
|
@ -150,9 +137,7 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
function alertText(options) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert(options).then(resolve, resolve);
|
||||
});
|
||||
|
@ -160,9 +145,7 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
function deleteItems(apiClient, itemIds) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let msg = globalize.translate('ConfirmDeleteItem');
|
||||
let title = globalize.translate('HeaderDeleteItem');
|
||||
|
||||
|
@ -172,28 +155,23 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
import('confirm').then(({default: confirm}) => {
|
||||
|
||||
confirm(msg, title).then(() => {
|
||||
const promises = itemIds.map(itemId => {
|
||||
apiClient.deleteItem(itemId);
|
||||
});
|
||||
|
||||
Promise.all(promises).then(resolve, () => {
|
||||
|
||||
alertText(globalize.translate('ErrorDeletingItem')).then(reject, reject);
|
||||
});
|
||||
}, reject);
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function showMenuForSelectedItems(e) {
|
||||
|
||||
const apiClient = connectionManager.currentApiClient();
|
||||
const apiClient = window.connectionManager.currentApiClient();
|
||||
|
||||
apiClient.getCurrentUser().then(user => {
|
||||
|
||||
const menuItems = [];
|
||||
|
||||
menuItems.push({
|
||||
|
@ -219,7 +197,7 @@ import 'css!./multiSelect';
|
|||
|
||||
if (user.Policy.EnableContentDownloading && appHost.supports('filedownload')) {
|
||||
menuItems.push({
|
||||
name: globalize.translate('ButtonDownload'),
|
||||
name: globalize.translate('Download'),
|
||||
id: 'download',
|
||||
icon: 'file_download'
|
||||
});
|
||||
|
@ -317,17 +295,14 @@ import 'css!./multiSelect';
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function dispatchNeedsRefresh() {
|
||||
|
||||
const elems = [];
|
||||
|
||||
[].forEach.call(selectedElements, i => {
|
||||
|
||||
const container = dom.parentWithAttribute(i, 'is', 'emby-itemscontainer');
|
||||
|
||||
if (container && !elems.includes(container)) {
|
||||
|
@ -341,9 +316,7 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
function combineVersions(apiClient, selection) {
|
||||
|
||||
if (selection.length < 2) {
|
||||
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert({
|
||||
|
||||
|
@ -361,7 +334,6 @@ import 'css!./multiSelect';
|
|||
url: apiClient.getUrl('Videos/MergeVersions', { Ids: selection.join(',') })
|
||||
|
||||
}).then(() => {
|
||||
|
||||
loading.hide();
|
||||
hideSelections();
|
||||
dispatchNeedsRefresh();
|
||||
|
@ -369,7 +341,6 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
function showSelections(initialCard) {
|
||||
|
||||
import('emby-checkbox').then(() => {
|
||||
const cards = document.querySelectorAll('.card');
|
||||
for (let i = 0, length = cards.length; i < length; i++) {
|
||||
|
@ -382,11 +353,9 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
function onContainerClick(e) {
|
||||
|
||||
const target = e.target;
|
||||
|
||||
if (selectedItems.length) {
|
||||
|
||||
const card = dom.parentWithClass(target, 'card');
|
||||
if (card) {
|
||||
const itemSelectionPanel = card.querySelector('.itemSelectionPanel');
|
||||
|
@ -404,17 +373,14 @@ import 'css!./multiSelect';
|
|||
document.addEventListener('viewbeforehide', hideSelections);
|
||||
|
||||
export default function (options) {
|
||||
|
||||
const self = this;
|
||||
|
||||
const container = options.container;
|
||||
|
||||
function onTapHold(e) {
|
||||
|
||||
const card = dom.parentWithClass(e.target, 'card');
|
||||
|
||||
if (card) {
|
||||
|
||||
showSelections(card);
|
||||
}
|
||||
|
||||
|
@ -427,7 +393,6 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
function getTouches(e) {
|
||||
|
||||
return e.changedTouches || e.targetTouches || e.touches;
|
||||
}
|
||||
|
||||
|
@ -436,7 +401,6 @@ import 'css!./multiSelect';
|
|||
let touchStartX;
|
||||
let touchStartY;
|
||||
function onTouchStart(e) {
|
||||
|
||||
const touch = getTouches(e)[0];
|
||||
touchTarget = null;
|
||||
touchStartX = 0;
|
||||
|
@ -451,7 +415,6 @@ import 'css!./multiSelect';
|
|||
const card = dom.parentWithClass(element, 'card');
|
||||
|
||||
if (card) {
|
||||
|
||||
if (touchStartTimeout) {
|
||||
clearTimeout(touchStartTimeout);
|
||||
touchStartTimeout = null;
|
||||
|
@ -465,7 +428,6 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
function onTouchMove(e) {
|
||||
|
||||
if (touchTarget) {
|
||||
const touch = getTouches(e)[0];
|
||||
let deltaX;
|
||||
|
@ -487,12 +449,10 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
function onTouchEnd(e) {
|
||||
|
||||
onMouseOut(e);
|
||||
}
|
||||
|
||||
function onMouseDown(e) {
|
||||
|
||||
if (touchStartTimeout) {
|
||||
clearTimeout(touchStartTimeout);
|
||||
touchStartTimeout = null;
|
||||
|
@ -503,7 +463,6 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
function onMouseOut(e) {
|
||||
|
||||
if (touchStartTimeout) {
|
||||
clearTimeout(touchStartTimeout);
|
||||
touchStartTimeout = null;
|
||||
|
@ -512,7 +471,6 @@ import 'css!./multiSelect';
|
|||
}
|
||||
|
||||
function onTouchStartTimerFired() {
|
||||
|
||||
if (!touchTarget) {
|
||||
return;
|
||||
}
|
||||
|
@ -521,13 +479,11 @@ import 'css!./multiSelect';
|
|||
touchTarget = null;
|
||||
|
||||
if (card) {
|
||||
|
||||
showSelections(card);
|
||||
}
|
||||
}
|
||||
|
||||
function initTapHold(element) {
|
||||
|
||||
// mobile safari doesn't allow contextmenu override
|
||||
if (browser.touch && !browser.safari) {
|
||||
element.addEventListener('contextmenu', onTapHold);
|
||||
|
@ -565,7 +521,6 @@ import 'css!./multiSelect';
|
|||
self.onContainerClick = onContainerClick;
|
||||
|
||||
self.destroy = () => {
|
||||
|
||||
container.removeEventListener('click', onContainerClick);
|
||||
container.removeEventListener('contextmenu', onTapHold);
|
||||
|
||||
|
@ -580,10 +535,6 @@ import 'css!./multiSelect';
|
|||
dom.removeEventListener(element, 'touchend', onTouchEnd, {
|
||||
passive: true
|
||||
});
|
||||
// this fires in safari due to magnifying class
|
||||
//dom.removeEventListener(element, "touchcancel", onTouchEnd, {
|
||||
// passive: true
|
||||
//});
|
||||
dom.removeEventListener(element, 'mousedown', onMouseDown, {
|
||||
passive: true
|
||||
});
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'require'], function (serverNotifications, playbackManager, events, globalize, require) {
|
||||
'use strict';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import playbackManager from 'playbackManager';
|
||||
import events from 'events';
|
||||
import globalize from 'globalize';
|
||||
|
||||
function onOneDocumentClick() {
|
||||
function onOneDocumentClick() {
|
||||
document.removeEventListener('click', onOneDocumentClick);
|
||||
document.removeEventListener('keydown', onOneDocumentClick);
|
||||
|
||||
|
@ -10,14 +12,14 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
|
|||
/* eslint-disable-next-line compat/compat */
|
||||
Notification.requestPermission();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', onOneDocumentClick);
|
||||
document.addEventListener('keydown', onOneDocumentClick);
|
||||
document.addEventListener('click', onOneDocumentClick);
|
||||
document.addEventListener('keydown', onOneDocumentClick);
|
||||
|
||||
var serviceWorkerRegistration;
|
||||
let serviceWorkerRegistration;
|
||||
|
||||
function closeAfter(notification, timeoutMs) {
|
||||
function closeAfter(notification, timeoutMs) {
|
||||
setTimeout(function () {
|
||||
if (notification.close) {
|
||||
notification.close();
|
||||
|
@ -25,28 +27,27 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
|
|||
notification.cancel();
|
||||
}
|
||||
}, timeoutMs);
|
||||
}
|
||||
}
|
||||
|
||||
function resetRegistration() {
|
||||
function resetRegistration() {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
var serviceWorker = navigator.serviceWorker;
|
||||
let serviceWorker = navigator.serviceWorker;
|
||||
if (serviceWorker) {
|
||||
serviceWorker.ready.then(function (registration) {
|
||||
serviceWorkerRegistration = registration;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resetRegistration();
|
||||
resetRegistration();
|
||||
|
||||
function showPersistentNotification(title, options, timeoutMs) {
|
||||
function showPersistentNotification(title, options, timeoutMs) {
|
||||
serviceWorkerRegistration.showNotification(title, options);
|
||||
}
|
||||
|
||||
function showNonPersistentNotification(title, options, timeoutMs) {
|
||||
}
|
||||
|
||||
function showNonPersistentNotification(title, options, timeoutMs) {
|
||||
try {
|
||||
var notif = new Notification(title, options); /* eslint-disable-line compat/compat */
|
||||
let notif = new Notification(title, options); /* eslint-disable-line compat/compat */
|
||||
|
||||
if (notif.show) {
|
||||
notif.show();
|
||||
|
@ -63,11 +64,10 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
|
|||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showNotification(options, timeoutMs, apiClient) {
|
||||
|
||||
var title = options.title;
|
||||
function showNotification(options, timeoutMs, apiClient) {
|
||||
let title = options.title;
|
||||
|
||||
options.data = options.data || {};
|
||||
options.data.serverId = apiClient.serverInfo().Id;
|
||||
|
@ -82,36 +82,30 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
|
|||
}
|
||||
|
||||
showNonPersistentNotification(title, options, timeoutMs);
|
||||
}
|
||||
|
||||
function showNewItemNotification(item, apiClient) {
|
||||
}
|
||||
|
||||
function showNewItemNotification(item, apiClient) {
|
||||
if (playbackManager.isPlayingLocally(['Video'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
var body = item.Name;
|
||||
let body = item.Name;
|
||||
|
||||
if (item.SeriesName) {
|
||||
body = item.SeriesName + ' - ' + body;
|
||||
}
|
||||
|
||||
var notification = {
|
||||
let notification = {
|
||||
title: 'New ' + item.Type,
|
||||
body: body,
|
||||
vibrate: true,
|
||||
tag: 'newItem' + item.Id,
|
||||
data: {
|
||||
//options: {
|
||||
// url: LibraryBrowser.getHref(item)
|
||||
//}
|
||||
}
|
||||
data: {}
|
||||
};
|
||||
|
||||
var imageTags = item.ImageTags || {};
|
||||
let imageTags = item.ImageTags || {};
|
||||
|
||||
if (imageTags.Primary) {
|
||||
|
||||
notification.icon = apiClient.getScaledImageUrl(item.Id, {
|
||||
width: 80,
|
||||
tag: imageTags.Primary,
|
||||
|
@ -120,11 +114,10 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
|
|||
}
|
||||
|
||||
showNotification(notification, 15000, apiClient);
|
||||
}
|
||||
}
|
||||
|
||||
function onLibraryChanged(data, apiClient) {
|
||||
|
||||
var newItems = data.ItemsAdded;
|
||||
function onLibraryChanged(data, apiClient) {
|
||||
let newItems = data.ItemsAdded;
|
||||
|
||||
if (!newItems.length) {
|
||||
return;
|
||||
|
@ -147,30 +140,26 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
|
|||
EnableTotalRecordCount: false
|
||||
|
||||
}).then(function (result) {
|
||||
let items = result.Items;
|
||||
|
||||
var items = result.Items;
|
||||
|
||||
for (var i = 0, length = items.length ; i < length; i++) {
|
||||
|
||||
showNewItemNotification(items[i], apiClient);
|
||||
for (const item of items) {
|
||||
showNewItemNotification(item, apiClient);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getIconUrl(name) {
|
||||
function getIconUrl(name) {
|
||||
name = name || 'notificationicon.png';
|
||||
return require.toUrl('.').split('?')[0] + '/' + name;
|
||||
}
|
||||
|
||||
function showPackageInstallNotification(apiClient, installation, status) {
|
||||
return './components/notifications/' + name;
|
||||
}
|
||||
|
||||
function showPackageInstallNotification(apiClient, installation, status) {
|
||||
apiClient.getCurrentUser().then(function (user) {
|
||||
|
||||
if (!user.Policy.IsAdministrator) {
|
||||
return;
|
||||
}
|
||||
|
||||
var notification = {
|
||||
let notification = {
|
||||
tag: 'install' + installation.Id,
|
||||
data: {}
|
||||
};
|
||||
|
@ -199,60 +188,58 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
|
|||
}
|
||||
|
||||
if (status === 'progress') {
|
||||
|
||||
var percentComplete = Math.round(installation.PercentComplete || 0);
|
||||
let percentComplete = Math.round(installation.PercentComplete || 0);
|
||||
|
||||
notification.body = percentComplete + '% complete.';
|
||||
}
|
||||
|
||||
var timeout = status === 'cancelled' ? 5000 : 0;
|
||||
let timeout = status === 'cancelled' ? 5000 : 0;
|
||||
|
||||
showNotification(notification, timeout, apiClient);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
events.on(serverNotifications, 'LibraryChanged', function (e, apiClient, data) {
|
||||
events.on(serverNotifications, 'LibraryChanged', function (e, apiClient, data) {
|
||||
onLibraryChanged(data, apiClient);
|
||||
});
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'PackageInstallationCompleted', function (e, apiClient, data) {
|
||||
events.on(serverNotifications, 'PackageInstallationCompleted', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'completed');
|
||||
});
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'PackageInstallationFailed', function (e, apiClient, data) {
|
||||
events.on(serverNotifications, 'PackageInstallationFailed', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'failed');
|
||||
});
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'PackageInstallationCancelled', function (e, apiClient, data) {
|
||||
events.on(serverNotifications, 'PackageInstallationCancelled', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'cancelled');
|
||||
});
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'PackageInstalling', function (e, apiClient, data) {
|
||||
events.on(serverNotifications, 'PackageInstalling', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'progress');
|
||||
});
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'ServerShuttingDown', function (e, apiClient, data) {
|
||||
var serverId = apiClient.serverInfo().Id;
|
||||
var notification = {
|
||||
events.on(serverNotifications, 'ServerShuttingDown', function (e, apiClient, data) {
|
||||
let serverId = apiClient.serverInfo().Id;
|
||||
let notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('ServerNameIsShuttingDown', apiClient.serverInfo().Name)
|
||||
};
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'ServerRestarting', function (e, apiClient, data) {
|
||||
var serverId = apiClient.serverInfo().Id;
|
||||
var notification = {
|
||||
events.on(serverNotifications, 'ServerRestarting', function (e, apiClient, data) {
|
||||
let serverId = apiClient.serverInfo().Id;
|
||||
let notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('ServerNameIsRestarting', apiClient.serverInfo().Name)
|
||||
};
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'RestartRequired', function (e, apiClient) {
|
||||
|
||||
var serverId = apiClient.serverInfo().Id;
|
||||
var notification = {
|
||||
events.on(serverNotifications, 'RestartRequired', function (e, apiClient) {
|
||||
let serverId = apiClient.serverInfo().Id;
|
||||
let notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('PleaseRestartServerName', apiClient.serverInfo().Name)
|
||||
};
|
||||
|
@ -261,11 +248,11 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
|
|||
[
|
||||
{
|
||||
action: 'restart',
|
||||
title: globalize.translate('ButtonRestart'),
|
||||
title: globalize.translate('Restart'),
|
||||
icon: getIconUrl()
|
||||
}
|
||||
];
|
||||
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import require from 'require';
|
||||
import datetime from 'datetime';
|
||||
import itemHelper from 'itemHelper';
|
||||
import events from 'events';
|
||||
import browser from 'browser';
|
||||
import imageLoader from 'imageLoader';
|
||||
|
@ -9,7 +7,6 @@ import playbackManager from 'playbackManager';
|
|||
import nowPlayingHelper from 'nowPlayingHelper';
|
||||
import appHost from 'apphost';
|
||||
import dom from 'dom';
|
||||
import connectionManager from 'connectionManager';
|
||||
import itemContextMenu from 'itemContextMenu';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-ratingbutton';
|
||||
|
@ -39,7 +36,6 @@ import 'emby-ratingbutton';
|
|||
let isVisibilityAllowed = true;
|
||||
|
||||
function getNowPlayingBarHtml() {
|
||||
|
||||
let html = '';
|
||||
|
||||
html += '<div class="nowPlayingBar hide nowPlayingBar-hidden">';
|
||||
|
@ -99,12 +95,10 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
function onSlideDownComplete() {
|
||||
|
||||
this.classList.add('hide');
|
||||
}
|
||||
|
||||
function slideDown(elem) {
|
||||
|
||||
// trigger reflow
|
||||
void elem.offsetWidth;
|
||||
|
||||
|
@ -116,7 +110,6 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
function slideUp(elem) {
|
||||
|
||||
dom.removeEventListener(elem, dom.whichTransitionEvent(), onSlideDownComplete, {
|
||||
once: true
|
||||
});
|
||||
|
@ -134,7 +127,6 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
function bindEvents(elem) {
|
||||
|
||||
currentTimeElement = elem.querySelector('.nowPlayingBarCurrentTime');
|
||||
nowPlayingImageElement = elem.querySelector('.nowPlayingImage');
|
||||
nowPlayingTextElement = elem.querySelector('.nowPlayingBarText');
|
||||
|
@ -147,15 +139,12 @@ import 'emby-ratingbutton';
|
|||
volumeSliderContainer = elem.querySelector('.nowPlayingBarVolumeSliderContainer');
|
||||
|
||||
muteButton.addEventListener('click', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
playbackManager.toggleMute(currentPlayer);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
elem.querySelector('.stopButton').addEventListener('click', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
playbackManager.stop(currentPlayer);
|
||||
}
|
||||
|
@ -166,7 +155,6 @@ import 'emby-ratingbutton';
|
|||
});
|
||||
|
||||
elem.querySelector('.nextTrackButton').addEventListener('click', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
playbackManager.nextTrack(currentPlayer);
|
||||
}
|
||||
|
@ -226,18 +214,14 @@ import 'emby-ratingbutton';
|
|||
});
|
||||
|
||||
positionSlider.addEventListener('change', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
|
||||
const newPercent = parseFloat(this.value);
|
||||
|
||||
playbackManager.seekPercent(newPercent, currentPlayer);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
positionSlider.getBubbleText = function (value) {
|
||||
|
||||
const state = lastPlayerState;
|
||||
|
||||
if (!state || !state.NowPlayingItem || !currentRuntimeTicks) {
|
||||
|
@ -252,7 +236,6 @@ import 'emby-ratingbutton';
|
|||
};
|
||||
|
||||
elem.addEventListener('click', function (e) {
|
||||
|
||||
if (!dom.parentWithTag(e.target, ['BUTTON', 'INPUT'])) {
|
||||
showRemoteControl();
|
||||
}
|
||||
|
@ -260,7 +243,6 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
function showRemoteControl() {
|
||||
|
||||
import('appRouter').then(({default: appRouter}) => {
|
||||
appRouter.showNowPlaying();
|
||||
});
|
||||
|
@ -268,7 +250,6 @@ import 'emby-ratingbutton';
|
|||
|
||||
let nowPlayingBarElement;
|
||||
function getNowPlayingBar() {
|
||||
|
||||
if (nowPlayingBarElement) {
|
||||
return Promise.resolve(nowPlayingBarElement);
|
||||
}
|
||||
|
@ -329,7 +310,6 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
function updatePlayerStateInternal(event, state, player) {
|
||||
|
||||
showNowPlayingBar();
|
||||
|
||||
lastPlayerState = state;
|
||||
|
@ -417,7 +397,6 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
function updatePlayerVolumeState(isMuted, volumeLevel) {
|
||||
|
||||
const supportedCommands = currentPlayerSupportedCommands;
|
||||
|
||||
let showMuteButton = true;
|
||||
|
@ -448,7 +427,6 @@ import 'emby-ratingbutton';
|
|||
|
||||
// See bindEvents for why this is necessary
|
||||
if (volumeSlider) {
|
||||
|
||||
volumeSliderContainer.classList.toggle('hide', !showVolumeSlider);
|
||||
|
||||
if (!volumeSlider.dragging) {
|
||||
|
@ -458,7 +436,6 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
function seriesImageUrl(item, options) {
|
||||
|
||||
if (!item) {
|
||||
throw new Error('item cannot be null!');
|
||||
}
|
||||
|
@ -471,28 +448,23 @@ import 'emby-ratingbutton';
|
|||
options.type = options.type || 'Primary';
|
||||
|
||||
if (options.type === 'Primary') {
|
||||
|
||||
if (item.SeriesPrimaryImageTag) {
|
||||
|
||||
options.tag = item.SeriesPrimaryImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.type === 'Thumb') {
|
||||
|
||||
if (item.SeriesThumbImageTag) {
|
||||
|
||||
options.tag = item.SeriesThumbImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
}
|
||||
if (item.ParentThumbImageTag) {
|
||||
|
||||
options.tag = item.ParentThumbImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,7 +472,6 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
function imageUrl(item, options) {
|
||||
|
||||
if (!item) {
|
||||
throw new Error('item cannot be null!');
|
||||
}
|
||||
|
@ -509,15 +480,13 @@ import 'emby-ratingbutton';
|
|||
options.type = options.type || 'Primary';
|
||||
|
||||
if (item.ImageTags && item.ImageTags[options.type]) {
|
||||
|
||||
options.tag = item.ImageTags[options.type];
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options);
|
||||
}
|
||||
|
||||
if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
|
||||
options.tag = item.AlbumPrimaryImageTag;
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -525,26 +494,25 @@ import 'emby-ratingbutton';
|
|||
|
||||
let currentImgUrl;
|
||||
function updateNowPlayingInfo(state) {
|
||||
|
||||
const nowPlayingItem = state.NowPlayingItem;
|
||||
|
||||
const textLines = nowPlayingItem ? nowPlayingHelper.getNowPlayingNames(nowPlayingItem) : [];
|
||||
nowPlayingTextElement.innerHTML = '';
|
||||
if (textLines) {
|
||||
let itemText = document.createElement('div');
|
||||
let secondaryText = document.createElement('div');
|
||||
const itemText = document.createElement('div');
|
||||
const secondaryText = document.createElement('div');
|
||||
secondaryText.classList.add('nowPlayingBarSecondaryText');
|
||||
if (textLines.length > 1) {
|
||||
textLines[1].secondary = true;
|
||||
if (textLines[1].text) {
|
||||
let text = document.createElement('a');
|
||||
const text = document.createElement('a');
|
||||
text.innerHTML = textLines[1].text;
|
||||
secondaryText.appendChild(text);
|
||||
}
|
||||
}
|
||||
|
||||
if (textLines[0].text) {
|
||||
let text = document.createElement('a');
|
||||
const text = document.createElement('a');
|
||||
text.innerHTML = textLines[0].text;
|
||||
itemText.appendChild(text);
|
||||
}
|
||||
|
@ -579,18 +547,17 @@ import 'emby-ratingbutton';
|
|||
|
||||
if (nowPlayingItem.Id) {
|
||||
if (isRefreshing) {
|
||||
|
||||
const apiClient = connectionManager.getApiClient(nowPlayingItem.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(nowPlayingItem.ServerId);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), nowPlayingItem.Id).then(function (item) {
|
||||
const userData = item.UserData || {};
|
||||
const likes = userData.Likes == null ? '' : userData.Likes;
|
||||
if (!layoutManager.mobile) {
|
||||
let contextButton = nowPlayingBarElement.querySelector('.btnToggleContextMenu');
|
||||
// We remove the previous event listener by replacing the item in each update event
|
||||
let contextButtonClone = contextButton.cloneNode(true);
|
||||
const contextButtonClone = contextButton.cloneNode(true);
|
||||
contextButton.parentNode.replaceChild(contextButtonClone, contextButton);
|
||||
contextButton = nowPlayingBarElement.querySelector('.btnToggleContextMenu');
|
||||
let options = {
|
||||
const options = {
|
||||
play: false,
|
||||
queue: false,
|
||||
clearQueue: true,
|
||||
|
@ -632,10 +599,10 @@ import 'emby-ratingbutton';
|
|||
return;
|
||||
}
|
||||
|
||||
let shuffleMode = playbackManager.getQueueShuffleMode();
|
||||
let context = nowPlayingBarElement;
|
||||
const shuffleMode = playbackManager.getQueueShuffleMode();
|
||||
const context = nowPlayingBarElement;
|
||||
const cssClass = 'buttonActive';
|
||||
let toggleShuffleButton = context.querySelector('.btnShuffleQueue');
|
||||
const toggleShuffleButton = context.querySelector('.btnShuffleQueue');
|
||||
switch (shuffleMode) {
|
||||
case 'Shuffle':
|
||||
toggleShuffleButton.classList.add(cssClass);
|
||||
|
@ -657,7 +624,6 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
function hideNowPlayingBar() {
|
||||
|
||||
isEnabled = false;
|
||||
|
||||
// Use a timeout to prevent the bar from hiding and showing quickly
|
||||
|
@ -666,13 +632,11 @@ import 'emby-ratingbutton';
|
|||
// Don't call getNowPlayingBar here because we don't want to end up creating it just to hide it
|
||||
const elem = document.getElementsByClassName('nowPlayingBar')[0];
|
||||
if (elem) {
|
||||
|
||||
slideDown(elem);
|
||||
}
|
||||
}
|
||||
|
||||
function onPlaybackStopped(e, state) {
|
||||
|
||||
console.debug('nowplaying event: ' + e.type);
|
||||
const player = this;
|
||||
|
||||
|
@ -688,7 +652,6 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
function onPlayPauseStateChanged(e) {
|
||||
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
@ -698,7 +661,6 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
function onStateChanged(event, state) {
|
||||
|
||||
console.debug('nowplaying event: ' + event.type);
|
||||
const player = this;
|
||||
|
||||
|
@ -725,7 +687,6 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
function onTimeUpdate(e) {
|
||||
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
@ -733,18 +694,16 @@ import 'emby-ratingbutton';
|
|||
// Try to avoid hammering the document with changes
|
||||
const now = new Date().getTime();
|
||||
if ((now - lastUpdateTime) < 700) {
|
||||
|
||||
return;
|
||||
}
|
||||
lastUpdateTime = now;
|
||||
|
||||
const player = this;
|
||||
currentRuntimeTicks = playbackManager.duration(player);
|
||||
updateTimeDisplay(playbackManager.currentTime(player), currentRuntimeTicks, playbackManager.getBufferedRanges(player));
|
||||
updateTimeDisplay(playbackManager.currentTime(player) * 10000, currentRuntimeTicks, playbackManager.getBufferedRanges(player));
|
||||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
|
||||
const player = currentPlayer;
|
||||
|
||||
if (player) {
|
||||
|
@ -764,7 +723,6 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
function onVolumeChanged(e) {
|
||||
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
@ -775,14 +733,12 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
function refreshFromPlayer(player) {
|
||||
|
||||
const state = playbackManager.getPlayerState(player);
|
||||
|
||||
onStateChanged.call(player, { type: 'init' }, state);
|
||||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
|
||||
if (player === currentPlayer) {
|
||||
return;
|
||||
}
|
||||
|
@ -815,16 +771,12 @@ import 'emby-ratingbutton';
|
|||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
|
||||
document.addEventListener('viewbeforeshow', function (e) {
|
||||
|
||||
if (!e.detail.options.enableMediaControl) {
|
||||
|
||||
if (isVisibilityAllowed) {
|
||||
isVisibilityAllowed = false;
|
||||
hideNowPlayingBar();
|
||||
}
|
||||
|
||||
} else if (!isVisibilityAllowed) {
|
||||
|
||||
isVisibilityAllowed = true;
|
||||
if (currentPlayer) {
|
||||
refreshFromPlayer(currentPlayer);
|
||||
|
|
|
@ -1,141 +1,65 @@
|
|||
define(['appSettings', 'pluginManager'], function (appSettings, pluginManager) {
|
||||
'use strict';
|
||||
import appSettings from 'appSettings';
|
||||
import pluginManager from 'pluginManager';
|
||||
/* eslint-disable indent */
|
||||
|
||||
var settingsKey = 'installedpackages1';
|
||||
class PackageManager {
|
||||
#packagesList = [];
|
||||
#settingsKey = 'installedpackages1';
|
||||
|
||||
function addPackage(packageManager, pkg) {
|
||||
init() {
|
||||
console.groupCollapsed('loading packages');
|
||||
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
|
||||
|
||||
packageManager.packagesList = packageManager.packagesList.filter(function (p) {
|
||||
|
||||
return p.name !== pkg.name;
|
||||
});
|
||||
|
||||
packageManager.packagesList.push(pkg);
|
||||
}
|
||||
|
||||
function removeUrl(url) {
|
||||
|
||||
var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]');
|
||||
|
||||
manifestUrls = manifestUrls.filter(function (i) {
|
||||
return i !== url;
|
||||
});
|
||||
|
||||
appSettings.set(settingsKey, JSON.stringify(manifestUrls));
|
||||
}
|
||||
|
||||
function loadPackage(packageManager, url, throwError) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
var originalUrl = url;
|
||||
url += url.indexOf('?') === -1 ? '?' : '&';
|
||||
url += 't=' + new Date().getTime();
|
||||
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
var onError = function () {
|
||||
|
||||
if (throwError === true) {
|
||||
reject();
|
||||
} else {
|
||||
removeUrl(originalUrl);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onload = function (e) {
|
||||
if (this.status < 400) {
|
||||
|
||||
var pkg = JSON.parse(this.response);
|
||||
pkg.url = originalUrl;
|
||||
|
||||
addPackage(packageManager, pkg);
|
||||
|
||||
var plugins = pkg.plugins || [];
|
||||
if (pkg.plugin) {
|
||||
plugins.push(pkg.plugin);
|
||||
}
|
||||
var promises = plugins.map(function (pluginUrl) {
|
||||
return pluginManager.loadPlugin(packageManager.mapPath(pkg, pluginUrl));
|
||||
});
|
||||
Promise.all(promises).then(resolve, resolve);
|
||||
|
||||
} else {
|
||||
onError();
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = onError;
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
function PackageManager() {
|
||||
|
||||
this.packagesList = [];
|
||||
}
|
||||
|
||||
PackageManager.prototype.init = function () {
|
||||
var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]');
|
||||
|
||||
var instance = this;
|
||||
return Promise.all(manifestUrls.map(function (u) {
|
||||
|
||||
return loadPackage(instance, u);
|
||||
|
||||
})).then(function () {
|
||||
return Promise.all(manifestUrls.map((url) => {
|
||||
return this.loadPackage(url);
|
||||
}))
|
||||
.then(() => {
|
||||
console.debug('finished loading packages');
|
||||
return Promise.resolve();
|
||||
}, function () {
|
||||
})
|
||||
.catch(() => {
|
||||
return Promise.resolve();
|
||||
}).finally(() => {
|
||||
console.groupEnd('loading packages');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
PackageManager.prototype.packages = function () {
|
||||
return this.packagesList.slice(0);
|
||||
};
|
||||
get packages() {
|
||||
return this.#packagesList.slice(0);
|
||||
}
|
||||
|
||||
PackageManager.prototype.install = function (url) {
|
||||
install(url) {
|
||||
return this.loadPackage(url, true).then((pkg) => {
|
||||
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
|
||||
|
||||
return loadPackage(this, url, true).then(function (pkg) {
|
||||
|
||||
var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]');
|
||||
|
||||
if (manifestUrls.indexOf(url) === -1) {
|
||||
if (!manifestUrls.includes(url)) {
|
||||
manifestUrls.push(url);
|
||||
appSettings.set(settingsKey, JSON.stringify(manifestUrls));
|
||||
appSettings.set(this.#settingsKey, JSON.stringify(manifestUrls));
|
||||
}
|
||||
|
||||
return pkg;
|
||||
});
|
||||
};
|
||||
|
||||
PackageManager.prototype.uninstall = function (name) {
|
||||
|
||||
var pkg = this.packagesList.filter(function (p) {
|
||||
}
|
||||
|
||||
uninstall(name) {
|
||||
var pkg = this.#packagesList.filter((p) => {
|
||||
return p.name === name;
|
||||
})[0];
|
||||
|
||||
if (pkg) {
|
||||
|
||||
this.packagesList = this.packagesList.filter(function (p) {
|
||||
|
||||
this.#packagesList = this.#packagesList.filter((p) => {
|
||||
return p.name !== name;
|
||||
});
|
||||
|
||||
removeUrl(pkg.url);
|
||||
this.removeUrl(pkg.url);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
PackageManager.prototype.mapPath = function (pkg, pluginUrl) {
|
||||
}
|
||||
|
||||
mapPath(pkg, pluginUrl) {
|
||||
var urlLower = pluginUrl.toLowerCase();
|
||||
if (urlLower.indexOf('http:') === 0 || urlLower.indexOf('https:') === 0 || urlLower.indexOf('file:') === 0) {
|
||||
if (urlLower.startsWith('http:') || urlLower.startsWith('https:') || urlLower.startsWith('file:')) {
|
||||
return pluginUrl;
|
||||
}
|
||||
|
||||
|
@ -146,7 +70,71 @@ define(['appSettings', 'pluginManager'], function (appSettings, pluginManager) {
|
|||
packageUrl += pluginUrl;
|
||||
|
||||
return packageUrl;
|
||||
}
|
||||
|
||||
addPackage(pkg) {
|
||||
this.#packagesList = this.#packagesList.filter((p) => {
|
||||
return p.name !== pkg.name;
|
||||
});
|
||||
|
||||
this.#packagesList.push(pkg);
|
||||
}
|
||||
|
||||
removeUrl(url) {
|
||||
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
|
||||
|
||||
manifestUrls = manifestUrls.filter((i) => {
|
||||
return i !== url;
|
||||
});
|
||||
|
||||
appSettings.set(this.#settingsKey, JSON.stringify(manifestUrls));
|
||||
}
|
||||
|
||||
loadPackage(url, throwError = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var xhr = new XMLHttpRequest();
|
||||
var originalUrl = url;
|
||||
url += url.indexOf('?') === -1 ? '?' : '&';
|
||||
url += 't=' + new Date().getTime();
|
||||
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
var onError = () => {
|
||||
if (throwError === true) {
|
||||
reject();
|
||||
} else {
|
||||
this.removeUrl(originalUrl);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
return new PackageManager();
|
||||
});
|
||||
xhr.onload = () => {
|
||||
if (this.status < 400) {
|
||||
var pkg = JSON.parse(this.response);
|
||||
pkg.url = originalUrl;
|
||||
|
||||
this.addPackage(pkg);
|
||||
|
||||
var plugins = pkg.plugins || [];
|
||||
if (pkg.plugin) {
|
||||
plugins.push(pkg.plugin);
|
||||
}
|
||||
var promises = plugins.map((pluginUrl) => {
|
||||
return pluginManager.loadPlugin(this.mapPath(pkg, pluginUrl));
|
||||
});
|
||||
Promise.all(promises).then(resolve, resolve);
|
||||
} else {
|
||||
onError();
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = onError;
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default new PackageManager();
|
||||
|
|
|
@ -23,10 +23,8 @@ function getOsdElementHtml() {
|
|||
}
|
||||
|
||||
function ensureOsdElement() {
|
||||
|
||||
var elem = osdElement;
|
||||
if (!elem) {
|
||||
|
||||
enableAnimation = browser.supportsCssAnimation();
|
||||
|
||||
elem = document.createElement('div');
|
||||
|
@ -50,7 +48,6 @@ function onHideComplete() {
|
|||
|
||||
var hideTimeout;
|
||||
function showOsd() {
|
||||
|
||||
clearHideTimeout();
|
||||
|
||||
var elem = osdElement;
|
||||
|
@ -79,12 +76,10 @@ function clearHideTimeout() {
|
|||
}
|
||||
|
||||
function hideOsd() {
|
||||
|
||||
clearHideTimeout();
|
||||
|
||||
var elem = osdElement;
|
||||
if (elem) {
|
||||
|
||||
if (enableAnimation) {
|
||||
// trigger reflow
|
||||
void elem.offsetWidth;
|
||||
|
@ -108,7 +103,6 @@ function setIcon(iconElement, icon) {
|
|||
}
|
||||
|
||||
function updateElementsFromPlayer(brightness) {
|
||||
|
||||
if (iconElement) {
|
||||
if (brightness >= 80) {
|
||||
setIcon(iconElement, 'brightness_high');
|
||||
|
@ -124,7 +118,6 @@ function updateElementsFromPlayer(brightness) {
|
|||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
|
||||
var player = currentPlayer;
|
||||
|
||||
if (player) {
|
||||
|
@ -135,7 +128,6 @@ function releaseCurrentPlayer() {
|
|||
}
|
||||
|
||||
function onBrightnessChanged(e) {
|
||||
|
||||
var player = this;
|
||||
|
||||
ensureOsdElement();
|
||||
|
@ -146,7 +138,6 @@ function onBrightnessChanged(e) {
|
|||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
|
||||
if (player === currentPlayer) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import playbackManager from 'playbackManager';
|
||||
import nowPlayingHelper from 'nowPlayingHelper';
|
||||
import events from 'events';
|
||||
import connectionManager from 'connectionManager';
|
||||
/* eslint-disable indent */
|
||||
|
||||
// Reports media playback to the device for lock screen control
|
||||
|
@ -16,16 +15,16 @@ import connectionManager from 'connectionManager';
|
|||
} else if (options.type === 'Primary' && item.SeriesPrimaryImageTag) {
|
||||
options.tag = item.SeriesPrimaryImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
} else if (options.type === 'Thumb') {
|
||||
if (item.SeriesThumbImageTag) {
|
||||
options.tag = item.SeriesThumbImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
} else if (item.ParentThumbImageTag) {
|
||||
options.tag = item.ParentThumbImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,11 +37,11 @@ import connectionManager from 'connectionManager';
|
|||
if (item.ImageTags && item.ImageTags[options.type]) {
|
||||
options.tag = item.ImageTags[options.type];
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.Id, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.Id, options);
|
||||
} else if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
options.tag = item.AlbumPrimaryImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -127,7 +126,7 @@ import connectionManager from 'connectionManager';
|
|||
artwork: getImageUrls(item)
|
||||
});
|
||||
} else {
|
||||
let itemImageUrl = seriesImageUrl(item, { maxHeight: 3000 }) || imageUrl(item, { maxHeight: 3000 });
|
||||
const itemImageUrl = seriesImageUrl(item, { maxHeight: 3000 }) || imageUrl(item, { maxHeight: 3000 });
|
||||
|
||||
window.NativeShell.updateMediaSession({
|
||||
action: eventName,
|
||||
|
@ -244,10 +243,10 @@ import connectionManager from 'connectionManager';
|
|||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
navigator.mediaSession.setActionHandler('seekto', function (object) {
|
||||
let item = playbackManager.getPlayerState(currentPlayer).NowPlayingItem;
|
||||
const item = playbackManager.getPlayerState(currentPlayer).NowPlayingItem;
|
||||
// Convert to ms
|
||||
let duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0);
|
||||
let wantedTime = object.seekTime * 1000;
|
||||
const duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0);
|
||||
const wantedTime = object.seekTime * 1000;
|
||||
playbackManager.seekPercent(wantedTime / duration * 100, currentPlayer);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
|
||||
|
||||
var topItem = nowPlayingItem;
|
||||
var bottomItem = null;
|
||||
var topText = nowPlayingItem.Name;
|
||||
|
@ -25,7 +24,6 @@ export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
|
|||
var bottomText = '';
|
||||
|
||||
if (nowPlayingItem.ArtistItems && nowPlayingItem.ArtistItems.length) {
|
||||
|
||||
bottomItem = {
|
||||
Id: nowPlayingItem.ArtistItems[0].Id,
|
||||
Name: nowPlayingItem.ArtistItems[0].Name,
|
||||
|
@ -36,9 +34,7 @@ export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
|
|||
bottomText = nowPlayingItem.ArtistItems.map(function (a) {
|
||||
return a.Name;
|
||||
}).join(', ');
|
||||
|
||||
} else if (nowPlayingItem.Artists && nowPlayingItem.Artists.length) {
|
||||
|
||||
bottomText = nowPlayingItem.Artists.join(', ');
|
||||
} else if (nowPlayingItem.SeriesName || nowPlayingItem.Album) {
|
||||
bottomText = topText;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -14,15 +14,13 @@ function onOrientationChangeError(err) {
|
|||
}
|
||||
|
||||
events.on(playbackManager, 'playbackstart', function (e, player, state) {
|
||||
|
||||
var isLocalVideo = player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player);
|
||||
|
||||
if (isLocalVideo && layoutManager.mobile) {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
var lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation || (screen.orientation && screen.orientation.lock);
|
||||
var lockOrientation = window.screen.lockOrientation || window.screen.mozLockOrientation || window.screen.msLockOrientation || (window.screen.orientation && window.screen.orientation.lock);
|
||||
|
||||
if (lockOrientation) {
|
||||
|
||||
try {
|
||||
var promise = lockOrientation('landscape');
|
||||
if (promise.then) {
|
||||
|
@ -39,11 +37,9 @@ events.on(playbackManager, 'playbackstart', function (e, player, state) {
|
|||
});
|
||||
|
||||
events.on(playbackManager, 'playbackstop', function (e, playbackStopInfo) {
|
||||
|
||||
if (orientationLocked && !playbackStopInfo.nextMediaType) {
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
var unlockOrientation = screen.unlockOrientation || screen.mozUnlockOrientation || screen.msUnlockOrientation || (screen.orientation && screen.orientation.unlock);
|
||||
var unlockOrientation = window.screen.unlockOrientation || window.screen.mozUnlockOrientation || window.screen.msUnlockOrientation || (window.screen.orientation && window.screen.orientation.unlock);
|
||||
|
||||
if (unlockOrientation) {
|
||||
try {
|
||||
|
|
|
@ -8,7 +8,6 @@ import globalize from 'globalize';
|
|||
import appHost from 'apphost';
|
||||
|
||||
function mirrorItem(info, player) {
|
||||
|
||||
var item = info.item;
|
||||
|
||||
playbackManager.displayContent({
|
||||
|
@ -21,9 +20,7 @@ function mirrorItem(info, player) {
|
|||
}
|
||||
|
||||
function mirrorIfEnabled(info) {
|
||||
|
||||
if (info && playbackManager.enableDisplayMirroring()) {
|
||||
|
||||
var getPlayerInfo = playbackManager.getPlayerInfo();
|
||||
|
||||
if (getPlayerInfo) {
|
||||
|
@ -39,9 +36,7 @@ function emptyCallback() {
|
|||
}
|
||||
|
||||
function getTargetSecondaryText(target) {
|
||||
|
||||
if (target.user) {
|
||||
|
||||
return target.user.Name;
|
||||
}
|
||||
|
||||
|
@ -49,7 +44,6 @@ function getTargetSecondaryText(target) {
|
|||
}
|
||||
|
||||
function getIcon(target) {
|
||||
|
||||
var deviceType = target.deviceType;
|
||||
|
||||
if (!deviceType && target.isLocalPlayer) {
|
||||
|
@ -67,7 +61,6 @@ function getIcon(target) {
|
|||
}
|
||||
|
||||
switch (deviceType) {
|
||||
|
||||
case 'smartphone':
|
||||
return 'smartphone';
|
||||
case 'tablet':
|
||||
|
@ -84,7 +77,6 @@ function getIcon(target) {
|
|||
}
|
||||
|
||||
export function show(button) {
|
||||
|
||||
var currentPlayerInfo = playbackManager.getPlayerInfo();
|
||||
|
||||
if (currentPlayerInfo) {
|
||||
|
@ -99,9 +91,7 @@ export function show(button) {
|
|||
loading.show();
|
||||
|
||||
playbackManager.getTargets().then(function (targets) {
|
||||
|
||||
var menuItems = targets.map(function (t) {
|
||||
|
||||
var name = t.name;
|
||||
|
||||
if (t.appName && t.appName !== t.name) {
|
||||
|
@ -115,11 +105,9 @@ export function show(button) {
|
|||
secondaryText: getTargetSecondaryText(t),
|
||||
icon: getIcon(t)
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
import('actionsheet').then(({default: actionsheet}) => {
|
||||
|
||||
loading.hide();
|
||||
|
||||
var menuOptions = {
|
||||
|
@ -133,12 +121,11 @@ export function show(button) {
|
|||
|
||||
// Unfortunately we can't allow the url to change or chromecast will throw a security error
|
||||
// Might be able to solve this in the future by moving the dialogs to hashbangs
|
||||
if (!(!browser.chrome || appHost.supports('castmenuhashchange'))) {
|
||||
if (!(!browser.chrome && !browser.edgeChromium || appHost.supports('castmenuhashchange'))) {
|
||||
menuOptions.enableHistory = false;
|
||||
}
|
||||
|
||||
actionsheet.show(menuOptions).then(function (id) {
|
||||
|
||||
var target = targets.filter(function (t) {
|
||||
return t.id === id;
|
||||
})[0];
|
||||
|
@ -146,7 +133,6 @@ export function show(button) {
|
|||
playbackManager.trySetActivePlayer(target.playerName, target);
|
||||
|
||||
mirrorIfEnabled();
|
||||
|
||||
}, emptyCallback);
|
||||
});
|
||||
});
|
||||
|
@ -164,11 +150,8 @@ function showActivePlayerMenu(playerInfo) {
|
|||
}
|
||||
|
||||
function disconnectFromPlayer(currentDeviceName) {
|
||||
|
||||
if (playbackManager.getSupportedCommands().indexOf('EndSession') !== -1) {
|
||||
|
||||
import('dialog').then(({default: dialog}) => {
|
||||
|
||||
var menuItems = [];
|
||||
|
||||
menuItems.push({
|
||||
|
@ -182,12 +165,10 @@ function disconnectFromPlayer(currentDeviceName) {
|
|||
|
||||
dialog({
|
||||
buttons: menuItems,
|
||||
//positionTo: positionTo,
|
||||
text: globalize.translate('ConfirmEndPlayerSession', currentDeviceName)
|
||||
|
||||
}).then(function (id) {
|
||||
switch (id) {
|
||||
|
||||
case 'yes':
|
||||
playbackManager.getCurrentPlayer().endSession();
|
||||
playbackManager.setDefaultPlayerActive();
|
||||
|
@ -199,17 +180,13 @@ function disconnectFromPlayer(currentDeviceName) {
|
|||
break;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
playbackManager.setDefaultPlayerActive();
|
||||
}
|
||||
}
|
||||
|
||||
function showActivePlayerMenuInternal(dialogHelper, playerInfo) {
|
||||
|
||||
var html = '';
|
||||
|
||||
var dialogOptions = {
|
||||
|
@ -235,7 +212,6 @@ function showActivePlayerMenuInternal(dialogHelper, playerInfo) {
|
|||
html += '<div>';
|
||||
|
||||
if (playerInfo.supportedCommands.indexOf('DisplayContent') !== -1) {
|
||||
|
||||
html += '<label class="checkboxContainer">';
|
||||
var checkedHtml = playbackManager.enableDisplayMirroring() ? ' checked' : '';
|
||||
html += '<input type="checkbox" is="emby-checkbox" class="chkMirror"' + checkedHtml + '/>';
|
||||
|
@ -294,7 +270,6 @@ function onMirrorChange() {
|
|||
}
|
||||
|
||||
document.addEventListener('viewshow', function (e) {
|
||||
|
||||
var state = e.detail.state || {};
|
||||
var item = state.item;
|
||||
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import connectionManager from 'connectionManager';
|
||||
import actionsheet from 'actionsheet';
|
||||
import playbackManager from 'playbackManager';
|
||||
import globalize from 'globalize';
|
||||
import qualityoptions from 'qualityoptions';
|
||||
|
||||
function showQualityMenu(player, btn) {
|
||||
|
||||
var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) {
|
||||
return stream.Type === 'Video';
|
||||
})[0];
|
||||
|
@ -88,8 +86,6 @@ function showRepeatModeMenu(player, btn) {
|
|||
|
||||
function getQualitySecondaryText(player) {
|
||||
var state = playbackManager.getPlayerState(player);
|
||||
var isAutoEnabled = playbackManager.enableAutomaticBitrateDetection(player);
|
||||
var currentMaxBitrate = playbackManager.getMaxStreamingBitrate(player);
|
||||
|
||||
var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) {
|
||||
return stream.Type === 'Video';
|
||||
|
@ -106,20 +102,6 @@ function getQualitySecondaryText(player) {
|
|||
enableAuto: true
|
||||
});
|
||||
|
||||
var menuItems = options.map(function (o) {
|
||||
var opt = {
|
||||
name: o.name,
|
||||
id: o.bitrate,
|
||||
asideText: o.secondaryText
|
||||
};
|
||||
|
||||
if (o.selected) {
|
||||
opt.selected = true;
|
||||
}
|
||||
|
||||
return opt;
|
||||
});
|
||||
|
||||
var selectedOption = options.filter(function (o) {
|
||||
return o.selected;
|
||||
});
|
||||
|
@ -166,9 +148,30 @@ function showAspectRatioMenu(player, btn) {
|
|||
});
|
||||
}
|
||||
|
||||
function showPlaybackRateMenu(player, btn) {
|
||||
// each has a name and id
|
||||
const currentId = playbackManager.getPlaybackRate(player);
|
||||
const menuItems = playbackManager.getSupportedPlaybackRates(player).map(i => ({
|
||||
id: i.id,
|
||||
name: i.name,
|
||||
selected: i.id === currentId
|
||||
}));
|
||||
|
||||
return actionsheet.show({
|
||||
items: menuItems,
|
||||
positionTo: btn
|
||||
}).then(function (id) {
|
||||
if (id) {
|
||||
playbackManager.setPlaybackRate(id, player);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
}
|
||||
|
||||
function showWithUser(options, player, user) {
|
||||
var supportedCommands = playbackManager.getSupportedCommands(player);
|
||||
var mediaType = options.mediaType;
|
||||
|
||||
var menuItems = [];
|
||||
if (supportedCommands.indexOf('SetAspectRatio') !== -1) {
|
||||
|
@ -184,6 +187,17 @@ function showWithUser(options, player, user) {
|
|||
});
|
||||
}
|
||||
|
||||
if (supportedCommands.indexOf('PlaybackRate') !== -1) {
|
||||
const currentPlaybackRateId = playbackManager.getPlaybackRate(player);
|
||||
const currentPlaybackRate = playbackManager.getSupportedPlaybackRates(player).filter(i => i.id === currentPlaybackRateId)[0];
|
||||
|
||||
menuItems.push({
|
||||
name: globalize.translate('PlaybackRate'),
|
||||
id: 'playbackrate',
|
||||
asideText: currentPlaybackRate ? currentPlaybackRate.name : null
|
||||
});
|
||||
}
|
||||
|
||||
if (user && user.Policy.EnableVideoPlaybackTranscoding) {
|
||||
var secondaryQualityText = getQualitySecondaryText(player);
|
||||
|
||||
|
@ -236,7 +250,7 @@ export function show(options) {
|
|||
return showWithUser(options, player, null);
|
||||
}
|
||||
|
||||
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
var apiClient = window.connectionManager.getApiClient(currentItem.ServerId);
|
||||
return apiClient.getCurrentUser().then(function (user) {
|
||||
return showWithUser(options, player, user);
|
||||
});
|
||||
|
@ -248,6 +262,8 @@ function handleSelectedOption(id, options, player) {
|
|||
return showQualityMenu(player, options.positionTo);
|
||||
case 'aspectratio':
|
||||
return showAspectRatioMenu(player, options.positionTo);
|
||||
case 'playbackrate':
|
||||
return showPlaybackRateMenu(player, options.positionTo);
|
||||
case 'repeatmode':
|
||||
return showRepeatModeMenu(player, options.positionTo);
|
||||
case 'stats':
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
export function getDisplayPlayMethod(session) {
|
||||
|
||||
if (!session.NowPlayingItem) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,64 +1,56 @@
|
|||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
var currentId = 0;
|
||||
function addUniquePlaylistItemId(item) {
|
||||
/*eslint prefer-const: "error"*/
|
||||
|
||||
let currentId = 0;
|
||||
function addUniquePlaylistItemId(item) {
|
||||
if (!item.PlaylistItemId) {
|
||||
|
||||
item.PlaylistItemId = 'playlistItem' + currentId;
|
||||
currentId++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findPlaylistIndex(playlistItemId, list) {
|
||||
|
||||
for (var i = 0, length = list.length; i < length; i++) {
|
||||
function findPlaylistIndex(playlistItemId, list) {
|
||||
for (let i = 0, length = list.length; i < length; i++) {
|
||||
if (list[i].PlaylistItemId === playlistItemId) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
function PlayQueueManager() {
|
||||
}
|
||||
|
||||
class PlayQueueManager {
|
||||
constructor() {
|
||||
this._sortedPlaylist = [];
|
||||
this._playlist = [];
|
||||
this._repeatMode = 'RepeatNone';
|
||||
this._shuffleMode = 'Sorted';
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.getPlaylist = function () {
|
||||
getPlaylist() {
|
||||
return this._playlist.slice(0);
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.setPlaylist = function (items) {
|
||||
}
|
||||
|
||||
setPlaylist(items) {
|
||||
items = items.slice(0);
|
||||
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
for (let i = 0, length = items.length; i < length; i++) {
|
||||
addUniquePlaylistItemId(items[i]);
|
||||
}
|
||||
|
||||
this._currentPlaylistItemId = null;
|
||||
this._playlist = items;
|
||||
this._repeatMode = 'RepeatNone';
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.queue = function (items) {
|
||||
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
}
|
||||
|
||||
queue(items) {
|
||||
for (let i = 0, length = items.length; i < length; i++) {
|
||||
addUniquePlaylistItemId(items[i]);
|
||||
|
||||
this._playlist.push(items[i]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.shufflePlaylist = function () {
|
||||
shufflePlaylist() {
|
||||
this._sortedPlaylist = [];
|
||||
for (const item of this._playlist) {
|
||||
this._sortedPlaylist.push(item);
|
||||
|
@ -73,43 +65,31 @@ define([], function () {
|
|||
}
|
||||
this._playlist.unshift(currentPlaylistItem);
|
||||
this._shuffleMode = 'Shuffle';
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.sortShuffledPlaylist = function () {
|
||||
sortShuffledPlaylist() {
|
||||
this._playlist = [];
|
||||
for (let item of this._sortedPlaylist) {
|
||||
for (const item of this._sortedPlaylist) {
|
||||
this._playlist.push(item);
|
||||
}
|
||||
this._sortedPlaylist = [];
|
||||
this._shuffleMode = 'Sorted';
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.clearPlaylist = function (clearCurrentItem = false) {
|
||||
clearPlaylist(clearCurrentItem = false) {
|
||||
const currentPlaylistItem = this._playlist.splice(this.getCurrentPlaylistIndex(), 1)[0];
|
||||
this._playlist = [];
|
||||
if (!clearCurrentItem) {
|
||||
this._playlist.push(currentPlaylistItem);
|
||||
}
|
||||
};
|
||||
|
||||
function arrayInsertAt(destArray, pos, arrayToInsert) {
|
||||
var args = [];
|
||||
args.push(pos); // where to insert
|
||||
args.push(0); // nothing to remove
|
||||
args = args.concat(arrayToInsert); // add on array to insert
|
||||
destArray.splice.apply(destArray, args); // splice it in
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.queueNext = function (items) {
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
queueNext(items) {
|
||||
for (let i = 0, length = items.length; i < length; i++) {
|
||||
addUniquePlaylistItemId(items[i]);
|
||||
}
|
||||
|
||||
var currentIndex = this.getCurrentPlaylistIndex();
|
||||
let currentIndex = this.getCurrentPlaylistIndex();
|
||||
|
||||
if (currentIndex === -1) {
|
||||
currentIndex = this._playlist.length;
|
||||
|
@ -118,48 +98,43 @@ define([], function () {
|
|||
}
|
||||
|
||||
arrayInsertAt(this._playlist, currentIndex, items);
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.getCurrentPlaylistIndex = function () {
|
||||
}
|
||||
|
||||
getCurrentPlaylistIndex() {
|
||||
return findPlaylistIndex(this.getCurrentPlaylistItemId(), this._playlist);
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.getCurrentItem = function () {
|
||||
|
||||
var index = findPlaylistIndex(this.getCurrentPlaylistItemId(), this._playlist);
|
||||
getCurrentItem() {
|
||||
const index = findPlaylistIndex(this.getCurrentPlaylistItemId(), this._playlist);
|
||||
|
||||
return index === -1 ? null : this._playlist[index];
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.getCurrentPlaylistItemId = function () {
|
||||
getCurrentPlaylistItemId() {
|
||||
return this._currentPlaylistItemId;
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.setPlaylistState = function (playlistItemId, playlistIndex) {
|
||||
}
|
||||
|
||||
setPlaylistState(playlistItemId, playlistIndex) {
|
||||
this._currentPlaylistItemId = playlistItemId;
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.setPlaylistIndex = function (playlistIndex) {
|
||||
}
|
||||
|
||||
setPlaylistIndex(playlistIndex) {
|
||||
if (playlistIndex < 0) {
|
||||
this.setPlaylistState(null);
|
||||
} else {
|
||||
this.setPlaylistState(this._playlist[playlistIndex].PlaylistItemId);
|
||||
}
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.removeFromPlaylist = function (playlistItemIds) {
|
||||
}
|
||||
|
||||
removeFromPlaylist(playlistItemIds) {
|
||||
if (this._playlist.length <= playlistItemIds.length) {
|
||||
return {
|
||||
result: 'empty'
|
||||
};
|
||||
}
|
||||
|
||||
var currentPlaylistItemId = this.getCurrentPlaylistItemId();
|
||||
var isCurrentIndex = playlistItemIds.indexOf(currentPlaylistItemId) !== -1;
|
||||
const currentPlaylistItemId = this.getCurrentPlaylistItemId();
|
||||
const isCurrentIndex = playlistItemIds.indexOf(currentPlaylistItemId) !== -1;
|
||||
|
||||
this._sortedPlaylist = this._sortedPlaylist.filter(function (item) {
|
||||
return !playlistItemIds.includes(item.PlaylistItemId);
|
||||
|
@ -173,18 +148,13 @@ define([], function () {
|
|||
result: 'removed',
|
||||
isCurrentIndex: isCurrentIndex
|
||||
};
|
||||
};
|
||||
|
||||
function moveInArray(array, from, to) {
|
||||
array.splice(to, 0, array.splice(from, 1)[0]);
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.movePlaylistItem = function (playlistItemId, newIndex) {
|
||||
movePlaylistItem(playlistItemId, newIndex) {
|
||||
const playlist = this.getPlaylist();
|
||||
|
||||
var playlist = this.getPlaylist();
|
||||
|
||||
var oldIndex;
|
||||
for (var i = 0, length = playlist.length; i < length; i++) {
|
||||
let oldIndex;
|
||||
for (let i = 0, length = playlist.length; i < length; i++) {
|
||||
if (playlist[i].PlaylistItemId === playlistItemId) {
|
||||
oldIndex = i;
|
||||
break;
|
||||
|
@ -210,31 +180,30 @@ define([], function () {
|
|||
playlistItemId: playlistItemId,
|
||||
newIndex: newIndex
|
||||
};
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.reset = function () {
|
||||
}
|
||||
|
||||
reset() {
|
||||
this._sortedPlaylist = [];
|
||||
this._playlist = [];
|
||||
this._currentPlaylistItemId = null;
|
||||
this._repeatMode = 'RepeatNone';
|
||||
this._shuffleMode = 'Sorted';
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.setRepeatMode = function (value) {
|
||||
setRepeatMode(value) {
|
||||
const repeatModes = ['RepeatOne', 'RepeatAll', 'RepeatNone'];
|
||||
if (repeatModes.includes(value)) {
|
||||
this._repeatMode = value;
|
||||
} else {
|
||||
throw new TypeError('invalid value provided for setRepeatMode');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.getRepeatMode = function () {
|
||||
getRepeatMode() {
|
||||
return this._repeatMode;
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.setShuffleMode = function (value) {
|
||||
setShuffleMode(value) {
|
||||
switch (value) {
|
||||
case 'Shuffle':
|
||||
this.shufflePlaylist();
|
||||
|
@ -245,9 +214,9 @@ define([], function () {
|
|||
default:
|
||||
throw new TypeError('invalid value provided to setShuffleMode');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.toggleShuffleMode = function () {
|
||||
toggleShuffleMode() {
|
||||
switch (this._shuffleMode) {
|
||||
case 'Shuffle':
|
||||
this.setShuffleMode('Sorted');
|
||||
|
@ -258,20 +227,18 @@ define([], function () {
|
|||
default:
|
||||
throw new TypeError('current value for shufflequeue is invalid');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.getShuffleMode = function () {
|
||||
getShuffleMode() {
|
||||
return this._shuffleMode;
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.getNextItemInfo = function () {
|
||||
|
||||
var newIndex;
|
||||
var playlist = this.getPlaylist();
|
||||
var playlistLength = playlist.length;
|
||||
getNextItemInfo() {
|
||||
let newIndex;
|
||||
const playlist = this.getPlaylist();
|
||||
const playlistLength = playlist.length;
|
||||
|
||||
switch (this.getRepeatMode()) {
|
||||
|
||||
case 'RepeatOne':
|
||||
newIndex = this.getCurrentPlaylistIndex();
|
||||
break;
|
||||
|
@ -290,7 +257,7 @@ define([], function () {
|
|||
return null;
|
||||
}
|
||||
|
||||
var item = playlist[newIndex];
|
||||
const item = playlist[newIndex];
|
||||
|
||||
if (!item) {
|
||||
return null;
|
||||
|
@ -300,7 +267,19 @@ define([], function () {
|
|||
item: item,
|
||||
index: newIndex
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return PlayQueueManager;
|
||||
});
|
||||
function arrayInsertAt(destArray, pos, arrayToInsert) {
|
||||
let args = [];
|
||||
args.push(pos); // where to insert
|
||||
args.push(0); // nothing to remove
|
||||
args = args.concat(arrayToInsert); // add on array to insert
|
||||
destArray.splice.apply(destArray, args); // splice it in
|
||||
}
|
||||
|
||||
function moveInArray(array, from, to) {
|
||||
array.splice(to, 0, array.splice(from, 1)[0]);
|
||||
}
|
||||
|
||||
export default PlayQueueManager;
|
||||
|
|
|
@ -23,10 +23,8 @@ function getOsdElementHtml() {
|
|||
}
|
||||
|
||||
function ensureOsdElement() {
|
||||
|
||||
var elem = osdElement;
|
||||
if (!elem) {
|
||||
|
||||
enableAnimation = browser.supportsCssAnimation();
|
||||
|
||||
elem = document.createElement('div');
|
||||
|
@ -50,7 +48,6 @@ function onHideComplete() {
|
|||
|
||||
var hideTimeout;
|
||||
function showOsd() {
|
||||
|
||||
clearHideTimeout();
|
||||
|
||||
var elem = osdElement;
|
||||
|
@ -79,12 +76,10 @@ function clearHideTimeout() {
|
|||
}
|
||||
|
||||
function hideOsd() {
|
||||
|
||||
clearHideTimeout();
|
||||
|
||||
var elem = osdElement;
|
||||
if (elem) {
|
||||
|
||||
if (enableAnimation) {
|
||||
// trigger reflow
|
||||
void elem.offsetWidth;
|
||||
|
@ -103,7 +98,6 @@ function hideOsd() {
|
|||
}
|
||||
|
||||
function updatePlayerVolumeState(isMuted, volume) {
|
||||
|
||||
if (iconElement) {
|
||||
iconElement.classList.remove('volume_off', 'volume_up');
|
||||
iconElement.classList.add(isMuted ? 'volume_off' : 'volume_up');
|
||||
|
@ -114,7 +108,6 @@ function updatePlayerVolumeState(isMuted, volume) {
|
|||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
|
||||
var player = currentPlayer;
|
||||
|
||||
if (player) {
|
||||
|
@ -125,7 +118,6 @@ function releaseCurrentPlayer() {
|
|||
}
|
||||
|
||||
function onVolumeChanged(e) {
|
||||
|
||||
var player = this;
|
||||
|
||||
ensureOsdElement();
|
||||
|
@ -136,7 +128,6 @@ function onVolumeChanged(e) {
|
|||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
|
||||
if (player === currentPlayer) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import focusManager from 'focusManager';
|
|||
import qualityoptions from 'qualityoptions';
|
||||
import globalize from 'globalize';
|
||||
import loading from 'loading';
|
||||
import connectionManager from 'connectionManager';
|
||||
import events from 'events';
|
||||
import 'emby-select';
|
||||
import 'emby-checkbox';
|
||||
|
@ -13,7 +12,6 @@ import 'emby-checkbox';
|
|||
/* eslint-disable indent */
|
||||
|
||||
function fillSkipLengths(select) {
|
||||
|
||||
const options = [5, 10, 15, 20, 25, 30];
|
||||
|
||||
select.innerHTML = options.map(option => {
|
||||
|
@ -27,13 +25,11 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function populateLanguages(select, languages) {
|
||||
|
||||
let html = '';
|
||||
|
||||
html += `<option value=''>${globalize.translate('AnyLanguage')}</option>`;
|
||||
|
||||
for (let i = 0, length = languages.length; i < length; i++) {
|
||||
|
||||
const culture = languages[i];
|
||||
|
||||
html += `<option value='${culture.ThreeLetterISOLanguageName}'>${culture.DisplayName}</option>`;
|
||||
|
@ -43,7 +39,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function setMaxBitrateIntoField(select, isInNetwork, mediatype) {
|
||||
|
||||
const options = mediatype === 'Audio' ? qualityoptions.getAudioQualityOptions({
|
||||
|
||||
currentMaxBitrate: appSettings.maxStreamingBitrate(isInNetwork, mediatype),
|
||||
|
@ -59,7 +54,6 @@ import 'emby-checkbox';
|
|||
});
|
||||
|
||||
select.innerHTML = options.map(i => {
|
||||
|
||||
// render empty string instead of 0 for the auto option
|
||||
return `<option value="${i.bitrate || ''}">${i.name}</option>`;
|
||||
}).join('');
|
||||
|
@ -72,7 +66,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function fillChromecastQuality(select) {
|
||||
|
||||
const options = qualityoptions.getVideoQualityOptions({
|
||||
|
||||
currentMaxBitrate: appSettings.maxChromecastBitrate(),
|
||||
|
@ -81,7 +74,6 @@ import 'emby-checkbox';
|
|||
});
|
||||
|
||||
select.innerHTML = options.map(i => {
|
||||
|
||||
// render empty string instead of 0 for the auto option
|
||||
return `<option value="${i.bitrate || ''}">${i.name}</option>`;
|
||||
}).join('');
|
||||
|
@ -90,7 +82,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function setMaxBitrateFromField(select, isInNetwork, mediatype) {
|
||||
|
||||
if (select.value) {
|
||||
appSettings.maxStreamingBitrate(isInNetwork, mediatype, select.value);
|
||||
appSettings.enableAutomaticBitrateDetection(isInNetwork, mediatype, false);
|
||||
|
@ -100,7 +91,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function showHideQualityFields(context, user, apiClient) {
|
||||
|
||||
if (user.Policy.EnableVideoPlaybackTranscoding) {
|
||||
context.querySelector('.videoQualitySection').classList.remove('hide');
|
||||
} else {
|
||||
|
@ -108,7 +98,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
if (appHost.supports('multiserver')) {
|
||||
|
||||
context.querySelector('.fldVideoInNetworkQuality').classList.remove('hide');
|
||||
context.querySelector('.fldVideoInternetQuality').classList.remove('hide');
|
||||
|
||||
|
@ -122,15 +111,12 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
apiClient.getEndpointInfo().then(endpointInfo => {
|
||||
|
||||
if (endpointInfo.IsInNetwork) {
|
||||
|
||||
context.querySelector('.fldVideoInNetworkQuality').classList.remove('hide');
|
||||
|
||||
context.querySelector('.fldVideoInternetQuality').classList.add('hide');
|
||||
context.querySelector('.musicQualitySection').classList.add('hide');
|
||||
} else {
|
||||
|
||||
context.querySelector('.fldVideoInNetworkQuality').classList.add('hide');
|
||||
|
||||
context.querySelector('.fldVideoInternetQuality').classList.remove('hide');
|
||||
|
@ -145,7 +131,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function showOrHideEpisodesField(context) {
|
||||
|
||||
if (browser.tizen || browser.web0s) {
|
||||
context.querySelector('.fldEpisodeAutoPlay').classList.add('hide');
|
||||
return;
|
||||
|
@ -155,14 +140,12 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function loadForm(context, user, userSettings, apiClient) {
|
||||
|
||||
const loggedInUserId = apiClient.getCurrentUserId();
|
||||
const userId = user.Id;
|
||||
|
||||
showHideQualityFields(context, user, apiClient);
|
||||
|
||||
apiClient.getCultures().then(allCultures => {
|
||||
|
||||
populateLanguages(context.querySelector('#selectAudioLanguage'), allCultures);
|
||||
|
||||
context.querySelector('#selectAudioLanguage', context).value = user.Configuration.AudioLanguagePreference || '';
|
||||
|
@ -171,7 +154,6 @@ import 'emby-checkbox';
|
|||
|
||||
// hide cinema mode options if disabled at server level
|
||||
apiClient.getNamedConfiguration('cinemamode').then(cinemaConfig => {
|
||||
|
||||
if (cinemaConfig.EnableIntrosForMovies || cinemaConfig.EnableIntrosForEpisodes) {
|
||||
context.querySelector('.cinemaModeOptions').classList.remove('hide');
|
||||
} else {
|
||||
|
@ -232,7 +214,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function saveUser(context, user, userSettingsInstance, apiClient) {
|
||||
|
||||
appSettings.enableSystemExternalPlayers(context.querySelector('.chkExternalVideoPlayer').checked);
|
||||
|
||||
appSettings.maxChromecastBitrate(context.querySelector('.selectChromecastVideoQuality').value);
|
||||
|
@ -256,13 +237,10 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
|
||||
|
||||
loading.show();
|
||||
|
||||
apiClient.getUser(userId).then(user => {
|
||||
|
||||
saveUser(context, user, userSettings, apiClient).then(() => {
|
||||
|
||||
loading.hide();
|
||||
if (enableSaveConfirmation) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
|
@ -271,7 +249,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
events.trigger(instance, 'saved');
|
||||
|
||||
}, () => {
|
||||
loading.hide();
|
||||
});
|
||||
|
@ -279,14 +256,12 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
|
||||
const self = this;
|
||||
const apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userId = self.options.userId;
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(() => {
|
||||
|
||||
const enableSaveConfirmation = self.options.enableSaveConfirmation;
|
||||
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
|
||||
});
|
||||
|
@ -299,9 +274,7 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
function embed(options, self) {
|
||||
|
||||
return import('text!./playbackSettings.template.html').then(({default: template}) => {
|
||||
|
||||
options.element.innerHTML = globalize.translateHtml(template, 'core');
|
||||
|
||||
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
|
||||
|
@ -325,20 +298,17 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
loadData() {
|
||||
|
||||
const self = this;
|
||||
const context = self.options.element;
|
||||
|
||||
loading.show();
|
||||
|
||||
const userId = self.options.userId;
|
||||
const apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
apiClient.getUser(userId).then(user => {
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(() => {
|
||||
|
||||
self.dataLoaded = true;
|
||||
|
||||
loadForm(context, user, userSettings, apiClient);
|
||||
|
@ -351,7 +321,6 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
destroy() {
|
||||
|
||||
this.options = null;
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue