Merge remote-tracking branch 'upstream/master' into global-globalize

This commit is contained in:
ferferga 2020-04-26 14:44:01 +02:00
commit 54eb916cfe
177 changed files with 4742 additions and 2819 deletions

View File

@ -2,8 +2,7 @@ trigger:
batch: true
branches:
include:
- master
- release-*
- '*'
tags:
include:
- '*'
@ -13,90 +12,94 @@ pr:
- '*'
jobs:
- job: build
displayName: 'Build'
- job: Build
displayName: 'Build'
pool:
vmImage: 'ubuntu-latest'
strategy:
matrix:
Development:
BuildConfiguration: development
Production:
BuildConfiguration: production
Standalone:
BuildConfiguration: standalone
strategy:
matrix:
Development:
BuildConfiguration: development
Production:
BuildConfiguration: production
Standalone:
BuildConfiguration: standalone
maxParallel: 3
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
displayName: 'Install Node'
inputs:
versionSpec: '12.x'
steps:
- task: NodeTool@0
displayName: 'Install Node'
inputs:
versionSpec: '12.x'
- task: Cache@2
displayName: 'Check Cache'
inputs:
key: 'yarn | yarn.lock'
path: 'node_modules'
cacheHitVar: CACHE_RESTORED
- task: Cache@2
displayName: 'Check Cache'
inputs:
key: 'yarn | yarn.lock'
path: 'node_modules'
cacheHitVar: CACHE_RESTORED
- script: 'yarn install --frozen-lockfile'
displayName: 'Install Dependencies'
condition: ne(variables.CACHE_RESTORED, 'true')
- script: 'yarn install --frozen-lockfile'
displayName: 'Install Dependencies'
condition: ne(variables.CACHE_RESTORED, 'true')
- script: 'yarn build:development'
displayName: 'Build Development'
condition: eq(variables['BuildConfiguration'], 'development')
- script: 'yarn build:development'
displayName: 'Build Development'
condition: eq(variables['BuildConfiguration'], 'development')
- script: 'yarn build:production'
displayName: 'Build Bundle'
condition: eq(variables['BuildConfiguration'], 'production')
- script: 'yarn build:production'
displayName: 'Build Bundle'
condition: eq(variables['BuildConfiguration'], 'production')
- script: 'yarn build:standalone'
displayName: 'Build Standalone'
condition: eq(variables['BuildConfiguration'], 'standalone')
- script: 'yarn build:standalone'
displayName: 'Build Standalone'
condition: eq(variables['BuildConfiguration'], 'standalone')
- script: 'test -d dist'
displayName: 'Check Build'
- script: 'test -d dist'
displayName: 'Check Build'
- script: 'mv dist jellyfin-web'
displayName: 'Rename Directory'
condition: succeeded()
- script: 'mv dist jellyfin-web'
displayName: 'Rename Directory'
- task: PublishPipelineArtifact@1
displayName: 'Publish Release'
condition: succeeded()
inputs:
targetPath: '$(Build.SourcesDirectory)/jellyfin-web'
artifactName: 'jellyfin-web-$(BuildConfiguration)'
- task: ArchiveFiles@2
displayName: 'Archive Directory'
inputs:
rootFolderOrFile: 'jellyfin-web'
includeRootFolder: true
archiveFile: 'jellyfin-web-$(BuildConfiguration)'
- job: lint
displayName: 'Lint'
- task: PublishPipelineArtifact@1
displayName: 'Publish Release'
inputs:
targetPath: '$(Build.SourcesDirectory)/jellyfin-web-$(BuildConfiguration).zip'
artifactName: 'jellyfin-web-$(BuildConfiguration)'
pool:
vmImage: 'ubuntu-latest'
- job: Lint
displayName: 'Lint'
steps:
- task: NodeTool@0
displayName: 'Install Node'
inputs:
versionSpec: '12.x'
pool:
vmImage: 'ubuntu-latest'
- task: Cache@2
displayName: 'Check Cache'
inputs:
key: 'yarn | yarn.lock'
path: 'node_modules'
cacheHitVar: CACHE_RESTORED
steps:
- task: NodeTool@0
displayName: 'Install Node'
inputs:
versionSpec: '12.x'
- script: 'yarn install --frozen-lockfile'
displayName: 'Install Dependencies'
condition: ne(variables.CACHE_RESTORED, 'true')
- task: Cache@2
displayName: 'Check Cache'
inputs:
key: 'yarn | yarn.lock'
path: 'node_modules'
cacheHitVar: CACHE_RESTORED
- script: 'yarn run lint'
displayName: 'Run ESLint'
- script: 'yarn install --frozen-lockfile'
displayName: 'Install Dependencies'
condition: ne(variables.CACHE_RESTORED, 'true')
- script: 'yarn run stylelint'
displayName: 'Run Stylelint'
- script: 'yarn run lint --quiet'
displayName: 'Run ESLint'
- script: 'yarn run stylelint'
displayName: 'Run Stylelint'

View File

@ -1,21 +1,32 @@
env:
es6: true
browser: true
amd: true
browser: true
es6: true
es2017: true
es2020: true
parserOptions:
ecmaVersion: 6
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:
# New browser globals
DataView: readonly
# Browser globals
MediaMetadata: readonly
Promise: readonly
# Deprecated browser globals
DocumentTouch: readonly
# Tizen globals
tizen: readonly
webapis: readonly
@ -24,7 +35,6 @@ globals:
# Dependency globals
$: readonly
jQuery: readonly
queryString: readonly
requirejs: readonly
# Jellyfin globals
ApiClient: writable
@ -40,8 +50,7 @@ globals:
getWindowLocationSearch: writable
Globalize: writable
Hls: writable
humaneDate: writable
humaneElapsed: writable
dfnshelper: writable
LibraryMenu: writable
LinkParser: writable
LiveTvHelpers: writable
@ -52,9 +61,6 @@ globals:
UserParentalControlPage: writable
Windows: readonly
extends:
- eslint:recommended
rules:
block-spacing: ["error"]
brace-style: ["error"]
@ -69,9 +75,97 @@ rules:
no-multiple-empty-lines: ["error", { "max": 1 }]
no-trailing-spaces: ["error"]
one-var: ["error", "never"]
semi: ["warn"]
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

3
babel.config.json Normal file
View File

@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env"]
}

View File

@ -62,7 +62,7 @@ function serve() {
port: 8080
});
let events = ['add', 'change'];
const events = ['add', 'change'];
watch(options.javascript.query).on('all', function (event, path) {
if (events.includes(event)) {
@ -105,7 +105,7 @@ function clean() {
return del(['dist/']);
}
let pipelineJavascript = lazypipe()
const pipelineJavascript = lazypipe()
.pipe(function () {
return mode.development(sourcemaps.init({ loadMaps: true }));
})
@ -140,7 +140,7 @@ function apploader(standalone) {
.pipe(pipelineJavascript())
.pipe(dest('dist/'))
.pipe(browserSync.stream());
};
}
task.displayName = 'apploader';
@ -183,6 +183,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 +199,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

@ -18,6 +18,10 @@
"cssnano": "^4.1.10",
"del": "^5.1.0",
"eslint": "^6.8.0",
"eslint-plugin-compat": "^3.5.1",
"eslint-plugin-eslint-comments": "^3.1.2",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-promise": "^4.2.1",
"file-loader": "^6.0.0",
"gulp": "^4.0.2",
"gulp-babel": "^8.0.0",
@ -51,23 +55,29 @@
},
"dependencies": {
"alameda": "^1.4.0",
"classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
"core-js": "^3.6.4",
"date-fns": "^2.11.1",
"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",
"jstree": "^3.3.7",
"libass-wasm": "https://github.com/jellyfin/JavascriptSubtitlesOctopus#4.0.0-jf",
"libass-wasm": "https://github.com/jellyfin/JavascriptSubtitlesOctopus#4.0.0-jf-cordova",
"material-design-icons-iconfont": "^5.0.1",
"native-promise-only": "^0.8.0-a",
"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"
},
@ -85,8 +95,13 @@
"src/components/filesystem.js",
"src/components/input/keyboardnavigation.js",
"src/components/sanatizefilename.js",
"src/components/scrollManager.js",
"src/scripts/settings/appSettings.js",
"src/scripts/settings/userSettings.js",
"src/scripts/settings/webSettings.js",
"src/components/scrollManager.js"
"src/scripts/dfnshelper.js",
"src/scripts/imagehelper.js",
"src/scripts/inputManager.js"
],
"plugins": [
"@babel/plugin-transform-modules-amd"
@ -110,7 +125,7 @@
"Firefox ESR"
],
"scripts": {
"serve": "gulp serve",
"serve": "gulp serve --development",
"prepare": "gulp --production",
"build:development": "gulp --development",
"build:production": "gulp --production",

View File

@ -21,7 +21,11 @@
}
.libraryPage {
padding-top: 7em;
padding-top: 7em !important;
}
.layout-mobile .libraryPage {
padding-top: 4em !important;
}
.itemDetailPage {
@ -128,10 +132,6 @@
margin-top: 0;
}
.layout-mobile .pageTitleWithDefaultLogo {
background-image: url(../img/icon-transparent.png);
}
.headerLeft,
.skinHeader {
display: -webkit-box;
@ -246,6 +246,7 @@
}
@media all and (min-width: 40em) {
.dashboardDocument .adminDrawerLogo,
.dashboardDocument .mainDrawerButton {
display: none !important;
}
@ -313,7 +314,7 @@
}
.dashboardDocument .mainDrawer-scrollContainer {
margin-top: 4.6em !important;
margin-top: 4.65em !important;
}
}
@ -516,6 +517,13 @@
.itemName {
margin: 0.5em 0;
font-weight: 600;
}
.nameContainer {
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
.itemMiscInfo {
@ -533,7 +541,6 @@
.layout-mobile .itemName,
.layout-mobile .itemMiscInfo,
.layout-mobile .mainDetailButtons {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
@ -575,7 +582,6 @@
.infoText {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
}
@ -606,12 +612,11 @@
}
.detailLogo {
width: 67.25vw;
height: 14.5vh;
width: 30vw;
height: 25vh;
position: absolute;
top: 15vh;
right: 0;
-webkit-background-size: contain;
top: 10vh;
right: 20vw;
background-size: contain;
}
@ -619,26 +624,8 @@
display: none;
}
@media all and (max-width: 87.5em) {
.detailLogo {
right: 5%;
}
}
@media all and (max-width: 75em) {
.detailLogo {
right: 2%;
}
}
@media all and (max-width: 68.75em) {
.detailLogo {
width: 14.91em;
height: 3.5em;
right: 5%;
bottom: 5%;
top: auto;
background-position: center right;
display: none;
}
}

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

@ -13,7 +13,7 @@ _define("document-register-element", function() {
// fetch
var fetch = require("whatwg-fetch");
_define("fetch", function() {
return fetch
return fetch;
});
// query-string
@ -85,15 +85,15 @@ _define("webcomponents", function() {
});
// libass-wasm
var libass_wasm = require("libass-wasm");
var libassWasm = require("libass-wasm");
_define("JavascriptSubtitlesOctopus", function() {
return libass_wasm;
return libassWasm;
});
// material-icons
var material_icons = require("material-design-icons-iconfont/dist/material-design-icons.css");
var materialIcons = require("material-design-icons-iconfont/dist/material-design-icons.css");
_define("material-icons", function() {
return material_icons;
return materialIcons;
});
// noto font
@ -112,3 +112,43 @@ var polyfill = require("@babel/polyfill/dist/polyfill");
_define("polyfill", function () {
return polyfill;
});
// domtokenlist-shim
var classlist = require("classlist.js");
_define("classlist-polyfill", function () {
return classlist;
});
// Date-FNS
var dateFns = require("date-fns");
_define("date-fns", function () {
return dateFns;
});
var dateFnsLocale = require("date-fns/locale");
_define("date-fns/locale", function () {
return dateFnsLocale;
});
var fast_text_encoding = require("fast-text-encoding");
_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(["events", "globalize", "dom", "datetime", "userSettings", "serverNotifications", "connectionManager", "emby-button", "listViewStyle"], function (events, globalize, dom, datetime, userSettings, serverNotifications, connectionManager) {
define(["events", "globalize", "dom", "date-fns", "dfnshelper", "userSettings", "serverNotifications", "connectionManager", "emby-button", "listViewStyle"], function (events, globalize, dom, datefns, dfnshelper, userSettings, serverNotifications, connectionManager) {
"use strict";
function getEntryHtml(entry, apiClient) {
@ -16,7 +16,7 @@ define(["events", "globalize", "dom", "datetime", "userSettings", "serverNotific
html += '<i class="listItemIcon material-icons" style="width:2em!important;height:2em!important;padding:0;color:transparent;background-color:' + color + ";background-image:url('" + apiClient.getUserImageUrl(entry.UserId, {
type: "Primary",
tag: entry.UserPrimaryImageTag
}) + "');background-repeat:no-repeat;background-position:center center;background-size: cover;\">dvr</i>"
}) + "');background-repeat:no-repeat;background-position:center center;background-size: cover;\">dvr</i>";
} else {
html += '<i class="listItemIcon material-icons" style="background-color:' + color + '">' + icon + '</i>';
}
@ -26,8 +26,7 @@ define(["events", "globalize", "dom", "datetime", "userSettings", "serverNotific
html += entry.Name;
html += "</div>";
html += '<div class="listItemBodyText secondary">';
var date = datetime.parseISO8601Date(entry.Date, true);
html += datetime.toLocaleString(date).toLowerCase();
html += datefns.formatRelative(Date.parse(entry.Date), Date.parse(new Date()), { locale: dfnshelper.getLocale() });
html += "</div>";
html += '<div class="listItemBodyText secondary listItemBodyText-nowrap">';
html += entry.ShortOverview || "";

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;
@ -268,6 +268,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
}
function getMaxBandwidth() {
/* eslint-disable compat/compat */
if (navigator.connection) {
var max = navigator.connection.downlinkMax;
if (max && max > 0 && max < Number.POSITIVE_INFINITY) {
@ -279,6 +280,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
return max;
}
}
/* eslint-enable compat/compat */
return null;
}
@ -577,8 +579,9 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
function showDirect(path) {
return new Promise(function(resolve, reject) {
resolveOnNextShow = resolve, page.show(baseUrl()+path)
})
resolveOnNextShow = resolve;
page.show(baseUrl() + path);
});
}
function show(path, options) {

View File

@ -237,10 +237,6 @@ define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings", "g
features.push("voiceinput");
}
if (!browser.tv && !browser.xboxOne) {
browser.ps4;
}
if (supportsHtmlMediaAutoplay()) {
features.push("htmlaudioautoplay");
features.push("htmlvideoautoplay");
@ -279,8 +275,8 @@ define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings", "g
features.push("screensaver");
webSettings.enableMultiServer().then(enabled => {
if (enabled) features.push("multiserver")
})
if (enabled) features.push("multiserver");
});
if (!browser.orsay && !browser.msie && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) {
features.push("subtitleappearancesettings");
@ -351,8 +347,6 @@ define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings", "g
var deviceName;
var appName = "Jellyfin Web";
var appVersion = "10.5.0";
var visibilityChange;
var visibilityState;
var appHost = {
getWindowState: function () {
@ -383,7 +377,7 @@ define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings", "g
return window.NativeShell.AppHost.getDefaultLayout();
}
return getDefaultLayout()
return getDefaultLayout();
},
getDeviceProfile: getDeviceProfile,
init: function () {
@ -426,40 +420,26 @@ define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings", "g
}
};
var doc = self.document;
var isHidden = false;
var hidden;
var visibilityChange;
if (doc) {
if (void 0 !== doc.visibilityState) {
visibilityChange = "visibilitychange";
visibilityState = "hidden";
if (typeof document.hidden !== "undefined") { /* eslint-disable-line compat/compat */
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
document.addEventListener(visibilityChange, function () {
/* eslint-disable-next-line compat/compat */
if (document[hidden]) {
onAppHidden();
} else {
if (void 0 !== doc.mozHidden) {
visibilityChange = "mozvisibilitychange";
visibilityState = "mozVisibilityState";
} else {
if (void 0 !== doc.msHidden) {
visibilityChange = "msvisibilitychange";
visibilityState = "msVisibilityState";
} else {
if (void 0 !== doc.webkitHidden) {
visibilityChange = "webkitvisibilitychange";
visibilityState = "webkitVisibilityState";
}
}
}
onAppVisible();
}
}
if (doc) {
doc.addEventListener(visibilityChange, function () {
if (document[visibilityState]) {
onAppHidden();
} else {
onAppVisible();
}
});
}
}, false);
if (self.addEventListener) {
self.addEventListener("focus", onAppVisible);

View File

@ -95,8 +95,10 @@ import layoutManager from "layoutManager";
return focusedElement;
}
export default {
isEnabled: isEnabled,
enable: enable,
autoFocus: autoFocus
};
/* eslint-enable indent */
export default {
isEnabled: isEnabled,
enable: enable,
autoFocus: autoFocus
};

View File

@ -52,5 +52,5 @@ define(["connectionManager"], function (connectionManager) {
currentSlideshow = null;
}
};
}
};
});

View File

@ -1082,11 +1082,7 @@ import 'programStyles';
if (options.showPersonRoleOrType) {
if (item.Role) {
lines.push('as ' + item.Role);
} else if (item.Type) {
lines.push(globalize.translate('' + item.Type));
} else {
lines.push('');
lines.push(globalize.translate('PersonRole', item.Role));
}
}
}
@ -1854,6 +1850,8 @@ import 'programStyles';
}
}
/* eslint-enable indent */
export default {
getCardsHtml: getCardsHtml,
getDefaultBackgroundClass: getDefaultBackgroundClass,

View File

@ -188,9 +188,9 @@ define(['events'], function (events) {
return apiClient.getEndpointInfo().then(function (endpoint) {
if (endpoint.IsInNetwork) {
return apiClient.getPublicSystemInfo().then(function (info) {
var localAddress = info.LocalAddress
var localAddress = info.LocalAddress;
if (!localAddress) {
console.debug("No valid local address returned, defaulting to external one")
console.debug("No valid local address returned, defaulting to external one");
localAddress = serverAddress;
}
addToCache(serverAddress, localAddress);

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

@ -7,11 +7,11 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
systemInfo = info;
return info;
}
)
);
}
function onDialogClosed() {
loading.hide()
loading.hide();
}
function refreshDirectoryBrowser(page, path, fileOptions, updatePathOnError) {
@ -24,7 +24,7 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
var promises = [];
if ("Network" === path) {
promises.push(ApiClient.getNetworkDevices())
promises.push(ApiClient.getNetworkDevices());
} else {
if (path) {
promises.push(ApiClient.getDirectoryContents(path, fileOptions));
@ -89,7 +89,7 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
var instruction = options.instruction ? options.instruction + "<br/><br/>" : "";
html += '<div class="infoBanner" style="margin-bottom:1.5em;">';
html += instruction;
html += globalize.translate("MessageDirectoryPickerInstruction").replace("{0}", "<b>\\\\server</b>").replace("{1}", "<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/>";
@ -101,7 +101,7 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
html += globalize.translate("MessageDirectoryPickerLinuxInstruction");
html += "<br/>";
}
html += "</div>"
html += "</div>";
}
html += '<form style="margin:auto;">';
html += '<div class="inputContainer" style="display: flex; align-items: center;">';
@ -144,13 +144,13 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
function alertText(text) {
alertTextWithOptions({
text: text
})
});
}
function alertTextWithOptions(options) {
require(["alert"], function(alert) {
alert(options)
})
alert(options);
});
}
function validatePath(path, validateWriteable, apiClient) {
@ -163,21 +163,20 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
}
}).catch(function(response) {
if (response) {
// TODO All alerts (across the project), should use Globalize.translate()
if (response.status === 404) {
alertText("The path could not be found. Please ensure the path is valid and try again.");
alertText(Globalize.translate("PathNotFound"));
return Promise.reject();
}
if (response.status === 500) {
if (validateWriteable) {
alertText("Jellyfin Server requires write access to this folder. Please ensure write access and try again.");
alertText(Globalize.translate("WriteAccessRequired"));
} else {
alertText("The path could not be found. Please ensure the path is valid and try again.")
alertText(Globalize.translate("PathNotFound"));
}
return Promise.reject()
return Promise.reject();
}
}
return Promise.resolve()
return Promise.resolve();
});
}
@ -189,7 +188,7 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
if (lnkPath.classList.contains("lnkFile")) {
content.querySelector("#txtDirectoryPickerPath").value = path;
} else {
refreshDirectoryBrowser(content, path, fileOptions, true)
refreshDirectoryBrowser(content, path, fileOptions, true);
}
}
});
@ -276,7 +275,7 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
dlg.addEventListener("close", onDialogClosed);
dialogHelper.open(dlg);
dlg.querySelector(".btnCloseDialog").addEventListener("click", function() {
dialogHelper.close(dlg)
dialogHelper.close(dlg);
});
currentDialog = dlg;
dlg.querySelector("#txtDirectoryPickerPath").value = initialPath;
@ -294,9 +293,9 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
if (currentDialog) {
dialogHelper.close(currentDialog);
}
}
};
}
var systemInfo;
return directoryBrowser
return directoryBrowser;
});

View File

@ -186,6 +186,8 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
context.querySelector('#selectLanguage').value = userSettings.language() || '';
context.querySelector('.selectDateTimeLocale').value = userSettings.dateTimeLocale() || '';
context.querySelector('#txtLibraryPageSize').value = userSettings.libraryPageSize();
selectDashboardTheme.value = userSettings.dashboardTheme() || '';
selectTheme.value = userSettings.theme() || '';
@ -215,6 +217,8 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
userSettingsInstance.soundEffects(context.querySelector('.selectSoundEffects').value);
userSettingsInstance.screensaver(context.querySelector('.selectScreensaver').value);
userSettingsInstance.libraryPageSize(context.querySelector('#txtLibraryPageSize').value);
userSettingsInstance.skin(context.querySelector('.selectSkin').value);
userSettingsInstance.enableFastFadein(context.querySelector('#chkFadein').checked);

View File

@ -143,6 +143,11 @@
<select is="emby-select" class="selectSoundEffects" label="${LabelSoundEffects}"></select>
</div>
<div class="inputContainer inputContainer-withDescription fldFadein">
<input is="emby-input" type="number" id="txtLibraryPageSize" pattern="[0-9]*" required="required" min="0" max="1000" step="1" label="${LabelLibraryPageSize}" />
<div class="fieldDescription">${LabelLibraryPageSizeHelp}</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription fldFadein">
<label>
<input type="checkbox" is="emby-checkbox" id="chkFadein" />

View File

@ -262,15 +262,17 @@
return _transitionEvent;
}
export default {
parentWithAttribute: parentWithAttribute,
parentWithClass: parentWithClass,
parentWithTag: parentWithTag,
addEventListener: addEventListener,
removeEventListener: removeEventListener,
getWindowSize: getWindowSize,
getScreenWidth: getScreenWidth,
whichTransitionEvent: whichTransitionEvent,
whichAnimationEvent: whichAnimationEvent,
whichAnimationCancelEvent: whichAnimationCancelEvent
};
/* eslint-enable indent */
export default {
parentWithAttribute: parentWithAttribute,
parentWithClass: parentWithClass,
parentWithTag: parentWithTag,
addEventListener: addEventListener,
removeEventListener: removeEventListener,
getWindowSize: getWindowSize,
getScreenWidth: getScreenWidth,
whichTransitionEvent: whichTransitionEvent,
whichAnimationEvent: whichAnimationEvent,
whichAnimationCancelEvent: whichAnimationCancelEvent
};

View File

@ -1,10 +1,10 @@
import multiDownload from "multi-download"
import multiDownload from "multi-download";
export function download(items) {
if (window.NativeShell) {
items.map(function (item) {
window.NativeShell.downloadFile(item.url);
window.NativeShell.downloadFile(item);
});
} else {
multiDownload(items.map(function (item) {

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,4 +1,4 @@
define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', 'scrollHelper', 'serverNotifications', 'loading', 'datetime', 'focusManager', 'playbackManager', 'userSettings', 'imageLoader', 'events', 'layoutManager', 'itemShortcuts', 'dom', 'css!./guide.css', 'programStyles', 'material-icons', 'scrollStyles', 'emby-button', 'paper-icon-button-light', 'emby-tabs', 'emby-scroller', 'flexStyles', 'registerElement'], function (require, inputManager, browser, globalize, connectionManager, scrollHelper, serverNotifications, loading, datetime, focusManager, playbackManager, userSettings, imageLoader, events, layoutManager, itemShortcuts, dom) {
define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', 'scrollHelper', 'serverNotifications', 'loading', 'datetime', 'focusManager', 'playbackManager', 'userSettings', 'imageLoader', 'events', 'layoutManager', 'itemShortcuts', 'dom', 'css!./guide.css', 'programStyles', 'material-icons', 'scrollStyles', 'emby-programcell', 'emby-button', 'paper-icon-button-light', 'emby-tabs', 'emby-scroller', 'flexStyles', 'registerElement'], function (require, inputManager, browser, globalize, connectionManager, scrollHelper, serverNotifications, loading, datetime, focusManager, playbackManager, userSettings, imageLoader, events, layoutManager, itemShortcuts, dom) {
'use strict';
function showViewSettings(instance) {
@ -1252,18 +1252,5 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
});
}
var ProgramCellPrototype = Object.create(HTMLButtonElement.prototype);
ProgramCellPrototype.detachedCallback = function () {
this.posLeft = null;
this.posWidth = null;
this.guideProgramName = null;
};
document.registerElement('emby-programcell', {
prototype: ProgramCellPrototype,
extends: 'button'
});
return Guide;
});

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

@ -10,6 +10,13 @@
<div class="fieldDescription">${LabelPleaseRestart}</div>
</div>
<div class="verticalSection verticalSection-extrabottompadding">
<label class="checkboxContainer">
<input class="chkHidePlayedFromLatest" type="checkbox" is="emby-checkbox" />
<span>${HideWatchedContentFromLatestMedia}</span>
</label>
</div>
<div class="selectContainer">
<select is="emby-select" id="selectHomeSection1" label="{section1label}">
<option value="smalllibrarytiles">${HeaderMyMedia}</option>
@ -110,13 +117,6 @@
<div class="perLibrarySettings"></div>
<div class="verticalSection verticalSection-extrabottompadding">
<label class="checkboxContainer">
<input class="chkHidePlayedFromLatest" type="checkbox" is="emby-checkbox" />
<span>${HideWatchedContentFromLatestMedia}</span>
</label>
</div>
<div class="verticalSection verticalSection-extrabottompadding">
<h2 class="sectionTitle">${HeaderLibraryFolders}</h2>
<div>

View File

@ -64,18 +64,18 @@ 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", '<a id="button-createLibrary" class="button-link">', '</a>');
} else {
noLibDescription = globalize.translate("AskAdminToCreateLibrary");
}
html += '<div class="centerMessage padded-left padded-right">';
html += '<h2>' + globalize.translate("MessageNothingHere") + '</h2>';
html += '<p>' + noLibDescription + '</p>'
html += '<p>' + noLibDescription + '</p>';
html += '</div>';
elem.innerHTML = html;
var createNowLink = elem.querySelector("#button-createLibrary")
var createNowLink = elem.querySelector("#button-createLibrary");
if (createNowLink) {
createNowLink.addEventListener("click", function () {
Dashboard.navigate("library.html");
@ -131,7 +131,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} else if (section === 'librarytiles' || section === 'smalllibrarytiles' || section === 'smalllibrarytiles-automobile' || section === 'librarytiles-automobile') {
loadLibraryTiles(elem, apiClient, user, userSettings, 'smallBackdrop', userViews, allSections);
} else if (section === 'librarybuttons') {
loadlibraryButtons(elem, apiClient, user, userSettings, userViews, allSections);
loadlibraryButtons(elem, apiClient, user, userSettings, userViews);
} else if (section === 'resume') {
loadResumeVideo(elem, apiClient, userId);
} else if (section === 'resumeaudio') {
@ -640,7 +640,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
if (enableScrollX()) {
html += '<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">';
html += '<div is="emby-itemscontainer" class="itemsContainer scrollSlider focuscontainer-x">'
html += '<div is="emby-itemscontainer" class="itemsContainer scrollSlider focuscontainer-x">';
} else {
html += '<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right vertical-wrap focuscontainer-x">';
}
@ -714,7 +714,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
if (enableScrollX()) {
html += '<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">';
html += '<div is="emby-itemscontainer" class="itemsContainer scrollSlider focuscontainer-x" data-monitor="videoplayback,markplayed">'
html += '<div is="emby-itemscontainer" class="itemsContainer scrollSlider focuscontainer-x" data-monitor="videoplayback,markplayed">';
} else {
html += '<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right vertical-wrap focuscontainer-x" data-monitor="videoplayback,markplayed">';
}
@ -786,7 +786,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
if (enableScrollX()) {
html += '<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">';
html += '<div is="emby-itemscontainer" class="itemsContainer scrollSlider focuscontainer-x">'
html += '<div is="emby-itemscontainer" class="itemsContainer scrollSlider focuscontainer-x">';
} else {
html += '<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right vertical-wrap focuscontainer-x">';
}

View File

@ -31,7 +31,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
}
function enableHlsShakaPlayer(item, mediaSource, mediaType) {
/* eslint-disable-next-line compat/compat */
if (!!window.MediaSource && !!MediaSource.isTypeSupported) {
if (canPlayNativeHls()) {
@ -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;
@ -171,13 +171,31 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
// Appending #t=xxx to the query string doesn't seem to work with HLS
// For plain video files, not all browsers support it either
var delay = browser.safari ? 2500 : 0;
if (delay) {
setTimeout(function () {
setCurrentTimeIfNeeded(element, seconds);
}, delay);
} else {
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"];
var onMediaChange = function(e) {
if (element.currentTime === 0 && element.duration >= seconds) {
// seek only when video position is exactly zero,
// as this is true only if video hasn't started yet or
// user rewound to the very beginning
// (but rewinding cannot happen as the first event with media of non-empty duration)
console.debug(`seeking to ${seconds} on ${e.type} event`);
setCurrentTimeIfNeeded(element, seconds);
events.map(function(name) {
element.removeEventListener(name, onMediaChange);
});
if (onMediaReady) onMediaReady();
}
};
events.map(function (name) {
element.addEventListener(name, onMediaChange);
});
}
}
}

View File

@ -101,7 +101,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
self._timeUpdated = false;
self._currentTime = null;
var elem = createMediaElement(options);
var elem = createMediaElement();
return setCurrentSrc(elem, options);
};

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 */
@ -116,8 +116,9 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
});
}
function normalizeTrackEventText(text) {
return text.replace(/\\N/gi, '\n');
function normalizeTrackEventText(text, useHtml) {
var result = text.replace(/\\N/gi, '\n').replace(/\r/gi, '');
return useHtml ? result.replace(/\n/gi, '<br>') : result;
}
function setTracks(elem, tracks, item, mediaSource) {
@ -567,19 +568,19 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
self.resetSubtitleOffset = function() {
currentTrackOffset = 0;
showTrackOffset = false;
}
};
self.enableShowingSubtitleOffset = function() {
showTrackOffset = true;
}
};
self.disableShowingSubtitleOffset = function() {
showTrackOffset = false;
}
};
self.isShowingSubtitleOffsetEnabled = function() {
return showTrackOffset;
}
};
function getTextTrack() {
var videoElement = self._mediaElement;
@ -599,8 +600,9 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
var offsetValue = parseFloat(offset);
// if .ass currently rendering
if (currentAssRenderer) {
if (currentSubtitlesOctopus) {
updateCurrentTrackOffset(offsetValue);
currentSubtitlesOctopus.timeOffset = offsetValue;
} else {
var trackElement = getTextTrack();
// if .vtt currently rendering
@ -651,7 +653,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
self.getSubtitleOffset = function() {
return currentTrackOffset;
}
};
function isAudioStreamSupported(stream, deviceProfile) {
@ -793,7 +795,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
dlg.parentNode.removeChild(dlg);
}
fullscreenManager.exitFullscreen();
screenfull.exit();
};
function onEnded() {
@ -855,7 +857,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) {
@ -1019,7 +1023,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
xhr.onerror = function (e) {
reject(e);
decrementFetchQueue();
}
};
xhr.send();
});
@ -1048,11 +1052,12 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
function renderSsaAss(videoElement, track, item) {
var attachments = self._currentPlayOptions.mediaSource.MediaAttachments || [];
var apiClient = connectionManager.getApiClient(item);
var options = {
video: videoElement,
subUrl: getTextTrackUrl(track, item),
fonts: attachments.map(function (i) {
return i.DeliveryUrl;
return apiClient.getUrl(i.DeliveryUrl);
}),
workerUrl: appRouter.baseUrl() + "/libraries/subtitles-octopus-worker.js",
legacyWorkerUrl: appRouter.baseUrl() + "/libraries/subtitles-octopus-worker-legacy.js",
@ -1208,7 +1213,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
data.TrackEvents.forEach(function (trackEvent) {
var trackCueObject = window.VTTCue || window.TextTrackCue;
var cue = new trackCueObject(trackEvent.StartPositionTicks / 10000000, trackEvent.EndPositionTicks / 10000000, normalizeTrackEventText(trackEvent.Text));
var cue = new trackCueObject(trackEvent.StartPositionTicks / 10000000, trackEvent.EndPositionTicks / 10000000, normalizeTrackEventText(trackEvent.Text, false));
trackElement.addCue(cue);
});
@ -1218,11 +1223,6 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
function updateSubtitleText(timeMs) {
// handle offset for ass tracks
if (currentTrackOffset) {
timeMs += (currentTrackOffset * 1000);
}
var clock = currentClock;
if (clock) {
try {
@ -1249,8 +1249,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
}
if (selectedTrackEvent && selectedTrackEvent.Text) {
subtitleTextElement.innerHTML = normalizeTrackEventText(selectedTrackEvent.Text);
subtitleTextElement.innerHTML = normalizeTrackEventText(selectedTrackEvent.Text, true);
subtitleTextElement.classList.remove('hide');
} else {
@ -1427,11 +1426,11 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
}
if (browser.safari || browser.iOS || browser.iPad) {
list.push('AirPlay')
list.push('AirPlay');
}
list.push('SetBrightness');
list.push("SetAspectRatio")
list.push("SetAspectRatio");
return list;
}
@ -1554,11 +1553,11 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
if (video) {
if (isEnabled) {
video.requestAirPlay().catch(function(err) {
console.error("Error requesting AirPlay", err)
console.error("Error requesting AirPlay", err);
});
} else {
document.exitAirPLay().catch(function(err) {
console.error("Error exiting AirPlay", err)
console.error("Error exiting AirPlay", err);
});
}
}
@ -1691,12 +1690,12 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
var mediaElement = this._mediaElement;
if (mediaElement) {
if ("auto" === val) {
mediaElement.style.removeProperty("object-fit")
mediaElement.style.removeProperty("object-fit");
} else {
mediaElement.style["object-fit"] = val
mediaElement.style["object-fit"] = val;
}
}
this._currentAspectRatio = val
this._currentAspectRatio = val;
};
HtmlVideoPlayer.prototype.getAspectRatio = function () {
@ -1713,7 +1712,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
}, {
name: "Fill",
id: "fill"
}]
}];
};
HtmlVideoPlayer.prototype.togglePictureInPicture = function () {

View File

@ -1,74 +0,0 @@
define(["datetime"], function (datetime) {
"use strict";
function humaneDate(date_str) {
var format;
var time_formats = [
[90, "a minute"],
[3600, "minutes", 60],
[5400, "an hour"],
[86400, "hours", 3600],
[129600, "a day"],
[604800, "days", 86400],
[907200, "a week"],
[2628e3, "weeks", 604800],
[3942e3, "a month"],
[31536e3, "months", 2628e3],
[47304e3, "a year"],
[31536e5, "years", 31536e3]
];
var dt = new Date();
var date = datetime.parseISO8601Date(date_str, true);
var seconds = (dt - date) / 1000.0;
var i = 0;
if (seconds < 0) {
seconds = Math.abs(seconds);
}
// eslint-disable-next-line no-cond-assign
for (; format = time_formats[i++];) {
if (seconds < format[0]) {
if (2 == format.length) {
return format[1] + " ago";
}
return Math.round(seconds / format[2]) + " " + format[1] + " ago";
}
}
if (seconds > 47304e5) {
return Math.round(seconds / 47304e5) + " centuries ago";
}
return date_str;
}
function humaneElapsed(firstDateStr, secondDateStr) {
// TODO replace this whole script with a library or something
var dateOne = new Date(firstDateStr);
var dateTwo = new Date(secondDateStr);
var delta = (dateTwo.getTime() - dateOne.getTime()) / 1e3;
var days = Math.floor(delta % 31536e3 / 86400);
var hours = Math.floor(delta % 31536e3 % 86400 / 3600);
var minutes = Math.floor(delta % 31536e3 % 86400 % 3600 / 60);
var seconds = Math.round(delta % 31536e3 % 86400 % 3600 % 60);
var elapsed = "";
elapsed += 1 == days ? days + " day " : "";
elapsed += days > 1 ? days + " days " : "";
elapsed += 1 == hours ? hours + " hour " : "";
elapsed += hours > 1 ? hours + " hours " : "";
elapsed += 1 == minutes ? minutes + " minute " : "";
elapsed += minutes > 1 ? minutes + " minutes " : "";
elapsed += elapsed.length > 0 ? "and " : "";
elapsed += 1 == seconds ? seconds + " second" : "";
elapsed += 0 == seconds || seconds > 1 ? seconds + " seconds" : "";
return elapsed;
}
window.humaneDate = humaneDate;
window.humaneElapsed = humaneElapsed;
return {
humaneDate: humaneDate,
humaneElapsed: humaneElapsed
};
});

View File

@ -109,7 +109,7 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
html += '<span style="margin-right: 10px;">';
var startAtDisplay = totalRecordCount ? startIndex + 1 : 0;
html += startAtDisplay + '-' + recordsEnd + ' of ' + totalRecordCount;
html += globalize.translate("ListPaging", startAtDisplay, recordsEnd, totalRecordCount);
html += '</span>';

View File

@ -1,10 +1,6 @@
define(['lazyLoader', 'imageFetcher', 'layoutManager', 'browser', 'appSettings', 'userSettings', 'require', 'css!./style'], function (lazyLoader, imageFetcher, layoutManager, browser, appSettings, userSettings, require) {
'use strict';
var requestIdleCallback = window.requestIdleCallback || function (fn) {
fn();
};
var self = {};
function fillImage(elem, source, enableEffects) {

View File

@ -1,4 +1,4 @@
define(['datetime', 'itemHelper', 'css!./indicators.css', 'material-icons'], function (datetime, itemHelper) {
define(['datetime', 'itemHelper', 'emby-progressbar', 'css!./indicators.css', 'material-icons'], function (datetime, itemHelper) {
'use strict';
function enableProgressIndicator(item) {
@ -183,45 +183,6 @@ define(['datetime', 'itemHelper', 'css!./indicators.css', 'material-icons'], fun
return '';
}
var ProgressBarPrototype = Object.create(HTMLDivElement.prototype);
function onAutoTimeProgress() {
var start = parseInt(this.getAttribute('data-starttime'));
var end = parseInt(this.getAttribute('data-endtime'));
var now = new Date().getTime();
var total = end - start;
var pct = 100 * ((now - start) / total);
pct = Math.min(100, pct);
pct = Math.max(0, pct);
var itemProgressBarForeground = this.querySelector('.itemProgressBarForeground');
itemProgressBarForeground.style.width = pct + '%';
}
ProgressBarPrototype.attachedCallback = function () {
if (this.timeInterval) {
clearInterval(this.timeInterval);
}
if (this.getAttribute('data-automode') === 'time') {
this.timeInterval = setInterval(onAutoTimeProgress.bind(this), 60000);
}
};
ProgressBarPrototype.detachedCallback = function () {
if (this.timeInterval) {
clearInterval(this.timeInterval);
this.timeInterval = null;
}
};
document.registerElement('emby-progressbar', {
prototype: ProgressBarPrototype,
extends: 'div'
});
return {
getProgressHtml: getProgressHtml,
getProgressBarHtml: getProgressBarHtml,

View File

@ -184,7 +184,7 @@ require(['apphost'], function (appHost) {
function allowInput() {
// This would be nice but always seems to return true with electron
if (!isElectron && document.hidden) {
if (!isElectron && document.hidden) { /* eslint-disable-line compat/compat */
return false;
}
@ -254,7 +254,7 @@ require(['apphost'], function (appHost) {
var inputLoopTimer;
function runInputLoop() {
// Get the latest gamepad state.
var gamepads = navigator.getGamepads();
var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */
for (var i = 0, len = gamepads.length; i < len; i++) {
var gamepad = gamepads[i];
if (!gamepad) {
@ -362,7 +362,7 @@ require(['apphost'], function (appHost) {
}
function isGamepadConnected() {
var gamepads = navigator.getGamepads();
var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */
for (var i = 0, len = gamepads.length; i < len; i++) {
var gamepad = gamepads[i];
if (gamepad && gamepad.connected) {
@ -373,6 +373,7 @@ require(['apphost'], function (appHost) {
}
function onFocusOrGamepadAttach(e) {
/* eslint-disable-next-line compat/compat */
if (isGamepadConnected() && document.hasFocus()) {
console.log("Gamepad connected! Starting input loop");
startInputLoop();
@ -380,6 +381,7 @@ require(['apphost'], function (appHost) {
}
function onFocusOrGamepadDetach(e) {
/* eslint-disable-next-line compat/compat */
if (!isGamepadConnected() || !document.hasFocus()) {
console.log("Gamepad disconnected! No other gamepads are connected, stopping input loop");
stopInputLoop();

View File

@ -159,7 +159,9 @@ function attachGamepadScript(e) {
}
// No need to check for gamepads manually at load time, the eventhandler will be fired for that
window.addEventListener("gamepadconnected", attachGamepadScript);
if (navigator.getGamepads) { /* eslint-disable-line compat/compat */
window.addEventListener("gamepadconnected", attachGamepadScript);
}
export default {
enable: enable,

View File

@ -116,7 +116,7 @@ define(["dialogHelper", "require", "layoutManager", "globalize", "userSettings",
}
function createAttribute(label, value) {
return '<span class="mediaInfoLabel">' + label + '</span><span class="mediaInfoAttribute">' + value + "</span>"
return '<span class="mediaInfoLabel">' + label + '</span><span class="mediaInfoAttribute">' + value + "</span>";
}
function showMediaInfoMore(itemId, serverId, template) {

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",
@ -339,7 +339,9 @@ define(["apphost", "globalize", "connectionManager", "itemHelper", "appRouter",
fileDownloader.download([{
url: downloadHref,
itemId: itemId,
serverId: serverId
serverId: serverId,
title: item.Name,
filename: item.Path.replace(/^.*[\\\/]/, '')
}]);
getResolveFunction(getResolveFunction(resolve, id), id)();
});
@ -352,6 +354,7 @@ define(["apphost", "globalize", "connectionManager", "itemHelper", "appRouter",
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
if (document.execCommand("copy")) {
require(["toast"], function (toast) {
toast(globalize.translate("CopyStreamURLSuccess"));
@ -361,14 +364,19 @@ define(["apphost", "globalize", "connectionManager", "itemHelper", "appRouter",
}
document.body.removeChild(textArea);
};
/* eslint-disable-next-line compat/compat */
if (navigator.clipboard === undefined) {
textAreaCopy();
} else {
/* eslint-disable-next-line compat/compat */
navigator.clipboard.writeText(downloadHref).then(function () {
require(["toast"], function (toast) {
toast(globalize.translate("CopyStreamURLSuccess"));
});
}, textAreaCopy);
}).catch(function () {
textAreaCopy();
});
}
getResolveFunction(resolve, id)();
break;

View File

@ -309,7 +309,7 @@ define(["dialogHelper", "loading", "connectionManager", "require", "globalize",
fullName = idInfo.Name + " " + globalize.translate(idInfo.Type);
}
var idLabel = globalize.translate("LabelDynamicExternalId").replace("{0}", fullName);
var idLabel = globalize.translate("LabelDynamicExternalId", fullName);
html += '<input is="emby-input" class="txtLookupId" data-providerkey="' + idInfo.Key + '" id="' + id + '" label="' + idLabel + '"/>';

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

@ -4,10 +4,6 @@ define(['visibleinviewport', 'dom', 'browser'], function (visibleinviewport, dom
var thresholdX;
var thresholdY;
var requestIdleCallback = window.requestIdleCallback || function (fn) {
fn();
};
function resetThresholds() {
var threshold = 0.3;

View File

@ -36,7 +36,7 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct
html += "<option value='" + culture.TwoLetterISORegionName + "'>" + culture.DisplayName + "</option>";
}
select.innerHTML = html;
})
});
}
function populateRefreshInterval(select) {
@ -120,7 +120,7 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct
html += plugin.Name;
html += "</h3>";
html += "</div>";
i > 0 ? html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate("ButtonUp") + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + i + '"><i class="material-icons keyboard_arrow_up"></i></button>' : plugins.length > 1 && (html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate("ButtonDown") + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + i + '"><i class="material-icons keyboard_arrow_down"></i></button>'), html += "</div>"
i > 0 ? html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate("ButtonUp") + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + i + '"><i class="material-icons keyboard_arrow_up"></i></button>' : plugins.length > 1 && (html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate("ButtonDown") + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + i + '"><i class="material-icons keyboard_arrow_down"></i></button>'), html += "</div>";
}
html += "</div>";
html += '<div class="fieldDescription">' + globalize.translate("LabelMetadataDownloadersHelp") + "</div>";
@ -265,10 +265,10 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct
renderMetadataFetchers(parent, availableOptions, {});
renderSubtitleFetchers(parent, availableOptions, {});
renderImageFetchers(parent, availableOptions, {});
availableOptions.SubtitleFetchers.length ? parent.querySelector(".subtitleDownloadSettings").classList.remove("hide") : parent.querySelector(".subtitleDownloadSettings").classList.add("hide")
availableOptions.SubtitleFetchers.length ? parent.querySelector(".subtitleDownloadSettings").classList.remove("hide") : parent.querySelector(".subtitleDownloadSettings").classList.add("hide");
}).catch(function() {
return Promise.resolve();
})
});
}
function adjustSortableListElement(elem) {
@ -296,8 +296,8 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct
Type: type
}, currentLibraryOptions.TypeOptions.push(typeOptions));
var availableOptions = getTypeOptions(currentAvailableOptions || {}, type);
(new ImageOptionsEditor).show(type, typeOptions, availableOptions)
})
(new ImageOptionsEditor).show(type, typeOptions, availableOptions);
});
}
function onImageFetchersContainerClick(e) {
@ -315,12 +315,12 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct
var list = dom.parentWithClass(li, "paperList");
if (btnSortable.classList.contains("btnSortableMoveDown")) {
var next = li.nextSibling;
next && (li.parentNode.removeChild(li), next.parentNode.insertBefore(li, next.nextSibling))
next && (li.parentNode.removeChild(li), next.parentNode.insertBefore(li, next.nextSibling));
} else {
var prev = li.previousSibling;
prev && (li.parentNode.removeChild(li), prev.parentNode.insertBefore(li, prev))
prev && (li.parentNode.removeChild(li), prev.parentNode.insertBefore(li, prev));
}
Array.prototype.forEach.call(list.querySelectorAll(".sortableOption"), adjustSortableListElement)
Array.prototype.forEach.call(list.querySelectorAll(".sortableOption"), adjustSortableListElement);
}
}
@ -407,13 +407,13 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct
function setSubtitleFetchersIntoOptions(parent, options) {
options.DisabledSubtitleFetchers = Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll(".chkSubtitleFetcher"), function(elem) {
return !elem.checked
return !elem.checked;
}), function(elem) {
return elem.getAttribute("data-pluginname")
return elem.getAttribute("data-pluginname");
});
options.SubtitleFetcherOrder = Array.prototype.map.call(parent.querySelectorAll(".subtitleFetcherItem"), function(elem) {
return elem.getAttribute("data-pluginname")
return elem.getAttribute("data-pluginname");
});
}
@ -455,13 +455,13 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct
}
typeOptions.ImageFetchers = Array.prototype.map.call(Array.prototype.filter.call(section.querySelectorAll(".chkImageFetcher"), function(elem) {
return elem.checked
return elem.checked;
}), function(elem) {
return elem.getAttribute("data-pluginname")
return elem.getAttribute("data-pluginname");
});
typeOptions.ImageFetcherOrder = Array.prototype.map.call(section.querySelectorAll(".imageFetcherItem"), function(elem) {
return elem.getAttribute("data-pluginname")
return elem.getAttribute("data-pluginname");
});
}
}
@ -505,20 +505,20 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct
SaveSubtitlesWithMedia: parent.querySelector("#chkSaveSubtitlesLocally").checked,
RequirePerfectSubtitleMatch: parent.querySelector("#chkRequirePerfectMatch").checked,
MetadataSavers: Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll(".chkMetadataSaver"), function(elem) {
return elem.checked
return elem.checked;
}), function(elem) {
return elem.getAttribute("data-pluginname")
return elem.getAttribute("data-pluginname");
}),
TypeOptions: []
};
options.LocalMetadataReaderOrder = Array.prototype.map.call(parent.querySelectorAll(".localReaderOption"), function(elem) {
return elem.getAttribute("data-pluginname")
return elem.getAttribute("data-pluginname");
});
options.SubtitleDownloadLanguages = Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll(".chkSubtitleLanguage"), function(elem) {
return elem.checked
return elem.checked;
}), function(elem) {
return elem.getAttribute("data-lang")
return elem.getAttribute("data-lang");
});
setSubtitleFetchersIntoOptions(parent, options);
setMetadataFetchersIntoOptions(parent, options);
@ -531,7 +531,7 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct
function getOrderedPlugins(plugins, configuredOrder) {
plugins = plugins.slice(0);
plugins.sort(function(a, b) {
return a = configuredOrder.indexOf(a.Name), b = configuredOrder.indexOf(b.Name), a < b ? -1 : a > b ? 1 : 0
return a = configuredOrder.indexOf(a.Name), b = configuredOrder.indexOf(b.Name), a < b ? -1 : a > b ? 1 : 0;
});
return plugins;
}
@ -558,10 +558,10 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct
parent.querySelector("#chkSkipIfAudioTrackPresent").checked = options.SkipSubtitlesIfAudioTrackMatches;
parent.querySelector("#chkRequirePerfectMatch").checked = options.RequirePerfectSubtitleMatch;
Array.prototype.forEach.call(parent.querySelectorAll(".chkMetadataSaver"), function(elem) {
elem.checked = options.MetadataSavers ? -1 !== options.MetadataSavers.indexOf(elem.getAttribute("data-pluginname")) : "true" === elem.getAttribute("data-defaultenabled")
elem.checked = options.MetadataSavers ? -1 !== options.MetadataSavers.indexOf(elem.getAttribute("data-pluginname")) : "true" === elem.getAttribute("data-defaultenabled");
});
Array.prototype.forEach.call(parent.querySelectorAll(".chkSubtitleLanguage"), function(elem) {
elem.checked = !!options.SubtitleDownloadLanguages && -1 !== options.SubtitleDownloadLanguages.indexOf(elem.getAttribute("data-lang"))
elem.checked = !!options.SubtitleDownloadLanguages && -1 !== options.SubtitleDownloadLanguages.indexOf(elem.getAttribute("data-lang"));
});
renderMetadataReaders(parent, getOrderedPlugins(parent.availableOptions.MetadataReaders, options.LocalMetadataReaderOrder || []));
renderMetadataFetchers(parent, parent.availableOptions, options);
@ -578,5 +578,5 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct
getLibraryOptions: getLibraryOptions,
setLibraryOptions: setLibraryOptions,
setAdvancedVisible: setAdvancedVisible
}
};
});

View File

@ -188,5 +188,5 @@ define(["pluginManager"], function (pluginManager) {
}
}
};
}
};
});

View File

@ -470,7 +470,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
fullName = idInfo.Name + " " + globalize.translate(idInfo.Type);
}
var labelText = globalize.translate("LabelDynamicExternalId").replace("{0}", fullName);
var labelText = globalize.translate('LabelDynamicExternalId', fullName);
html += '<div class="inputContainer">';
html += '<div class="flex align-items-center">';

View File

@ -6,6 +6,7 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
document.removeEventListener('keydown', onOneDocumentClick);
if (window.Notification) {
/* eslint-disable-next-line compat/compat */
Notification.requestPermission();
}
}
@ -26,6 +27,7 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
}
function resetRegistration() {
/* eslint-disable-next-line compat/compat */
var serviceWorker = navigator.serviceWorker;
if (serviceWorker) {
serviceWorker.ready.then(function (registration) {
@ -173,15 +175,15 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
};
if (status === 'completed') {
notification.title = globalize.translate('PackageInstallCompleted').replace('{0}', installation.Name + ' ' + installation.Version);
notification.title = globalize.translate('PackageInstallCompleted', installation.Name, installation.Version);
notification.vibrate = true;
} else if (status === 'cancelled') {
notification.title = globalize.translate('PackageInstallCancelled').replace('{0}', installation.Name + ' ' + installation.Version);
notification.title = globalize.translate('PackageInstallCancelled', installation.Name, installation.Version);
} else if (status === 'failed') {
notification.title = globalize.translate('PackageInstallFailed').replace('{0}', installation.Name + ' ' + installation.Version);
notification.title = globalize.translate('PackageInstallFailed', installation.Name, installation.Version);
notification.vibrate = true;
} else if (status === 'progress') {
notification.title = globalize.translate('InstallingPackage').replace('{0}', installation.Name + ' ' + installation.Version);
notification.title = globalize.translate('InstallingPackage', installation.Name, installation.Version);
notification.actions =
[

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,8 +224,8 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
elem.addEventListener('click', function (e) {
if (!dom.parentWithTag(e.target, ['BUTTON', 'INPUT', 'A'])) {
showRemoteControl(0);
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,7 +20,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
}
function bindToFullscreenChange(player) {
events.on(fullscreenManager, 'fullscreenchange', function () {
screenfull.on('change', function () {
events.trigger(player, 'fullscreenchange');
});
}
@ -38,6 +41,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 +66,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 +1534,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
return player.isFullscreen();
}
return fullscreenManager.isFullScreen();
return screenfull.isFullscreen;
};
self.toggleFullscreen = function (player) {
@ -1528,10 +1544,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
return player.toggleFulscreen();
}
if (fullscreenManager.isFullScreen()) {
fullscreenManager.exitFullscreen();
} else {
fullscreenManager.requestFullscreen();
if (screenfull.isEnabled) {
screenfull.toggle();
}
};
@ -1633,29 +1647,29 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
self.supportSubtitleOffset = function(player) {
player = player || self._currentPlayer;
return player && 'setSubtitleOffset' in player;
}
};
self.enableShowingSubtitleOffset = function(player) {
player = player || self._currentPlayer;
player.enableShowingSubtitleOffset();
}
};
self.disableShowingSubtitleOffset = function(player) {
player = player || self._currentPlayer;
if (player.disableShowingSubtitleOffset) {
player.disableShowingSubtitleOffset();
}
}
};
self.isShowingSubtitleOffsetEnabled = function(player) {
player = player || self._currentPlayer;
return player.isShowingSubtitleOffsetEnabled();
}
};
self.isSubtitleStreamExternal = function(index, player) {
var stream = getSubtitleStream(player, index);
return stream ? getDeliveryMethod(stream) === 'External' : false;
}
};
self.setSubtitleOffset = function (value, player) {
player = player || self._currentPlayer;
@ -1669,12 +1683,12 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
if (player.getSubtitleOffset) {
return player.getSubtitleOffset();
}
}
};
self.canHandleOffsetOnCurrentSubtitle = function(player) {
var index = self.getSubtitleStreamIndex(player);
return index !== -1 && self.isSubtitleStreamExternal(index, player);
}
};
self.seek = function (ticks, player) {
@ -3140,7 +3154,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
AllowVideoStreamCopy: false,
AllowAudioStreamCopy: currentlyPreventsAudioStreamCopy || currentlyPreventsVideoStreamCopy ? false : null
}, true);
});
return;
}
@ -3378,7 +3392,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

@ -17,6 +17,7 @@ define(['playbackManager', 'layoutManager', 'events'], function (playbackManager
var isLocalVideo = player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player);
if (isLocalVideo && layoutManager.mobile) {
/* eslint-disable-next-line compat/compat */
var lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation || (screen.orientation && screen.orientation.lock);
if (lockOrientation) {
@ -40,6 +41,7 @@ define(['playbackManager', 'layoutManager', 'events'], function (playbackManager
if (orientationLocked && !playbackStopInfo.nextMediaType) {
/* eslint-disable-next-line compat/compat */
var unlockOrientation = screen.unlockOrientation || screen.mozUnlockOrientation || screen.msUnlockOrientation || (screen.orientation && screen.orientation.unlock);
if (unlockOrientation) {

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,25 @@ 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);
}
var contextmenuHtml = '<button id="toggleContextMenu" is="paper-icon-button-light" class="btnToggleContextMenu" title=' + globalize.translate('ButtonToggleContextMenu') + '><i class="material-icons more_vert"></i></button>';
var 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;
}
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 +700,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() {

View File

@ -544,8 +544,10 @@ import layoutManager from "layoutManager";
}, {capture: true});
}
export default {
isEnabled: isEnabled,
scrollTo: scrollTo,
scrollToElement: scrollToElement
};
/* eslint-enable indent */
export default {
isEnabled: isEnabled,
scrollTo: scrollTo,
scrollToElement: scrollToElement
};

View File

@ -1,8 +1,18 @@
define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'focusManager', 'browser', 'apphost', 'loading', 'css!./style', 'material-icons', 'paper-icon-button-light'], function (dialogHelper, inputManager, connectionManager, layoutManager, focusManager, browser, appHost, loading) {
/**
* Image viewer component
* @module components/slideshow/slideshow
*/
define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'focusManager', 'browser', 'apphost', 'css!./style', 'material-icons', 'paper-icon-button-light'], function (dialogHelper, inputManager, connectionManager, layoutManager, focusManager, browser, appHost) {
'use strict';
/**
* Retrieves an item's image URL from the API.
* @param {object|string} item - Item used to generate the image URL.
* @param {object} options - Options of the image.
* @param {object} apiClient - API client instance used to retrieve the image.
* @returns {null|string} URL of the item's image.
*/
function getImageUrl(item, options, apiClient) {
options = options || {};
options.type = options.type || "Primary";
@ -11,7 +21,6 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
}
if (item.ImageTags && item.ImageTags[options.type]) {
options.tag = item.ImageTags[options.type];
return apiClient.getScaledImageUrl(item.Id, options);
}
@ -27,8 +36,14 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
return null;
}
/**
* Retrieves a backdrop's image URL from the API.
* @param {object} item - Item used to generate the image URL.
* @param {object} options - Options of the image.
* @param {object} apiClient - API client instance used to retrieve the image.
* @returns {null|string} URL of the item's backdrop.
*/
function getBackdropImageUrl(item, options, apiClient) {
options = options || {};
options.type = options.type || "Backdrop";
@ -46,19 +61,19 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
return null;
}
function getImgUrl(item, original) {
/**
* Dispatches a request for an item's image to its respective handler.
* @param {object} item - Item used to generate the image URL.
* @returns {string} URL of the item's image.
*/
function getImgUrl(item) {
var apiClient = connectionManager.getApiClient(item.ServerId);
var imageOptions = {};
if (!original) {
imageOptions.maxWidth = screen.availWidth;
}
if (item.BackdropImageTags && item.BackdropImageTags.length) {
return getBackdropImageUrl(item, imageOptions, apiClient);
} else {
if (item.MediaType === 'Photo' && original) {
if (item.MediaType === 'Photo') {
return apiClient.getItemDownloadUrl(item.Id);
}
imageOptions.type = "Primary";
@ -66,15 +81,25 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
}
}
/**
* Generates a button using the specified icon, classes and properties.
* @param {string} icon - Name of the material icon on the button
* @param {string} cssClass - CSS classes to assign to the button
* @param {boolean} canFocus - Flag to set the tabindex attribute on the button to -1.
* @param {boolean} autoFocus - Flag to set the autofocus attribute on the button.
* @returns {string} The HTML markup of the button.
*/
function getIcon(icon, cssClass, canFocus, autoFocus) {
var tabIndex = canFocus ? '' : ' tabindex="-1"';
autoFocus = autoFocus ? ' autofocus' : '';
return '<button is="paper-icon-button-light" class="autoSize ' + cssClass + '"' + tabIndex + autoFocus + '><i class="material-icons slideshowButtonIcon ' + icon + '"></i></button>';
}
/**
* Sets the viewport meta tag to enable or disable scaling by the user.
* @param {boolean} scalable - Flag to set the scalability of the viewport.
*/
function setUserScalable(scalable) {
try {
appHost.setUserScalable(scalable);
} catch (err) {
@ -83,23 +108,31 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
}
return function (options) {
var self = this;
/** Initialized instance of Swiper. */
var swiperInstance;
var dlg;
var currentTimeout;
var currentIntervalMs;
/** Initialized instance of the dialog containing the Swiper instance. */
var dialog;
/** Options of the slideshow components */
var currentOptions;
var currentIndex;
/** ID of the timeout used to hide the OSD. */
var hideTimeout;
/** Last coordinates of the mouse pointer. */
var lastMouseMoveData;
/** Visibility status of the OSD. */
var _osdOpen = false;
// small hack since this is not possible anyway
if (browser.chromecast) {
options.interactive = false;
}
// Use autoplay on Chromecast since it is non-interactive.
options.interactive = !browser.chromecast;
/**
* Creates the HTML markup for the dialog and the OSD.
* @param {Object} options - Options used to create the dialog and slideshow.
*/
function createElements(options) {
currentOptions = options;
dlg = dialogHelper.createDialog({
dialog = dialogHelper.createDialog({
exitAnimationDuration: options.interactive ? 400 : 800,
size: 'fullscreen',
autoFocus: false,
@ -108,17 +141,15 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
removeOnClose: true
});
dlg.classList.add('slideshowDialog');
dialog.classList.add('slideshowDialog');
var html = '';
if (options.interactive) {
html += '<div class="slideshowSwiperContainer"><div class="swiper-wrapper"></div></div>';
if (options.interactive && !layoutManager.tv) {
var actionButtonsOnTop = layoutManager.mobile;
html += '<div>';
html += '<div class="slideshowSwiperContainer"><div class="swiper-wrapper"></div></div>';
html += getIcon('keyboard_arrow_left', 'btnSlideshowPrevious slideshowButton hide-mouse-idle-tv', false);
html += getIcon('keyboard_arrow_right', 'btnSlideshowNext slideshowButton hide-mouse-idle-tv', false);
@ -137,7 +168,7 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
if (!actionButtonsOnTop) {
html += '<div class="slideshowBottomBar hide">';
html += getIcon('pause', 'btnSlideshowPause slideshowButton', true, true);
html += getIcon('play_arrow', 'btnSlideshowPause slideshowButton', true, true);
if (appHost.supports('filedownload')) {
html += getIcon('file_download', 'btnDownload slideshowButton', true);
}
@ -148,33 +179,28 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
html += '</div>';
}
html += '</div>';
} else {
html += '<div class="slideshowImage"></div><h1 class="slideshowImageText"></h1>';
}
dlg.innerHTML = html;
dialog.innerHTML = html;
if (options.interactive) {
dlg.querySelector('.btnSlideshowExit').addEventListener('click', function (e) {
dialogHelper.close(dlg);
if (options.interactive && !layoutManager.tv) {
dialog.querySelector('.btnSlideshowExit').addEventListener('click', function (e) {
dialogHelper.close(dialog);
});
dlg.querySelector('.btnSlideshowNext').addEventListener('click', nextImage);
dlg.querySelector('.btnSlideshowPrevious').addEventListener('click', previousImage);
var btnPause = dlg.querySelector('.btnSlideshowPause');
var btnPause = dialog.querySelector('.btnSlideshowPause');
if (btnPause) {
btnPause.addEventListener('click', playPause);
}
var btnDownload = dlg.querySelector('.btnDownload');
var btnDownload = dialog.querySelector('.btnDownload');
if (btnDownload) {
btnDownload.addEventListener('click', download);
}
var btnShare = dlg.querySelector('.btnShare');
var btnShare = dialog.querySelector('.btnShare');
if (btnShare) {
btnShare.addEventListener('click', share);
}
@ -182,81 +208,111 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
setUserScalable(true);
dialogHelper.open(dlg).then(function () {
dialogHelper.open(dialog).then(function () {
setUserScalable(false);
stopInterval();
});
inputManager.on(window, onInputCommand);
document.addEventListener((window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove);
dlg.addEventListener('close', onDialogClosed);
dialog.addEventListener('close', onDialogClosed);
if (options.interactive) {
loadSwiper(dlg);
}
loadSwiper(dialog, options);
}
/**
* Handles OSD changes when the autoplay is started.
*/
function onAutoplayStart() {
var btnSlideshowPause = dlg.querySelector('.btnSlideshowPause i');
var btnSlideshowPause = dialog.querySelector('.btnSlideshowPause i');
if (btnSlideshowPause) {
btnSlideshowPause.classList.remove("play_arrow");
btnSlideshowPause.classList.add("pause");
btnSlideshowPause.classList.replace("play_arrow", "pause");
}
}
/**
* Handles OSD changes when the autoplay is stopped.
*/
function onAutoplayStop() {
var btnSlideshowPause = dlg.querySelector('.btnSlideshowPause i');
var btnSlideshowPause = dialog.querySelector('.btnSlideshowPause i');
if (btnSlideshowPause) {
btnSlideshowPause.classList.remove("pause");
btnSlideshowPause.classList.add("play_arrow");
btnSlideshowPause.classList.replace("pause", "play_arrow");
}
}
function loadSwiper(dlg) {
/**
* Initializes the Swiper instance and binds the relevant events.
* @param {HTMLElement} dialog - Element containing the dialog.
* @param {Object} options - Options used to initialize the Swiper instance.
*/
function loadSwiper(dialog, options) {
var slides;
if (currentOptions.slides) {
dlg.querySelector('.swiper-wrapper').innerHTML = currentOptions.slides.map(getSwiperSlideHtmlFromSlide).join('');
slides = currentOptions.slides;
} else {
dlg.querySelector('.swiper-wrapper').innerHTML = currentOptions.items.map(getSwiperSlideHtmlFromItem).join('');
slides = currentOptions.items;
}
require(['swiper'], function (Swiper) {
swiperInstance = new Swiper(dlg.querySelector('.slideshowSwiperContainer'), {
// Optional parameters
swiperInstance = new Swiper(dialog.querySelector('.slideshowSwiperContainer'), {
direction: 'horizontal',
loop: options.loop !== false,
autoplay: {
delay: options.interval || 8000
// Loop is disabled due to the virtual slides option not supporting it.
loop: false,
zoom: {
minRatio: 1,
toggle: true,
containerClass: 'slider-zoom-container'
},
// Disable preloading of all images
preloadImages: false,
// Enable lazy loading
lazy: true,
loadPrevNext: true,
disableOnInteraction: false,
autoplay: !options.interactive,
keyboard: {
enabled: true
},
preloadImages: true,
slidesPerView: 1,
slidesPerColumn: 1,
initialSlide: options.startIndex || 0,
speed: 240
speed: 240,
navigation: {
nextEl: '.btnSlideshowNext',
prevEl: '.btnSlideshowPrevious'
},
// Virtual slides reduce memory consumption for large libraries while allowing preloading of images;
virtual: {
slides: slides,
cache: true,
renderSlide: getSwiperSlideHtml,
addSlidesBefore: 1,
addSlidesAfter: 1
}
});
swiperInstance.on('autoplayStart', onAutoplayStart);
swiperInstance.on('autoplayStop', onAutoplayStop);
if (layoutManager.mobile) {
pause();
} else {
play();
}
});
}
function getSwiperSlideHtmlFromItem(item) {
/**
* Renders the HTML markup of a slide for an item or a slide.
* @param {Object} item - The item used to render the slide.
* @param {number} index - The index of the item in the Swiper instance.
* @returns {string} The HTML markup of the slide.
*/
function getSwiperSlideHtml(item, index) {
if (currentOptions.slides) {
return getSwiperSlideHtmlFromSlide(item);
} else {
return getSwiperSlideHtmlFromItem(item);
}
}
/**
* Renders the HTML markup of a slide for an item.
* @param {Object} item - Item used to generate the slide.
* @returns {string} The HTML markup of the slide.
*/
function getSwiperSlideHtmlFromItem(item) {
return getSwiperSlideHtmlFromSlide({
imageUrl: getImgUrl(item),
originalImage: getImgUrl(item, true),
originalImage: getImgUrl(item),
//title: item.Name,
//description: item.Overview
Id: item.Id,
@ -264,11 +320,17 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
});
}
/**
* Renders the HTML markup of a slide for a slide object.
* @param {Object} item - Slide object used to generate the slide.
* @returns {string} The HTML markup of the slide.
*/
function getSwiperSlideHtmlFromSlide(item) {
var html = '';
html += '<div class="swiper-slide" data-imageurl="' + item.imageUrl + '" data-original="' + item.originalImage + '" data-itemid="' + item.Id + '" data-serverid="' + item.ServerId + '">';
html += '<img data-src="' + item.imageUrl + '" class="swiper-lazy swiper-slide-img">';
html += '<div class="swiper-slide" data-original="' + item.originalImage + '" data-itemid="' + item.Id + '" data-serverid="' + item.ServerId + '">';
html += '<div class="slider-zoom-container">';
html += '<img src="' + item.originalImage + '" class="swiper-slide-img">';
html += '</div>';
if (item.title || item.subtitle) {
html += '<div class="slideText">';
html += '<div class="slideTextInner">';
@ -290,42 +352,18 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
return html;
}
function previousImage() {
if (swiperInstance) {
swiperInstance.slidePrev();
} else {
stopInterval();
showNextImage(currentIndex - 1);
}
}
function nextImage() {
if (swiperInstance) {
if (options.loop === false) {
if (swiperInstance.activeIndex >= swiperInstance.slides.length - 1) {
dialogHelper.close(dlg);
return;
}
}
swiperInstance.slideNext();
} else {
stopInterval();
showNextImage(currentIndex + 1);
}
}
/**
* Fetches the information of the currently displayed slide.
* @returns {null|{itemId: string, shareUrl: string, serverId: string, url: string}} Object containing the information of the currently displayed slide.
*/
function getCurrentImageInfo() {
if (swiperInstance) {
var slide = document.querySelector('.swiper-slide-active');
if (slide) {
return {
url: slide.getAttribute('data-original'),
shareUrl: slide.getAttribute('data-imageurl'),
shareUrl: slide.getAttribute('data-original'),
itemId: slide.getAttribute('data-itemid'),
serverId: slide.getAttribute('data-serverid')
};
@ -336,8 +374,10 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
}
}
/**
* Starts a download for the currently displayed slide.
*/
function download() {
var imageInfo = getCurrentImageInfo();
require(['fileDownloader'], function (fileDownloader) {
@ -345,8 +385,10 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
});
}
/**
* Shares the currently displayed slide using the browser's built-in sharing feature.
*/
function share() {
var imageInfo = getCurrentImageInfo();
navigator.share({
@ -354,20 +396,29 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
});
}
/**
* Starts the autoplay feature of the Swiper instance.
*/
function play() {
if (swiperInstance.autoplay) {
swiperInstance.autoplay.start();
}
}
/**
* Pauses the autoplay feature of the Swiper instance;
*/
function pause() {
if (swiperInstance.autoplay) {
swiperInstance.autoplay.stop();
}
}
/**
* Toggles the autoplay feature of the Swiper instance.
*/
function playPause() {
var paused = !dlg.querySelector('.btnSlideshowPause i').classList.contains("pause");
var paused = !dialog.querySelector('.btnSlideshowPause i').classList.contains("pause");
if (paused) {
play();
} else {
@ -375,8 +426,10 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
}
}
/**
* Closes the dialog and destroys the Swiper instance.
*/
function onDialogClosed() {
var swiper = swiperInstance;
if (swiper) {
swiper.destroy(true, true);
@ -387,53 +440,38 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
document.removeEventListener((window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove);
}
function startInterval(options) {
currentOptions = options;
stopInterval();
createElements(options);
if (!options.interactive) {
currentIntervalMs = options.interval || 11000;
showNextImage(options.startIndex || 0, true);
}
}
var _osdOpen = false;
function isOsdOpen() {
return _osdOpen;
}
function getOsdBottom() {
return dlg.querySelector('.slideshowBottomBar');
}
/**
* Shows the OSD.
*/
function showOsd() {
var bottom = getOsdBottom();
var bottom = dialog.querySelector('.slideshowBottomBar');
if (bottom) {
slideUpToShow(bottom);
startHideTimer();
}
}
/**
* Hides the OSD.
*/
function hideOsd() {
var bottom = getOsdBottom();
var bottom = dialog.querySelector('.slideshowBottomBar');
if (bottom) {
slideDownToHide(bottom);
}
}
var hideTimeout;
/**
* Starts the timer used to automatically hide the OSD.
*/
function startHideTimer() {
stopHideTimer();
hideTimeout = setTimeout(hideOsd, 4000);
hideTimeout = setTimeout(hideOsd, 3000);
}
/**
* Stops the timer used to automatically hide the OSD.
*/
function stopHideTimer() {
if (hideTimeout) {
clearTimeout(hideTimeout);
@ -441,71 +479,76 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
}
}
function slideUpToShow(elem) {
if (!elem.classList.contains('hide')) {
/**
* Shows the OSD by sliding it into view.
* @param {HTMLElement} element - Element containing the OSD.
*/
function slideUpToShow(element) {
if (!element.classList.contains('hide')) {
return;
}
_osdOpen = true;
elem.classList.remove('hide');
element.classList.remove('hide');
var onFinish = function () {
focusManager.focus(elem.querySelector('.btnSlideshowPause'));
focusManager.focus(element.querySelector('.btnSlideshowPause'));
};
if (!elem.animate) {
if (!element.animate) {
onFinish();
return;
}
requestAnimationFrame(function () {
var keyframes = [
{ transform: 'translate3d(0,' + elem.offsetHeight + 'px,0)', opacity: '.3', offset: 0 },
{ transform: 'translate3d(0,' + element.offsetHeight + 'px,0)', opacity: '.3', offset: 0 },
{ transform: 'translate3d(0,0,0)', opacity: '1', offset: 1 }
];
var timing = { duration: 300, iterations: 1, easing: 'ease-out' };
elem.animate(keyframes, timing).onfinish = onFinish;
element.animate(keyframes, timing).onfinish = onFinish;
});
}
function slideDownToHide(elem) {
if (elem.classList.contains('hide')) {
/**
* Hides the OSD by sliding it out of view.
* @param {HTMLElement} element - Element containing the OSD.
*/
function slideDownToHide(element) {
if (element.classList.contains('hide')) {
return;
}
var onFinish = function () {
elem.classList.add('hide');
element.classList.add('hide');
_osdOpen = false;
};
if (!elem.animate) {
if (!element.animate) {
onFinish();
return;
}
requestAnimationFrame(function () {
var keyframes = [
{ transform: 'translate3d(0,0,0)', opacity: '1', offset: 0 },
{ transform: 'translate3d(0,' + elem.offsetHeight + 'px,0)', opacity: '.3', offset: 1 }
{ transform: 'translate3d(0,' + element.offsetHeight + 'px,0)', opacity: '.3', offset: 1 }
];
var timing = { duration: 300, iterations: 1, easing: 'ease-out' };
elem.animate(keyframes, timing).onfinish = onFinish;
element.animate(keyframes, timing).onfinish = onFinish;
});
}
var lastMouseMoveData;
function onPointerMove(e) {
var pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse');
/**
* Shows the OSD when moving the mouse pointer or touching the screen.
* @param {Event} event - Pointer movement event.
*/
function onPointerMove(event) {
var pointerType = event.pointerType || (layoutManager.mobile ? 'touch' : 'mouse');
if (pointerType === 'mouse') {
var eventX = e.screenX || 0;
var eventY = e.screenY || 0;
var eventX = event.screenX || 0;
var eventY = event.screenY || 0;
var obj = lastMouseMoveData;
if (!obj) {
@ -528,125 +571,46 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
}
}
function onInputCommand(e) {
switch (e.detail.command) {
case 'left':
if (!isOsdOpen()) {
e.preventDefault();
e.stopPropagation();
previousImage();
}
break;
case 'right':
if (!isOsdOpen()) {
e.preventDefault();
e.stopPropagation();
nextImage();
}
break;
/**
* Dispatches keyboard inputs to their proper handlers.
* @param {Event} event - Keyboard input event.
*/
function onInputCommand(event) {
switch (event.detail.command) {
case 'up':
case 'down':
case 'select':
case 'menu':
case 'info':
case 'play':
case 'playpause':
case 'pause':
showOsd();
break;
case 'play':
play();
break;
case 'pause':
pause();
break;
case 'playpause':
playPause();
break;
default:
break;
}
}
function showNextImage(index, skipPreload) {
index = Math.max(0, index);
if (index >= currentOptions.items.length) {
index = 0;
}
currentIndex = index;
var options = currentOptions;
var items = options.items;
var item = items[index];
var imgUrl = getImgUrl(item);
var onSrcLoaded = function () {
var cardImageContainer = dlg.querySelector('.slideshowImage');
var newCardImageContainer = document.createElement('div');
newCardImageContainer.className = cardImageContainer.className;
if (options.cover) {
newCardImageContainer.classList.add('slideshowImage-cover');
}
newCardImageContainer.style.backgroundImage = "url('" + imgUrl + "')";
newCardImageContainer.classList.add('hide');
cardImageContainer.parentNode.appendChild(newCardImageContainer);
if (options.showTitle) {
dlg.querySelector('.slideshowImageText').innerHTML = item.Name;
} else {
dlg.querySelector('.slideshowImageText').innerHTML = '';
}
newCardImageContainer.classList.remove('hide');
var onAnimationFinished = function () {
var parentNode = cardImageContainer.parentNode;
if (parentNode) {
parentNode.removeChild(cardImageContainer);
}
};
if (newCardImageContainer.animate) {
var keyframes = [
{ opacity: '0', offset: 0 },
{ opacity: '1', offset: 1 }
];
var timing = { duration: 1200, iterations: 1 };
newCardImageContainer.animate(keyframes, timing).onfinish = onAnimationFinished;
} else {
onAnimationFinished();
}
stopInterval();
currentTimeout = setTimeout(function () {
showNextImage(index + 1, true);
}, currentIntervalMs);
};
if (!skipPreload) {
var img = new Image();
img.onload = onSrcLoaded;
img.src = imgUrl;
} else {
onSrcLoaded();
}
}
function stopInterval() {
if (currentTimeout) {
clearTimeout(currentTimeout);
currentTimeout = null;
}
}
/**
* Shows the slideshow component.
*/
self.show = function () {
startInterval(options);
createElements(options);
};
/**
* Hides the slideshow element.
*/
self.hide = function () {
var dialog = dlg;
var dialog = dialog;
if (dialog) {
dialogHelper.close(dialog);
}
};

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

@ -30,7 +30,7 @@ define(['playbackManager', 'layoutManager', 'text!./subtitlesync.template.html',
subtitleSyncTextField.updateOffset = function(offset) {
this.textContent = offset + "s";
}
};
subtitleSyncTextField.addEventListener("keypress", function(event) {
@ -66,7 +66,7 @@ define(['playbackManager', 'layoutManager', 'text!./subtitlesync.template.html',
subtitleSyncSlider.updateOffset = function(percent) {
// default value is 0s = 50%
this.value = percent === undefined ? 50 : percent;
}
};
subtitleSyncSlider.addEventListener("change", function () {
// set new offset
@ -132,7 +132,7 @@ define(['playbackManager', 'layoutManager', 'text!./subtitlesync.template.html',
elem.parentNode.removeChild(elem);
this.element = null;
}
}
};
SubtitleSync.prototype.toggle = function(action) {
@ -166,7 +166,7 @@ define(['playbackManager', 'layoutManager', 'text!./subtitlesync.template.html',
}
/* eslint-enable no-fallthrough */
}
}
};
return SubtitleSync;
});

View File

@ -24,9 +24,11 @@ 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({

View File

@ -95,7 +95,7 @@ define(["loading", "appRouter", "layoutManager", "appSettings", "apphost", "focu
}
function showServerConnectionFailure() {
alertText(globalize.translate("MessageUnableToConnectToServer"), globalize.translate("HeaderConnectionFailure"));
alertText(globalize.translate("MessageUnableToConnectToServer"));
}
return function (view, params) {

View File

@ -1,4 +1,4 @@
define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globalize", "loading", "connectionManager", "playMethodHelper", "cardBuilder", "imageLoader", "components/activitylog", "scripts/imagehelper", "indicators", "humanedate", "listViewStyle", "emby-button", "flexStyles", "emby-button", "emby-itemscontainer"], function (datetime, events, itemHelper, serverNotifications, dom, globalize, loading, connectionManager, playMethodHelper, cardBuilder, imageLoader, ActivityLog, imageHelper, indicators) {
define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globalize", "date-fns", "dfnshelper", "loading", "connectionManager", "playMethodHelper", "cardBuilder", "imageLoader", "components/activitylog", "scripts/imagehelper", "indicators", "listViewStyle", "emby-button", "flexStyles", "emby-button", "emby-itemscontainer"], function (datetime, events, itemHelper, serverNotifications, dom, globalize, datefns, dfnshelper, loading, connectionManager, playMethodHelper, cardBuilder, imageLoader, ActivityLog, imageHelper, indicators) {
"use strict";
function showPlaybackInfo(btn, session) {
@ -467,10 +467,11 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa
getNowPlayingName: function (session) {
var imgUrl = "";
var nowPlayingItem = session.NowPlayingItem;
// FIXME: It seems that, sometimes, server sends date in the future, so date-fns displays messages like 'in less than a minute'. We should fix
// how dates are returned by the server when the session is active and show something like 'Active now', instead of past/future sentences
if (!nowPlayingItem) {
return {
html: "Last seen " + humaneDate(session.LastActivityDate),
html: globalize.translate("LastSeen", datefns.formatDistanceToNow(Date.parse(session.LastActivityDate), dfnshelper.localeWithSuffix)),
image: imgUrl
};
}

View File

@ -29,5 +29,5 @@ define(["datetime", "loading", "apphost", "listViewStyle", "emby-button", "flexS
loading.hide();
});
});
}
};
});

View File

@ -49,12 +49,12 @@ define(["loading", "libraryMenu", "globalize", "listViewStyle", "emby-button"],
}
page.querySelector(".notificationList").innerHTML = html;
loading.hide();
})
});
}
return function(view, params) {
view.addEventListener("viewshow", function() {
reload(view);
});
}
};
});

View File

@ -84,7 +84,7 @@ define(["jQuery", "loading", "libraryMenu", "globalize", "connectionManager", "e
}
if (installedPlugin) {
var currentVersionText = globalize.translate("MessageYouHaveVersionInstalled").replace("{0}", "<strong>" + installedPlugin.Version + "</strong>");
var currentVersionText = globalize.translate("MessageYouHaveVersionInstalled", "<strong>" + installedPlugin.Version + "</strong>");
$("#pCurrentVersion", page).show().html(currentVersionText);
} else {
$("#pCurrentVersion", page).hide().html("");

View File

@ -116,7 +116,7 @@ define(["loading", "libraryMenu", "globalize", "cardStyle", "emby-button", "emby
return ip.Id == plugin.guid;
})[0];
html += "<div class='cardText cardText-secondary'>";
html += installedPlugin ? globalize.translate("LabelVersionInstalled").replace("{0}", installedPlugin.Version) : "&nbsp;";
html += installedPlugin ? globalize.translate("LabelVersionInstalled", installedPlugin.Version) : "&nbsp;";
html += "</div>";
html += "</div>";
html += "</div>";

View File

@ -2,7 +2,7 @@ define(["loading", "libraryMenu", "dom", "globalize", "cardStyle", "emby-button"
"use strict";
function deletePlugin(page, uniqueid, name) {
var msg = globalize.translate("UninstallPluginConfirmation").replace("{0}", name);
var msg = globalize.translate("UninstallPluginConfirmation", name);
require(["confirm"], function (confirm) {
confirm({

View File

@ -75,17 +75,19 @@ define(["jQuery", "loading", "datetime", "dom", "globalize", "emby-input", "emby
html += "</div>";
context.querySelector(".taskTriggers").innerHTML = html;
},
// TODO: Replace this mess with date-fns and remove datetime completely
getTriggerFriendlyName: function (trigger) {
if ("DailyTrigger" == trigger.Type) {
return "Daily at " + ScheduledTaskPage.getDisplayTime(trigger.TimeOfDayTicks);
return globalize.translate("DailyAt", ScheduledTaskPage.getDisplayTime(trigger.TimeOfDayTicks));
}
if ("WeeklyTrigger" == trigger.Type) {
return trigger.DayOfWeek + "s at " + ScheduledTaskPage.getDisplayTime(trigger.TimeOfDayTicks);
// TODO: The day of week isn't localised as well
return globalize.translate("WeeklyAt", trigger.DayOfWeek, ScheduledTaskPage.getDisplayTime(trigger.TimeOfDayTicks));
}
if ("SystemEventTrigger" == trigger.Type && "WakeFromSleep" == trigger.SystemEvent) {
return "On wake from sleep";
return globalize.translate("OnWakeFromSleep");
}
if (trigger.Type == "IntervalTrigger") {
@ -93,23 +95,23 @@ define(["jQuery", "loading", "datetime", "dom", "globalize", "emby-input", "emby
var hours = trigger.IntervalTicks / 36e9;
if (hours == 0.25) {
return "Every 15 minutes";
return globalize.translate("EveryXMinutes", "15");
}
if (hours == 0.5) {
return "Every 30 minutes";
return globalize.translate("EveryXMinutes", "30");
}
if (hours == 0.75) {
return "Every 45 minutes";
return globalize.translate("EveryXMinutes", "45");
}
if (hours == 1) {
return "Every hour";
return globalize.translate("EveryHour");
}
return "Every " + hours + " hours";
return globalize.translate("EveryXHours", hours);
}
if (trigger.Type == "StartupTrigger") {
return "On application startup";
return globalize.translate("OnApplicationStartup");
}
return trigger.Type;

View File

@ -1,4 +1,4 @@
define(["jQuery", "loading", "events", "globalize", "serverNotifications", "humanedate", "listViewStyle", "emby-button"], function($, loading, events, globalize, serverNotifications) {
define(["jQuery", "loading", "events", "globalize", "serverNotifications", "date-fns", "dfnshelper", "listViewStyle", "emby-button"], function ($, loading, events, globalize, serverNotifications, datefns, dfnshelper) {
"use strict";
function reloadList(page) {
@ -7,7 +7,7 @@ define(["jQuery", "loading", "events", "globalize", "serverNotifications", "huma
}).then(function(tasks) {
populateList(page, tasks);
loading.hide();
})
});
}
function populateList(page, tasks) {
@ -66,7 +66,10 @@ define(["jQuery", "loading", "events", "globalize", "serverNotifications", "huma
var html = "";
if (task.State === "Idle") {
if (task.LastExecutionResult) {
html += globalize.translate("LabelScheduledTaskLastRan").replace("{0}", humaneDate(task.LastExecutionResult.EndTimeUtc)).replace("{1}", humaneElapsed(task.LastExecutionResult.StartTimeUtc, task.LastExecutionResult.EndTimeUtc));
var endtime = Date.parse(task.LastExecutionResult.EndTimeUtc);
var starttime = Date.parse(task.LastExecutionResult.StartTimeUtc);
html += globalize.translate("LabelScheduledTaskLastRan", datefns.formatDistanceToNow(endtime, dfnshelper.localeWithSuffix),
datefns.formatDistance(starttime, endtime, { locale: dfnshelper.getLocale() }));
if (task.LastExecutionResult.Status === "Failed") {
html += " <span style='color:#FF0000;'>(" + globalize.translate("LabelFailed") + ")</span>";
} else if (task.LastExecutionResult.Status === "Cancelled") {
@ -152,7 +155,7 @@ define(["jQuery", "loading", "events", "globalize", "serverNotifications", "huma
ApiClient.startScheduledTask(id).then(function() {
updateTaskButton(button, "Running");
reloadList(view);
})
});
});
$(".divScheduledTasks", view).on("click", ".btnStopTask", function() {
@ -161,7 +164,7 @@ define(["jQuery", "loading", "events", "globalize", "serverNotifications", "huma
ApiClient.stopScheduledTask(id).then(function() {
updateTaskButton(button, "");
reloadList(view);
})
});
});
view.addEventListener("viewbeforehide", function() {
@ -175,5 +178,5 @@ define(["jQuery", "loading", "events", "globalize", "serverNotifications", "huma
reloadList(view);
events.on(serverNotifications, "ScheduledTasksInfo", onScheduledTasksUpdate);
});
}
};
});

View File

@ -1,4 +1,4 @@
define(["loading", "dom", "libraryMenu", "globalize", "scripts/imagehelper", "humanedate", "emby-button", "emby-itemscontainer", "cardStyle"], function (loading, dom, libraryMenu, globalize, imageHelper) {
define(["loading", "dom", "libraryMenu", "globalize", "scripts/imagehelper", "date-fns", "dfnshelper", "emby-button", "emby-itemscontainer", "cardStyle"], function (loading, dom, libraryMenu, globalize, imageHelper, datefns, dfnshelper) {
"use strict";
function canDelete(deviceId) {
@ -103,7 +103,7 @@ define(["loading", "dom", "libraryMenu", "globalize", "scripts/imagehelper", "hu
if (device.LastUserName) {
deviceHtml += device.LastUserName;
deviceHtml += ", " + humaneDate(device.DateLastActivity);
deviceHtml += ", " + datefns.formatDistanceToNow(Date.parse(device.DateLastActivity), dfnshelper.localeWithSuffix);
}
deviceHtml += "&nbsp;";

View File

@ -258,14 +258,14 @@ define(["jQuery", "loading", "globalize", "fnchecked", "emby-select", "emby-butt
html += "<div>";
html += '<a is="emby-linkbutton" href="#" class="lnkEditSubProfile" data-profileindex="' + i + '">';
html += "<p>" + globalize.translate("ValueContainer").replace("{0}", profile.Container || allText) + "</p>";
html += "<p>" + globalize.translate("ValueContainer", profile.Container || allText) + "</p>";
if ("Video" == profile.Type) {
html += "<p>" + globalize.translate("ValueVideoCodec").replace("{0}", profile.VideoCodec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueAudioCodec").replace("{0}", 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").replace("{0}", profile.AudioCodec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueCodec", profile.AudioCodec || allText) + "</p>";
}
}
@ -319,14 +319,14 @@ define(["jQuery", "loading", "globalize", "fnchecked", "emby-select", "emby-butt
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").replace("{0}", profile.Container || allText) + "</p>";
html += "<p>" + globalize.translate("ValueContainer", profile.Container || allText) + "</p>";
if ("Video" == profile.Type) {
html += "<p>" + globalize.translate("ValueVideoCodec").replace("{0}", profile.VideoCodec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueAudioCodec").replace("{0}", 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").replace("{0}", profile.AudioCodec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueCodec", profile.AudioCodec || allText) + "</p>";
}
}
@ -404,11 +404,11 @@ define(["jQuery", "loading", "globalize", "fnchecked", "emby-select", "emby-butt
html += "<div>";
html += '<a is="emby-linkbutton" href="#" class="lnkEditSubProfile" data-profileindex="' + i + '">';
html += "<p>" + globalize.translate("ValueContainer").replace("{0}", 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").replace("{0}", 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", "globalize", "fnchecked", "emby-select", "emby-butt
html += "<div>";
html += '<a is="emby-linkbutton" href="#" class="lnkEditSubProfile" data-profileindex="' + i + '">';
html += "<p>" + globalize.translate("ValueCodec").replace("{0}", 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").replace("{0}", 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", "globalize", "fnchecked", "emby-select", "emby-butt
html += "<div>";
html += '<a is="emby-linkbutton" href="#" class="lnkEditSubProfile" data-profileindex="' + i + '">';
html += "<p>" + globalize.translate("ValueContainer").replace("{0}", profile.Container || allText) + "</p>";
html += "<p>" + globalize.translate("ValueContainer", profile.Container || allText) + "</p>";
if ("Video" == profile.Type) {
html += "<p>" + globalize.translate("ValueVideoCodec").replace("{0}", profile.VideoCodec || allText) + "</p>";
html += "<p>" + globalize.translate("ValueAudioCodec").replace("{0}", 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").replace("{0}", 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").replace("{0}", profile.Conditions.map(function (c) {
html += globalize.translate("ValueConditions", profile.Conditions.map(function (c) {
return c.Property;
}).join(", "));
html += "</p>";

View File

@ -14,6 +14,7 @@ define(["jQuery", "loading", "globalize", "dom", "libraryMenu"], function ($, lo
$("#txtVaapiDevice", page).val(config.VaapiDevice || "");
page.querySelector("#selectEncoderPreset").value = config.EncoderPreset || "";
page.querySelector("#txtH264Crf").value = config.H264Crf || "";
page.querySelector("#selectDeinterlaceMethod").value = config.DeinterlaceMethod || "";
page.querySelector("#chkEnableSubtitleExtraction").checked = config.EnableSubtitleExtraction || false;
page.querySelector("#chkEnableThrottling").checked = config.EnableThrottling || false;
page.querySelector("#selectVideoDecoder").dispatchEvent(new CustomEvent("change", {
@ -58,6 +59,7 @@ define(["jQuery", "loading", "globalize", "dom", "libraryMenu"], function ($, lo
config.VaapiDevice = $("#txtVaapiDevice", form).val();
config.EncoderPreset = form.querySelector("#selectEncoderPreset").value;
config.H264Crf = parseInt(form.querySelector("#txtH264Crf").value || "0");
config.DeinterlaceMethod = form.querySelector("#selectDeinterlaceMethod").value;
config.EnableSubtitleExtraction = form.querySelector("#chkEnableSubtitleExtraction").checked;
config.EnableThrottling = form.querySelector("#chkEnableThrottling").checked;
config.HardwareDecodingCodecs = Array.prototype.map.call(Array.prototype.filter.call(form.querySelectorAll(".chkDecodeCodec"), function (c) {

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;
@ -591,7 +605,7 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "userSetti
try {
var birthday = datetime.parseISO8601Date(item.PremiereDate, true).toDateString();
itemBirthday.classList.remove("hide");
itemBirthday.innerHTML = globalize.translate("BirthDateValue").replace("{0}", birthday);
itemBirthday.innerHTML = globalize.translate("BirthDateValue", birthday);
} catch (err) {
itemBirthday.classList.add("hide");
}
@ -605,7 +619,7 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "userSetti
try {
var deathday = datetime.parseISO8601Date(item.EndDate, true).toDateString();
itemDeathDate.classList.remove("hide");
itemDeathDate.innerHTML = globalize.translate("DeathDateValue").replace("{0}", deathday);
itemDeathDate.innerHTML = globalize.translate("DeathDateValue", deathday);
} catch (err) {
itemDeathDate.classList.add("hide");
}
@ -618,7 +632,7 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "userSetti
if ("Person" == item.Type && item.ProductionLocations && item.ProductionLocations.length) {
var gmap = '<a is="emby-linkbutton" class="button-link textlink" target="_blank" href="https://maps.google.com/maps?q=' + item.ProductionLocations[0] + '">' + item.ProductionLocations[0] + "</a>";
itemBirthLocation.classList.remove("hide");
itemBirthLocation.innerHTML = globalize.translate("BirthPlaceValue").replace("{0}", gmap);
itemBirthLocation.innerHTML = globalize.translate("BirthPlaceValue", gmap);
} else {
itemBirthLocation.classList.add("hide");
}

View File

@ -14,7 +14,7 @@ define(["globalize", "loading", "libraryMenu", "emby-checkbox", "emby-button", "
}, {
href: "metadatanfo.html",
name: globalize.translate("TabNfoSettings")
}]
}];
}
return function(view, params) {
@ -27,14 +27,10 @@ define(["globalize", "loading", "libraryMenu", "emby-checkbox", "emby-button", "
view.querySelector("#chkSaveMetadataHidden").checked = config.SaveMetadataHidden;
});
ApiClient.getNamedConfiguration("metadata").then(function(metadata) {
loadMetadataConfig(this, metadata)
view.querySelector("#selectDateAdded").selectedIndex = metadata.UseFileCreationTimeForDateAdded ? 1 : 0;
});
}
function loadMetadataConfig(page, config) {
$("#selectDateAdded", page).val(config.UseFileCreationTimeForDateAdded ? "1" : "0");
}
view.querySelector("form").addEventListener("submit", function(e) {
loading.show();
var form = this;
@ -67,5 +63,5 @@ define(["globalize", "loading", "libraryMenu", "emby-checkbox", "emby-button", "
}
});
});
}
};
});

View File

@ -1,4 +1,4 @@
define(["cardBuilder", "imageLoader", "libraryBrowser", "loading", "events", "emby-itemscontainer"], function (cardBuilder, imageLoader, libraryBrowser, loading, events) {
define(["cardBuilder", "imageLoader", "libraryBrowser", "loading", "events", "userSettings", "emby-itemscontainer"], function (cardBuilder, imageLoader, libraryBrowser, loading, events, userSettings) {
"use strict";
return function (view, params, tabContent) {
@ -7,12 +7,15 @@ define(["cardBuilder", "imageLoader", "libraryBrowser", "loading", "events", "em
pageData = {
query: {
StartIndex: 0,
Limit: 100,
Fields: "PrimaryImageAspectRatio"
}
};
}
if (userSettings.libraryPageSize() > 0) {
pageData.query['Limit'] = userSettings.libraryPageSize();
}
return pageData;
}
@ -39,7 +42,9 @@ define(["cardBuilder", "imageLoader", "libraryBrowser", "loading", "events", "em
return;
}
query.StartIndex += query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex += query.Limit;
}
reloadItems(context);
}
@ -48,7 +53,9 @@ define(["cardBuilder", "imageLoader", "libraryBrowser", "loading", "events", "em
return;
}
query.StartIndex -= query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex = Math.max(0, query.StartIndex - query.Limit);
}
reloadItems(context);
}

View File

@ -48,7 +48,7 @@ define(["layoutManager", "cardBuilder", "apphost", "imageLoader", "loading", "sc
}
function getBackdropShape() {
return enableScrollX() ? "overflowBackdrop" : "backdrop"
return enableScrollX() ? "overflowBackdrop" : "backdrop";
}
function renderActiveRecordings(context, promise) {

View File

@ -7,10 +7,10 @@ define(["jQuery", "dom", "loading", "libraryMenu", "globalize", "listViewStyle"]
html += "<option value=''></option>";
for (var i = 0, length = languages.length; i < length; i++) {
var culture = languages[i];
html += "<option value='" + culture.TwoLetterISOLanguageName + "'>" + culture.DisplayName + "</option>"
html += "<option value='" + culture.TwoLetterISOLanguageName + "'>" + culture.DisplayName + "</option>";
}
select.innerHTML = html
})
select.innerHTML = html;
});
}
function populateCountries(select) {
@ -19,25 +19,25 @@ define(["jQuery", "dom", "loading", "libraryMenu", "globalize", "listViewStyle"]
html += "<option value=''></option>";
for (var i = 0, length = allCountries.length; i < length; i++) {
var culture = allCountries[i];
html += "<option value='" + culture.TwoLetterISORegionName + "'>" + culture.DisplayName + "</option>"
html += "<option value='" + culture.TwoLetterISORegionName + "'>" + culture.DisplayName + "</option>";
}
select.innerHTML = html
})
select.innerHTML = html;
});
}
function loadPage(page) {
var promises = [ApiClient.getServerConfiguration(), populateLanguages(page.querySelector("#selectLanguage")), populateCountries(page.querySelector("#selectCountry"))];
Promise.all(promises).then(function(responses) {
var config = responses[0];
page.querySelector("#selectLanguage").value = config.PreferredMetadataLanguage || "", page.querySelector("#selectCountry").value = config.MetadataCountryCode || "", loading.hide()
})
page.querySelector("#selectLanguage").value = config.PreferredMetadataLanguage || "", page.querySelector("#selectCountry").value = config.MetadataCountryCode || "", loading.hide();
});
}
function onSubmit() {
var form = this;
return loading.show(), ApiClient.getServerConfiguration().then(function(config) {
config.PreferredMetadataLanguage = form.querySelector("#selectLanguage").value, config.MetadataCountryCode = form.querySelector("#selectCountry").value, ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult)
}), !1
config.PreferredMetadataLanguage = form.querySelector("#selectLanguage").value, config.MetadataCountryCode = form.querySelector("#selectCountry").value, ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult);
}), !1;
}
function getTabs() {
@ -53,12 +53,12 @@ define(["jQuery", "dom", "loading", "libraryMenu", "globalize", "listViewStyle"]
}, {
href: "metadatanfo.html",
name: globalize.translate("TabNfoSettings")
}]
}];
}
$(document).on("pageinit", "#metadataImagesConfigurationPage", function() {
$(".metadataImagesConfigurationForm").off("submit", onSubmit).on("submit", onSubmit)
$(".metadataImagesConfigurationForm").off("submit", onSubmit).on("submit", onSubmit);
}).on("pageshow", "#metadataImagesConfigurationPage", function() {
libraryMenu.setTabs("metadata", 2, getTabs), loading.show(), loadPage(this)
})
libraryMenu.setTabs("metadata", 2, getTabs), loading.show(), loadPage(this);
});
});

View File

@ -1,4 +1,4 @@
define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardBuilder", "globalize", "apphost", "emby-itemscontainer"], function (loading, events, libraryBrowser, imageLoader, listView, cardBuilder, globalize, appHost) {
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) {
@ -16,11 +16,15 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB
Fields: "PrimaryImageAspectRatio,SortName",
ImageTypeLimit: 1,
EnableImageTypes: "Primary,Backdrop,Banner,Thumb",
StartIndex: 0,
Limit: pageSize
StartIndex: 0
},
view: libraryBrowser.getSavedView(key) || "Poster"
};
if (userSettings.libraryPageSize() > 0) {
pageData.query['Limit'] = userSettings.libraryPageSize();
}
pageData.query.ParentId = params.topParentId;
libraryBrowser.loadSavedQueryValues(key, pageData.query);
}
@ -65,7 +69,9 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB
return;
}
query.StartIndex += query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex += query.Limit;
}
reloadItems(tabContent);
}
@ -74,7 +80,9 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB
return;
}
query.StartIndex -= query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex = Math.max(0, query.StartIndex - query.Limit);
}
reloadItems(tabContent);
}
@ -180,7 +188,6 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB
}
var self = this;
var pageSize = 100;
var data = {};
var isLoading = false;

View File

@ -184,12 +184,12 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader
};
self.getCurrentViewStyle = function () {
return getPageData(tabContent).view;
return getPageData().view;
};
self.setCurrentViewStyle = function (viewStyle) {
getPageData(tabContent).view = viewStyle;
libraryBrowser.saveViewSetting(getSavedQueryKey(tabContent), viewStyle);
getPageData().view = viewStyle;
libraryBrowser.saveViewSetting(getSavedQueryKey(), viewStyle);
fullyReload();
};

View File

@ -32,7 +32,9 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser",
return;
}
query.StartIndex += query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex += query.Limit;
}
itemsContainer.refreshItems();
}
@ -41,7 +43,9 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser",
return;
}
query.StartIndex -= query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex = Math.max(0, query.StartIndex - query.Limit);
}
itemsContainer.refreshItems();
}
@ -250,9 +254,13 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser",
ImageTypeLimit: 1,
EnableImageTypes: "Primary,Backdrop,Banner,Thumb",
StartIndex: 0,
Limit: 100,
ParentId: params.topParentId
};
if (userSettings.libraryPageSize() > 0) {
query['Limit'] = userSettings.libraryPageSize();
}
var isLoading = false;
if (options.mode === "favorites") {

View File

@ -91,21 +91,21 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu"
switch (recommendation.RecommendationType) {
case "SimilarToRecentlyPlayed":
title = globalize.translate("RecommendationBecauseYouWatched").replace("{0}", recommendation.BaselineItemName);
title = globalize.translate("RecommendationBecauseYouWatched", recommendation.BaselineItemName);
break;
case "SimilarToLikedItem":
title = globalize.translate("RecommendationBecauseYouLike").replace("{0}", recommendation.BaselineItemName);
title = globalize.translate("RecommendationBecauseYouLike", recommendation.BaselineItemName);
break;
case "HasDirectorFromRecentlyPlayed":
case "HasLikedDirector":
title = globalize.translate("RecommendationDirectedBy").replace("{0}", recommendation.BaselineItemName);
title = globalize.translate("RecommendationDirectedBy", recommendation.BaselineItemName);
break;
case "HasActorFromRecentlyPlayed":
case "HasLikedActor":
title = globalize.translate("RecommendationStarring").replace("{0}", recommendation.BaselineItemName);
title = globalize.translate("RecommendationStarring", recommendation.BaselineItemName);
break;
}

View File

@ -1,4 +1,4 @@
define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "alphaPicker", "listView", "cardBuilder", "apphost", "globalize", "emby-itemscontainer"], function (layoutManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, appHost, globalize) {
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) {
@ -16,11 +16,15 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "
Fields: "PrimaryImageAspectRatio,SortName,BasicSyncInfo",
ImageTypeLimit: 1,
EnableImageTypes: "Primary,Backdrop,Banner,Thumb",
StartIndex: 0,
Limit: pageSize
StartIndex: 0
},
view: libraryBrowser.getSavedView(key) || "Poster"
};
if (userSettings.libraryPageSize() > 0) {
pageData.query['Limit'] = userSettings.libraryPageSize();
}
libraryBrowser.loadSavedQueryValues(key, pageData.query);
}
@ -49,7 +53,9 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "
return;
}
query.StartIndex += query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex += query.Limit;
}
reloadItems();
}
@ -58,7 +64,9 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "
return;
}
query.StartIndex -= query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex = Math.max(0, query.StartIndex - query.Limit);
}
reloadItems();
}
@ -168,7 +176,6 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "
}
var self = this;
var pageSize = 100;
var data = {};
var isLoading = false;

View File

@ -1,4 +1,4 @@
define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser", "imageLoader", "alphaPicker", "listView", "cardBuilder", "apphost", "globalize", "emby-itemscontainer"], function (layoutManager, playbackManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, appHost, globalize) {
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) {
@ -30,11 +30,15 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser
Fields: "PrimaryImageAspectRatio,SortName,BasicSyncInfo",
ImageTypeLimit: 1,
EnableImageTypes: "Primary,Backdrop,Banner,Thumb",
StartIndex: 0,
Limit: pageSize
StartIndex: 0
},
view: libraryBrowser.getSavedView(key) || "Poster"
};
if (userSettings.libraryPageSize() > 0) {
pageData.query['Limit'] = userSettings.libraryPageSize();
}
pageData.query.ParentId = params.topParentId;
libraryBrowser.loadSavedQueryValues(key, pageData.query);
}
@ -79,7 +83,9 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser
return;
}
query.StartIndex += query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex += query.Limit;
}
reloadItems(tabContent);
}
@ -88,7 +94,9 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser
return;
}
query.StartIndex -= query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex = Math.max(0, query.StartIndex - query.Limit);
}
reloadItems(tabContent);
}
@ -175,7 +183,6 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser
var savedQueryKey;
var pageData;
var self = this;
var pageSize = 100;
var isLoading = false;
self.showFilterMenu = function () {

View File

@ -1,4 +1,4 @@
define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "alphaPicker", "listView", "cardBuilder", "apphost", "emby-itemscontainer"], function (layoutManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, appHost) {
define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "alphaPicker", "listView", "cardBuilder", "apphost", "userSettings", "emby-itemscontainer"], function (layoutManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, appHost, userSettings) {
"use strict";
return function (view, params, tabContent) {
@ -7,17 +7,22 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "
var pageData = data[key];
if (!pageData) {
var queryValues = {
SortBy: "SortName",
SortOrder: "Ascending",
Recursive: true,
Fields: "PrimaryImageAspectRatio,SortName,BasicSyncInfo",
StartIndex: 0,
ImageTypeLimit: 1,
EnableImageTypes: "Primary,Backdrop,Banner,Thumb"
};
if (userSettings.libraryPageSize() > 0) {
queryValues['Limit'] = userSettings.libraryPageSize();
}
pageData = data[key] = {
query: {
SortBy: "SortName",
SortOrder: "Ascending",
Recursive: true,
Fields: "PrimaryImageAspectRatio,SortName,BasicSyncInfo",
StartIndex: 0,
ImageTypeLimit: 1,
EnableImageTypes: "Primary,Backdrop,Banner,Thumb",
Limit: 100
},
query: queryValues,
view: libraryBrowser.getSavedView(key) || "Poster"
};
pageData.query.ParentId = params.topParentId;
@ -67,7 +72,9 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "
return;
}
query.StartIndex += query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex += query.Limit;
}
reloadItems(tabContent);
}
@ -76,7 +83,9 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "
return;
}
query.StartIndex -= query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex = Math.max(0, query.StartIndex - query.Limit);
}
reloadItems(tabContent);
}

View File

@ -107,12 +107,12 @@ define(["libraryBrowser", "cardBuilder", "apphost", "imageLoader", "loading"], f
};
self.getCurrentViewStyle = function () {
return getPageData(tabContent).view;
return getPageData().view;
};
self.setCurrentViewStyle = function (viewStyle) {
getPageData(tabContent).view = viewStyle;
libraryBrowser.saveViewSetting(getSavedQueryKey(tabContent), viewStyle);
getPageData().view = viewStyle;
libraryBrowser.saveViewSetting(getSavedQueryKey(), viewStyle);
fullyReload();
};

View File

@ -69,7 +69,7 @@ define(["libraryBrowser", "cardBuilder", "apphost", "imageLoader", "loading"], f
var data = {};
self.getCurrentViewStyle = function () {
return getPageData(tabContent).view;
return getPageData().view;
};
var promise;

View File

@ -1,4 +1,4 @@
define(["events", "libraryBrowser", "imageLoader", "listView", "loading", "globalize", "emby-itemscontainer"], function (events, libraryBrowser, imageLoader, listView, loading, globalize) {
define(["events", "libraryBrowser", "imageLoader", "listView", "loading", "userSettings", "globalize", "emby-itemscontainer"], function (events, libraryBrowser, imageLoader, listView, loading, userSettings, globalize) {
"use strict";
return function (view, params, tabContent) {
@ -14,12 +14,16 @@ define(["events", "libraryBrowser", "imageLoader", "listView", "loading", "globa
IncludeItemTypes: "Audio",
Recursive: true,
Fields: "AudioInfo,ParentId",
Limit: 100,
StartIndex: 0,
ImageTypeLimit: 1,
EnableImageTypes: "Primary"
}
};
if (userSettings.libraryPageSize() > 0) {
pageData.query['Limit'] = userSettings.libraryPageSize();
}
pageData.query.ParentId = params.topParentId;
libraryBrowser.loadSavedQueryValues(key, pageData.query);
}
@ -49,7 +53,9 @@ define(["events", "libraryBrowser", "imageLoader", "listView", "loading", "globa
return;
}
query.StartIndex += query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex += query.Limit;
}
reloadItems(tabContent);
}
@ -58,7 +64,9 @@ define(["events", "libraryBrowser", "imageLoader", "listView", "loading", "globa
return;
}
query.StartIndex -= query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex = Math.max(0, query.StartIndex - query.Limit);
}
reloadItems(tabContent);
}

View File

@ -1152,7 +1152,7 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med
case "GamepadDPadLeft":
case "GamepadLeftThumbstickLeft":
// Ignores gamepad events that are always triggered, even when not focused.
if (document.hasFocus()) {
if (document.hasFocus()) { /* eslint-disable-line compat/compat */
playbackManager.rewind(currentPlayer);
showOsd();
}
@ -1161,7 +1161,7 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med
case "GamepadDPadRight":
case "GamepadLeftThumbstickRight":
// Ignores gamepad events that are always triggered, even when not focused.
if (document.hasFocus()) {
if (document.hasFocus()) { /* eslint-disable-line compat/compat */
playbackManager.fastForward(currentPlayer);
showOsd();
}
@ -1272,7 +1272,6 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med
var programEndDateMs = 0;
var playbackStartTimeTicks = 0;
var subtitleSyncOverlay;
var volumeSliderTimer;
var nowPlayingVolumeSlider = view.querySelector(".osdVolumeSlider");
var nowPlayingVolumeSliderContainer = view.querySelector(".osdVolumeSliderContainer");
var nowPlayingPositionSlider = view.querySelector(".osdPositionSlider");
@ -1423,27 +1422,15 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med
}
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);
}
}
view.querySelector(".buttonMute").addEventListener("click", function () {
playbackManager.toggleMute(currentPlayer);
});
nowPlayingVolumeSlider.addEventListener("change", setVolume);
nowPlayingVolumeSlider.addEventListener("mousemove", setVolumeDelayed);
nowPlayingVolumeSlider.addEventListener("touchmove", setVolumeDelayed);
nowPlayingVolumeSlider.addEventListener("mousemove", setVolume);
nowPlayingVolumeSlider.addEventListener("touchmove", setVolume);
nowPlayingPositionSlider.addEventListener("change", function () {
var player = currentPlayer;

View File

@ -36,7 +36,7 @@ define(["jQuery", "loading", "libraryMenu", "globalize"], function ($, loading,
}
$(document).on("pageinit", "#playbackConfigurationPage", function () {
$(".playbackConfigurationForm").off("submit", onSubmit).on("submit", onSubmit)
$(".playbackConfigurationForm").off("submit", onSubmit).on("submit", onSubmit);
}).on("pageshow", "#playbackConfigurationPage", function () {
loading.show();
libraryMenu.setTabs("playback", 1, getTabs);

View File

@ -1,4 +1,4 @@
define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardBuilder", "globalize", "emby-itemscontainer"], function (loading, events, libraryBrowser, imageLoader, listView, cardBuilder, globalize) {
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) {
@ -17,11 +17,15 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB
IsMissing: false,
ImageTypeLimit: 1,
EnableImageTypes: "Primary,Backdrop,Thumb",
StartIndex: 0,
Limit: pageSize
StartIndex: 0
},
view: libraryBrowser.getSavedView(key) || "Poster"
};
if (userSettings.libraryPageSize() > 0) {
pageData.query['Limit'] = userSettings.libraryPageSize();
}
pageData.query.ParentId = params.topParentId;
libraryBrowser.loadSavedQueryValues(key, pageData.query);
}
@ -66,7 +70,9 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB
return;
}
query.StartIndex += query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex += query.Limit;
}
reloadItems(tabContent);
}
@ -75,7 +81,9 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB
return;
}
query.StartIndex -= query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex = Math.max(0, query.StartIndex - query.Limit);
}
reloadItems(tabContent);
}
@ -152,7 +160,6 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB
}
var self = this;
var pageSize = 100;
var data = {};
var isLoading = false;

View File

@ -113,6 +113,9 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader
itemsContainer: elem,
shape: getPortraitShape(),
scalable: true,
showTitle: true,
centerText: true,
showYear: true,
overlayMoreButton: true,
allowBottomPadding: false
});
@ -177,12 +180,12 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader
};
self.getCurrentViewStyle = function () {
return getPageData(tabContent).view;
return getPageData().view;
};
self.setCurrentViewStyle = function (viewStyle) {
getPageData(tabContent).view = viewStyle;
libraryBrowser.saveViewSetting(getSavedQueryKey(tabContent), viewStyle);
getPageData().view = viewStyle;
libraryBrowser.saveViewSetting(getSavedQueryKey(), viewStyle);
fullyReload();
};

View File

@ -1,4 +1,4 @@
define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "listView", "cardBuilder", "alphaPicker", "globalize", "emby-itemscontainer"], function (layoutManager, loading, events, libraryBrowser, imageLoader, listView, cardBuilder, alphaPicker, globalize) {
define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "listView", "cardBuilder", "alphaPicker", "userSettings", "globalize", "emby-itemscontainer"], function (layoutManager, loading, events, libraryBrowser, imageLoader, listView, cardBuilder, alphaPicker, userSettings, globalize) {
"use strict";
return function (view, params, tabContent) {
@ -16,11 +16,15 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "
Fields: "PrimaryImageAspectRatio,BasicSyncInfo",
ImageTypeLimit: 1,
EnableImageTypes: "Primary,Backdrop,Banner,Thumb",
StartIndex: 0,
Limit: pageSize
StartIndex: 0
},
view: libraryBrowser.getSavedView(key) || "Poster"
};
if (userSettings.libraryPageSize() > 0) {
pageData.query['Limit'] = userSettings.libraryPageSize();
}
pageData.query.ParentId = params.topParentId;
libraryBrowser.loadSavedQueryValues(key, pageData.query);
}
@ -65,7 +69,9 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "
return;
}
query.StartIndex += query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex += query.Limit;
}
reloadItems(tabContent);
}
@ -74,7 +80,9 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "
return;
}
query.StartIndex -= query.Limit;
if (userSettings.libraryPageSize() > 0) {
query.StartIndex = Math.max(0, query.StartIndex - query.Limit);
}
reloadItems(tabContent);
}
@ -185,7 +193,6 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "
}
var self = this;
var pageSize = 100;
var data = {};
var isLoading = false;

View File

@ -1,4 +1,4 @@
define(["displaySettings", "userSettingsBuilder", "userSettings", "autoFocuser"], function (DisplaySettings, userSettingsBuilder, currentUserSettings, autoFocuser) {
define(["displaySettings", "userSettings", "autoFocuser"], function (DisplaySettings, userSettings, autoFocuser) {
"use strict";
return function (view, params) {
@ -11,7 +11,7 @@ define(["displaySettings", "userSettingsBuilder", "userSettings", "autoFocuser"]
var settingsInstance;
var hasChanges;
var userId = params.userId || ApiClient.getCurrentUserId();
var userSettings = userId === ApiClient.getCurrentUserId() ? currentUserSettings : new userSettingsBuilder();
var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings();
view.addEventListener("viewshow", function () {
window.addEventListener("beforeunload", onBeforeUnload);
@ -22,7 +22,7 @@ define(["displaySettings", "userSettingsBuilder", "userSettings", "autoFocuser"]
serverId: ApiClient.serverId(),
userId: userId,
element: view.querySelector(".settingsContainer"),
userSettings: userSettings,
userSettings: currentSettings,
enableSaveButton: false,
enableSaveConfirmation: false,
autoFocus: autoFocuser.isEnabled()

View File

@ -1,4 +1,4 @@
define(["homescreenSettings", "userSettingsBuilder", "dom", "globalize", "loading", "userSettings", "autoFocuser", "listViewStyle"], function (HomescreenSettings, userSettingsBuilder, dom, globalize, loading, currentUserSettings, autoFocuser) {
define(["homescreenSettings", "dom", "globalize", "loading", "userSettings", "autoFocuser", "listViewStyle"], function (HomescreenSettings, dom, globalize, loading, userSettings, autoFocuser) {
"use strict";
return function (view, params) {
@ -11,7 +11,7 @@ define(["homescreenSettings", "userSettingsBuilder", "dom", "globalize", "loadin
var homescreenSettingsInstance;
var hasChanges;
var userId = params.userId || ApiClient.getCurrentUserId();
var userSettings = userId === ApiClient.getCurrentUserId() ? currentUserSettings : new userSettingsBuilder();
var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings();
view.addEventListener("viewshow", function () {
window.addEventListener("beforeunload", onBeforeUnload);
@ -22,7 +22,7 @@ define(["homescreenSettings", "userSettingsBuilder", "dom", "globalize", "loadin
serverId: ApiClient.serverId(),
userId: userId,
element: view.querySelector(".homeScreenSettingsContainer"),
userSettings: userSettings,
userSettings: currentSettings,
enableSaveButton: false,
enableSaveConfirmation: false,
autoFocus: autoFocuser.isEnabled()

View File

@ -1,4 +1,4 @@
define(["playbackSettings", "userSettingsBuilder", "dom", "globalize", "loading", "userSettings", "autoFocuser", "listViewStyle"], function (PlaybackSettings, userSettingsBuilder, dom, globalize, loading, currentUserSettings, autoFocuser) {
define(["playbackSettings", "dom", "globalize", "loading", "userSettings", "autoFocuser", "listViewStyle"], function (PlaybackSettings, dom, globalize, loading, userSettings, autoFocuser) {
"use strict";
return function (view, params) {
@ -11,7 +11,7 @@ define(["playbackSettings", "userSettingsBuilder", "dom", "globalize", "loading"
var settingsInstance;
var hasChanges;
var userId = params.userId || ApiClient.getCurrentUserId();
var userSettings = userId === ApiClient.getCurrentUserId() ? currentUserSettings : new userSettingsBuilder();
var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings();
view.addEventListener("viewshow", function () {
window.addEventListener("beforeunload", onBeforeUnload);
@ -22,7 +22,7 @@ define(["playbackSettings", "userSettingsBuilder", "dom", "globalize", "loading"
serverId: ApiClient.serverId(),
userId: userId,
element: view.querySelector(".settingsContainer"),
userSettings: userSettings,
userSettings: currentSettings,
enableSaveButton: false,
enableSaveConfirmation: false,
autoFocus: autoFocuser.isEnabled()

View File

@ -1,4 +1,4 @@
define(["subtitleSettings", "userSettingsBuilder", "userSettings", "autoFocuser"], function (SubtitleSettings, userSettingsBuilder, currentUserSettings, autoFocuser) {
define(["subtitleSettings", "userSettings", "autoFocuser"], function (SubtitleSettings, userSettings, autoFocuser) {
"use strict";
return function (view, params) {
@ -11,7 +11,7 @@ define(["subtitleSettings", "userSettingsBuilder", "userSettings", "autoFocuser"
var subtitleSettingsInstance;
var hasChanges;
var userId = params.userId || ApiClient.getCurrentUserId();
var userSettings = userId === ApiClient.getCurrentUserId() ? currentUserSettings : new userSettingsBuilder();
var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings();
view.addEventListener("viewshow", function () {
window.addEventListener("beforeunload", onBeforeUnload);
@ -22,7 +22,7 @@ define(["subtitleSettings", "userSettingsBuilder", "userSettings", "autoFocuser"
serverId: ApiClient.serverId(),
userId: userId,
element: view.querySelector(".settingsContainer"),
userSettings: userSettings,
userSettings: currentSettings,
enableSaveButton: false,
enableSaveConfirmation: false,
autoFocus: autoFocuser.isEnabled()

View File

@ -1,4 +1,4 @@
define(["loading", "dom", "globalize", "humanedate", "paper-icon-button-light", "cardStyle", "emby-button", "indicators", "flexStyles"], function (loading, dom, globalize) {
define(["loading", "dom", "globalize", "date-fns", "dfnshelper", "paper-icon-button-light", "cardStyle", "emby-button", "indicators", "flexStyles"], function (loading, dom, globalize, datefns, dfnshelper) {
"use strict";
function deleteUser(page, id) {
@ -125,10 +125,11 @@ define(["loading", "dom", "globalize", "humanedate", "paper-icon-button-light",
html += "</div>";
return html + "</div>";
}
// FIXME: It seems that, sometimes, server sends date in the future, so date-fns displays messages like 'in less than a minute'. We should fix
// how dates are returned by the server when the session is active and show something like 'Active now', instead of past/future sentences
function getLastSeenText(lastActivityDate) {
if (lastActivityDate) {
return "Last seen " + humaneDate(lastActivityDate);
return globalize.translate("LastSeen", datefns.formatDistanceToNow(Date.parse(lastActivityDate), dfnshelper.localeWithSuffix));
}
return "";

View File

@ -0,0 +1,16 @@
define([], function() {
'use strict';
var ProgramCellPrototype = Object.create(HTMLButtonElement.prototype);
ProgramCellPrototype.detachedCallback = function () {
this.posLeft = null;
this.posWidth = null;
this.guideProgramName = null;
};
document.registerElement('emby-programcell', {
prototype: ProgramCellPrototype,
extends: 'button'
});
});

View File

@ -0,0 +1,42 @@
define([], function() {
'use strict';
var ProgressBarPrototype = Object.create(HTMLDivElement.prototype);
function onAutoTimeProgress() {
var start = parseInt(this.getAttribute('data-starttime'));
var end = parseInt(this.getAttribute('data-endtime'));
var now = new Date().getTime();
var total = end - start;
var pct = 100 * ((now - start) / total);
pct = Math.min(100, pct);
pct = Math.max(0, pct);
var itemProgressBarForeground = this.querySelector('.itemProgressBarForeground');
itemProgressBarForeground.style.width = pct + '%';
}
ProgressBarPrototype.attachedCallback = function () {
if (this.timeInterval) {
clearInterval(this.timeInterval);
}
if (this.getAttribute('data-automode') === 'time') {
this.timeInterval = setInterval(onAutoTimeProgress.bind(this), 60000);
}
};
ProgressBarPrototype.detachedCallback = function () {
if (this.timeInterval) {
clearInterval(this.timeInterval);
this.timeInterval = null;
}
};
document.registerElement('emby-progressbar', {
prototype: ProgressBarPrototype,
extends: 'div'
});
});

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