Merge remote-tracking branch 'upstream/master' into media-session

This commit is contained in:
MrTimscampi 2020-05-01 16:14:54 +02:00
commit 81dffa3a93
189 changed files with 4537 additions and 2301 deletions

1
.copr/Makefile Symbolic link
View File

@ -0,0 +1 @@
../fedora/Makefile

View File

@ -7,3 +7,6 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf
[json]
indent_size = 2

View File

@ -1 +1,5 @@
libraries/
node_modules
dist
.idea
.vscode
src/libraries

190
.eslintrc.js Normal file
View File

@ -0,0 +1,190 @@
module.exports = {
root: true,
plugins: [
'promise',
'import',
'eslint-comments'
],
env: {
node: true,
es6: true,
es2017: true,
es2020: true
},
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
ecmaFeatures: {
impliedStrict: true
}
},
extends: [
'eslint:recommended',
// 'plugin:promise/recommended',
'plugin:import/errors',
'plugin:import/warnings',
'plugin:eslint-comments/recommended',
'plugin:compat/recommended'
],
rules: {
'block-spacing': ["error"],
'brace-style': ["error"],
'comma-dangle': ["error", "never"],
'comma-spacing': ["error"],
'eol-last': ["error"],
'indent': ["error", 4, { "SwitchCase": 1 }],
'keyword-spacing': ["error"],
'max-statements-per-line': ["error"],
'no-floating-decimal': ["error"],
'no-multi-spaces': ["error"],
'no-multiple-empty-lines': ["error", { "max": 1 }],
'no-trailing-spaces': ["error"],
'one-var': ["error", "never"],
'semi': ["error"],
'space-before-blocks': ["error"]
},
overrides: [
{
files: [
'./src/**/*.js'
],
env: {
node: false,
amd: true,
browser: true,
es6: true,
es2017: true,
es2020: true
},
globals: {
// Browser globals
'MediaMetadata': 'readonly',
// Tizen globals
'tizen': 'readonly',
'webapis': 'readonly',
// WebOS globals
'webOS': 'readonly',
// Dependency globals
'$': 'readonly',
'jQuery': 'readonly',
'requirejs': 'readonly',
// Jellyfin globals
'ApiClient': 'writable',
'AppInfo': 'writable',
'chrome': 'writable',
'ConnectionManager': 'writable',
'DlnaProfilePage': 'writable',
'Dashboard': 'writable',
'DashboardPage': 'writable',
'Emby': 'readonly',
'Events': 'writable',
'getParameterByName': 'writable',
'getWindowLocationSearch': 'writable',
'Globalize': 'writable',
'Hls': 'writable',
'dfnshelper': 'writable',
'LibraryMenu': 'writable',
'LinkParser': 'writable',
'LiveTvHelpers': 'writable',
'MetadataEditor': 'writable',
'pageClassOn': 'writable',
'pageIdOn': 'writable',
'PlaylistViewer': 'writable',
'UserParentalControlPage': 'writable',
'Windows': 'readonly'
},
rules: {
// TODO: Fix warnings and remove these rules
'no-redeclare': ["warn"],
'no-unused-vars': ["warn"],
'no-useless-escape': ["warn"],
// TODO: Remove after ES6 migration is complete
'import/no-unresolved': ["off"]
},
settings: {
polyfills: [
// Native Promises Only
'Promise',
// whatwg-fetch
'fetch',
// document-register-element
'document.registerElement',
// resize-observer-polyfill
'ResizeObserver',
// fast-text-encoding
'TextEncoder',
// intersection-observer
'IntersectionObserver',
// Core-js
'Object.assign',
'Object.is',
'Object.setPrototypeOf',
'Object.toString',
'Object.freeze',
'Object.seal',
'Object.preventExtensions',
'Object.isFrozen',
'Object.isSealed',
'Object.isExtensible',
'Object.getOwnPropertyDescriptor',
'Object.getPrototypeOf',
'Object.keys',
'Object.getOwnPropertyNames',
'Function.name',
'Function.hasInstance',
'Array.from',
'Array.arrayOf',
'Array.copyWithin',
'Array.fill',
'Array.find',
'Array.findIndex',
'Array.iterator',
'String.fromCodePoint',
'String.raw',
'String.iterator',
'String.codePointAt',
'String.endsWith',
'String.includes',
'String.repeat',
'String.startsWith',
'String.trim',
'String.anchor',
'String.big',
'String.blink',
'String.bold',
'String.fixed',
'String.fontcolor',
'String.fontsize',
'String.italics',
'String.link',
'String.small',
'String.strike',
'String.sub',
'String.sup',
'RegExp',
'Number',
'Math',
'Date',
'async',
'Symbol',
'Map',
'Set',
'WeakMap',
'WeakSet',
'ArrayBuffer',
'DataView',
'Int8Array',
'Uint8Array',
'Uint8ClampedArray',
'Int16Array',
'Uint16Array',
'Int32Array',
'Uint32Array',
'Float32Array',
'Float64Array',
'Reflect'
]
}
}
]
}

View File

@ -1,171 +0,0 @@
env:
amd: true
browser: true
es6: true
es2017: true
es2020: true
parserOptions:
ecmaVersion: 2020
sourceType: module
ecmaFeatures:
impliedStrict: true
plugins:
- promise
- import
- eslint-comments
extends:
- eslint:recommended
- plugin:promise/recommended
- plugin:import/errors
- plugin:import/warnings
- plugin:eslint-comments/recommended
- plugin:compat/recommended
globals:
# Browser globals
MediaMetadata: readonly
# Tizen globals
tizen: readonly
webapis: readonly
# WebOS globals
webOS: readonly
# Dependency globals
$: readonly
jQuery: readonly
requirejs: readonly
# Jellyfin globals
ApiClient: writable
AppInfo: writable
chrome: writable
ConnectionManager: writable
DlnaProfilePage: writable
Dashboard: writable
DashboardPage: writable
Emby: readonly
Events: writable
getParameterByName: writable
getWindowLocationSearch: writable
Globalize: writable
Hls: writable
dfnshelper: writable
LibraryMenu: writable
LinkParser: writable
LiveTvHelpers: writable
MetadataEditor: writable
pageClassOn: writable
pageIdOn: writable
PlaylistViewer: writable
UserParentalControlPage: writable
Windows: readonly
rules:
block-spacing: ["error"]
brace-style: ["error"]
comma-dangle: ["error", "never"]
comma-spacing: ["error"]
eol-last: ["error"]
indent: ["error", 4, { "SwitchCase": 1 }]
keyword-spacing: ["error"]
max-statements-per-line: ["error"]
no-floating-decimal: ["error"]
no-multi-spaces: ["error"]
no-multiple-empty-lines: ["error", { "max": 1 }]
no-trailing-spaces: ["error"]
one-var: ["error", "never"]
semi: ["error"]
space-before-blocks: ["error"]
# TODO: Fix warnings and remove these rules
no-redeclare: ["warn"]
no-unused-vars: ["warn"]
no-useless-escape: ["warn"]
promise/catch-or-return: ["warn"]
promise/always-return: ["warn"]
promise/no-return-wrap: ["warn"]
# TODO: Remove after ES6 migration is complete
import/no-unresolved: ["warn"]
settings:
polyfills:
# Native Promises Only
- Promise
# whatwg-fetch
- fetch
# document-register-element
- document.registerElement
# resize-observer-polyfill
- ResizeObserver
# fast-text-encoding
- TextEncoder
# intersection-observer
- IntersectionObserver
# Core-js
- Object.assign
- Object.is
- Object.setPrototypeOf
- Object.toString
- Object.freeze
- Object.seal
- Object.preventExtensions
- Object.isFrozen
- Object.isSealed
- Object.isExtensible
- Object.getOwnPropertyDescriptor
- Object.getPrototypeOf
- Object.keys
- Object.getOwnPropertyNames
- Function.name
- Function.hasInstance
- Array.from
- Array.arrayOf
- Array.copyWithin
- Array.fill
- Array.find
- Array.findIndex
- Array.iterator
- String.fromCodePoint
- String.raw
- String.iterator
- String.codePointAt
- String.endsWith
- String.includes
- String.repeat
- String.startsWith
- String.trim
- String.anchor
- String.big
- String.blink
- String.bold
- String.fixed
- String.fontcolor
- String.fontsize
- String.italics
- String.link
- String.small
- String.strike
- String.sub
- String.sup
- RegExp
- Number
- Math
- Date
- async
- Symbol
- Map
- Set
- WeakMap
- WeakSet
- ArrayBuffer
- DataView
- Int8Array
- Uint8Array
- Uint8ClampedArray
- Int16Array
- Uint16Array
- Int32Array
- Uint32Array
- Float32Array
- Float64Array
- Reflect

36
.gitattributes vendored
View File

@ -1 +1,35 @@
/CONTRIBUTORS.md merge=union
* text=auto
CONTRIBUTORS.md merge=union
README.md text
LICENSE text
*.css text
*.eot binary
*.gif binary
*.html text diff=html
*.ico binary
*.*ignore text
*.jpg binary
*.js text
*.json text
*.lock text -diff
*.map text -diff
*.md text
*.otf binary
*.png binary
*.py text diff=python
*.svg binary
*.ts text
*.ttf binary
*.sass text
*.vue text
*.webp binary
*.woff binary
*.woff2 binary
.editorconfig text
.gitattributes export-ignore
.gitignore export-ignore
*.gitattributes linguist-language=gitattributes

4
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,4 @@
.ci @dkanada @EraYaN
.github @jellyfin/core
build.sh @joshuaboniface
deployment @joshuaboniface

3
.gitignore vendored
View File

@ -3,8 +3,9 @@ config.json
# npm
dist
web
node_modules
# ide
.idea
.vscode
.vscode

110
build.sh Executable file
View File

@ -0,0 +1,110 @@
#!/usr/bin/env bash
# build.sh - Build Jellyfin binary packages
# Part of the Jellyfin Project
set -o errexit
set -o pipefail
usage() {
echo -e "build.sh - Build Jellyfin binary packages"
echo -e "Usage:"
echo -e " $0 -t/--type <BUILD_TYPE> -p/--platform <PLATFORM> [-k/--keep-artifacts] [-l/--list-platforms]"
echo -e "Notes:"
echo -e " * BUILD_TYPE can be one of: [native, docker] and must be specified"
echo -e " * native: Build using the build script in the host OS"
echo -e " * docker: Build using the build script in a standardized Docker container"
echo -e " * PLATFORM can be any platform shown by -l/--list-platforms and must be specified"
echo -e " * If -k/--keep-artifacts is specified, transient artifacts (e.g. Docker containers) will be"
echo -e " retained after the build is finished; the source directory will still be cleaned"
echo -e " * If -l/--list-platforms is specified, all other arguments are ignored; the script will print"
echo -e " the list of supported platforms and exit"
}
list_platforms() {
declare -a platforms
platforms=(
$( find deployment -maxdepth 1 -mindepth 1 -name "build.*" | awk -F'.' '{ $1=""; printf $2; if ($3 != ""){ printf "." $3; }; if ($4 != ""){ printf "." $4; }; print ""; }' | sort )
)
echo -e "Valid platforms:"
echo
for platform in ${platforms[@]}; do
echo -e "* ${platform} : $( grep '^#=' deployment/build.${platform} | sed 's/^#= //' )"
done
}
do_build_native() {
export IS_DOCKER=NO
deployment/build.${PLATFORM}
}
do_build_docker() {
if ! dpkg --print-architecture | grep -q 'amd64'; then
echo "Docker-based builds only support amd64-based cross-building; use a 'native' build instead."
exit 1
fi
if [[ ! -f deployment/Dockerfile.${PLATFORM} ]]; then
echo "Missing Dockerfile for platform ${PLATFORM}"
exit 1
fi
if [[ ${KEEP_ARTIFACTS} == YES ]]; then
docker_args=""
else
docker_args="--rm"
fi
docker build . -t "jellyfin-builder.${PLATFORM}" -f deployment/Dockerfile.${PLATFORM}
mkdir -p ${ARTIFACT_DIR}
docker run $docker_args -v "${SOURCE_DIR}:/jellyfin" -v "${ARTIFACT_DIR}:/dist" "jellyfin-builder.${PLATFORM}"
}
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
-t|--type)
BUILD_TYPE="$2"
shift
shift
;;
-p|--platform)
PLATFORM="$2"
shift
shift
;;
-k|--keep-artifacts)
KEEP_ARTIFACTS=YES
shift
;;
-l|--list-platforms)
list_platforms
exit 0
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option $1"
usage
exit 1
;;
esac
done
if [[ -z ${BUILD_TYPE} || -z ${PLATFORM} ]]; then
usage
exit 1
fi
export SOURCE_DIR="$( pwd )"
export ARTIFACT_DIR="${SOURCE_DIR}/../bin/${PLATFORM}"
# Determine build type
case ${BUILD_TYPE} in
native)
do_build_native
;;
docker)
do_build_docker
;;
esac

9
build.yaml Normal file
View File

@ -0,0 +1,9 @@
---
# We just wrap `build` so this is really it
name: "jellyfin-web"
version: "10.6.0"
packages:
- debian.all
- fedora.all
- centos.all
- portable

96
bump_version Executable file
View File

@ -0,0 +1,96 @@
#!/usr/bin/env bash
# bump_version - increase the shared version and generate changelogs
set -o errexit
set -o pipefail
usage() {
echo -e "bump_version - increase the shared version and generate changelogs"
echo -e ""
echo -e "Usage:"
echo -e " $ bump_version <new_version>"
}
if [[ -z $1 ]]; then
usage
exit 1
fi
shared_version_file="src/components/apphost.js"
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/'
)"
echo "Old version in appHost is: $old_version"
# Set the shared version to the specified new_version
old_version_sed="$( sed 's/\./\\./g' <<<"${old_version}" )" # Escape the '.' chars
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`"
# Set the build.yaml version to the specified new_version
old_version_sed="$( sed 's/\./\\./g' <<<"${old_version}" )" # Escape the '.' chars
sed -i "s/${old_version_sed}/${new_version}/g" ${build_file}
if [[ ${new_version} == *"-"* ]]; then
new_version_deb="$( sed 's/-/~/g' <<<"${new_version}" )"
else
new_version_deb="${new_version}-1"
fi
# Write out a temporary Debian changelog with our new stuff appended and some templated formatting
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
* New upstream version ${new_version}; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v${new_version}
-- Jellyfin Packaging Team <packaging@jellyfin.org> $( date --rfc-2822 )
" >> ${debian_changelog_temp}
cat ${debian_changelog_file} >> ${debian_changelog_temp}
# Move into place
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_changelog_temp="$( mktemp )"
fedora_spec_temp_dir="$( mktemp -d )"
fedora_spec_temp="${fedora_spec_temp_dir}/jellyfin.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
# Update the version in xx00
sed -i "s/${old_version_sed}/${new_version_sed}/g" xx00
# Remove the header from xx01
sed -i '/^%changelog/d' xx01
# Create new temp file with our changelog
echo -e "%changelog
* $( LANG=C date '+%a %b %d %Y' ) Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version ${new_version}; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v${new_version}" >> ${fedora_changelog_temp}
cat xx01 >> ${fedora_changelog_temp}
# Reassembble
cat xx00 ${fedora_changelog_temp} > ${fedora_spec_temp}
popd
# Move into place
mv ${fedora_spec_temp} ${fedora_spec_file}
# Clean up
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 status

5
debian/changelog vendored Normal file
View File

@ -0,0 +1,5 @@
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
-- Jellyfin Packaging Team <packaging@jellyfin.org> Mon, 16 Mar 2020 11:15:00 -0400

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
8

16
debian/control vendored Normal file
View File

@ -0,0 +1,16 @@
Source: jellyfin-web
Section: misc
Priority: optional
Maintainer: Jellyfin Team <team@jellyfin.org>
Build-Depends: debhelper (>= 9),
npm | nodejs
Standards-Version: 3.9.4
Homepage: https://jellyfin.org/
Vcs-Git: https://github.org/jellyfin/jellyfin-web.git
Vcs-Browser: https://github.org/jellyfin/jellyfin-web
Package: jellyfin-web
Recommends: jellyfin-server
Architecture: all
Description: Jellyfin is the Free Software Media System.
This package provides the Jellyfin web client.

28
debian/copyright vendored Normal file
View File

@ -0,0 +1,28 @@
Format: http://dep.debian.net/deps/dep5
Upstream-Name: jellyfin-web
Source: https://github.com/jellyfin/jellyfin-web
Files: *
Copyright: 2018-2020 Jellyfin Team
License: GPL-3.0
Files: debian/*
Copyright: 2020 Joshua Boniface <joshua@boniface.me>
License: GPL-3.0
License: GPL-3.0
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
.
On Debian systems, the complete text of the GNU General
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".

6
debian/gbp.conf vendored Normal file
View File

@ -0,0 +1,6 @@
[DEFAULT]
pristine-tar = False
cleaner = fakeroot debian/rules clean
[import-orig]
filter = [ ".git*", ".hg*", ".vs*", ".vscode*" ]

1
debian/install vendored Normal file
View File

@ -0,0 +1 @@
web usr/share/jellyfin/

1
debian/po/POTFILES.in vendored Normal file
View File

@ -0,0 +1 @@
[type: gettext/rfc822deb] templates

57
debian/po/templates.pot vendored Normal file
View File

@ -0,0 +1,57 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: jellyfin-server\n"
"Report-Msgid-Bugs-To: jellyfin-server@packages.debian.org\n"
"POT-Creation-Date: 2015-06-12 20:51-0600\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#. Type: note
#. Description
#: ../templates:1001
msgid "Jellyfin permission info:"
msgstr ""
#. Type: note
#. Description
#: ../templates:1001
msgid ""
"Jellyfin by default runs under a user named \"jellyfin\". Please ensure that the "
"user jellyfin has read and write access to any folders you wish to add to your "
"library. Otherwise please run jellyfin under a different user."
msgstr ""
#. Type: string
#. Description
#: ../templates:2001
msgid "Username to run Jellyfin as:"
msgstr ""
#. Type: string
#. Description
#: ../templates:2001
msgid "The user that jellyfin will run as."
msgstr ""
#. Type: note
#. Description
#: ../templates:3001
msgid "Jellyfin still running"
msgstr ""
#. Type: note
#. Description
#: ../templates:3001
msgid "Jellyfin is currently running. Please close it and try again."
msgstr ""

20
debian/rules vendored Executable file
View File

@ -0,0 +1,20 @@
#! /usr/bin/make -f
export DH_VERBOSE=1
%:
dh $@
# disable "make check"
override_dh_auto_test:
# disable stripping debugging symbols
override_dh_clistrip:
override_dh_auto_build:
npx yarn install
mv $(CURDIR)/dist $(CURDIR)/web
override_dh_auto_clean:
test -d $(CURDIR)/dist && rm -rf '$(CURDIR)/dist' || true
test -d $(CURDIR)/web && rm -rf '$(CURDIR)/web' || true
test -d $(CURDIR)/node_modules && rm -rf '$(CURDIR)/node_modules' || true

1
debian/source/format vendored Normal file
View File

@ -0,0 +1 @@
1.0

7
debian/source/options vendored Normal file
View File

@ -0,0 +1,7 @@
tar-ignore='.git*'
tar-ignore='**/.git'
tar-ignore='**/.hg'
tar-ignore='**/.vs'
tar-ignore='**/.vscode'
tar-ignore='deployment'
tar-ignore='*.deb'

View File

@ -0,0 +1,27 @@
FROM centos:7
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
# Docker run environment
ENV SOURCE_DIR=/jellyfin
ENV ARTIFACT_DIR=/dist
ENV IS_DOCKER=YES
# Prepare CentOS environment
RUN yum update -y \
&& yum install -y epel-release \
&& yum install -y @buildsys-build rpmdevtools git yum-plugins-core nodejs-yarn autoconf automake glibc-devel
# Install recent NodeJS and Yarn
RUN curl -fSsLo /etc/yum.repos.d/yarn.repo https://dl.yarnpkg.com/rpm/yarn.repo \
&& rpm -i https://rpm.nodesource.com/pub_10.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm \
&& yum install -y yarn
# Link to build script
RUN ln -sf ${SOURCE_DIR}/deployment/build.centos.all /build.sh
VOLUME ${SOURCE_DIR}/
VOLUME ${ARTIFACT_DIR}/
ENTRYPOINT ["/build.sh"]

View File

@ -0,0 +1,25 @@
FROM debian:10
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
# Docker run environment
ENV SOURCE_DIR=/jellyfin
ENV ARTIFACT_DIR=/dist
ENV DEB_BUILD_OPTIONS=noddebs
ENV IS_DOCKER=YES
# Prepare Debian build environment
RUN apt-get update \
&& apt-get install -y debhelper mmv npm git
# Prepare Yarn
RUN npm install -g yarn
# Link to build script
RUN ln -sf ${SOURCE_DIR}/deployment/build.debian.all /build.sh
VOLUME ${SOURCE_DIR}/
VOLUME ${ARTIFACT_DIR}/
ENTRYPOINT ["/build.sh"]

View File

@ -0,0 +1,21 @@
FROM fedora:31
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
# Docker run environment
ENV SOURCE_DIR=/jellyfin
ENV ARTIFACT_DIR=/dist
ENV IS_DOCKER=YES
# Prepare Fedora environment
RUN dnf update -y \
&& dnf install -y @buildsys-build rpmdevtools git dnf-plugins-core nodejs-yarn autoconf automake glibc-devel
# Link to build script
RUN ln -sf ${SOURCE_DIR}/deployment/build.fedora.all /build.sh
VOLUME ${SOURCE_DIR}/
VOLUME ${ARTIFACT_DIR}/
ENTRYPOINT ["/build.sh"]

View File

@ -0,0 +1,25 @@
FROM debian:10
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist
# Docker run environment
ENV SOURCE_DIR=/jellyfin
ENV ARTIFACT_DIR=/dist
ENV DEB_BUILD_OPTIONS=noddebs
ENV IS_DOCKER=YES
# Prepare Debian build environment
RUN apt-get update \
&& apt-get install -y mmv npm git
# Prepare Yarn
RUN npm install -g yarn
# Link to build script
RUN ln -sf ${SOURCE_DIR}/deployment/build.portable /build.sh
VOLUME ${SOURCE_DIR}/
VOLUME ${ARTIFACT_DIR}/
ENTRYPOINT ["/build.sh"]

27
deployment/build.centos.all Executable file
View File

@ -0,0 +1,27 @@
#!/bin/bash
#= CentOS 7 all .rpm
set -o errexit
set -o xtrace
# Move to source directory
pushd ${SOURCE_DIR}
cp -a yarn.lock /tmp/yarn.lock
# Build RPM
make -f fedora/Makefile srpm outdir=/root/rpmbuild/SRPMS
rpmbuild --rebuild -bb /root/rpmbuild/SRPMS/jellyfin-*.src.rpm
# Move the artifacts out
mv /root/rpmbuild/RPMS/noarch/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/
if [[ ${IS_DOCKER} == YES ]]; then
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
fi
rm -f fedora/jellyfin*.tar.gz
cp -a /tmp/yarn.lock yarn.lock
popd

25
deployment/build.debian.all Executable file
View File

@ -0,0 +1,25 @@
#!/bin/bash
#= Debian/Ubuntu all .deb
set -o errexit
set -o xtrace
# Move to source directory
pushd ${SOURCE_DIR}
cp -a yarn.lock /tmp/yarn.lock
# Build DEB
dpkg-buildpackage -us -uc --pre-clean --post-clean
mkdir -p ${ARTIFACT_DIR}/
mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} ${ARTIFACT_DIR}/
cp -a /tmp/yarn.lock yarn.lock
if [[ ${IS_DOCKER} == YES ]]; then
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
fi
popd

27
deployment/build.fedora.all Executable file
View File

@ -0,0 +1,27 @@
#!/bin/bash
#= Fedora 29+ all .rpm
set -o errexit
set -o xtrace
# Move to source directory
pushd ${SOURCE_DIR}
cp -a yarn.lock /tmp/yarn.lock
# Build RPM
make -f fedora/Makefile srpm outdir=/root/rpmbuild/SRPMS
rpmbuild -rb /root/rpmbuild/SRPMS/jellyfin-*.src.rpm
# Move the artifacts out
mv /root/rpmbuild/RPMS/noarch/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/
if [[ ${IS_DOCKER} == YES ]]; then
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
fi
rm -f fedora/jellyfin*.tar.gz
cp -a /tmp/yarn.lock yarn.lock
popd

28
deployment/build.portable Executable file
View File

@ -0,0 +1,28 @@
#!/bin/bash
#= Portable .NET DLL .tar.gz
set -o errexit
set -o xtrace
# Move to source directory
pushd ${SOURCE_DIR}
# Get version
version="$( grep "version:" ./build.yaml | sed -E 's/version: "([0-9\.]+.*)"/\1/' )"
# Build archives
npx yarn install
mv dist/ jellyfin-web_${version}
tar -czf jellyfin-web_${version}_portable.tar.gz jellyfin-web_${version}
rm -rf dist/
# Move the artifacts out
mkdir -p ${ARTIFACT_DIR}/
mv jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/
if [[ ${IS_DOCKER} == YES ]]; then
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
fi
popd

21
fedora/Makefile Normal file
View File

@ -0,0 +1,21 @@
VERSION := $(shell sed -ne '/^Version:/s/.* *//p' fedora/jellyfin-web.spec)
srpm:
cd fedora/; \
SOURCE_DIR=.. \
WORKDIR="$${PWD}"; \
tar \
--transform "s,^\.,jellyfin-web-$(VERSION)," \
--exclude='.git*' \
--exclude='**/.git' \
--exclude='**/.hg' \
--exclude='deployment' \
--exclude='*.deb' \
--exclude='*.rpm' \
--exclude='jellyfin-web-$(VERSION).tar.gz' \
-czf "jellyfin-web-$(VERSION).tar.gz" \
-C $${SOURCE_DIR} ./
cd fedora/; \
rpmbuild -bs jellyfin-web.spec \
--define "_sourcedir $$PWD/" \
--define "_srcrpmdir $(outdir)"

43
fedora/jellyfin-web.spec Normal file
View File

@ -0,0 +1,43 @@
%global debug_package %{nil}
Name: jellyfin-web
Version: 10.6.0
Release: 1%{?dist}
Summary: The Free Software Media System web client
License: GPLv3
URL: https://jellyfin.org
# Jellyfin Server tarball created by `make -f .copr/Makefile srpm`, real URL ends with `v%{version}.tar.gz`
Source0: jellyfin-web-%{version}.tar.gz
%if 0%{?centos}
BuildRequires: yarn
%else
BuildRequires nodejs-yarn
%endif
BuildArch: noarch
# Disable Automatic Dependency Processing
AutoReqProv: no
%description
Jellyfin is a free software media system that puts you in control of managing and streaming your media.
%prep
%autosetup -n jellyfin-web-%{version} -b 0
%build
%install
yarn install
%{__mkdir} -p %{buildroot}%{_datadir}
mv dist %{buildroot}%{_datadir}/jellyfin-web
%{__install} -D -m 0644 LICENSE %{buildroot}%{_datadir}/licenses/jellyfin/LICENSE
%files
%attr(755,root,root) %{_datadir}/jellyfin-web
%{_datadir}/licenses/jellyfin/LICENSE
%changelog
* Mon Mar 23 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
- Forthcoming stable release

View File

@ -1,5 +1,3 @@
'use strict';
const { src, dest, series, parallel, watch } = require('gulp');
const browserSync = require('browser-sync').create();
const del = require('del');
@ -183,6 +181,12 @@ function copy(query) {
.pipe(browserSync.stream());
}
function copyIndex() {
return src(options.injectBundle.query, { base: './src/' })
.pipe(dest('dist/'))
.pipe(browserSync.stream());
}
function injectBundle() {
return src(options.injectBundle.query, { base: './src/' })
.pipe(inject(
@ -193,9 +197,9 @@ function injectBundle() {
}
function build(standalone) {
return series(clean, parallel(javascript, apploader(standalone), webpack, css, html, images, copy), injectBundle);
return series(clean, parallel(javascript, apploader(standalone), webpack, css, html, images, copy));
}
exports.default = build(false);
exports.standalone = build(true);
exports.default = series(build(false), copyIndex);
exports.standalone = series(build(true), injectBundle);
exports.serve = series(exports.standalone, serve);

View File

@ -9,7 +9,7 @@
"@babel/plugin-transform-modules-amd": "^7.8.3",
"@babel/polyfill": "^7.8.7",
"@babel/preset-env": "^7.8.6",
"autoprefixer": "^9.7.4",
"autoprefixer": "^9.7.6",
"babel-loader": "^8.0.6",
"browser-sync": "^2.26.7",
"clean-webpack-plugin": "^3.0.0",
@ -61,11 +61,12 @@
"document-register-element": "^1.14.3",
"fast-text-encoding": "^1.0.1",
"flv.js": "^1.5.0",
"headroom.js": "^0.11.0",
"hls.js": "^0.13.1",
"howler": "^2.1.3",
"intersection-observer": "^0.7.0",
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
"jquery": "^3.4.1",
"jquery": "^3.5.0",
"jstree": "^3.3.7",
"libass-wasm": "https://github.com/jellyfin/JavascriptSubtitlesOctopus#4.0.0-jf-cordova",
"material-design-icons-iconfont": "^5.0.1",
@ -73,9 +74,10 @@
"page": "^1.11.5",
"query-string": "^6.11.1",
"resize-observer-polyfill": "^1.5.1",
"screenfull": "^5.0.2",
"shaka-player": "^2.5.10",
"sortablejs": "^1.10.2",
"swiper": "^5.3.1",
"swiper": "^5.3.7",
"webcomponents.js": "^0.7.24",
"whatwg-fetch": "^3.0.0"
},
@ -88,19 +90,19 @@
"test": [
"src/components/autoFocuser.js",
"src/components/cardbuilder/cardBuilder.js",
"src/components/dom.js",
"src/components/filedownloader.js",
"src/components/filesystem.js",
"src/components/input/keyboardnavigation.js",
"src/components/playback/mediasession.js",
"src/components/sanatizefilename.js",
"src/components/scrollManager.js",
"src/scripts/dfnshelper.js",
"src/scripts/dom.js",
"src/scripts/filesystem.js",
"src/scripts/imagehelper.js",
"src/scripts/inputManager.js",
"src/scripts/keyboardnavigation.js",
"src/scripts/settings/appSettings.js",
"src/scripts/settings/userSettings.js",
"src/scripts/settings/webSettings.js",
"src/scripts/dfnshelper.js",
"src/scripts/imagehelper.js",
"src/scripts/inputManager.js"
"src/scripts/settings/webSettings.js"
],
"plugins": [
"@babel/plugin-transform-modules-amd"
@ -129,7 +131,7 @@
"build:development": "gulp --development",
"build:production": "gulp --production",
"build:standalone": "gulp standalone --development",
"lint": "eslint \"src\"",
"lint": "eslint \".\"",
"stylelint": "stylelint \"src/**/*.css\""
}
}

View File

@ -1,11 +1,13 @@
const postcssPresetEnv = require('postcss-preset-env');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const config = () => ({
plugins: [
postcssPresetEnv(),
cssnano()
]
plugins: [
postcssPresetEnv(),
autoprefixer(),
cssnano()
]
});
module.exports = config
module.exports = config;

View File

@ -8,9 +8,8 @@
<a is="emby-linkbutton" class="raised button-alt headerHelpButton" target="_blank" href="https://docs.jellyfin.org/general/server/plugins/index.html">${Help}</a>
</div>
<p id="tagline" style="font-style: italic;"></p>
<p id="pPreviewImage"></p>
<p id="overview"></p>
<p id="overview" style="font-style: italic;"></p>
<p id="description"></p>
</div>
<div class="verticalSection">
@ -28,7 +27,6 @@
</button>
<div class="fieldDescription">${ServerRestartNeededAfterPluginInstall}</div>
</div>
<p id="nonServerMsg"></p>
</form>
</div>
</div>
@ -37,9 +35,6 @@
<div is="emby-collapse" title="${HeaderDeveloperInfo}">
<div class="collapseContent">
<p id="developer"></p>
<p id="pViewWebsite" style="display: none;">
<a is="emby-linkbutton" class="button-link" href="#" target="_blank">${ButtonViewWebsite}</a>
</p>
</div>
</div>

View File

@ -24,6 +24,10 @@
padding-top: 7em !important;
}
.layout-mobile .libraryPage {
padding-top: 4em !important;
}
.itemDetailPage {
padding-top: 0 !important;
}
@ -115,7 +119,7 @@
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex;
margin: 0.3em 0 0 0.5em;
margin: 0 0 0 0.5em;
height: 1.7em;
-webkit-box-align: center;
-webkit-align-items: center;
@ -268,12 +272,6 @@
}
}
@media all and (max-width: 60em) {
.libraryDocument .mainDrawerButton {
display: none;
}
}
@media all and (max-width: 84em) {
.withSectionTabs .headerTop {
padding-bottom: 0.55em;
@ -519,6 +517,13 @@
.itemName {
margin: 0.5em 0;
font-weight: 600;
}
.nameContainer {
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
.itemMiscInfo {
@ -536,7 +541,6 @@
.layout-mobile .itemName,
.layout-mobile .itemMiscInfo,
.layout-mobile .mainDetailButtons {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
@ -578,7 +582,6 @@
.infoText {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
}
@ -1103,3 +1106,50 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards {
.itemsViewSettingsContainer > .button-flat {
margin: 0;
}
.layout-mobile #myPreferencesMenuPage {
padding-top: 3.75em;
}
.itemDetailsGroup {
margin-bottom: 1.5em;
}
.trackSelections {
max-width: 44em;
}
.detailsGroupItem,
.trackSelections .selectContainer {
display: flex;
max-width: 44em;
margin: 0 0 0.5em !important;
}
.trackSelections .selectContainer {
margin: 0 0 0.3em !important;
}
.detailsGroupItem .label,
.trackSelections .selectContainer .selectLabel {
cursor: default;
flex-grow: 0;
flex-shrink: 0;
flex-basis: 6.25em;
margin: 0 0.6em 0 0;
}
.trackSelections .selectContainer .selectLabel {
margin: 0 0.2em 0 0;
}
.trackSelections .selectContainer .detailTrackSelect {
font-size: inherit;
padding: 0;
overflow: hidden;
}
.trackSelections .selectContainer .selectArrowContainer .selectArrow {
margin-top: 0;
font-size: 1.4em;
}

View File

@ -96,3 +96,16 @@ div[data-role=page] {
margin-right: auto;
width: 85%;
}
.headroom {
will-change: transform;
transition: transform 200ms linear;
}
.headroom--pinned {
transform: translateY(0%);
}
.headroom--unpinned {
transform: translateY(-100%);
}

View File

@ -135,7 +135,20 @@ _define("fast-text-encoding", function () {
return fast_text_encoding;
});
// intersection-observer
var intersection_observer = require("intersection-observer");
_define("intersection-observer", function () {
return intersection_observer;
});
// screenfull
var screenfull = require("screenfull");
_define("screenfull", function () {
return screenfull;
});
// headroom.js
var headroom = require("headroom.js/dist/headroom");
_define("headroom", function () {
return headroom;
});

View File

@ -1,4 +1,4 @@
define(["dialogHelper", "datetime", "emby-select", "paper-icon-button-light", "formDialogStyle"], function (dialogHelper, datetime) {
define(["dialogHelper", "datetime", "globalize", "emby-select", "paper-icon-button-light", "formDialogStyle"], function (dialogHelper, datetime, globalize) {
"use strict";
function getDisplayTime(hours) {
@ -38,7 +38,7 @@ define(["dialogHelper", "datetime", "emby-select", "paper-icon-button-light", "f
};
if (parseFloat(updatedSchedule.StartHour) >= parseFloat(updatedSchedule.EndHour)) {
return void alert(Globalize.translate("ErrorMessageStartHourGreaterThanEnd"));
return void alert(globalize.translate("ErrorMessageStartHourGreaterThanEnd"));
}
context.submitted = true;
@ -60,7 +60,7 @@ define(["dialogHelper", "datetime", "emby-select", "paper-icon-button-light", "f
});
dlg.classList.add("formDialog");
var html = "";
html += Globalize.translateDocument(template);
html += globalize.translateDocument(template);
dlg.innerHTML = html;
populateHours(dlg);
loadSchedule(dlg, options.schedule);

View File

@ -200,7 +200,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
var apiClient = this;
if (data.status === 401) {
if (data.status === 403) {
if (data.errorCode === "ParentalControl") {
var isCurrentAllowed = currentRouteInfo ? (currentRouteInfo.route.anonymous || currentRouteInfo.route.startup) : true;

View File

@ -1,4 +1,4 @@
define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings"], function (appSettings, browser, events, htmlMediaHelper, webSettings) {
define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings", "globalize"], function (appSettings, browser, events, htmlMediaHelper, webSettings, globalize) {
"use strict";
function getBaseProfileOptions(item) {
@ -46,20 +46,9 @@ define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings"], f
if (window.NativeShell) {
profile = window.NativeShell.AppHost.getDeviceProfile(profileBuilder);
} else {
profile = profileBuilder(getBaseProfileOptions(item));
if (item && !options.isRetry && "allcomplexformats" !== appSettings.get("subtitleburnin")) {
if (!browser.orsay && !browser.tizen) {
profile.SubtitleProfiles.push({
Format: "ass",
Method: "External"
});
profile.SubtitleProfiles.push({
Format: "ssa",
Method: "External"
});
}
}
var builderOpts = getBaseProfileOptions(item);
builderOpts.enableSsaRender = (item && !options.isRetry && "allcomplexformats" !== appSettings.get("subtitleburnin"));
profile = profileBuilder(builderOpts);
}
resolve(profile);
@ -237,10 +226,6 @@ define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings"], f
features.push("voiceinput");
}
if (!browser.tv && !browser.xboxOne) {
browser.ps4;
}
if (supportsHtmlMediaAutoplay()) {
features.push("htmlaudioautoplay");
features.push("htmlvideoautoplay");
@ -332,10 +317,10 @@ define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings"], f
require(["actionsheet"], function (actionsheet) {
exitPromise = actionsheet.show({
title: Globalize.translate("MessageConfirmAppExit"),
title: globalize.translate("MessageConfirmAppExit"),
items: [
{id: "yes", name: Globalize.translate("Yes")},
{id: "no", name: Globalize.translate("No")}
{id: "yes", name: globalize.translate("Yes")},
{id: "no", name: globalize.translate("No")}
]
}).then(function (value) {
if (value === "yes") {
@ -350,7 +335,7 @@ define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings"], f
var deviceId;
var deviceName;
var appName = "Jellyfin Web";
var appVersion = "10.5.0";
var appVersion = "10.6.0";
var appHost = {
getWindowState: function () {

View File

@ -5,7 +5,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
var currentResolve;
var currentReject;
var PlayerName = 'Chromecast';
var PlayerName = 'Google Cast';
function sendConnectionResult(isOk) {

View File

@ -1,4 +1,4 @@
define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-icon-button-light', 'css!./directorybrowser', 'formDialogStyle', 'emby-button'], function(loading, dialogHelper, dom) {
define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-input', 'paper-icon-button-light', 'css!./directorybrowser', 'formDialogStyle', 'emby-button'], function(loading, dialogHelper, dom, globalize) {
'use strict';
function getSystemInfo() {
@ -53,7 +53,7 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-
}
if (!path) {
html += getItem("lnkPath lnkDirectory", "", "Network", Globalize.translate("ButtonNetwork"));
html += getItem("lnkPath lnkDirectory", "", "Network", globalize.translate("ButtonNetwork"));
}
page.querySelector(".results").innerHTML = html;
@ -89,16 +89,16 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-
var instruction = options.instruction ? options.instruction + "<br/><br/>" : "";
html += '<div class="infoBanner" style="margin-bottom:1.5em;">';
html += instruction;
html += Globalize.translate("MessageDirectoryPickerInstruction", "<b>\\\\server</b>", "<b>\\\\192.168.1.101</b>");
html += globalize.translate("MessageDirectoryPickerInstruction", "<b>\\\\server</b>", "<b>\\\\192.168.1.101</b>");
if ("bsd" === systemInfo.OperatingSystem.toLowerCase()) {
html += "<br/>";
html += "<br/>";
html += Globalize.translate("MessageDirectoryPickerBSDInstruction");
html += globalize.translate("MessageDirectoryPickerBSDInstruction");
html += "<br/>";
} else if ("linux" === systemInfo.OperatingSystem.toLowerCase()) {
html += "<br/>";
html += "<br/>";
html += Globalize.translate("MessageDirectoryPickerLinuxInstruction");
html += globalize.translate("MessageDirectoryPickerLinuxInstruction");
html += "<br/>";
}
html += "</div>";
@ -113,10 +113,10 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-
labelKey = "LabelPath";
}
var readOnlyAttribute = options.pathReadOnly ? " readonly" : "";
html += '<input is="emby-input" id="txtDirectoryPickerPath" type="text" required="required" ' + readOnlyAttribute + ' label="' + Globalize.translate(labelKey) + '"/>';
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") + '"><i class="material-icons">search</i></button>';
html += '<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="' + globalize.translate("ButtonRefresh") + '"><i class="material-icons">search</i></button>';
}
html += "</div>";
if (!readOnlyAttribute) {
@ -124,14 +124,14 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-
}
if (options.enableNetworkSharePath) {
html += '<div class="inputContainer" style="margin-top:2em;">';
html += '<input is="emby-input" id="txtNetworkPath" type="text" label="' + Globalize.translate("LabelOptionalNetworkPath") + '"/>';
html += '<input is="emby-input" id="txtNetworkPath" type="text" label="' + globalize.translate("LabelOptionalNetworkPath") + '"/>';
html += '<div class="fieldDescription">';
html += Globalize.translate("LabelOptionalNetworkPathHelp");
html += globalize.translate("LabelOptionalNetworkPathHelp");
html += "</div>";
html += "</div>";
}
html += '<div class="formDialogFooter">';
html += '<button is="emby-button" type="submit" class="raised button-submit block formDialogFooterItem">' + Globalize.translate("ButtonOk") + "</button>";
html += '<button is="emby-button" type="submit" class="raised button-submit block formDialogFooterItem">' + globalize.translate("ButtonOk") + "</button>";
html += "</div>";
html += "</form>";
html += "</div>";
@ -164,14 +164,14 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-
}).catch(function(response) {
if (response) {
if (response.status === 404) {
alertText(Globalize.translate("PathNotFound"));
alertText(globalize.translate("PathNotFound"));
return Promise.reject();
}
if (response.status === 500) {
if (validateWriteable) {
alertText(Globalize.translate("WriteAccessRequired"));
alertText(globalize.translate("WriteAccessRequired"));
} else {
alertText(Globalize.translate("PathNotFound"));
alertText(globalize.translate("PathNotFound"));
}
return Promise.reject();
}
@ -266,7 +266,7 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-
html += '<div class="formDialogHeader">';
html += '<button is="paper-icon-button-light" class="btnCloseDialog autoSize" tabindex="-1"><i class="material-icons arrow_back"></i></button>';
html += '<h3 class="formDialogHeaderTitle">';
html += options.header || Globalize.translate("HeaderSelectPath");
html += options.header || globalize.translate("HeaderSelectPath");
html += "</h3>";
html += "</div>";
html += getEditorHtml(options, systemInfo);

View File

@ -24,9 +24,6 @@ define(["dom", "dialogHelper", "globalize", "connectionManager", "events", "brow
}
function renderFilters(context, result, query) {
if (result.Tags) {
result.Tags.length = Math.min(result.Tags.length, 50);
}
renderOptions(context, ".genreFilters", "chkGenreFilter", result.Genres, function (i) {
var delimeter = "|";
return (delimeter + (query.Genres || "") + delimeter).indexOf(delimeter + i + delimeter) != -1;

View File

@ -1,103 +0,0 @@
define(['events', 'dom', 'apphost', 'browser'], function (events, dom, appHost, browser) {
'use strict';
function fullscreenManager() {
}
fullscreenManager.prototype.requestFullscreen = function (element) {
element = element || document.documentElement;
if (element.requestFullscreen) {
element.requestFullscreen();
return;
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
return;
} else if (element.webkitRequestFullscreen) {
element.webkitRequestFullscreen();
return;
} else if (element.msRequestFullscreen) {
element.msRequestFullscreen();
return;
}
// Hack - This is only available for video elements in ios safari
if (element.tagName !== 'VIDEO') {
element = document.querySelector('video') || element;
}
if (element.webkitEnterFullscreen) {
element.webkitEnterFullscreen();
}
};
fullscreenManager.prototype.exitFullscreen = function () {
if (!this.isFullScreen()) {
return;
}
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.webkitCancelFullscreen) {
document.webkitCancelFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
};
// TODO: use screenfull.js
fullscreenManager.prototype.isFullScreen = function () {
return document.fullscreen ||
document.mozFullScreen ||
document.webkitIsFullScreen ||
document.msFullscreenElement || /* IE/Edge syntax */
document.fullscreenElement || /* Standard syntax */
document.webkitFullscreenElement || /* Chrome, Safari and Opera syntax */
document.mozFullScreenElement; /* Firefox syntax */
};
var manager = new fullscreenManager();
function onFullScreenChange() {
events.trigger(manager, 'fullscreenchange');
}
dom.addEventListener(document, 'fullscreenchange', onFullScreenChange, {
passive: true
});
dom.addEventListener(document, 'webkitfullscreenchange', onFullScreenChange, {
passive: true
});
dom.addEventListener(document, 'mozfullscreenchange', onFullScreenChange, {
passive: true
});
function isTargetValid(target) {
return !dom.parentWithTag(target, ['BUTTON', 'INPUT', 'TEXTAREA']);
}
if (appHost.supports("fullscreenchange") && (browser.edgeUwp || -1 !== navigator.userAgent.toLowerCase().indexOf("electron"))) {
dom.addEventListener(window, 'dblclick', function (e) {
if (isTargetValid(e.target)) {
if (manager.isFullScreen()) {
manager.exitFullscreen();
} else {
manager.requestFullscreen();
}
}
}, {
passive: true
});
}
return manager;
});

View File

@ -1,11 +0,0 @@
.headroom {
transition: transform 140ms linear;
}
.headroom--pinned {
transform: none;
}
.headroom--unpinned:not(.headroomDisabled) {
transform: translateY(-100%);
}

View File

@ -1,343 +0,0 @@
/*!
* headroom.js v0.7.0 - Give your page some headroom. Hide your header until you need it
* Copyright (c) 2014 Nick Williams - http://wicky.nillia.ms/headroom.js
* License: MIT
*/
define(['dom', 'layoutManager', 'browser', 'css!./headroom'], function (dom, layoutManager, browser) {
'use strict';
/* exported features */
var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
/**
* Handles debouncing of events via requestAnimationFrame
* @see http://www.html5rocks.com/en/tutorials/speed/animations/
* @param {Function} callback The callback to handle whichever event
*/
function Debouncer(callback) {
this.callback = callback;
this.ticking = false;
}
Debouncer.prototype = {
constructor: Debouncer,
/**
* dispatches the event to the supplied callback
* @private
*/
update: function () {
if (this.callback) {
this.callback();
}
this.ticking = false;
},
/**
* Attach this as the event listeners
*/
handleEvent: function () {
if (!this.ticking) {
requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this)));
this.ticking = true;
}
}
};
function onHeadroomClearedExternally() {
this.state = null;
}
/**
* UI enhancement for fixed headers.
* Hides header when scrolling down
* Shows header when scrolling up
* @constructor
* @param {DOMElement} elem the header element
* @param {Object} options options for the widget
*/
function Headroom(elems, options) {
options = Object.assign(Headroom.options, options || {});
this.lastKnownScrollY = 0;
this.elems = elems;
this.scroller = options.scroller;
this.debouncer = onScroll.bind(this);
this.offset = options.offset;
this.initialised = false;
this.initialClass = options.initialClass;
this.unPinnedClass = options.unPinnedClass;
this.pinnedClass = options.pinnedClass;
this.state = 'clear';
this.options = {
offset: 0,
scroller: window,
initialClass: 'headroom',
unPinnedClass: 'headroom--unpinned',
pinnedClass: 'headroom--pinned'
};
this.add = function (elem) {
if (browser.supportsCssAnimation()) {
elem.classList.add(this.initialClass);
elem.addEventListener('clearheadroom', onHeadroomClearedExternally.bind(this));
this.elems.push(elem);
}
};
this.remove = function (elem) {
elem.classList.remove(this.unPinnedClass);
elem.classList.remove(this.initialClass);
elem.classList.remove(this.pinnedClass);
var i = this.elems.indexOf(elem);
if (i !== -1) {
this.elems.splice(i, 1);
}
};
this.pause = function () {
this.paused = true;
};
this.resume = function () {
this.paused = false;
};
/**
* Unattaches events and removes any classes that were added
*/
this.destroy = function () {
this.initialised = false;
for (var i = 0, length = this.elems.length; i < length; i++) {
var classList = this.elems[i].classList;
classList.remove(this.unPinnedClass);
classList.remove(this.initialClass);
classList.remove(this.pinnedClass);
}
var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : 'scroll';
dom.removeEventListener(this.scroller, scrollEventName, this.debouncer, {
capture: false,
passive: true
});
};
/**
* Attaches the scroll event
* @private
*/
this.attachEvent = function () {
if (!this.initialised) {
this.lastKnownScrollY = this.getScrollY();
this.initialised = true;
var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : 'scroll';
dom.addEventListener(this.scroller, scrollEventName, this.debouncer, {
capture: false,
passive: true
});
this.update();
}
};
/**
* Unpins the header if it's currently pinned
*/
this.clear = function () {
if (this.state === 'clear') {
return;
}
this.state = 'clear';
var unpinnedClass = this.unPinnedClass;
var pinnedClass = this.pinnedClass;
for (var i = 0, length = this.elems.length; i < length; i++) {
var classList = this.elems[i].classList;
classList.remove(unpinnedClass);
//classList.remove(pinnedClass);
}
};
/**
* Unpins the header if it's currently pinned
*/
this.pin = function () {
if (this.state === 'pin') {
return;
}
this.state = 'pin';
var unpinnedClass = this.unPinnedClass;
var pinnedClass = this.pinnedClass;
for (var i = 0, length = this.elems.length; i < length; i++) {
var classList = this.elems[i].classList;
classList.remove(unpinnedClass);
classList.add(pinnedClass);
}
};
/**
* Unpins the header if it's currently pinned
*/
this.unpin = function () {
if (this.state === 'unpin') {
return;
}
this.state = 'unpin';
var unpinnedClass = this.unPinnedClass;
var pinnedClass = this.pinnedClass;
for (var i = 0, length = this.elems.length; i < length; i++) {
var classList = this.elems[i].classList;
classList.add(unpinnedClass);
//classList.remove(pinnedClass);
}
};
/**
* Gets the Y scroll position
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY
* @return {Number} pixels the page has scrolled along the Y-axis
*/
this.getScrollY = function () {
var scroller = this.scroller;
if (scroller.getScrollPosition) {
return scroller.getScrollPosition();
}
var pageYOffset = scroller.pageYOffset;
if (pageYOffset !== undefined) {
return pageYOffset;
}
var scrollTop = scroller.scrollTop;
if (scrollTop !== undefined) {
return scrollTop;
}
return (document.documentElement || document.body).scrollTop;
};
/**
* determine if it is appropriate to unpin
* @param {int} currentScrollY the current y scroll position
* @return {bool} true if should unpin, false otherwise
*/
this.shouldUnpin = function (currentScrollY) {
var scrollingDown = currentScrollY > this.lastKnownScrollY;
var pastOffset = currentScrollY >= this.offset;
return scrollingDown && pastOffset;
};
/**
* determine if it is appropriate to pin
* @param {int} currentScrollY the current y scroll position
* @return {bool} true if should pin, false otherwise
*/
this.shouldPin = function (currentScrollY) {
var scrollingUp = currentScrollY < this.lastKnownScrollY;
var pastOffset = currentScrollY <= this.offset;
return scrollingUp || pastOffset;
};
/**
* Handles updating the state of the widget
*/
this.update = function () {
if (this.paused) {
return;
}
var currentScrollY = this.getScrollY();
var lastKnownScrollY = this.lastKnownScrollY;
var isTv = layoutManager.tv;
if (currentScrollY <= (isTv ? 120 : 10)) {
this.clear();
} else if (this.shouldUnpin(currentScrollY)) {
this.unpin();
} else if (this.shouldPin(currentScrollY)) {
var toleranceExceeded = Math.abs(currentScrollY - lastKnownScrollY) >= 14;
if (currentScrollY && isTv) {
this.unpin();
} else if (toleranceExceeded) {
this.clear();
}
} else if (isTv) {
//this.clear();
}
this.lastKnownScrollY = currentScrollY;
};
if (browser.supportsCssAnimation()) {
for (var i = 0, length = this.elems.length; i < length; i++) {
this.elems[i].classList.add(this.initialClass);
this.elems[i].addEventListener('clearheadroom', onHeadroomClearedExternally.bind(this));
}
this.attachEvent();
}
}
function onScroll() {
if (this.paused) {
return;
}
requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this)));
}
/**
* Default options
* @type {Object}
*/
Headroom.options = {
offset: 0,
scroller: window,
initialClass: 'headroom',
unPinnedClass: 'headroom--unpinned',
pinnedClass: 'headroom--pinned'
};
return Headroom;
});

View File

@ -64,13 +64,13 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} else {
var noLibDescription;
if (user['Policy'] && user['Policy']['IsAdministrator']) {
noLibDescription = Globalize.translate("NoCreatedLibraries", '<a id="button-createLibrary" class="button-link">', '</a>');
noLibDescription = globalize.translate("NoCreatedLibraries", '<br><a id="button-createLibrary" class="button-link">', '</a>');
} else {
noLibDescription = Globalize.translate("AskAdminToCreateLibrary");
noLibDescription = globalize.translate("AskAdminToCreateLibrary");
}
html += '<div class="centerMessage padded-left padded-right">';
html += '<h2>' + Globalize.translate("MessageNothingHere") + '</h2>';
html += '<h2>' + globalize.translate("MessageNothingHere") + '</h2>';
html += '<p>' + noLibDescription + '</p>';
html += '</div>';
elem.innerHTML = html;
@ -243,9 +243,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
return function (items) {
var cardLayout = false;
var shape;
if (itemType === 'Channel' || viewType === 'movies' || viewType === 'books') {
if (itemType === 'Channel' || viewType === 'movies' || viewType === 'books' || viewType === 'tvshows') {
shape = getPortraitShape();
} else if (viewType === 'music') {
} else if (viewType === 'music' || viewType === 'homevideos') {
shape = getSquareShape();
} else {
shape = getThumbShape();

View File

@ -162,7 +162,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
}
}
function seekOnPlaybackStart(instance, element, ticks) {
function seekOnPlaybackStart(instance, element, ticks, onMediaReady) {
var seconds = (ticks || 0) / 10000000;
@ -175,6 +175,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
if (element.duration >= seconds) {
// media is ready, seek immediately
setCurrentTimeIfNeeded(element, seconds);
if (onMediaReady) onMediaReady();
} else {
// update video player position when media is ready to be sought
var events = ["durationchange", "loadeddata", "play", "loadedmetadata"];
@ -189,6 +190,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
events.map(function(name) {
element.removeEventListener(name, onMediaChange);
});
if (onMediaReady) onMediaReady();
}
};
events.map(function (name) {

View File

@ -1,4 +1,4 @@
define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackManager', 'appRouter', 'appSettings', 'connectionManager', 'htmlMediaHelper', 'itemHelper', 'fullscreenManager', 'globalize'], function (browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager, htmlMediaHelper, itemHelper, fullscreenManager, globalize) {
define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackManager', 'appRouter', 'appSettings', 'connectionManager', 'htmlMediaHelper', 'itemHelper', 'screenfull', 'globalize'], function (browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager, htmlMediaHelper, itemHelper, screenfull, globalize) {
"use strict";
/* globals cast */
@ -795,7 +795,9 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
dlg.parentNode.removeChild(dlg);
}
fullscreenManager.exitFullscreen();
if (screenfull.isEnabled) {
screenfull.exit();
}
};
function onEnded() {
@ -857,7 +859,9 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
loading.hide();
htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks);
htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks, function () {
if (currentSubtitlesOctopus) currentSubtitlesOctopus.resize();
});
if (self._currentPlayOptions.fullscreen) {

View File

@ -90,7 +90,7 @@ define(["apphost", "globalize", "connectionManager", "itemHelper", "appRouter",
});
}
if (itemHelper.supportsAddingToPlaylist(item)) {
if (itemHelper.supportsAddingToPlaylist(item) && options.playlist !== false) {
commands.push({
name: globalize.translate("AddToPlaylist"),
id: "addtoplaylist",
@ -218,7 +218,7 @@ define(["apphost", "globalize", "connectionManager", "itemHelper", "appRouter",
if (item.Type === "Program" && options.record !== false) {
if (item.TimerId) {
commands.push({
name: Globalize.translate("ManageRecording"),
name: globalize.translate("ManageRecording"),
id: "record",
icon: "fiber_manual_record"
});
@ -228,7 +228,7 @@ define(["apphost", "globalize", "connectionManager", "itemHelper", "appRouter",
if (item.Type === "Program" && options.record !== false) {
if (!item.TimerId) {
commands.push({
name: Globalize.translate("Record"),
name: globalize.translate("Record"),
id: "record",
icon: "fiber_manual_record"
});
@ -283,7 +283,7 @@ define(["apphost", "globalize", "connectionManager", "itemHelper", "appRouter",
if (options.openAlbum !== false && item.AlbumId && item.MediaType !== "Photo") {
commands.push({
name: Globalize.translate("ViewAlbum"),
name: globalize.translate("ViewAlbum"),
id: "album",
icon: "album"
});
@ -291,7 +291,7 @@ define(["apphost", "globalize", "connectionManager", "itemHelper", "appRouter",
if (options.openArtist !== false && item.ArtistItems && item.ArtistItems.length) {
commands.push({
name: Globalize.translate("ViewArtist"),
name: globalize.translate("ViewArtist"),
id: "artist",
icon: "person"
});

View File

@ -45,7 +45,7 @@ define(['browser', 'appSettings', 'events'], function (browser, appSettings, eve
// Take a guess at initial layout. The consuming app can override
if (browser.mobile) {
this.setLayout('mobile', false);
} else if (browser.tv || browser.xboxOne) {
} else if (browser.tv || browser.xboxOne || browser.ps4) {
this.setLayout('tv', false);
} else {
this.setLayout(this.defaultLayout || 'tv', false);

View File

@ -166,6 +166,7 @@ define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom,
}).join('') + '</div></div>';
tabsContainerElem.innerHTML = tabsHtml;
window.CustomElements.upgradeSubtree(tabsContainerElem);
document.body.classList.add('withSectionTabs');
tabOwnerView = view;

View File

@ -1,4 +1,4 @@
define(["loading", "dialogHelper", "dom", "jQuery", "components/libraryoptionseditor/libraryoptionseditor", "emby-toggle", "emby-input", "emby-select", "paper-icon-button-light", "listViewStyle", "formDialogStyle", "emby-button", "flexStyles"], function (loading, dialogHelper, dom, $, libraryoptionseditor) {
define(["loading", "dialogHelper", "dom", "jQuery", "components/libraryoptionseditor/libraryoptionseditor", "globalize", "emby-toggle", "emby-input", "emby-select", "paper-icon-button-light", "listViewStyle", "formDialogStyle", "emby-button", "flexStyles"], function (loading, dialogHelper, dom, $, libraryoptionseditor, globalize) {
"use strict";
function onAddLibrary() {
@ -9,7 +9,7 @@ define(["loading", "dialogHelper", "dom", "jQuery", "components/libraryoptionsed
if (pathInfos.length == 0) {
require(["alert"], function (alert) {
alert({
text: Globalize.translate("PleaseAddAtLeastOneFolder"),
text: globalize.translate("PleaseAddAtLeastOneFolder"),
type: "error"
});
});
@ -36,7 +36,7 @@ define(["loading", "dialogHelper", "dom", "jQuery", "components/libraryoptionsed
dialogHelper.close(dlg);
}, function () {
require(["toast"], function (toast) {
toast(Globalize.translate("ErrorAddingMediaPathToVirtualFolder"));
toast(globalize.translate("ErrorAddingMediaPathToVirtualFolder"));
});
isCreating = false;
@ -196,7 +196,7 @@ define(["loading", "dialogHelper", "dom", "jQuery", "components/libraryoptionsed
dlg.classList.add("background-theme-a");
dlg.classList.add("dlg-librarycreator");
dlg.classList.add("formDialog");
dlg.innerHTML = Globalize.translateDocument(template);
dlg.innerHTML = globalize.translateDocument(template);
initEditor(dlg, options.collectionTypeOptions);
dlg.addEventListener("close", onDialogClosed);
dialogHelper.open(dlg);

View File

@ -1,4 +1,4 @@
define(["jQuery", "loading", "dialogHelper", "dom", "components/libraryoptionseditor/libraryoptionseditor", "emby-button", "listViewStyle", "paper-icon-button-light", "formDialogStyle", "emby-toggle", "flexStyles"], function (jQuery, loading, dialogHelper, dom, libraryoptionseditor) {
define(["jQuery", "loading", "dialogHelper", "dom", "components/libraryoptionseditor/libraryoptionseditor", "globalize", "emby-button", "listViewStyle", "paper-icon-button-light", "formDialogStyle", "emby-toggle", "flexStyles"], function (jQuery, loading, dialogHelper, dom, libraryoptionseditor, globalize) {
"use strict";
function onEditLibrary() {
@ -31,7 +31,7 @@ define(["jQuery", "loading", "dialogHelper", "dom", "components/libraryoptionsed
refreshLibraryFromServer(page);
}, function () {
require(["toast"], function (toast) {
toast(Globalize.translate("ErrorAddingMediaPathToVirtualFolder"));
toast(globalize.translate("ErrorAddingMediaPathToVirtualFolder"));
});
});
}
@ -46,7 +46,7 @@ define(["jQuery", "loading", "dialogHelper", "dom", "components/libraryoptionsed
refreshLibraryFromServer(page);
}, function () {
require(["toast"], function (toast) {
toast(Globalize.translate("ErrorAddingMediaPathToVirtualFolder"));
toast(globalize.translate("ErrorAddingMediaPathToVirtualFolder"));
});
});
}
@ -57,9 +57,9 @@ define(["jQuery", "loading", "dialogHelper", "dom", "components/libraryoptionsed
require(["confirm"], function (confirm) {
confirm({
title: Globalize.translate("HeaderRemoveMediaLocation"),
text: Globalize.translate("MessageConfirmRemoveMediaLocation"),
confirmText: Globalize.translate("ButtonDelete"),
title: globalize.translate("HeaderRemoveMediaLocation"),
text: globalize.translate("MessageConfirmRemoveMediaLocation"),
confirmText: globalize.translate("ButtonDelete"),
primary: "delete"
}).then(function () {
var refreshAfterChange = currentOptions.refresh;
@ -68,7 +68,7 @@ define(["jQuery", "loading", "dialogHelper", "dom", "components/libraryoptionsed
refreshLibraryFromServer(dom.parentWithClass(button, "dlg-libraryeditor"));
}, function () {
require(["toast"], function (toast) {
toast(Globalize.translate("DefaultErrorMessage"));
toast(globalize.translate("DefaultErrorMessage"));
});
});
});
@ -213,7 +213,7 @@ define(["jQuery", "loading", "dialogHelper", "dom", "components/libraryoptionsed
dlg.classList.add("ui-body-a");
dlg.classList.add("background-theme-a");
dlg.classList.add("formDialog");
dlg.innerHTML = Globalize.translateDocument(template);
dlg.innerHTML = globalize.translateDocument(template);
dlg.querySelector(".formDialogHeaderTitle").innerHTML = options.library.Name;
initEditor(dlg, options);
dlg.addEventListener("close", onDialogClosed);

View File

@ -212,7 +212,7 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo
if (user.Policy.EnableContentDownloading && appHost.supports("filedownload")) {
menuItems.push({
name: Globalize.translate("ButtonDownload"),
name: globalize.translate("ButtonDownload"),
id: "download",
icon: "file_download"
});

View File

@ -5,7 +5,8 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
document.removeEventListener('click', onOneDocumentClick);
document.removeEventListener('keydown', onOneDocumentClick);
if (window.Notification) {
// don't request notification permissions if they're already granted or denied
if (window.Notification && window.Notification.permission === "default") {
/* eslint-disable-next-line compat/compat */
Notification.requestPermission();
}

View File

@ -1,4 +1,4 @@
define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', 'layoutManager', 'playbackManager', 'nowPlayingHelper', 'apphost', 'dom', 'connectionManager', 'paper-icon-button-light', 'emby-ratingbutton'], function (require, datetime, itemHelper, events, browser, imageLoader, layoutManager, playbackManager, nowPlayingHelper, appHost, dom, connectionManager) {
define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', 'layoutManager', 'playbackManager', 'nowPlayingHelper', 'apphost', 'dom', 'connectionManager', 'itemContextMenu', 'paper-icon-button-light', 'emby-ratingbutton'], function (require, datetime, itemHelper, events, browser, imageLoader, layoutManager, playbackManager, nowPlayingHelper, appHost, dom, connectionManager, itemContextMenu) {
'use strict';
var currentPlayer;
@ -66,7 +66,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
html += '</div>';
html += '<button is="paper-icon-button-light" class="playPauseButton mediaButton"><i class="material-icons">pause</i></button>';
html += '<button is="paper-icon-button-light" class="remoteControlButton mediaButton"><i class="material-icons playlist_play"></i></button>';
html += '<button is="paper-icon-button-light" class="btnToggleContextMenu"><i class="material-icons more_vert"></i></button>';
html += '</div>';
html += '</div>';
@ -155,8 +155,6 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
}
});
elem.querySelector('.remoteControlButton').addEventListener('click', showRemoteControl);
toggleRepeatButton = elem.querySelector('.toggleRepeatButton');
toggleRepeatButton.addEventListener('click', function () {
@ -187,29 +185,15 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
volumeSliderContainer.classList.remove('hide');
}
var volumeSliderTimer;
function setVolume() {
clearTimeout(volumeSliderTimer);
volumeSliderTimer = null;
if (currentPlayer) {
currentPlayer.setVolume(this.value);
}
}
function setVolumeDelayed() {
if (!volumeSliderTimer) {
var that = this;
volumeSliderTimer = setTimeout(function () {
setVolume.call(that);
}, 700);
}
}
volumeSlider.addEventListener('change', setVolume);
volumeSlider.addEventListener('mousemove', setVolumeDelayed);
volumeSlider.addEventListener('touchmove', setVolumeDelayed);
volumeSlider.addEventListener('mousemove', setVolume);
volumeSlider.addEventListener('touchmove', setVolume);
positionSlider = elem.querySelector('.nowPlayingBarPositionSlider');
positionSlider.addEventListener('change', function () {
@ -240,7 +224,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
elem.addEventListener('click', function (e) {
if (!dom.parentWithTag(e.target, ['BUTTON', 'INPUT', 'A'])) {
if (!dom.parentWithTag(e.target, ['BUTTON', 'INPUT'])) {
showRemoteControl();
}
});
@ -449,17 +433,13 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
}
}
function getTextActionButton(item, text, serverId) {
function getTextActionButton(item, text) {
if (!text) {
text = itemHelper.getDisplayName(item);
}
var html = '<button data-id="' + item.Id + '" data-serverid="' + (item.ServerId || serverId) + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-channelid="' + item.ChannelId + '" data-isfolder="' + item.IsFolder + '" type="button" class="itemAction textActionButton" data-action="link">';
html += text;
html += '</button>';
return html;
return `<a>${text}</a>`;
}
function seriesImageUrl(item, options) {
@ -537,16 +517,16 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
if (textLines.length > 1) {
textLines[1].secondary = true;
}
var serverId = nowPlayingItem ? nowPlayingItem.ServerId : null;
nowPlayingTextElement.innerHTML = textLines.map(function (nowPlayingName) {
var cssClass = nowPlayingName.secondary ? ' class="nowPlayingBarSecondaryText"' : '';
if (nowPlayingName.item) {
return '<div' + cssClass + '>' + getTextActionButton(nowPlayingName.item, nowPlayingName.text, serverId) + '</div>';
var nowPlayingText = getTextActionButton(nowPlayingName.item, nowPlayingName.text);
return `<div ${cssClass}>${nowPlayingText}</div>`;
}
return '<div' + cssClass + '>' + nowPlayingName.text + '</div>';
return `<div ${cssClass}>${nowPlayingText}</div>`;
}).join('');
@ -575,15 +555,25 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
if (isRefreshing) {
var apiClient = connectionManager.getApiClient(nowPlayingItem.ServerId);
apiClient.getItem(apiClient.getCurrentUserId(), nowPlayingItem.Id).then(function (item) {
var userData = item.UserData || {};
var likes = userData.Likes == null ? '' : userData.Likes;
var contextButton = document.querySelector('.btnToggleContextMenu');
var options = {
play: false,
queue: false,
positionTo: contextButton
};
nowPlayingUserData.innerHTML = '<button is="emby-ratingbutton" type="button" class="listItemButton mediaButton paper-icon-button-light" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-likes="' + likes + '" data-isfavorite="' + (userData.IsFavorite) + '"><i class="material-icons">favorite</i></button>';
apiClient.getCurrentUser().then(function(user) {
contextButton.addEventListener('click', function () {
itemContextMenu.show(Object.assign({
item: item,
user: user
}, options ));
});
});
});
}
} else {
nowPlayingUserData.innerHTML = '';

View File

@ -44,24 +44,15 @@ define(['connectionManager', 'globalize', 'userSettings', 'apphost'], function (
}
function showBlurayMessage() {
var message =
'Playback of Bluray folders in this app is experimental. Some titles may not work at all. For a better experience, consider converting to mkv video files, or use an Jellyfin app with native Bluray folder support.';
return showMessage(message, 'blurayexpirementalinfo', 'nativeblurayplayback');
return showMessage(globalize.translate("UnsupportedPlayback"), 'blurayexpirementalinfo', 'nativeblurayplayback');
}
function showDvdMessage() {
var message =
'Playback of Dvd folders in this app is experimental. Some titles may not work at all. For a better experience, consider converting to mkv video files, or use an Jellyfin app with native Dvd folder support.';
return showMessage(message, 'dvdexpirementalinfo', 'nativedvdplayback');
return showMessage(globalize.translate("UnsupportedPlayback"), 'dvdexpirementalinfo', 'nativedvdplayback');
}
function showIsoMessage() {
var message =
'Playback of ISO files in this app is experimental. Some titles may not work at all. For a better experience, consider converting to mkv video files, or use an Jellyfin app with native ISO support.';
return showMessage(message, 'isoexpirementalinfo', 'nativeisoplayback');
return showMessage(globalize.translate("UnsupportedPlayback"), 'isoexpirementalinfo', 'nativeisoplayback');
}
function ExpirementalPlaybackWarnings() {

View File

@ -1,6 +1,9 @@
define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'playQueueManager', 'userSettings', 'globalize', 'connectionManager', 'loading', 'apphost', 'fullscreenManager'], function (events, datetime, appSettings, itemHelper, pluginManager, PlayQueueManager, userSettings, globalize, connectionManager, loading, apphost, fullscreenManager) {
define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'playQueueManager', 'userSettings', 'globalize', 'connectionManager', 'loading', 'apphost', 'screenfull'], function (events, datetime, appSettings, itemHelper, pluginManager, PlayQueueManager, userSettings, globalize, connectionManager, loading, apphost, screenfull) {
'use strict';
/** Delay time in ms for reportPlayback logging */
const reportPlaybackLogDelay = 1e3;
function enableLocalPlaylistManagement(player) {
if (player.getPlaylist) {
@ -17,9 +20,11 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
}
function bindToFullscreenChange(player) {
events.on(fullscreenManager, 'fullscreenchange', function () {
events.trigger(player, 'fullscreenchange');
});
if (screenfull.isEnabled) {
screenfull.on('change', function () {
events.trigger(player, 'fullscreenchange');
});
}
}
function triggerPlayerChange(playbackManagerInstance, newPlayer, newTarget, previousPlayer, previousTargetInfo) {
@ -38,6 +43,12 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
events.trigger(playbackManagerInstance, 'playerchange', [newPlayer, newTarget, previousPlayer]);
}
/** Last invoked method */
let reportPlaybackLastMethod;
/** Last invoke time of method */
let reportPlaybackLastTime;
function reportPlayback(playbackManagerInstance, state, player, reportPlaylist, serverId, method, progressEventName) {
if (!serverId) {
@ -57,7 +68,14 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
addPlaylistToPlaybackReport(playbackManagerInstance, info, player, serverId);
}
console.debug(method + '-' + JSON.stringify(info));
const now = (new Date).getTime();
if (method !== reportPlaybackLastMethod || now - (reportPlaybackLastTime || 0) >= reportPlaybackLogDelay) {
console.debug(method + '-' + JSON.stringify(info));
reportPlaybackLastMethod = method;
reportPlaybackLastTime = now;
}
var apiClient = connectionManager.getApiClient(serverId);
apiClient[method](info);
}
@ -1518,7 +1536,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
return player.isFullscreen();
}
return fullscreenManager.isFullScreen();
return screenfull.isFullscreen;
};
self.toggleFullscreen = function (player) {
@ -1528,10 +1546,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
return player.toggleFulscreen();
}
if (fullscreenManager.isFullScreen()) {
fullscreenManager.exitFullscreen();
} else {
fullscreenManager.requestFullscreen();
if (screenfull.isEnabled) {
screenfull.toggle();
}
};
@ -3378,7 +3394,6 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
pluginManager.ofType('mediaplayer').map(initMediaPlayer);
function sendProgressUpdate(player, progressEventName, reportPlaylist) {
if (!player) {
throw new Error('player cannot be null');
}

View File

@ -1,24 +0,0 @@
if (typeof Object.assign != 'function') {
(function () {
Object.assign = function (target) {
'use strict';
if (target === undefined || target === null) {
throw new TypeError('Cannot convert undefined or null to object');
}
var output = Object(target);
for (var index = 1; index < arguments.length; index++) {
var source = arguments[index];
if (source !== undefined && source !== null) {
for (var nextKey in source) {
// eslint-disable-next-line no-prototype-builtins
if (source.hasOwnProperty(nextKey)) {
output[nextKey] = source[nextKey];
}
}
}
}
return output;
};
})();
}

View File

@ -1,3 +1,7 @@
.nowPlayingPage {
padding: 5em 0 0 0 !important;
}
.nowPlayingInfoContainer {
display: -webkit-box;
display: -webkit-flex;
@ -36,8 +40,30 @@
margin: 0 0 0.5em 0.5em;
}
.nowPlayingAlbum a,
.nowPlayingArtist a {
font-weight: normal;
text-align: left !important;
color: inherit !important;
}
.nowPlayingButtonsContainer {
display: flex;
}
.nowPlayingInfoContainerMedia {
text-align: left;
margin-bottom: 1em;
}
.nowPlayingPositionSlider {
width: stretch;
}
.nowPlayingPositionSliderContainer {
margin: 0.7em 0 0.7em 1em;
margin: 0.2em 1em 0.2em 1em;
width: 100%;
z-index: 0;
}
.nowPlayingInfoButtons {
@ -59,17 +85,32 @@
}
.nowPlayingPageImageContainer {
width: 20%;
margin-right: 0.25em;
width: 16%;
margin-right: 1em;
position: relative;
-webkit-flex-shrink: 0;
flex-shrink: 0;
}
@media all and (min-width: 50em) {
.nowPlayingPageImageContainer {
width: 16%;
}
.nowPlayingPageImageContainerNoAlbum {
width: 100%;
position: relative;
}
.nowPlayingPageImageContainerNoAlbum button {
cursor: default;
}
.nowPlayingPageImageContainerNoAlbum::after {
content: "";
display: block;
padding-bottom: 100%;
}
.btnPlayPause {
font-size: xx-large;
padding: 0;
margin: 0;
}
.nowPlayingInfoControls {
@ -87,14 +128,15 @@
}
.nowPlayingPageImage {
display: block;
bottom: 0;
left: 0;
right: 0;
margin: 0 auto;
width: 100%;
-webkit-box-shadow: 0 0 1.9vh #000;
box-shadow: 0 0 1.9vh #000;
border: 0.1em solid #222;
user-drag: none;
user-select: none;
-moz-user-select: none;
-webkit-user-drag: none;
@ -102,60 +144,16 @@
-ms-user-select: none;
}
@media all and (orientation: portrait) and (max-width: 50em) {
.nowPlayingInfoContainer {
-webkit-box-orient: vertical !important;
-webkit-box-direction: normal !important;
-webkit-flex-direction: column !important;
flex-direction: column !important;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
}
.nowPlayingPageTitle {
text-align: center;
margin: 0.5em 0 0.75em;
}
.nowPlayingPositionSliderContainer {
margin: 0.7em 1em;
}
.nowPlayingInfoButtons {
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
}
.nowPlayingPageImageContainer {
width: auto;
margin-right: 0;
}
.nowPlayingInfoControls {
margin-top: 1em;
max-width: 100%;
}
.nowPlayingPageImage {
width: auto;
height: 36vh;
}
.contextMenuList {
padding: 1.5em 0;
}
@media all and (orientation: portrait) and (max-width: 40em) {
.nowPlayingPageImage {
height: 30vh;
}
.contextMenuList a {
color: inherit !important;
}
.nowPlayingTime {
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
margin: 0 1em;
.contextMenuList i.listItemIcon {
font-size: x-large;
}
.nowPlayingSecondaryButtons {
@ -167,12 +165,17 @@
align-items: center;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
justify-content: flex-end;
z-index: 0;
}
@media all and (min-width: 50em) {
@media all and (min-width: 63em) {
.nowPlayingPage {
padding: 8em 0 0 0 !important;
}
.nowPlayingSecondaryButtons {
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
@ -181,6 +184,16 @@
-webkit-justify-content: flex-end;
justify-content: flex-end;
}
.nowPlayingPageUserDataButtonsTitle {
display: none !important;
}
.playlistSectionButton,
.nowPlayingPlaylist,
.nowPlayingContextMenu {
background: unset !important;
}
}
@media all and (min-width: 80em) {
@ -189,6 +202,414 @@
}
}
@media all and (orientation: portrait) and (max-width: 47em) {
.remoteControlContent {
padding-left: 7.3% !important;
padding-right: 7.3% !important;
display: flex;
height: 100%;
flex-direction: column;
}
.nowPlayingInfoContainer {
-webkit-box-orient: vertical !important;
-webkit-box-direction: normal !important;
-webkit-flex-direction: column !important;
flex-direction: column !important;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
width: 100%;
height: calc(100% - 4.2em);
}
.nowPlayingPageTitle {
/* text-align: center; */
margin: 0;
}
.nowPlayingAlbum,
.nowPlayingArtist {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.nowPlayingInfoContainerMedia {
text-align: left !important;
width: 80%;
}
.nowPlayingPositionSliderContainer {
margin: 0.2em 1em 0.2em 1em;
}
.nowPlayingInfoButtons {
/* margin: 1.5em 0 0 0; */
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
font-size: x-large;
height: 100%;
}
.nowPlayingPageImageContainer {
width: 100%;
margin: auto auto 0.5em;
}
.nowPlayingPageImageContainerNoAlbum .cardImageContainer .cardImageIcon {
font-size: 15em;
color: inherit;
}
.nowPlayingInfoControls {
margin: 0.5em 0 1em 0;
width: 100%;
-webkit-box-pack: start !important;
-webkit-justify-content: start !important;
justify-content: start !important;
}
.nowPlayingSecondaryButtons {
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
}
.nowPlayingInfoControls .nowPlayingPageUserDataButtonsTitle {
width: 20%;
font-size: large;
}
.nowPlayingInfoControls .nowPlayingPageUserDataButtonsTitle button {
padding-top: 0;
padding-right: 0;
margin-right: 0;
float: right;
border-radius: 0;
}
.nowPlayingInfoButtons .btnRewind {
position: absolute;
left: 0;
margin-left: 0;
padding-left: 7.3%;
font-size: smaller;
}
.nowPlayingInfoButtons .btnFastForward {
position: absolute;
right: 0;
margin-right: 0;
padding-right: 7.3%;
font-size: smaller;
}
.paper-icon-button-light:hover {
color: #fff !important;
background-color: transparent !important;
}
.btnPlayPause {
padding: 0;
margin: 0;
font-size: 1.7em;
}
.btnPlayPause:hover {
background-color: transparent !important;
}
.nowPlayingPageImage {
/* width: inherit; */
overflow-y: hidden;
overflow: hidden;
margin: 0 auto;
}
.nowPlayingPageImage.nowPlayingPageImageAudio {
width: 100%;
}
.nowPlayingPageImageContainer.nowPlayingPageImagePoster {
height: 50%;
overflow: hidden;
}
.nowPlayingPageImageContainer.nowPlayingPageImagePoster img {
height: 100%;
width: auto;
}
#nowPlayingPage .playlistSection .playlist,
#nowPlayingPage .playlistSection .contextMenu {
position: absolute;
top: 12.2em;
bottom: 4.2em;
overflow: scroll;
padding: 0 1em;
display: inline-block;
left: 0;
right: 0;
z-index: 1000;
}
.playlistSectionButton {
position: fixed;
bottom: 0;
left: 0;
height: 4.2em;
right: 0;
padding-left: 7.3%;
padding-right: 7.3%;
}
.playlistSectionButton .btnTogglePlaylist {
font-size: larger;
margin: 0;
padding-left: 0;
}
.playlistSectionButton .btnSavePlaylist {
margin: 0;
padding-right: 0;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1;
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
justify-content: flex-end;
border-radius: 0;
}
.playlistSectionButton .btnToggleContextMenu {
font-size: larger;
margin: 0;
padding-right: 0;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1;
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
justify-content: flex-end;
border-radius: 0;
}
.playlistSectionButton .volumecontrol {
width: 100%;
}
.remoteControlSection {
margin: 0;
padding: 0 0 4.2em 0;
}
.nowPlayingButtonsContainer {
display: flex;
height: 100%;
flex-direction: column;
}
}
@media all and (orientation: landscape) and (max-width: 63em) {
.remoteControlContent {
padding-left: 4.3% !important;
padding-right: 4.3% !important;
display: flex;
height: 100%;
flex-direction: column;
}
.nowPlayingInfoContainer {
-webkit-box-orient: horizontal !important;
-webkit-box-direction: normal !important;
-webkit-flex-direction: row !important;
flex-direction: row !important;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
width: 100%;
height: calc(100% - 4.2em);
}
.nowPlayingPageTitle {
/* text-align: center; */
margin: 0;
}
.nowPlayingInfoContainerMedia {
text-align: left !important;
width: 80%;
}
.nowPlayingPositionSliderContainer {
margin: 0.2em 1em 0.2em 1em;
}
.nowPlayingInfoButtons {
/* margin: 1.5em 0 0 0; */
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
font-size: x-large;
height: 100%;
}
.nowPlayingPageImageContainer {
width: 30%;
margin: auto 1em auto auto;
}
.nowPlayingPageImageContainerNoAlbum .cardImageContainer .cardImageIcon {
font-size: 12em;
color: inherit;
}
.nowPlayingInfoControls {
margin: 0.5em 0 1em 0;
width: 100%;
-webkit-box-pack: start !important;
-webkit-justify-content: start !important;
justify-content: start !important;
}
.nowPlayingSecondaryButtons {
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
}
.nowPlayingInfoControls .nowPlayingPageUserDataButtonsTitle {
width: 20%;
font-size: large;
}
.nowPlayingInfoControls .nowPlayingPageUserDataButtonsTitle button {
padding-top: 0;
padding-right: 0;
margin-right: 0;
float: right;
border-radius: 0;
}
.paper-icon-button-light:hover {
color: #fff !important;
background-color: transparent !important;
}
.btnPlayPause {
padding: 0;
margin: 0;
font-size: 1.7em;
}
.btnPlayPause:hover {
background-color: transparent !important;
}
.nowPlayingPageImage {
/* width: inherit; */
overflow-y: hidden;
overflow: hidden;
margin: 0 auto;
}
.nowPlayingPageImage.nowPlayingPageImageAudio {
width: 100%;
}
.nowPlayingPageImageContainer.nowPlayingPageImagePoster {
height: 100%;
overflow: hidden;
}
.nowPlayingPageImageContainer.nowPlayingPageImagePoster img {
height: 100%;
width: auto;
}
#nowPlayingPage .playlistSection .playlist,
#nowPlayingPage .playlistSection .contextMenu {
position: absolute;
top: 7.2em;
bottom: 4.2em;
overflow: scroll;
padding: 0 1em;
display: inline-block;
left: 0;
right: 0;
z-index: 1000;
}
.playlistSectionButton {
position: fixed;
bottom: 0;
left: 0;
height: 4.2em;
right: 0;
padding-left: 4.3%;
padding-right: 4.3%;
}
.playlistSectionButton .btnTogglePlaylist {
font-size: larger;
margin: 0;
padding-left: 0;
}
.playlistSectionButton .btnSavePlaylist {
margin: 0;
padding-right: 0;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1;
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
justify-content: flex-end;
border-radius: 0;
}
.playlistSectionButton .btnToggleContextMenu {
font-size: larger;
margin: 0;
padding-right: 0;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1;
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
justify-content: flex-end;
border-radius: 0;
}
.playlistSectionButton .volumecontrol {
width: 100%;
}
.remoteControlSection {
margin: 4.2em 0 0 0;
padding: 0 0 4.2em 0;
}
.nowPlayingButtonsContainer {
display: flex;
height: 100%;
flex-direction: column;
}
}
.nowPlayingTime {
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
margin: 0 1em;
}
.nowPlayingNavButtonContainer {
width: 30em;
}
@ -214,8 +635,11 @@
width: 9em;
}
@media all and (max-width: 50em) {
.nowPlayingInfoButtons .nowPlayingPageUserDataButtons {
@media all and (max-width: 63em) {
.nowPlayingSecondaryButtons .nowPlayingPageUserDataButtons,
.nowPlayingSecondaryButtons .repeatToggleButton,
.nowPlayingInfoButtons .playlist .listItemMediaInfo,
.nowPlayingInfoButtons .btnStop {
display: none !important;
}
@ -223,17 +647,3 @@
font-size: 4em;
}
}
@media all and (max-width: 47em) {
.nowPlayingInfoButtons .repeatToggleButton {
display: none !important;
}
}
@media all and (max-width: 34em) {
.nowPlayingInfoButtons .btnNowPlayingFastForward,
.nowPlayingInfoButtons .btnNowPlayingRewind,
.nowPlayingInfoButtons .playlist .listItemMediaInfo {
display: none !important;
}
}

View File

@ -1,4 +1,4 @@
define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageLoader", "playbackManager", "nowPlayingHelper", "events", "connectionManager", "apphost", "globalize", "layoutManager", "userSettings", "cardStyle", "emby-itemscontainer", "css!./remotecontrol.css", "emby-ratingbutton"], function (browser, datetime, backdrop, libraryBrowser, listView, imageLoader, playbackManager, nowPlayingHelper, events, connectionManager, appHost, globalize, layoutManager, userSettings) {
define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageLoader", "playbackManager", "nowPlayingHelper", "events", "connectionManager", "apphost", "globalize", "layoutManager", "userSettings", "cardBuilder", "cardStyle", "emby-itemscontainer", "css!./remotecontrol.css", "emby-ratingbutton"], function (browser, datetime, backdrop, libraryBrowser, listView, imageLoader, playbackManager, nowPlayingHelper, events, connectionManager, appHost, globalize, layoutManager, userSettings, cardBuilder) {
"use strict";
function showAudioMenu(context, player, button, item) {
@ -110,49 +110,93 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL
return null;
}
function updateNowPlayingInfo(context, state) {
function updateNowPlayingInfo(context, state, serverId) {
var item = state.NowPlayingItem;
var displayName = item ? getNowPlayingNameHtml(item).replace("<br/>", " - ") : "";
context.querySelector(".nowPlayingPageTitle").innerHTML = displayName;
if (typeof item !== 'undefined') {
var nowPlayingServerId = (item.ServerId || serverId);
if (item.Type == "Audio" || item.MediaStreams[0].Type == "Audio") {
var songName = item.Name;
if (item.Album != null && item.Artists != null) {
var albumName = item.Album;
var artistName;
if (item.ArtistItems != null) {
artistName = item.ArtistItems[0].Name;
context.querySelector(".nowPlayingAlbum").innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=' + item.AlbumId + `&amp;serverId=${nowPlayingServerId}">${albumName}</a>`;
context.querySelector(".nowPlayingArtist").innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=' + item.ArtistItems[0].Id + `&amp;serverId=${nowPlayingServerId}">${artistName}</a>`;
context.querySelector(".contextMenuAlbum").innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=' + item.AlbumId + `&amp;serverId=${nowPlayingServerId}"><i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons album"></i> ` + globalize.translate("ViewAlbum") + '</a>';
context.querySelector(".contextMenuArtist").innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=' + item.ArtistItems[0].Id + `&amp;serverId=${nowPlayingServerId}"><i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons person"></i> ` + globalize.translate("ViewArtist") + '</a>';
} else {
artistName = item.Artists;
context.querySelector(".nowPlayingAlbum").innerHTML = albumName;
context.querySelector(".nowPlayingArtist").innerHTML = artistName;
}
}
context.querySelector(".nowPlayingSongName").innerHTML = songName;
} else if (item.Type == "Episode") {
if (item.SeasonName != null) {
var seasonName = item.SeasonName;
context.querySelector(".nowPlayingSeason").innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=' + item.SeasonId + `&amp;serverId=${nowPlayingServerId}">${seasonName}</a>`;
}
if (item.SeriesName != null) {
var seriesName = item.SeriesName;
if (item.SeriesId !=null) {
context.querySelector(".nowPlayingSerie").innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=' + item.SeriesId + `&amp;serverId=${nowPlayingServerId}">${seriesName}</a>`;
} else {
context.querySelector(".nowPlayingSerie").innerHTML = seriesName;
}
}
context.querySelector(".nowPlayingEpisode").innerHTML = item.Name;
} else {
context.querySelector(".nowPlayingPageTitle").innerHTML = displayName;
}
if (displayName.length > 0) {
context.querySelector(".nowPlayingPageTitle").classList.remove("hide");
} else {
context.querySelector(".nowPlayingPageTitle").classList.add("hide");
}
if (displayName.length > 0 && item.Type != "Audio" && item.Type != "Episode") {
context.querySelector(".nowPlayingPageTitle").classList.remove("hide");
} else {
context.querySelector(".nowPlayingPageTitle").classList.add("hide");
}
var url = item ? seriesImageUrl(item, {
maxHeight: 300 * 2
}) || imageUrl(item, {
maxHeight: 300 * 2
}) : null;
var url = item ? seriesImageUrl(item, {
maxHeight: 300 * 2
}) || imageUrl(item, {
maxHeight: 300 * 2
}) : null;
console.debug("updateNowPlayingInfo");
setImageUrl(context, url);
if (item) {
backdrop.setBackdrops([item]);
var apiClient = connectionManager.getApiClient(item.ServerId);
apiClient.getItem(apiClient.getCurrentUserId(), item.Id).then(function (fullItem) {
var userData = fullItem.UserData || {};
var likes = null == userData.Likes ? "" : userData.Likes;
context.querySelector(".nowPlayingPageUserDataButtons").innerHTML = '<button is="emby-ratingbutton" type="button" class="listItemButton paper-icon-button-light" data-id="' + fullItem.Id + '" data-serverid="' + fullItem.ServerId + '" data-itemtype="' + fullItem.Type + '" data-likes="' + likes + '" data-isfavorite="' + userData.IsFavorite + '"><i class="material-icons">favorite</i></button>';
});
} else {
backdrop.clear();
context.querySelector(".nowPlayingPageUserDataButtons").innerHTML = "";
console.debug("updateNowPlayingInfo");
setImageUrl(context, state, url);
if (item) {
backdrop.setBackdrops([item]);
var apiClient = connectionManager.getApiClient(item.ServerId);
apiClient.getItem(apiClient.getCurrentUserId(), item.Id).then(function (fullItem) {
var userData = fullItem.UserData || {};
var likes = null == userData.Likes ? "" : userData.Likes;
context.querySelector(".nowPlayingPageUserDataButtonsTitle").innerHTML = '<button is="emby-ratingbutton" type="button" class="listItemButton paper-icon-button-light" data-id="' + fullItem.Id + '" data-serverid="' + fullItem.ServerId + '" data-itemtype="' + fullItem.Type + '" data-likes="' + likes + '" data-isfavorite="' + userData.IsFavorite + '"><i class="material-icons">favorite</i></button>';
context.querySelector(".nowPlayingPageUserDataButtons").innerHTML = '<button is="emby-ratingbutton" type="button" class="listItemButton paper-icon-button-light" data-id="' + fullItem.Id + '" data-serverid="' + fullItem.ServerId + '" data-itemtype="' + fullItem.Type + '" data-likes="' + likes + '" data-isfavorite="' + userData.IsFavorite + '"><i class="material-icons">favorite</i></button>';
});
} else {
backdrop.clear();
context.querySelector(".nowPlayingPageUserDataButtons").innerHTML = "";
}
}
}
function setImageUrl(context, url) {
function setImageUrl(context, state, url) {
currentImgUrl = url;
var item = state.NowPlayingItem;
var imgContainer = context.querySelector(".nowPlayingPageImageContainer");
if (url) {
imgContainer.innerHTML = '<img class="nowPlayingPageImage" src="' + url + '" />';
imgContainer.classList.remove("hide");
if (item.Type == "Audio") {
context.querySelector(".nowPlayingPageImage").classList.add("nowPlayingPageImageAudio");
context.querySelector(".nowPlayingPageImageContainer").classList.remove("nowPlayingPageImageAudio");
} else {
context.querySelector(".nowPlayingPageImageContainer").classList.add("nowPlayingPageImagePoster");
context.querySelector(".nowPlayingPageImage").classList.remove("nowPlayingPageImageAudio");
}
} else {
imgContainer.classList.add("hide");
imgContainer.innerHTML = "";
imgContainer.innerHTML = '<div class="nowPlayingPageImageContainerNoAlbum"><button data-action="link" class="cardContent-button cardImageContainer coveredImage ' + cardBuilder.getDefaultBackgroundClass(item.Name) + ' cardContent cardContent-shadow itemAction"><i class="cardImageIcon material-icons">album</i></button></div>';
}
}
@ -199,28 +243,35 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL
var supportedCommands = playerInfo.supportedCommands;
currentPlayerSupportedCommands = supportedCommands;
var playState = state.PlayState || {};
buttonVisible(context.querySelector(".btnToggleFullscreen"), item && "Video" == item.MediaType && -1 != supportedCommands.indexOf("ToggleFullscreen"));
var isSupportedCommands = supportedCommands.includes("DisplayMessage") || supportedCommands.includes("SendString") || supportedCommands.includes("Select");
buttonVisible(context.querySelector(".btnToggleFullscreen"), item && "Video" == item.MediaType && supportedCommands.includes("ToggleFullscreen"));
updateAudioTracksDisplay(player, context);
updateSubtitleTracksDisplay(player, context);
if (-1 != supportedCommands.indexOf("DisplayMessage") && !currentPlayer.isLocalPlayer) {
if (supportedCommands.includes("DisplayMessage") && !currentPlayer.isLocalPlayer) {
context.querySelector(".sendMessageSection").classList.remove("hide");
} else {
context.querySelector(".sendMessageSection").classList.add("hide");
}
if (-1 != supportedCommands.indexOf("SendString") && !currentPlayer.isLocalPlayer) {
if (supportedCommands.includes("SendString") && !currentPlayer.isLocalPlayer) {
context.querySelector(".sendTextSection").classList.remove("hide");
} else {
context.querySelector(".sendTextSection").classList.add("hide");
}
if (-1 != supportedCommands.indexOf("Select") && !currentPlayer.isLocalPlayer) {
if (supportedCommands.includes("Select") && !currentPlayer.isLocalPlayer) {
context.querySelector(".navigationSection").classList.remove("hide");
} else {
context.querySelector(".navigationSection").classList.add("hide");
}
if (isSupportedCommands && !currentPlayer.isLocalPlayer) {
context.querySelector(".remoteControlSection").classList.remove("hide");
} else {
context.querySelector(".remoteControlSection").classList.add("hide");
}
buttonVisible(context.querySelector(".btnStop"), null != item);
buttonVisible(context.querySelector(".btnNextTrack"), null != item);
buttonVisible(context.querySelector(".btnPreviousTrack"), null != item);
@ -331,7 +382,7 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL
function updatePlayPauseState(isPaused, isActive) {
var context = dlg;
var btnPlayPause = context.querySelector(".btnPlayPause");
btnPlayPause.querySelector("i").innerHTML = isPaused ? "&#xE037;" : "pause";
btnPlayPause.querySelector("i").innerHTML = isPaused ? "&#xE038;" : "&#xE035;";
buttonVisible(btnPlayPause, isActive);
}
@ -374,9 +425,9 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL
});
if (items.length) {
context.querySelector(".playlistSection").classList.remove("hide");
context.querySelector(".btnTogglePlaylist").classList.remove("hide");
} else {
context.querySelector(".playlistSection").classList.add("hide");
context.querySelector(".btnTogglePlaylist").classList.add("hide");
}
var itemsContainer = context.querySelector(".playlist");
@ -393,6 +444,9 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL
}
imageLoader.lazyChildren(itemsContainer);
context.querySelector(".playlist").classList.add("hide");
context.querySelector(".contextMenu").classList.add("hide");
context.querySelector(".btnSavePlaylist").classList.add("hide");
});
}
@ -614,27 +668,13 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL
return datetime.getDisplayRunningTime(ticks);
};
var volumeSliderTimer;
function setVolume() {
clearTimeout(volumeSliderTimer);
volumeSliderTimer = null;
playbackManager.setVolume(this.value, currentPlayer);
}
function setVolumeDelayed() {
if (!volumeSliderTimer) {
var that = this;
volumeSliderTimer = setTimeout(function () {
setVolume.call(that);
}, 700);
}
}
context.querySelector(".nowPlayingVolumeSlider").addEventListener("change", setVolume);
context.querySelector(".nowPlayingVolumeSlider").addEventListener("mousemove", setVolumeDelayed);
context.querySelector(".nowPlayingVolumeSlider").addEventListener("touchmove", setVolumeDelayed);
context.querySelector(".nowPlayingVolumeSlider").addEventListener("mousemove", setVolume);
context.querySelector(".nowPlayingVolumeSlider").addEventListener("touchmove", setVolume);
context.querySelector(".buttonMute").addEventListener("click", function () {
playbackManager.toggleMute(currentPlayer);
});
@ -648,6 +688,27 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL
playbackManager.movePlaylistItem(playlistItemId, newIndex, currentPlayer);
});
context.querySelector(".btnSavePlaylist").addEventListener("click", savePlaylist);
context.querySelector(".btnTogglePlaylist").addEventListener("click", function () {
if (context.querySelector(".playlist").classList.contains("hide")) {
context.querySelector(".playlist").classList.remove("hide");
context.querySelector(".btnSavePlaylist").classList.remove("hide");
context.querySelector(".contextMenu").classList.add("hide");
context.querySelector(".volumecontrol").classList.add("hide");
} else {
context.querySelector(".playlist").classList.add("hide");
context.querySelector(".btnSavePlaylist").classList.add("hide");
context.querySelector(".volumecontrol").classList.remove("hide");
}
});
context.querySelector(".btnToggleContextMenu").addEventListener("click", function () {
if (context.querySelector(".contextMenu").classList.contains("hide")) {
context.querySelector(".contextMenu").classList.remove("hide");
context.querySelector(".btnSavePlaylist").classList.add("hide");
context.querySelector(".playlist").classList.add("hide");
} else {
context.querySelector(".contextMenu").classList.add("hide");
}
});
}
function onPlayerChange() {
@ -694,6 +755,18 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL
}
function init(ownerView, context) {
let contextmenuHtml = `<button id="toggleContextMenu" is="paper-icon-button-light" class="btnToggleContextMenu" title=${globalize.translate('ButtonToggleContextMenu')}><i class="material-icons more_vert"></i></button>`;
let volumecontrolHtml = '<div class="volumecontrol flex align-items-center flex-wrap-wrap justify-content-center">';
volumecontrolHtml += `<button is="paper-icon-button-light" class="buttonMute autoSize" title=${globalize.translate('Mute')}><i class="xlargePaperIconButton material-icons"></i></button>`;
volumecontrolHtml += '<div class="sliderContainer nowPlayingVolumeSliderContainer"><input is="emby-slider" type="range" step="1" min="0" max="100" value="0" class="nowPlayingVolumeSlider"/></div>';
volumecontrolHtml += '</div>';
if (!layoutManager.mobile) {
context.querySelector('.nowPlayingSecondaryButtons').innerHTML += volumecontrolHtml;
context.querySelector('.playlistSectionButton').innerHTML += contextmenuHtml;
} else {
context.querySelector('.playlistSectionButton').innerHTML += volumecontrolHtml + contextmenuHtml;
}
bindEvents(context);
context.querySelector(".sendMessageForm").addEventListener("submit", onMessageSubmit);
context.querySelector(".typeTextForm").addEventListener("submit", onSendStringSubmit);

View File

@ -258,6 +258,11 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
direction: 'horizontal',
// Loop is disabled due to the virtual slides option not supporting it.
loop: false,
zoom: {
minRatio: 1,
toggle: true,
containerClass: 'slider-zoom-container'
},
autoplay: !options.interactive,
keyboard: {
enabled: true

View File

@ -41,17 +41,12 @@
}
.swiper-slide-img {
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
-ms-transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
position: absolute;
left: 50%;
top: 50%;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.slideshowButtonIcon {
@ -138,3 +133,12 @@
.slideSubtitle {
color: #ccc;
}
.swiper-slide {
display: flex;
flex-direction: column;
}
.slider-zoom-container {
margin: auto;
}

View File

@ -397,7 +397,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings',
var items = [];
items.push({
name: Globalize.translate('Download'),
name: globalize.translate('Download'),
id: 'download'
});

View File

@ -1,4 +1,4 @@
define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "emby-select", "emby-button", "flexStyles"], function ($, loading) {
define(["jQuery", "loading", "globalize", "emby-checkbox", "listViewStyle", "emby-input", "emby-select", "emby-button", "flexStyles"], function ($, loading, globalize) {
"use strict";
return function (page, providerId, options) {
@ -69,7 +69,7 @@ define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "em
$(page.querySelector(".txtZipCode")).trigger("change");
}, function () { // ApiClient.getJSON() error handler
Dashboard.alert({
message: Globalize.translate("ErrorGettingTvLineups")
message: globalize.translate("ErrorGettingTvLineups")
});
});
loading.hide();
@ -130,7 +130,7 @@ define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "em
reload();
}, function () {
Dashboard.alert({ // ApiClient.ajax() error handler
message: Globalize.translate("ErrorSavingTvProvider")
message: globalize.translate("ErrorSavingTvProvider")
});
});
});
@ -141,7 +141,7 @@ define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "em
if (!selectedListingsId) {
return void Dashboard.alert({
message: Globalize.translate("ErrorPleaseSelectLineup")
message: globalize.translate("ErrorPleaseSelectLineup")
});
}
@ -178,7 +178,7 @@ define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "em
}, function () {
loading.hide();
Dashboard.alert({
message: Globalize.translate("ErrorAddingListingsToSchedulesDirect")
message: globalize.translate("ErrorAddingListingsToSchedulesDirect")
});
});
});
@ -210,7 +210,7 @@ define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "em
loading.hide();
}, function (result) {
Dashboard.alert({
message: Globalize.translate("ErrorGettingTvLineups")
message: globalize.translate("ErrorGettingTvLineups")
});
refreshListings("");
loading.hide();
@ -290,7 +290,7 @@ define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "em
page.querySelector(".selectTunersSection").classList.remove("hide");
}
});
$(".createAccountHelp", page).html(Globalize.translate("MessageCreateAccountAt", '<a is="emby-linkbutton" class="button-link" href="http://www.schedulesdirect.org" target="_blank">http://www.schedulesdirect.org</a>'));
$(".createAccountHelp", page).html(globalize.translate("MessageCreateAccountAt", '<a is="emby-linkbutton" class="button-link" href="http://www.schedulesdirect.org" target="_blank">http://www.schedulesdirect.org</a>'));
reload();
};
};

View File

@ -1,4 +1,4 @@
define(["jQuery", "loading", "emby-checkbox", "emby-input", "listViewStyle", "paper-icon-button-light"], function ($, loading) {
define(["jQuery", "loading", "globalize", "emby-checkbox", "emby-input", "listViewStyle", "paper-icon-button-light"], function ($, loading, globalize) {
"use strict";
return function (page, providerId, options) {
@ -92,7 +92,7 @@ define(["jQuery", "loading", "emby-checkbox", "emby-input", "listViewStyle", "pa
}, function () {
loading.hide();
Dashboard.alert({
message: Globalize.translate("ErrorAddingXmlTvFile")
message: globalize.translate("ErrorAddingXmlTvFile")
});
});
});

View File

@ -1,4 +1,4 @@
define(["appSettings", "loading", "browser", "emby-button"], function(appSettings, loading, browser) {
define(["appSettings", "loading", "browser", "globalize", "emby-button"], function(appSettings, loading, browser, globalize) {
"use strict";
function handleConnectionResult(page, result) {
@ -17,13 +17,13 @@ define(["appSettings", "loading", "browser", "emby-button"], function(appSetting
break;
case "ServerUpdateNeeded":
Dashboard.alert({
message: Globalize.translate("ServerUpdateNeeded", '<a href="https://github.com/jellyfin/jellyfin">https://github.com/jellyfin/jellyfin</a>')
message: globalize.translate("ServerUpdateNeeded", '<a href="https://github.com/jellyfin/jellyfin">https://github.com/jellyfin/jellyfin</a>')
});
break;
case "Unavailable":
Dashboard.alert({
message: Globalize.translate("MessageUnableToConnectToServer"),
title: Globalize.translate("HeaderConnectionFailure")
message: globalize.translate("MessageUnableToConnectToServer"),
title: globalize.translate("HeaderConnectionFailure")
});
}
}

View File

@ -1,23 +1,23 @@
define([], function () {
define(["globalize"], function (globalize) {
"use strict";
function processForgotPasswordResult(result) {
if ("ContactAdmin" == result.Action) {
return void Dashboard.alert({
message: Globalize.translate("MessageContactAdminToResetPassword"),
title: Globalize.translate("HeaderForgotPassword")
message: globalize.translate("MessageContactAdminToResetPassword"),
title: globalize.translate("HeaderForgotPassword")
});
}
if ("InNetworkRequired" == result.Action) {
return void Dashboard.alert({
message: Globalize.translate("MessageForgotPasswordInNetworkRequired"),
title: Globalize.translate("HeaderForgotPassword")
message: globalize.translate("MessageForgotPasswordInNetworkRequired"),
title: globalize.translate("HeaderForgotPassword")
});
}
if ("PinCode" == result.Action) {
var msg = Globalize.translate("MessageForgotPasswordFileCreated");
var msg = globalize.translate("MessageForgotPasswordFileCreated");
msg += "<br/>";
msg += "<br/>";
msg += "Enter PIN here to finish Password Reset<br/>";
@ -26,7 +26,7 @@ define([], function () {
msg += "<br/>";
return void Dashboard.alert({
message: msg,
title: Globalize.translate("HeaderForgotPassword"),
title: globalize.translate("HeaderForgotPassword"),
callback: function () {
Dashboard.navigate("forgotpasswordpin.html");
}

View File

@ -1,15 +1,15 @@
define([], function () {
define(["globalize"], function (globalize) {
"use strict";
function processForgotPasswordResult(result) {
if (result.Success) {
var msg = Globalize.translate("MessagePasswordResetForUsers");
var msg = globalize.translate("MessagePasswordResetForUsers");
msg += "<br/>";
msg += "<br/>";
msg += result.UsersReset.join("<br/>");
return void Dashboard.alert({
message: msg,
title: Globalize.translate("HeaderPasswordReset"),
title: globalize.translate("HeaderPasswordReset"),
callback: function () {
window.location.href = "index.html";
}
@ -17,8 +17,8 @@ define([], function () {
}
Dashboard.alert({
message: Globalize.translate("MessageInvalidForgotPasswordPin"),
title: Globalize.translate("HeaderPasswordReset")
message: globalize.translate("MessageInvalidForgotPasswordPin"),
title: globalize.translate("HeaderPasswordReset")
});
}

View File

@ -1,4 +1,4 @@
define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layoutManager", "browser", "cardStyle", "emby-checkbox"], function (appHost, appSettings, dom, connectionManager, loading, layoutManager, browser) {
define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layoutManager", "browser", "globalize", "cardStyle", "emby-checkbox"], function (appHost, appSettings, dom, connectionManager, loading, layoutManager, browser, globalize) {
"use strict";
var enableFocusTransform = !browser.slow && !browser.edge;
@ -24,14 +24,16 @@ define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layout
page.querySelector("#txtManualPassword").value = "";
loading.hide();
if (response.status === 401) {
const UnauthorizedOrForbidden = [401, 403];
if (UnauthorizedOrForbidden.includes(response.status)) {
require(["toast"], function (toast) {
toast(Globalize.translate("MessageInvalidUser"));
const messageKey = response.status === 401 ? "MessageInvalidUser" : "MessageUnauthorizedUser";
toast(globalize.translate(messageKey));
});
} else {
Dashboard.alert({
message: Globalize.translate("MessageUnableToConnectToServer"),
title: Globalize.translate("HeaderConnectionFailure")
message: globalize.translate("MessageUnableToConnectToServer"),
title: globalize.translate("HeaderConnectionFailure")
});
}
});

View File

@ -1,4 +1,4 @@
define(["jQuery", "loading", "fnchecked", "emby-select", "emby-button", "emby-input", "emby-checkbox", "listViewStyle", "emby-button"], function ($, loading) {
define(["jQuery", "loading", "globalize", "fnchecked", "emby-select", "emby-button", "emby-input", "emby-checkbox", "listViewStyle", "emby-button"], function ($, loading, globalize) {
"use strict";
function loadProfile(page) {
@ -258,14 +258,14 @@ define(["jQuery", "loading", "fnchecked", "emby-select", "emby-button", "emby-in
html += "<div>";
html += '<a is="emby-linkbutton" href="#" class="lnkEditSubProfile" data-profileindex="' + i + '">';
html += "<p>" + Globalize.translate("ValueContainer", profile.Container || allText) + "</p>";
html += "<p>" + globalize.translate("ValueContainer", profile.Container || allText) + "</p>";
if ("Video" == profile.Type) {
html += "<p>" + Globalize.translate("ValueVideoCodec", profile.VideoCodec || allText) + "</p>";
html += "<p>" + Globalize.translate("ValueAudioCodec", profile.AudioCodec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueVideoCodec", profile.VideoCodec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueAudioCodec", profile.AudioCodec || allText) + "</p>";
} else {
if ("Audio" == profile.Type) {
html += "<p>" + Globalize.translate("ValueCodec", profile.AudioCodec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueCodec", profile.AudioCodec || allText) + "</p>";
}
}
@ -319,14 +319,14 @@ define(["jQuery", "loading", "fnchecked", "emby-select", "emby-button", "emby-in
html += "<div>";
html += '<a is="emby-linkbutton" href="#" class="lnkEditSubProfile" data-profileindex="' + i + '">';
html += "<p>Protocol: " + (profile.Protocol || "Http") + "</p>";
html += "<p>" + Globalize.translate("ValueContainer", profile.Container || allText) + "</p>";
html += "<p>" + globalize.translate("ValueContainer", profile.Container || allText) + "</p>";
if ("Video" == profile.Type) {
html += "<p>" + Globalize.translate("ValueVideoCodec", profile.VideoCodec || allText) + "</p>";
html += "<p>" + Globalize.translate("ValueAudioCodec", profile.AudioCodec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueVideoCodec", profile.VideoCodec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueAudioCodec", profile.AudioCodec || allText) + "</p>";
} else {
if ("Audio" == profile.Type) {
html += "<p>" + Globalize.translate("ValueCodec", profile.AudioCodec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueCodec", profile.AudioCodec || allText) + "</p>";
}
}
@ -404,11 +404,11 @@ define(["jQuery", "loading", "fnchecked", "emby-select", "emby-button", "emby-in
html += "<div>";
html += '<a is="emby-linkbutton" href="#" class="lnkEditSubProfile" data-profileindex="' + i + '">';
html += "<p>" + Globalize.translate("ValueContainer", profile.Container || allText) + "</p>";
html += "<p>" + globalize.translate("ValueContainer", profile.Container || allText) + "</p>";
if (profile.Conditions && profile.Conditions.length) {
html += "<p>";
html += Globalize.translate("ValueConditions", profile.Conditions.map(function (c) {
html += globalize.translate("ValueConditions", profile.Conditions.map(function (c) {
return c.Property;
}).join(", "));
html += "</p>";
@ -476,11 +476,11 @@ define(["jQuery", "loading", "fnchecked", "emby-select", "emby-button", "emby-in
html += "<div>";
html += '<a is="emby-linkbutton" href="#" class="lnkEditSubProfile" data-profileindex="' + i + '">';
html += "<p>" + Globalize.translate("ValueCodec", profile.Codec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueCodec", profile.Codec || allText) + "</p>";
if (profile.Conditions && profile.Conditions.length) {
html += "<p>";
html += Globalize.translate("ValueConditions", profile.Conditions.map(function (c) {
html += globalize.translate("ValueConditions", profile.Conditions.map(function (c) {
return c.Property;
}).join(", "));
html += "</p>";
@ -547,20 +547,20 @@ define(["jQuery", "loading", "fnchecked", "emby-select", "emby-button", "emby-in
html += "<div>";
html += '<a is="emby-linkbutton" href="#" class="lnkEditSubProfile" data-profileindex="' + i + '">';
html += "<p>" + Globalize.translate("ValueContainer", profile.Container || allText) + "</p>";
html += "<p>" + globalize.translate("ValueContainer", profile.Container || allText) + "</p>";
if ("Video" == profile.Type) {
html += "<p>" + Globalize.translate("ValueVideoCodec", profile.VideoCodec || allText) + "</p>";
html += "<p>" + Globalize.translate("ValueAudioCodec", profile.AudioCodec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueVideoCodec", profile.VideoCodec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueAudioCodec", profile.AudioCodec || allText) + "</p>";
} else {
if ("Audio" == profile.Type) {
html += "<p>" + Globalize.translate("ValueCodec", profile.AudioCodec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueCodec", profile.AudioCodec || allText) + "</p>";
}
}
if (profile.Conditions && profile.Conditions.length) {
html += "<p>";
html += Globalize.translate("ValueConditions", profile.Conditions.map(function (c) {
html += globalize.translate("ValueConditions", profile.Conditions.map(function (c) {
return c.Property;
}).join(", "));
html += "</p>";
@ -690,7 +690,7 @@ define(["jQuery", "loading", "fnchecked", "emby-select", "emby-button", "emby-in
var currentProfile;
var currentSubProfile;
var isSubProfileNew;
var allText = Globalize.translate("LabelAll");
var allText = globalize.translate("LabelAll");
$(document).on("pageinit", "#dlnaProfilePage", function () {
var page = this;

View File

@ -1,4 +1,4 @@
define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, libraryMenu) {
define(["jQuery", "loading", "libraryMenu", "globalize", "fnchecked"], function ($, loading, libraryMenu, globalize) {
"use strict";
function loadPage(page, config, users) {
@ -34,10 +34,10 @@ define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading,
function getTabs() {
return [{
href: "dlnasettings.html",
name: Globalize.translate("TabSettings")
name: globalize.translate("TabSettings")
}, {
href: "dlnaprofiles.html",
name: Globalize.translate("TabProfiles")
name: globalize.translate("TabProfiles")
}];
}

View File

@ -116,13 +116,13 @@ define(["jQuery", "loading", "globalize", "dom", "libraryMenu"], function ($, lo
function getTabs() {
return [{
href: "encodingsettings.html",
name: Globalize.translate("Transcoding")
name: globalize.translate("Transcoding")
}, {
href: "playbackconfiguration.html",
name: Globalize.translate("TabResumeSettings")
name: globalize.translate("TabResumeSettings")
}, {
href: "streamingsettings.html",
name: Globalize.translate("TabStreaming")
name: globalize.translate("TabStreaming")
}];
}

View File

@ -1,4 +1,4 @@
define(["jQuery", "loading", "fnchecked", "emby-checkbox", "emby-textarea", "emby-input", "emby-select", "emby-button"], function ($, loading) {
define(["jQuery", "loading", "globalize", "fnchecked", "emby-checkbox", "emby-textarea", "emby-input", "emby-select", "emby-button"], function ($, loading, globalize) {
"use strict";
function loadPage(page, config, languageOptions, systemInfo) {
@ -58,7 +58,7 @@ define(["jQuery", "loading", "fnchecked", "emby-checkbox", "emby-textarea", "emb
});
}, function () {
require(["alert"], function (alert) {
alert(Globalize.translate("DefaultErrorMessage"));
alert(globalize.translate("DefaultErrorMessage"));
});
Dashboard.processServerConfigurationUpdateResult();
@ -83,8 +83,8 @@ define(["jQuery", "loading", "fnchecked", "emby-checkbox", "emby-textarea", "emb
picker.close();
},
validateWriteable: true,
header: Globalize.translate("HeaderSelectServerCachePath"),
instruction: Globalize.translate("HeaderSelectServerCachePathHelp")
header: globalize.translate("HeaderSelectServerCachePath"),
instruction: globalize.translate("HeaderSelectServerCachePathHelp")
});
});
});
@ -106,8 +106,8 @@ define(["jQuery", "loading", "fnchecked", "emby-checkbox", "emby-textarea", "emb
picker.close();
},
validateWriteable: true,
header: Globalize.translate("HeaderSelectMetadataPath"),
instruction: Globalize.translate("HeaderSelectMetadataPathHelp"),
header: globalize.translate("HeaderSelectMetadataPath"),
instruction: globalize.translate("HeaderSelectMetadataPathHelp"),
enableNetworkSharePath: true
});
});

View File

@ -4,16 +4,16 @@ define(["globalize", "loading", "libraryMenu", "emby-checkbox", "emby-button", "
function getTabs() {
return [{
href: "library.html",
name: Globalize.translate("HeaderLibraries")
name: globalize.translate("HeaderLibraries")
}, {
href: "librarydisplay.html",
name: Globalize.translate("TabDisplay")
name: globalize.translate("TabDisplay")
}, {
href: "metadataimages.html",
name: Globalize.translate("TabMetadata")
name: globalize.translate("TabMetadata")
}, {
href: "metadatanfo.html",
name: Globalize.translate("TabNfoSettings")
name: globalize.translate("TabNfoSettings")
}];
}

View File

@ -1,4 +1,4 @@
define(["jQuery", "dom", "loading", "libraryMenu", "listViewStyle"], function($, dom, loading, libraryMenu) {
define(["jQuery", "dom", "loading", "libraryMenu", "globalize", "listViewStyle"], function($, dom, loading, libraryMenu, globalize) {
"use strict";
function populateLanguages(select) {
@ -43,16 +43,16 @@ define(["jQuery", "dom", "loading", "libraryMenu", "listViewStyle"], function($,
function getTabs() {
return [{
href: "library.html",
name: Globalize.translate("HeaderLibraries")
name: globalize.translate("HeaderLibraries")
}, {
href: "librarydisplay.html",
name: Globalize.translate("TabDisplay")
name: globalize.translate("TabDisplay")
}, {
href: "metadataimages.html",
name: Globalize.translate("TabMetadata")
name: globalize.translate("TabMetadata")
}, {
href: "metadatanfo.html",
name: Globalize.translate("TabNfoSettings")
name: globalize.translate("TabNfoSettings")
}];
}

View File

@ -1,8 +1,8 @@
define(["jQuery", "loading", "libraryMenu"], function ($, loading, libraryMenu) {
define(["jQuery", "loading", "libraryMenu", "globalize"], function ($, loading, libraryMenu, globalize) {
"use strict";
function loadPage(page, config, users) {
var html = '<option value="" selected="selected">' + Globalize.translate("OptionNone") + "</option>";
var html = '<option value="" selected="selected">' + globalize.translate("OptionNone") + "</option>";
html += users.map(function (user) {
return '<option value="' + user.Id + '">' + user.Name + "</option>";
}).join("");
@ -33,7 +33,7 @@ define(["jQuery", "loading", "libraryMenu"], function ($, loading, libraryMenu)
function showConfirmMessage(config) {
var msg = [];
msg.push(Globalize.translate("MetadataSettingChangeHelp"));
msg.push(globalize.translate("MetadataSettingChangeHelp"));
require(["alert"], function (alert) {
alert({
@ -45,16 +45,16 @@ define(["jQuery", "loading", "libraryMenu"], function ($, loading, libraryMenu)
function getTabs() {
return [{
href: "library.html",
name: Globalize.translate("HeaderLibraries")
name: globalize.translate("HeaderLibraries")
}, {
href: "librarydisplay.html",
name: Globalize.translate("TabDisplay")
name: globalize.translate("TabDisplay")
}, {
href: "metadataimages.html",
name: Globalize.translate("TabMetadata")
name: globalize.translate("TabMetadata")
}, {
href: "metadatanfo.html",
name: Globalize.translate("TabNfoSettings")
name: globalize.translate("TabNfoSettings")
}];
}

View File

@ -1,4 +1,4 @@
define(["jQuery", "loading", "libraryMenu"], function ($, loading, libraryMenu) {
define(["jQuery", "loading", "libraryMenu", "globalize"], function ($, loading, libraryMenu, globalize) {
"use strict";
function loadPage(page, config) {
@ -25,13 +25,13 @@ define(["jQuery", "loading", "libraryMenu"], function ($, loading, libraryMenu)
function getTabs() {
return [{
href: "encodingsettings.html",
name: Globalize.translate("Transcoding")
name: globalize.translate("Transcoding")
}, {
href: "playbackconfiguration.html",
name: Globalize.translate("TabResumeSettings")
name: globalize.translate("TabResumeSettings")
}, {
href: "streamingsettings.html",
name: Globalize.translate("TabStreaming")
name: globalize.translate("TabStreaming")
}];
}

View File

@ -7,8 +7,8 @@ define(["jQuery", "loading", "libraryMenu", "globalize", "connectionManager", "e
for (var i = 0; i < length; i++) {
var version = packageInfo.versions[i];
html += '<h2 style="margin:.5em 0;">' + version.versionStr + " (" + version.classification + ")</h2>";
html += '<div style="margin-bottom:1.5em;">' + version.description + "</div>";
html += '<h2 style="margin:.5em 0;">' + version.version + "</h2>";
html += '<div style="margin-bottom:1.5em;">' + version.changelog + "</div>";
}
$("#revisionHistory", page).html(html);
@ -19,7 +19,7 @@ define(["jQuery", "loading", "libraryMenu", "globalize", "connectionManager", "e
for (var i = 0; i < packageInfo.versions.length; i++) {
var version = packageInfo.versions[i];
html += '<option value="' + version.versionStr + "|" + version.classification + '">' + version.versionStr + " (" + version.classification + ")</option>";
html += '<option value="' + version.version + '">' + version.version + "</option>";
}
var selectmenu = $("#selectVersion", page).html(html);
@ -28,16 +28,9 @@ define(["jQuery", "loading", "libraryMenu", "globalize", "connectionManager", "e
$("#pCurrentVersion", page).hide().html("");
}
var packageVersion = packageInfo.versions.filter(function (current) {
return "Release" == current.classification;
})[0];
packageVersion = packageVersion || packageInfo.versions.filter(function (current) {
return "Beta" == current.classification;
})[0];
var packageVersion = packageInfo.versions[0];
if (packageVersion) {
var val = packageVersion.versionStr + "|" + packageVersion.classification;
selectmenu.val(val);
selectmenu.val(packageVersion.version);
}
}
@ -45,44 +38,23 @@ define(["jQuery", "loading", "libraryMenu", "globalize", "connectionManager", "e
var installedPlugin = installedPlugins.filter(function (ip) {
return ip.Name == pkg.name;
})[0];
populateVersions(pkg, page, installedPlugin);
populateHistory(pkg, page);
$(".pluginName", page).html(pkg.name);
$("#btnInstallDiv", page).removeClass("hide");
$("#pSelectVersion", page).removeClass("hide");
if ("Server" == pkg.targetSystem) {
$("#btnInstallDiv", page).removeClass("hide");
$("#nonServerMsg", page).hide();
$("#pSelectVersion", page).removeClass("hide");
if (pkg.overview) {
$("#overview", page).show().html(pkg.overview);
} else {
$("#btnInstallDiv", page).addClass("hide");
$("#pSelectVersion", page).addClass("hide");
var msg = globalize.translate("MessageInstallPluginFromApp");
$("#nonServerMsg", page).html(msg).show();
$("#overview", page).hide();
}
if (pkg.shortDescription) {
$("#tagline", page).show().html(pkg.shortDescription);
} else {
$("#tagline", page).hide();
}
$("#overview", page).html(pkg.overview || "");
$("#description", page).html(pkg.description);
$("#developer", page).html(pkg.owner);
if (pkg.richDescUrl) {
$("#pViewWebsite", page).show();
$("#pViewWebsite a", page).attr("href", pkg.richDescUrl);
} else {
$("#pViewWebsite", page).hide();
}
if (pkg.previewImage || pkg.thumbImage) {
var img = pkg.previewImage ? pkg.previewImage : pkg.thumbImage;
$("#pPreviewImage", page).show().html("<img class='pluginPreviewImg' src='" + img + "' style='max-width: 100%;' />");
} else {
$("#pPreviewImage", page).hide().html("");
}
if (installedPlugin) {
var currentVersionText = globalize.translate("MessageYouHaveVersionInstalled", "<strong>" + installedPlugin.Version + "</strong>");
$("#pCurrentVersion", page).show().html(currentVersionText);

View File

@ -98,21 +98,14 @@ define(["loading", "libraryMenu", "globalize", "cardStyle", "emby-button", "emby
html += '<div class="cardScalable visualCardBox-cardScalable">';
html += '<div class="cardPadder cardPadder-backdrop"></div>';
html += '<a class="cardContent cardImageContainer" is="emby-linkbutton" href="' + href + '"' + target + ">";
if (plugin.thumbImage) {
html += '<div class="cardImage coveredImage" style="background-image:url(\'' + plugin.thumbImage + "');\">";
html += "</div>";
} else {
html += '<i class="cardImageIcon material-icons">folder</i>';
}
html += '<i class="cardImageIcon material-icons">folder</i>';
html += "</a>";
html += "</div>";
html += '<div class="cardFooter">';
html += "<div class='cardText'>";
html += plugin.name;
html += "</div>";
var installedPlugin = plugin.isApp ? null : installedPlugins.filter(function (ip) {
var installedPlugin = installedPlugins.filter(function (ip) {
return ip.Id == plugin.guid;
})[0];
html += "<div class='cardText cardText-secondary'>";

View File

@ -42,14 +42,7 @@ define(["loading", "libraryMenu", "dom", "globalize", "cardStyle", "emby-button"
html += '<div class="cardScalable">';
html += '<div class="cardPadder cardPadder-backdrop"></div>';
html += configPageUrl ? '<a class="cardContent cardImageContainer" is="emby-linkbutton" href="' + configPageUrl + '">' : '<div class="cardContent noConfigPluginCard noHoverEffect cardImageContainer">';
if (plugin.ImageUrl) {
html += '<div class="cardImage coveredImage" style="background-image:url(\'' + plugin.ImageUrl + "');\">";
html += "</div>";
} else {
html += '<i class="cardImageIcon material-icons">folder</i>';
}
html += '<i class="cardImageIcon material-icons">folder</i>';
html += configPageUrl ? "</a>" : "</div>";
html += "</div>";
html += '<div class="cardFooter">';
@ -57,7 +50,7 @@ define(["loading", "libraryMenu", "dom", "globalize", "cardStyle", "emby-button"
html += '<button type="button" is="paper-icon-button-light" class="btnCardMenu autoSize"><i class="material-icons more_horiz"></i></button>';
html += "</div>";
html += "<div class='cardText'>";
html += configPage ? configPage.DisplayName || plugin.Name : plugin.Name;
html += configPage.DisplayName || plugin.Name;
html += "</div>";
html += "<div class='cardText cardText-secondary'>";
html += plugin.Version;

View File

@ -1,4 +1,4 @@
define(["jQuery", "libraryMenu", "loading"], function ($, libraryMenu, loading) {
define(["jQuery", "libraryMenu", "loading", "globalize"], function ($, libraryMenu, loading, globalize) {
"use strict";
function loadPage(page, config) {
@ -20,13 +20,13 @@ define(["jQuery", "libraryMenu", "loading"], function ($, libraryMenu, loading)
function getTabs() {
return [{
href: "encodingsettings.html",
name: Globalize.translate("Transcoding")
name: globalize.translate("Transcoding")
}, {
href: "playbackconfiguration.html",
name: Globalize.translate("TabResumeSettings")
name: globalize.translate("TabResumeSettings")
}, {
href: "streamingsettings.html",
name: Globalize.translate("TabStreaming")
name: globalize.translate("TabStreaming")
}];
}

View File

@ -336,7 +336,6 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "userSetti
return html = html.join(" / ");
}
function renderName(item, container, isStatic, context) {
var parentRoute;
var parentNameHtml = [];
@ -401,14 +400,25 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "userSetti
} else if (item.Album) {
parentNameHtml.push(item.Album);
}
// FIXME: This whole section needs some refactoring, so it becames easier to scale across all form factors. See GH #1022
var html = "";
var tvShowHtml = parentNameHtml[0];
var tvSeasonHtml = parentNameHtml[1];
if (parentNameHtml.length) {
if (parentNameLast) {
html = '<h3 class="parentName" style="margin: .25em 0;">' + parentNameHtml.join(" - ") + "</h3>";
// Music
if (layoutManager.mobile) {
html = '<h3 class="parentName" style="margin: .25em 0;">' + parentNameHtml.join("</br>") + "</h3>";
} else {
html = '<h3 class="parentName" style="margin: .25em 0;">' + parentNameHtml.join(" - ") + "</h3>";
}
} else {
html = '<h1 class="parentName" style="margin: .1em 0 .25em;">' + parentNameHtml.join(" - ") + "</h1>";
if (layoutManager.mobile) {
html = '<h1 class="parentName" style="margin: .1em 0 .25em;">' + parentNameHtml.join("</br>") + "</h1>";
} else {
html = '<h1 class="parentName" style="margin: .1em 0 .25em;">' + tvShowHtml + "</h1>";
}
}
}
@ -418,13 +428,17 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "userSetti
var offset = parentNameLast ? ".25em" : ".5em";
if (html && !parentNameLast) {
html += '<h3 class="itemName infoText" style="margin: .25em 0 .5em;">' + name + '</h3>';
if (!layoutManager.mobile && tvSeasonHtml) {
html += '<h3 class="itemName infoText" style="margin: .25em 0 .5em;">' + tvSeasonHtml + ' - ' + name + '</h3>';
} else {
html += '<h3 class="itemName infoText" style="margin: .25em 0 .5em;">' + name + '</h3>';
}
} else {
html = '<h1 class="itemName infoText" style="margin: .1em 0 ' + offset + ';">' + name + "</h1>" + html;
}
if (item.OriginalTitle && item.OriginalTitle != item.Name) {
html += '<h4 class="itemName infoText" style="margin: -' + offset + ' 0 0">' + item.OriginalTitle + '</h4>';
html += '<h4 class="itemName infoText" style="margin: -' + offset + ' 0 0;">' + item.OriginalTitle + '</h4>';
}
container.innerHTML = html;
@ -540,7 +554,7 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "userSetti
renderTimerEditor(page, item, apiClient, user);
renderImage(page, item, apiClient, user);
renderLogo(page, item, apiClient);
setTitle(item, apiClient);
Emby.Page.setTitle('');
setInitialCollapsibleState(page, item, apiClient, context, user);
renderDetails(page, item, apiClient, context);
renderTrackSelections(page, instance, item);
@ -652,19 +666,6 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "userSetti
return null;
}
function setTitle(item, apiClient) {
var url = logoImageUrl(item, apiClient, {});
if (url != null) {
var pageTitle = document.querySelector(".pageTitle");
pageTitle.style.backgroundImage = "url('" + url + "')";
pageTitle.classList.add("pageTitleWithLogo");
pageTitle.innerHTML = "";
} else {
Emby.Page.setTitle("");
}
}
function renderLogo(page, item, apiClient) {
var url = logoImageUrl(item, apiClient, {
maxWidth: 400
@ -2102,7 +2103,7 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "userSetti
if (e.detail.isRestored) {
if (currentItem) {
setTitle(currentItem, connectionManager.getApiClient(currentItem.ServerId));
Emby.Page.setTitle('');
renderTrackSelections(page, self, currentItem, true);
}
} else {

View File

@ -1,4 +1,4 @@
define(["events", "loading"], function (events, loading) {
define(["events", "loading", "globalize"], function (events, loading, globalize) {
"use strict";
function onListingsSubmitted() {
@ -17,7 +17,7 @@ define(["events", "loading"], function (events, loading) {
function loadTemplate(page, type, providerId) {
require(["text!./components/tvproviders/" + type + ".template.html"], function (html) {
page.querySelector(".providerTemplate").innerHTML = Globalize.translateDocument(html);
page.querySelector(".providerTemplate").innerHTML = globalize.translateDocument(html);
init(page, type, providerId);
});
}

View File

@ -1,4 +1,4 @@
define(["jQuery", "loading", "fnchecked", "emby-button"], function ($, loading) {
define(["jQuery", "loading", "globalize", "fnchecked", "emby-button"], function ($, loading, globalize) {
"use strict";
function loadPage(page, config) {
@ -44,7 +44,7 @@ define(["jQuery", "loading", "fnchecked", "emby-button"], function ($, loading)
var msg = "";
if (recordingPathChanged) {
msg += Globalize.translate("RecordingPathChangeMessage");
msg += globalize.translate("RecordingPathChangeMessage");
}
if (msg) {

View File

@ -1,4 +1,4 @@
define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardBuilder", "userSettings", "emby-itemscontainer"], function (loading, events, libraryBrowser, imageLoader, listView, cardBuilder, userSettings) {
define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardBuilder", "userSettings", "globalize", "emby-itemscontainer"], function (loading, events, libraryBrowser, imageLoader, listView, cardBuilder, userSettings, globalize) {
"use strict";
return function (view, params, tabContent) {
@ -171,7 +171,7 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB
}
if (!result.Items.length) {
html = '<p style="text-align:center;">' + Globalize.translate("MessageNoCollectionsAvailable") + "</p>";
html = '<p style="text-align:center;">' + globalize.translate("MessageNoCollectionsAvailable") + "</p>";
}
var itemsContainer = tabContent.querySelector(".itemsContainer");
@ -199,19 +199,19 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB
tabContent.querySelector(".btnSort").addEventListener("click", function (e) {
libraryBrowser.showSortMenu({
items: [{
name: Globalize.translate("OptionNameSort"),
name: globalize.translate("OptionNameSort"),
id: "SortName"
}, {
name: Globalize.translate("OptionImdbRating"),
name: globalize.translate("OptionImdbRating"),
id: "CommunityRating,SortName"
}, {
name: Globalize.translate("OptionDateAdded"),
name: globalize.translate("OptionDateAdded"),
id: "DateCreated,SortName"
}, {
name: Globalize.translate("OptionParentalRating"),
name: globalize.translate("OptionParentalRating"),
id: "OfficialRating,SortName"
}, {
name: Globalize.translate("OptionReleaseDate"),
name: globalize.translate("OptionReleaseDate"),
id: "PremiereDate,SortName"
}],
callback: function () {

View File

@ -1,4 +1,4 @@
define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", "alphaPicker", "listView", "cardBuilder", "emby-itemscontainer"], function (loading, layoutManager, userSettings, events, libraryBrowser, alphaPicker, listView, cardBuilder) {
define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", "alphaPicker", "listView", "cardBuilder", "globalize", "emby-itemscontainer"], function (loading, layoutManager, userSettings, events, libraryBrowser, alphaPicker, listView, cardBuilder, globalize) {
"use strict";
return function (view, params, tabContent, options) {
@ -191,31 +191,31 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser",
btnSort.addEventListener("click", function (e) {
libraryBrowser.showSortMenu({
items: [{
name: Globalize.translate("OptionNameSort"),
name: globalize.translate("OptionNameSort"),
id: "SortName,ProductionYear"
}, {
name: Globalize.translate("OptionImdbRating"),
name: globalize.translate("OptionImdbRating"),
id: "CommunityRating,SortName,ProductionYear"
}, {
name: Globalize.translate("OptionCriticRating"),
name: globalize.translate("OptionCriticRating"),
id: "CriticRating,SortName,ProductionYear"
}, {
name: Globalize.translate("OptionDateAdded"),
name: globalize.translate("OptionDateAdded"),
id: "DateCreated,SortName,ProductionYear"
}, {
name: Globalize.translate("OptionDatePlayed"),
name: globalize.translate("OptionDatePlayed"),
id: "DatePlayed,SortName,ProductionYear"
}, {
name: Globalize.translate("OptionParentalRating"),
name: globalize.translate("OptionParentalRating"),
id: "OfficialRating,SortName,ProductionYear"
}, {
name: Globalize.translate("OptionPlayCount"),
name: globalize.translate("OptionPlayCount"),
id: "PlayCount,SortName,ProductionYear"
}, {
name: Globalize.translate("OptionReleaseDate"),
name: globalize.translate("OptionReleaseDate"),
id: "PremiereDate,SortName,ProductionYear"
}, {
name: Globalize.translate("OptionRuntime"),
name: globalize.translate("OptionRuntime"),
id: "Runtime,SortName,ProductionYear"
}],
callback: function () {

View File

@ -1,4 +1,4 @@
define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu", "mainTabsManager", "cardBuilder", "dom", "imageLoader", "playbackManager", "emby-scroller", "emby-itemscontainer", "emby-tabs", "emby-button"], function (events, layoutManager, inputManager, userSettings, libraryMenu, mainTabsManager, cardBuilder, dom, imageLoader, playbackManager) {
define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu", "mainTabsManager", "cardBuilder", "dom", "imageLoader", "playbackManager", "globalize", "emby-scroller", "emby-itemscontainer", "emby-tabs", "emby-button"], function (events, layoutManager, inputManager, userSettings, libraryMenu, mainTabsManager, cardBuilder, dom, imageLoader, playbackManager, globalize) {
"use strict";
function enableScrollX() {
@ -91,21 +91,21 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu"
switch (recommendation.RecommendationType) {
case "SimilarToRecentlyPlayed":
title = Globalize.translate("RecommendationBecauseYouWatched", recommendation.BaselineItemName);
title = globalize.translate("RecommendationBecauseYouWatched", recommendation.BaselineItemName);
break;
case "SimilarToLikedItem":
title = Globalize.translate("RecommendationBecauseYouLike", recommendation.BaselineItemName);
title = globalize.translate("RecommendationBecauseYouLike", recommendation.BaselineItemName);
break;
case "HasDirectorFromRecentlyPlayed":
case "HasLikedDirector":
title = Globalize.translate("RecommendationDirectedBy", recommendation.BaselineItemName);
title = globalize.translate("RecommendationDirectedBy", recommendation.BaselineItemName);
break;
case "HasActorFromRecentlyPlayed":
case "HasLikedActor":
title = Globalize.translate("RecommendationStarring", recommendation.BaselineItemName);
title = globalize.translate("RecommendationStarring", recommendation.BaselineItemName);
break;
}
@ -211,19 +211,19 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu"
function getTabs() {
return [{
name: Globalize.translate("Movies")
name: globalize.translate("Movies")
}, {
name: Globalize.translate("TabSuggestions")
name: globalize.translate("TabSuggestions")
}, {
name: Globalize.translate("TabTrailers")
name: globalize.translate("TabTrailers")
}, {
name: Globalize.translate("TabFavorites")
name: globalize.translate("TabFavorites")
}, {
name: Globalize.translate("TabCollections")
name: globalize.translate("TabCollections")
}, {
name: Globalize.translate("TabGenres")
name: globalize.translate("TabGenres")
}, {
name: Globalize.translate("ButtonSearch"),
name: globalize.translate("ButtonSearch"),
cssClass: "searchTabButton"
}];
}
@ -398,8 +398,8 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu"
libraryMenu.setTitle(item.Name);
});
} else {
view.setAttribute("data-title", Globalize.translate("TabMovies"));
libraryMenu.setTitle(Globalize.translate("TabMovies"));
view.setAttribute("data-title", globalize.translate("TabMovies"));
libraryMenu.setTitle(globalize.translate("TabMovies"));
}
}

View File

@ -1,4 +1,4 @@
define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "alphaPicker", "listView", "cardBuilder", "userSettings", "emby-itemscontainer"], function (layoutManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, userSettings) {
define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "alphaPicker", "listView", "cardBuilder", "userSettings", "globalize", "emby-itemscontainer"], function (layoutManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, userSettings, globalize) {
"use strict";
return function (view, params, tabContent) {
@ -158,7 +158,7 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "
}
if (!result.Items.length) {
html = '<p style="text-align:center;">' + Globalize.translate("MessageNoTrailersFound") + "</p>";
html = '<p style="text-align:center;">' + globalize.translate("MessageNoTrailersFound") + "</p>";
}
var itemsContainer = tabContent.querySelector(".itemsContainer");
@ -223,25 +223,25 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "
tabContent.querySelector(".btnSort").addEventListener("click", function (e) {
libraryBrowser.showSortMenu({
items: [{
name: Globalize.translate("OptionNameSort"),
name: globalize.translate("OptionNameSort"),
id: "SortName"
}, {
name: Globalize.translate("OptionImdbRating"),
name: globalize.translate("OptionImdbRating"),
id: "CommunityRating,SortName"
}, {
name: Globalize.translate("OptionDateAdded"),
name: globalize.translate("OptionDateAdded"),
id: "DateCreated,SortName"
}, {
name: Globalize.translate("OptionDatePlayed"),
name: globalize.translate("OptionDatePlayed"),
id: "DatePlayed,SortName"
}, {
name: Globalize.translate("OptionParentalRating"),
name: globalize.translate("OptionParentalRating"),
id: "OfficialRating,SortName"
}, {
name: Globalize.translate("OptionPlayCount"),
name: globalize.translate("OptionPlayCount"),
id: "PlayCount,SortName"
}, {
name: Globalize.translate("OptionReleaseDate"),
name: globalize.translate("OptionReleaseDate"),
id: "PremiereDate,SortName"
}],
callback: function () {

View File

@ -1,4 +1,4 @@
define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser", "imageLoader", "alphaPicker", "listView", "cardBuilder", "userSettings", "emby-itemscontainer"], function (layoutManager, playbackManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, userSettings) {
define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser", "imageLoader", "alphaPicker", "listView", "cardBuilder", "userSettings", "globalize", "emby-itemscontainer"], function (layoutManager, playbackManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, userSettings, globalize) {
"use strict";
return function (view, params, tabContent) {
@ -230,25 +230,25 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser
tabContent.querySelector(".btnSort").addEventListener("click", function (e) {
libraryBrowser.showSortMenu({
items: [{
name: Globalize.translate("OptionNameSort"),
name: globalize.translate("OptionNameSort"),
id: "SortName"
}, {
name: Globalize.translate("OptionAlbumArtist"),
name: globalize.translate("OptionAlbumArtist"),
id: "AlbumArtist,SortName"
}, {
name: Globalize.translate("OptionCommunityRating"),
name: globalize.translate("OptionCommunityRating"),
id: "CommunityRating,SortName"
}, {
name: Globalize.translate("OptionCriticRating"),
name: globalize.translate("OptionCriticRating"),
id: "CriticRating,SortName"
}, {
name: Globalize.translate("OptionDateAdded"),
name: globalize.translate("OptionDateAdded"),
id: "DateCreated,SortName"
}, {
name: Globalize.translate("OptionReleaseDate"),
name: globalize.translate("OptionReleaseDate"),
id: "ProductionYear,PremiereDate,SortName"
}, {
name: Globalize.translate("OptionRandom"),
name: globalize.translate("OptionRandom"),
id: "Random,SortName"
}],
callback: function () {

View File

@ -1,4 +1,4 @@
define(["browser", "layoutManager", "userSettings", "inputManager", "loading", "cardBuilder", "dom", "apphost", "imageLoader", "libraryMenu", "playbackManager", "mainTabsManager", "scrollStyles", "emby-itemscontainer", "emby-tabs", "emby-button", "flexStyles"], function (browser, layoutManager, userSettings, inputManager, loading, cardBuilder, dom, appHost, imageLoader, libraryMenu, playbackManager, mainTabsManager) {
define(["browser", "layoutManager", "userSettings", "inputManager", "loading", "cardBuilder", "dom", "apphost", "imageLoader", "libraryMenu", "playbackManager", "mainTabsManager", "globalize", "scrollStyles", "emby-itemscontainer", "emby-tabs", "emby-button", "flexStyles"], function (browser, layoutManager, userSettings, inputManager, loading, cardBuilder, dom, appHost, imageLoader, libraryMenu, playbackManager, mainTabsManager, globalize) {
"use strict";
function itemsPerRow() {
@ -167,21 +167,21 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", "
function getTabs() {
return [{
name: Globalize.translate("TabSuggestions")
name: globalize.translate("TabSuggestions")
}, {
name: Globalize.translate("TabAlbums")
name: globalize.translate("TabAlbums")
}, {
name: Globalize.translate("TabAlbumArtists")
name: globalize.translate("TabAlbumArtists")
}, {
name: Globalize.translate("TabArtists")
name: globalize.translate("TabArtists")
}, {
name: Globalize.translate("TabPlaylists")
name: globalize.translate("TabPlaylists")
}, {
name: Globalize.translate("TabSongs")
name: globalize.translate("TabSongs")
}, {
name: Globalize.translate("TabGenres")
name: globalize.translate("TabGenres")
}, {
name: Globalize.translate("ButtonSearch"),
name: globalize.translate("ButtonSearch"),
cssClass: "searchTabButton"
}];
}
@ -388,8 +388,8 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", "
libraryMenu.setTitle(item.Name);
});
} else {
view.setAttribute("data-title", Globalize.translate("TabMusic"));
libraryMenu.setTitle(Globalize.translate("TabMusic"));
view.setAttribute("data-title", globalize.translate("TabMusic"));
libraryMenu.setTitle(globalize.translate("TabMusic"));
}
}

Some files were not shown because too many files have changed in this diff Show More