mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge remote-tracking branch 'upstream/master' into fonts
This commit is contained in:
commit
f1804009e6
326 changed files with 21514 additions and 23576 deletions
|
@ -2,6 +2,7 @@ import connectionManager from 'connectionManager';
|
|||
import loading from 'loading';
|
||||
import keyboardnavigation from 'keyboardnavigation';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import dom from 'dom';
|
||||
import events from 'events';
|
||||
import 'css!./style';
|
||||
import 'material-icons';
|
||||
|
@ -26,16 +27,16 @@ export class BookPlayer {
|
|||
this._loaded = false;
|
||||
|
||||
loading.show();
|
||||
let elem = this.createMediaElement();
|
||||
const elem = this.createMediaElement();
|
||||
return this.setCurrentSrc(elem, options);
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.unbindEvents();
|
||||
|
||||
let elem = this._mediaElement;
|
||||
let tocElement = this._tocElement;
|
||||
let rendition = this._rendition;
|
||||
const elem = this._mediaElement;
|
||||
const tocElement = this._tocElement;
|
||||
const rendition = this._rendition;
|
||||
|
||||
if (elem) {
|
||||
dialogHelper.close(elem);
|
||||
|
@ -92,24 +93,23 @@ export class BookPlayer {
|
|||
}
|
||||
|
||||
onWindowKeyUp(e) {
|
||||
let key = keyboardnavigation.getKeyName(e);
|
||||
let rendition = this._rendition;
|
||||
let book = rendition.book;
|
||||
const key = keyboardnavigation.getKeyName(e);
|
||||
|
||||
// TODO: depending on the event this can be the document or the rendition itself
|
||||
const rendition = this._rendition || this;
|
||||
const book = rendition.book;
|
||||
|
||||
if (this._loaded === false) return;
|
||||
switch (key) {
|
||||
case 'l':
|
||||
case 'ArrowRight':
|
||||
case 'Right':
|
||||
if (this._loaded) {
|
||||
book.package.metadata.direction === 'rtl' ? rendition.prev() : rendition.next();
|
||||
}
|
||||
book.package.metadata.direction === 'rtl' ? rendition.prev() : rendition.next();
|
||||
break;
|
||||
case 'j':
|
||||
case 'ArrowLeft':
|
||||
case 'Left':
|
||||
if (this._loaded) {
|
||||
book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev();
|
||||
}
|
||||
book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev();
|
||||
break;
|
||||
case 'Escape':
|
||||
if (this._tocElement) {
|
||||
|
@ -123,12 +123,32 @@ export class BookPlayer {
|
|||
}
|
||||
}
|
||||
|
||||
onTouchStart(e) {
|
||||
// TODO: depending on the event this can be the document or the rendition itself
|
||||
const rendition = this._rendition || this;
|
||||
const book = rendition.book;
|
||||
|
||||
// check that the event is from the book or the document
|
||||
if (!book || this._loaded === false) return;
|
||||
|
||||
// epubjs stores pages off the screen or something for preloading
|
||||
// get the modulus of the touch event to account for the increased width
|
||||
if (!e.touches || e.touches.length === 0) return;
|
||||
|
||||
const touch = e.touches[0].clientX % dom.getWindowSize().innerWidth;
|
||||
if (touch < dom.getWindowSize().innerWidth / 2) {
|
||||
book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev();
|
||||
} else {
|
||||
book.package.metadata.direction === 'rtl' ? rendition.prev() : rendition.next();
|
||||
}
|
||||
}
|
||||
|
||||
onDialogClosed() {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
bindMediaElementEvents() {
|
||||
let elem = this._mediaElement;
|
||||
const elem = this._mediaElement;
|
||||
|
||||
elem.addEventListener('close', this.onDialogClosed, {once: true});
|
||||
elem.querySelector('.btnBookplayerExit').addEventListener('click', this.onDialogClosed, {once: true});
|
||||
|
@ -139,12 +159,15 @@ export class BookPlayer {
|
|||
this.bindMediaElementEvents();
|
||||
|
||||
document.addEventListener('keyup', this.onWindowKeyUp);
|
||||
document.addEventListener('touchstart', this.onTouchStart);
|
||||
|
||||
// FIXME: I don't really get why document keyup event is not triggered when epub is in focus
|
||||
this._rendition.on('keyup', this.onWindowKeyUp);
|
||||
this._rendition.on('touchstart', this.onTouchStart);
|
||||
}
|
||||
|
||||
unbindMediaElementEvents() {
|
||||
let elem = this._mediaElement;
|
||||
const elem = this._mediaElement;
|
||||
|
||||
elem.removeEventListener('close', this.onDialogClosed);
|
||||
elem.querySelector('.btnBookplayerExit').removeEventListener('click', this.onDialogClosed);
|
||||
|
@ -155,9 +178,13 @@ export class BookPlayer {
|
|||
if (this._mediaElement) {
|
||||
this.unbindMediaElementEvents();
|
||||
}
|
||||
|
||||
document.removeEventListener('keyup', this.onWindowKeyUp);
|
||||
document.removeEventListener('touchstart', this.onTouchStart);
|
||||
|
||||
if (this._rendition) {
|
||||
this._rendition.off('keyup', this.onWindowKeyUp);
|
||||
this._rendition.off('touchstart', this.onTouchStart);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,13 +196,11 @@ export class BookPlayer {
|
|||
|
||||
createMediaElement() {
|
||||
let elem = this._mediaElement;
|
||||
|
||||
if (elem) {
|
||||
return elem;
|
||||
}
|
||||
|
||||
elem = document.getElementById('bookPlayer');
|
||||
|
||||
if (!elem) {
|
||||
elem = dialogHelper.createDialog({
|
||||
exitAnimationDuration: 400,
|
||||
|
@ -185,6 +210,7 @@ export class BookPlayer {
|
|||
exitAnimation: 'fadeout',
|
||||
removeOnClose: true
|
||||
});
|
||||
|
||||
elem.id = 'bookPlayer';
|
||||
|
||||
let html = '';
|
||||
|
@ -206,7 +232,7 @@ export class BookPlayer {
|
|||
}
|
||||
|
||||
setCurrentSrc(elem, options) {
|
||||
let item = options.items[0];
|
||||
const item = options.items[0];
|
||||
this._currentItem = item;
|
||||
this.streamInfo = {
|
||||
started: true,
|
||||
|
@ -216,24 +242,25 @@ export class BookPlayer {
|
|||
}
|
||||
};
|
||||
|
||||
let serverId = item.ServerId;
|
||||
let apiClient = connectionManager.getApiClient(serverId);
|
||||
const serverId = item.ServerId;
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
import('epubjs').then(({default: epubjs}) => {
|
||||
let downloadHref = apiClient.getItemDownloadUrl(item.Id);
|
||||
let book = epubjs.default(downloadHref, {openAs: 'epub'});
|
||||
let rendition = book.renderTo(elem, {width: '100%', height: '97%'});
|
||||
const downloadHref = apiClient.getItemDownloadUrl(item.Id);
|
||||
const book = epubjs(downloadHref, {openAs: 'epub'});
|
||||
const rendition = book.renderTo(elem, {width: '100%', height: '97%'});
|
||||
|
||||
this._currentSrc = downloadHref;
|
||||
this._rendition = rendition;
|
||||
let cancellationToken = {
|
||||
const cancellationToken = {
|
||||
shouldCancel: false
|
||||
};
|
||||
|
||||
this._cancellationToken = cancellationToken;
|
||||
|
||||
return rendition.display().then(() => {
|
||||
let epubElem = document.querySelector('.epub-container');
|
||||
const epubElem = document.querySelector('.epub-container');
|
||||
epubElem.style.display = 'none';
|
||||
|
||||
this.bindEvents();
|
||||
|
@ -253,7 +280,6 @@ export class BookPlayer {
|
|||
epubElem.style.display = 'block';
|
||||
rendition.on('relocated', (locations) => {
|
||||
this._progress = book.locations.percentageFromCfi(locations.start.cfi);
|
||||
|
||||
events.trigger(this, 'timeupdate');
|
||||
});
|
||||
|
||||
|
@ -262,7 +288,7 @@ export class BookPlayer {
|
|||
return resolve();
|
||||
});
|
||||
}, () => {
|
||||
console.error('Failed to display epub');
|
||||
console.error('failed to display epub');
|
||||
return reject();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,7 +11,7 @@ export default class TableOfContents {
|
|||
}
|
||||
|
||||
destroy() {
|
||||
let elem = this._elem;
|
||||
const elem = this._elem;
|
||||
if (elem) {
|
||||
this.unbindEvents();
|
||||
dialogHelper.close(elem);
|
||||
|
@ -21,14 +21,14 @@ export default class TableOfContents {
|
|||
}
|
||||
|
||||
bindEvents() {
|
||||
let elem = this._elem;
|
||||
const elem = this._elem;
|
||||
|
||||
elem.addEventListener('close', this.onDialogClosed, {once: true});
|
||||
elem.querySelector('.btnBookplayerTocClose').addEventListener('click', this.onDialogClosed, {once: true});
|
||||
}
|
||||
|
||||
unbindEvents() {
|
||||
let elem = this._elem;
|
||||
const elem = this._elem;
|
||||
|
||||
elem.removeEventListener('close', this.onDialogClosed);
|
||||
elem.querySelector('.btnBookplayerTocClose').removeEventListener('click', this.onDialogClosed);
|
||||
|
@ -39,10 +39,10 @@ export default class TableOfContents {
|
|||
}
|
||||
|
||||
replaceLinks(contents, f) {
|
||||
let links = contents.querySelectorAll('a[href]');
|
||||
const links = contents.querySelectorAll('a[href]');
|
||||
|
||||
links.forEach((link) => {
|
||||
let href = link.getAttribute('href');
|
||||
const href = link.getAttribute('href');
|
||||
|
||||
link.onclick = () => {
|
||||
f(href);
|
||||
|
@ -52,9 +52,9 @@ export default class TableOfContents {
|
|||
}
|
||||
|
||||
createMediaElement() {
|
||||
let rendition = this._rendition;
|
||||
const rendition = this._rendition;
|
||||
|
||||
let elem = dialogHelper.createDialog({
|
||||
const elem = dialogHelper.createDialog({
|
||||
size: 'small',
|
||||
autoFocus: false,
|
||||
removeOnClose: true
|
||||
|
@ -69,7 +69,7 @@ export default class TableOfContents {
|
|||
rendition.book.navigation.forEach((chapter) => {
|
||||
tocHtml += '<li>';
|
||||
// Remove '../' from href
|
||||
let link = chapter.href.startsWith('../') ? chapter.href.substr(3) : chapter.href;
|
||||
const link = chapter.href.startsWith('../') ? chapter.href.substr(3) : chapter.href;
|
||||
tocHtml += `<a href="${rendition.book.path.directory + link}">${chapter.label}</a>`;
|
||||
tocHtml += '</li>';
|
||||
});
|
||||
|
@ -78,7 +78,7 @@ export default class TableOfContents {
|
|||
elem.innerHTML = tocHtml;
|
||||
|
||||
this.replaceLinks(elem, (href) => {
|
||||
let relative = rendition.book.path.relative(href);
|
||||
const relative = rendition.book.path.relative(href);
|
||||
rendition.display(relative);
|
||||
this.destroy();
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,59 +1,61 @@
|
|||
define(['connectionManager', 'globalize', 'userSettings', 'apphost'], function (connectionManager, globalize, userSettings, appHost) {
|
||||
'use strict';
|
||||
import globalize from 'globalize';
|
||||
import * as userSettings from 'userSettings';
|
||||
import appHost from 'apphost';
|
||||
|
||||
// TODO: Replace with date-fns
|
||||
// https://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php
|
||||
function getWeek(date) {
|
||||
var d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
||||
var dayNum = d.getUTCDay() || 7;
|
||||
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
|
||||
var yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
||||
return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
|
||||
// TODO: Replace with date-fns
|
||||
// https://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php
|
||||
function getWeek(date) {
|
||||
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
||||
const dayNum = d.getUTCDay() || 7;
|
||||
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
|
||||
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
||||
return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
|
||||
}
|
||||
|
||||
function showMessage(text, userSettingsKey, appHostFeature) {
|
||||
if (appHost.supports(appHostFeature)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function showMessage(text, userSettingsKey, appHostFeature) {
|
||||
if (appHost.supports(appHostFeature)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
const now = new Date();
|
||||
|
||||
var now = new Date();
|
||||
// TODO: Use date-fns
|
||||
userSettingsKey += now.getFullYear() + '-w' + getWeek(now);
|
||||
|
||||
// TODO: Use date-fns
|
||||
userSettingsKey += now.getFullYear() + '-w' + getWeek(now);
|
||||
if (userSettings.get(userSettingsKey, false) === '1') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (userSettings.get(userSettingsKey, false) === '1') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise(function (resolve, reject) {
|
||||
userSettings.set(userSettingsKey, '1', false);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
userSettings.set(userSettingsKey, '1', false);
|
||||
|
||||
require(['alert'], function (alert) {
|
||||
return alert(text).then(resolve, resolve);
|
||||
});
|
||||
import('alert').then(({default: alert}) => {
|
||||
return alert(text).then(resolve, resolve);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showBlurayMessage() {
|
||||
return showMessage(globalize.translate('UnsupportedPlayback'), 'blurayexpirementalinfo', 'nativeblurayplayback');
|
||||
}
|
||||
function showBlurayMessage() {
|
||||
return showMessage(globalize.translate('UnsupportedPlayback'), 'blurayexpirementalinfo', 'nativeblurayplayback');
|
||||
}
|
||||
|
||||
function showDvdMessage() {
|
||||
return showMessage(globalize.translate('UnsupportedPlayback'), 'dvdexpirementalinfo', 'nativedvdplayback');
|
||||
}
|
||||
function showDvdMessage() {
|
||||
return showMessage(globalize.translate('UnsupportedPlayback'), 'dvdexpirementalinfo', 'nativedvdplayback');
|
||||
}
|
||||
|
||||
function showIsoMessage() {
|
||||
return showMessage(globalize.translate('UnsupportedPlayback'), 'isoexpirementalinfo', 'nativeisoplayback');
|
||||
}
|
||||
function showIsoMessage() {
|
||||
return showMessage(globalize.translate('UnsupportedPlayback'), 'isoexpirementalinfo', 'nativeisoplayback');
|
||||
}
|
||||
|
||||
function ExpirementalPlaybackWarnings() {
|
||||
class ExpirementalPlaybackWarnings {
|
||||
constructor() {
|
||||
this.name = 'Experimental playback warnings';
|
||||
this.type = 'preplayintercept';
|
||||
this.id = 'expirementalplaybackwarnings';
|
||||
}
|
||||
|
||||
ExpirementalPlaybackWarnings.prototype.intercept = function (options) {
|
||||
var item = options.item;
|
||||
intercept(options) {
|
||||
const item = options.item;
|
||||
if (!item) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
@ -71,7 +73,7 @@ define(['connectionManager', 'globalize', 'userSettings', 'apphost'], function (
|
|||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return ExpirementalPlaybackWarnings;
|
||||
});
|
||||
export default ExpirementalPlaybackWarnings;
|
||||
|
|
|
@ -1,91 +1,92 @@
|
|||
define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelper'], function (events, browser, require, appHost, appSettings, htmlMediaHelper) {
|
||||
'use strict';
|
||||
import events from 'events';
|
||||
import browser from 'browser';
|
||||
import appHost from 'apphost';
|
||||
import * as htmlMediaHelper from 'htmlMediaHelper';
|
||||
|
||||
function getDefaultProfile() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(['browserdeviceprofile'], function (profileBuilder) {
|
||||
resolve(profileBuilder({}));
|
||||
});
|
||||
function getDefaultProfile() {
|
||||
return import('browserdeviceprofile').then(({ default: profileBuilder }) => {
|
||||
return profileBuilder({});
|
||||
});
|
||||
}
|
||||
|
||||
let fadeTimeout;
|
||||
function fade(instance, elem, startingVolume) {
|
||||
instance._isFadingOut = true;
|
||||
|
||||
// Need to record the starting volume on each pass rather than querying elem.volume
|
||||
// This is due to iOS safari not allowing volume changes and always returning the system volume value
|
||||
const newVolume = Math.max(0, startingVolume - 0.15);
|
||||
console.debug('fading volume to ' + newVolume);
|
||||
elem.volume = newVolume;
|
||||
|
||||
if (newVolume <= 0) {
|
||||
instance._isFadingOut = false;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
cancelFadeTimeout();
|
||||
fadeTimeout = setTimeout(function () {
|
||||
fade(instance, elem, newVolume).then(resolve, reject);
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
function cancelFadeTimeout() {
|
||||
const timeout = fadeTimeout;
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
fadeTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
function supportsFade() {
|
||||
if (browser.tv) {
|
||||
// Not working on tizen.
|
||||
// We could possibly enable on other tv's, but all smart tv browsers tend to be pretty primitive
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function requireHlsPlayer(callback) {
|
||||
import('hlsjs').then(({ default: hls }) => {
|
||||
window.Hls = hls;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function enableHlsPlayer(url, item, mediaSource, mediaType) {
|
||||
if (!htmlMediaHelper.enableHlsJsPlayer(mediaSource.RunTimeTicks, mediaType)) {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
if (url.indexOf('.m3u8') !== -1) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// issue head request to get content type
|
||||
return new Promise(function (resolve, reject) {
|
||||
import('fetchHelper').then((fetchHelper) => {
|
||||
fetchHelper.ajax({
|
||||
url: url,
|
||||
type: 'HEAD'
|
||||
}).then(function (response) {
|
||||
const contentType = (response.headers.get('Content-Type') || '').toLowerCase();
|
||||
if (contentType === 'application/x-mpegurl') {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var fadeTimeout;
|
||||
function fade(instance, elem, startingVolume) {
|
||||
instance._isFadingOut = true;
|
||||
|
||||
// Need to record the starting volume on each pass rather than querying elem.volume
|
||||
// This is due to iOS safari not allowing volume changes and always returning the system volume value
|
||||
var newVolume = Math.max(0, startingVolume - 0.15);
|
||||
console.debug('fading volume to ' + newVolume);
|
||||
elem.volume = newVolume;
|
||||
|
||||
if (newVolume <= 0) {
|
||||
instance._isFadingOut = false;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
cancelFadeTimeout();
|
||||
fadeTimeout = setTimeout(function () {
|
||||
fade(instance, elem, newVolume).then(resolve, reject);
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
function cancelFadeTimeout() {
|
||||
var timeout = fadeTimeout;
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
fadeTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
function supportsFade() {
|
||||
if (browser.tv) {
|
||||
// Not working on tizen.
|
||||
// We could possibly enable on other tv's, but all smart tv browsers tend to be pretty primitive
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function requireHlsPlayer(callback) {
|
||||
require(['hlsjs'], function (hls) {
|
||||
window.Hls = hls;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function enableHlsPlayer(url, item, mediaSource, mediaType) {
|
||||
if (!htmlMediaHelper.enableHlsJsPlayer(mediaSource.RunTimeTicks, mediaType)) {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
if (url.indexOf('.m3u8') !== -1) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// issue head request to get content type
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(['fetchHelper'], function (fetchHelper) {
|
||||
fetchHelper.ajax({
|
||||
url: url,
|
||||
type: 'HEAD'
|
||||
}).then(function (response) {
|
||||
var contentType = (response.headers.get('Content-Type') || '').toLowerCase();
|
||||
if (contentType === 'application/x-mpegurl') {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
}, reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function HtmlAudioPlayer() {
|
||||
var self = this;
|
||||
class HtmlAudioPlayer {
|
||||
constructor() {
|
||||
const self = this;
|
||||
|
||||
self.name = 'Html Audio Player';
|
||||
self.type = 'mediaplayer';
|
||||
|
@ -99,7 +100,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
|
|||
self._timeUpdated = false;
|
||||
self._currentTime = null;
|
||||
|
||||
var elem = createMediaElement();
|
||||
const elem = createMediaElement();
|
||||
return setCurrentSrc(elem, options);
|
||||
};
|
||||
|
||||
|
@ -109,11 +110,11 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
|
|||
unBindEvents(elem);
|
||||
bindEvents(elem);
|
||||
|
||||
var val = options.url;
|
||||
let val = options.url;
|
||||
console.debug('playing url: ' + val);
|
||||
|
||||
// Convert to seconds
|
||||
var seconds = (options.playerStartPositionTicks || 0) / 10000000;
|
||||
const seconds = (options.playerStartPositionTicks || 0) / 10000000;
|
||||
if (seconds) {
|
||||
val += '#t=' + seconds;
|
||||
}
|
||||
|
@ -122,7 +123,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
|
|||
|
||||
self._currentPlayOptions = options;
|
||||
|
||||
var crossOrigin = htmlMediaHelper.getCrossOriginValue(options.mediaSource);
|
||||
const crossOrigin = htmlMediaHelper.getCrossOriginValue(options.mediaSource);
|
||||
if (crossOrigin) {
|
||||
elem.crossOrigin = crossOrigin;
|
||||
}
|
||||
|
@ -130,9 +131,9 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
|
|||
return enableHlsPlayer(val, options.item, options.mediaSource, 'Audio').then(function () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
requireHlsPlayer(function () {
|
||||
var hls = new Hls({
|
||||
const hls = new Hls({
|
||||
manifestLoadingTimeOut: 20000,
|
||||
xhrSetup: function(xhr, url) {
|
||||
xhrSetup: function (xhr, url) {
|
||||
xhr.withCredentials = true;
|
||||
}
|
||||
});
|
||||
|
@ -183,8 +184,8 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
|
|||
self.stop = function (destroyPlayer) {
|
||||
cancelFadeTimeout();
|
||||
|
||||
var elem = self._mediaElement;
|
||||
var src = self._currentSrc;
|
||||
const elem = self._mediaElement;
|
||||
const src = self._currentSrc;
|
||||
|
||||
if (elem && src) {
|
||||
if (!destroyPlayer || !supportsFade()) {
|
||||
|
@ -198,7 +199,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
|
|||
return Promise.resolve();
|
||||
}
|
||||
|
||||
var originalVolume = elem.volume;
|
||||
const originalVolume = elem.volume;
|
||||
|
||||
return fade(self, elem, elem.volume).then(function () {
|
||||
elem.pause();
|
||||
|
@ -219,7 +220,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
|
|||
};
|
||||
|
||||
function createMediaElement() {
|
||||
var elem = self._mediaElement;
|
||||
let elem = self._mediaElement;
|
||||
|
||||
if (elem) {
|
||||
return elem;
|
||||
|
@ -248,7 +249,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
|
|||
|
||||
function onTimeUpdate() {
|
||||
// Get the player position + the transcoding offset
|
||||
var time = this.currentTime;
|
||||
const time = this.currentTime;
|
||||
|
||||
// Don't trigger events after user stop
|
||||
if (!self._isFadingOut) {
|
||||
|
@ -287,11 +288,11 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
|
|||
}
|
||||
|
||||
function onError() {
|
||||
var errorCode = this.error ? (this.error.code || 0) : 0;
|
||||
var errorMessage = this.error ? (this.error.message || '') : '';
|
||||
const errorCode = this.error ? (this.error.code || 0) : 0;
|
||||
const errorMessage = this.error ? (this.error.message || '') : '';
|
||||
console.error('media element error: ' + errorCode.toString() + ' ' + errorMessage);
|
||||
|
||||
var type;
|
||||
let type;
|
||||
|
||||
switch (errorCode) {
|
||||
case 1:
|
||||
|
@ -325,59 +326,59 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
|
|||
}
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.currentSrc = function () {
|
||||
currentSrc() {
|
||||
return this._currentSrc;
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.canPlayMediaType = function (mediaType) {
|
||||
canPlayMediaType(mediaType) {
|
||||
return (mediaType || '').toLowerCase() === 'audio';
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.getDeviceProfile = function (item) {
|
||||
getDeviceProfile(item) {
|
||||
if (appHost.getDeviceProfile) {
|
||||
return appHost.getDeviceProfile(item);
|
||||
}
|
||||
|
||||
return getDefaultProfile();
|
||||
};
|
||||
}
|
||||
|
||||
// Save this for when playback stops, because querying the time at that point might return 0
|
||||
HtmlAudioPlayer.prototype.currentTime = function (val) {
|
||||
var mediaElement = this._mediaElement;
|
||||
currentTime(val) {
|
||||
const mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
if (val != null) {
|
||||
mediaElement.currentTime = val / 1000;
|
||||
return;
|
||||
}
|
||||
|
||||
var currentTime = this._currentTime;
|
||||
const currentTime = this._currentTime;
|
||||
if (currentTime) {
|
||||
return currentTime * 1000;
|
||||
}
|
||||
|
||||
return (mediaElement.currentTime || 0) * 1000;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.duration = function (val) {
|
||||
var mediaElement = this._mediaElement;
|
||||
duration(val) {
|
||||
const mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
var duration = mediaElement.duration;
|
||||
const duration = mediaElement.duration;
|
||||
if (htmlMediaHelper.isValidDuration(duration)) {
|
||||
return duration * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.seekable = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
seekable() {
|
||||
const mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
var seekable = mediaElement.seekable;
|
||||
const seekable = mediaElement.seekable;
|
||||
if (seekable && seekable.length) {
|
||||
var start = seekable.start(0);
|
||||
var end = seekable.end(0);
|
||||
let start = seekable.start(0);
|
||||
let end = seekable.end(0);
|
||||
|
||||
if (!htmlMediaHelper.isValidDuration(start)) {
|
||||
start = 0;
|
||||
|
@ -391,124 +392,120 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
|
|||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.getBufferedRanges = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
getBufferedRanges() {
|
||||
const mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
return htmlMediaHelper.getBufferedRanges(this, mediaElement);
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.pause = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
pause() {
|
||||
const mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
mediaElement.pause();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// This is a retry after error
|
||||
HtmlAudioPlayer.prototype.resume = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
resume() {
|
||||
const mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
mediaElement.play();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.unpause = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
unpause() {
|
||||
const mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
mediaElement.play();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.paused = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
paused() {
|
||||
const mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
return mediaElement.paused;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.setPlaybackRate = function (value) {
|
||||
var mediaElement = this._mediaElement;
|
||||
setPlaybackRate(value) {
|
||||
const mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
mediaElement.playbackRate = value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.getPlaybackRate = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
getPlaybackRate() {
|
||||
const mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
return mediaElement.playbackRate;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.setVolume = function (val) {
|
||||
var mediaElement = this._mediaElement;
|
||||
setVolume(val) {
|
||||
const mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
mediaElement.volume = val / 100;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.getVolume = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
getVolume() {
|
||||
const mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
return Math.min(Math.round(mediaElement.volume * 100), 100);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.volumeUp = function () {
|
||||
volumeUp() {
|
||||
this.setVolume(Math.min(this.getVolume() + 2, 100));
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.volumeDown = function () {
|
||||
volumeDown() {
|
||||
this.setVolume(Math.max(this.getVolume() - 2, 0));
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.setMute = function (mute) {
|
||||
var mediaElement = this._mediaElement;
|
||||
setMute(mute) {
|
||||
const mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
mediaElement.muted = mute;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.isMuted = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
isMuted() {
|
||||
const mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
return mediaElement.muted;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.destroy = function () {
|
||||
|
||||
};
|
||||
|
||||
var supportedFeatures;
|
||||
|
||||
function getSupportedFeatures() {
|
||||
var list = [];
|
||||
var audio = document.createElement('audio');
|
||||
|
||||
if (typeof audio.playbackRate === 'number') {
|
||||
list.push('PlaybackRate');
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
HtmlAudioPlayer.prototype.supports = function (feature) {
|
||||
supports(feature) {
|
||||
if (!supportedFeatures) {
|
||||
supportedFeatures = getSupportedFeatures();
|
||||
}
|
||||
|
||||
return supportedFeatures.indexOf(feature) !== -1;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return HtmlAudioPlayer;
|
||||
});
|
||||
let supportedFeatures;
|
||||
|
||||
function getSupportedFeatures() {
|
||||
const list = [];
|
||||
const audio = document.createElement('audio');
|
||||
|
||||
if (typeof audio.playbackRate === 'number') {
|
||||
list.push('PlaybackRate');
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
export default HtmlAudioPlayer;
|
||||
|
|
|
@ -105,7 +105,7 @@ function tryRemoveElement(elem) {
|
|||
}
|
||||
|
||||
function hidePrePlaybackPage() {
|
||||
let animatedPage = document.querySelector('.page:not(.hide)');
|
||||
const animatedPage = document.querySelector('.page:not(.hide)');
|
||||
animatedPage.classList.add('hide');
|
||||
// At this point, we must hide the scrollbar placeholder, so it's not being displayed while the item is being loaded
|
||||
document.body.classList.remove('force-scroll');
|
||||
|
@ -150,7 +150,7 @@ function tryRemoveElement(elem) {
|
|||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
name
|
||||
name;
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
|
@ -730,7 +730,7 @@ function tryRemoveElement(elem) {
|
|||
const elem = e.target;
|
||||
this.destroyCustomTrack(elem);
|
||||
onEndedInternal(this, elem, this.onError);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
|
@ -760,7 +760,7 @@ function tryRemoveElement(elem) {
|
|||
}
|
||||
|
||||
events.trigger(this, 'timeupdate');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
|
@ -773,7 +773,7 @@ function tryRemoveElement(elem) {
|
|||
const elem = e.target;
|
||||
saveVolume(elem.volume);
|
||||
events.trigger(this, 'volumechange');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
|
@ -785,7 +785,7 @@ function tryRemoveElement(elem) {
|
|||
|
||||
this.onStartedAndNavigatedToOsd();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
|
@ -832,14 +832,14 @@ function tryRemoveElement(elem) {
|
|||
}
|
||||
}
|
||||
events.trigger(this, 'playing');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onPlay = () => {
|
||||
events.trigger(this, 'unpause');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
|
@ -865,21 +865,21 @@ function tryRemoveElement(elem) {
|
|||
*/
|
||||
onClick = () => {
|
||||
events.trigger(this, 'click');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onDblClick = () => {
|
||||
events.trigger(this, 'dblclick');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onPause = () => {
|
||||
events.trigger(this, 'pause');
|
||||
}
|
||||
};
|
||||
|
||||
onWaiting() {
|
||||
events.trigger(this, 'waiting');
|
||||
|
@ -929,7 +929,7 @@ function tryRemoveElement(elem) {
|
|||
}
|
||||
|
||||
onErrorInternal(this, type);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
|
@ -1152,7 +1152,7 @@ function tryRemoveElement(elem) {
|
|||
*/
|
||||
getCueCss(appearance, selector) {
|
||||
return `${selector}::cue {
|
||||
${appearance.text.map((s) => `${s.name}:${s.value}!important;`).join('')}
|
||||
${appearance.text.map((s) => s.value !== undefined && s.value !== '' ? `${s.name}:${s.value}!important;` : '').join('')}
|
||||
}`;
|
||||
}
|
||||
|
||||
|
@ -1170,7 +1170,7 @@ function tryRemoveElement(elem) {
|
|||
document.getElementsByTagName('head')[0].appendChild(styleElem);
|
||||
}
|
||||
|
||||
styleElem.innerHTML = this.getCueCss(subtitleAppearanceHelper.getStyles(userSettings.getSubtitleAppearanceSettings(), true), '.htmlvideoplayer');
|
||||
styleElem.innerHTML = this.getCueCss(subtitleAppearanceHelper.getStyles(userSettings.getSubtitleAppearanceSettings()), '.htmlvideoplayer');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1215,17 +1215,28 @@ function tryRemoveElement(elem) {
|
|||
|
||||
// download the track json
|
||||
this.fetchSubtitles(track, item).then(function (data) {
|
||||
// show in ui
|
||||
console.debug(`downloaded ${data.TrackEvents.length} track events`);
|
||||
// add some cues to show the text
|
||||
// in safari, the cues need to be added before setting the track mode to showing
|
||||
for (const trackEvent of data.TrackEvents) {
|
||||
const trackCueObject = window.VTTCue || window.TextTrackCue;
|
||||
const cue = new trackCueObject(trackEvent.StartPositionTicks / 10000000, trackEvent.EndPositionTicks / 10000000, normalizeTrackEventText(trackEvent.Text, false));
|
||||
import('userSettings').then((userSettings) => {
|
||||
// show in ui
|
||||
console.debug(`downloaded ${data.TrackEvents.length} track events`);
|
||||
|
||||
trackElement.addCue(cue);
|
||||
}
|
||||
trackElement.mode = 'showing';
|
||||
const subtitleAppearance = userSettings.getSubtitleAppearanceSettings();
|
||||
const cueLine = parseInt(subtitleAppearance.verticalPosition, 10);
|
||||
|
||||
// add some cues to show the text
|
||||
// in safari, the cues need to be added before setting the track mode to showing
|
||||
for (const trackEvent of data.TrackEvents) {
|
||||
const trackCueObject = window.VTTCue || window.TextTrackCue;
|
||||
const cue = new trackCueObject(trackEvent.StartPositionTicks / 10000000, trackEvent.EndPositionTicks / 10000000, normalizeTrackEventText(trackEvent.Text, false));
|
||||
|
||||
if (cue.line === 'auto') {
|
||||
cue.line = cueLine;
|
||||
}
|
||||
|
||||
trackElement.addCue(cue);
|
||||
}
|
||||
|
||||
trackElement.mode = 'showing';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1308,7 +1319,7 @@ function tryRemoveElement(elem) {
|
|||
}
|
||||
|
||||
let html = '';
|
||||
let cssClass = 'htmlvideoplayer';
|
||||
const cssClass = 'htmlvideoplayer';
|
||||
|
||||
// Can't autoplay in these browsers so we need to use the full controls, at least until playback starts
|
||||
if (!appHost.supports('htmlvideoautoplay')) {
|
||||
|
@ -1643,6 +1654,31 @@ function tryRemoveElement(elem) {
|
|||
return null;
|
||||
}
|
||||
|
||||
getSupportedPlaybackRates() {
|
||||
return [{
|
||||
name: '0.5x',
|
||||
id: 0.5
|
||||
}, {
|
||||
name: '0.75x',
|
||||
id: 0.75
|
||||
}, {
|
||||
name: '1x',
|
||||
id: 1.0
|
||||
}, {
|
||||
name: '1.25x',
|
||||
id: 1.25
|
||||
}, {
|
||||
name: '1.5x',
|
||||
id: 1.5
|
||||
}, {
|
||||
name: '1.75x',
|
||||
id: 1.75
|
||||
}, {
|
||||
name: '2x',
|
||||
id: 2.0
|
||||
}];
|
||||
}
|
||||
|
||||
setVolume(val) {
|
||||
const mediaElement = this.#mediaElement;
|
||||
if (mediaElement) {
|
||||
|
@ -1683,7 +1719,7 @@ function tryRemoveElement(elem) {
|
|||
setAspectRatio(val) {
|
||||
const mediaElement = this.#mediaElement;
|
||||
if (mediaElement) {
|
||||
if ('auto' === val) {
|
||||
if (val === 'auto') {
|
||||
mediaElement.style.removeProperty('object-fit');
|
||||
} else {
|
||||
mediaElement.style['object-fit'] = val;
|
||||
|
|
|
@ -33,16 +33,22 @@ video::-webkit-media-controls {
|
|||
text-shadow: 0.14em 0.14em 0.14em rgba(0, 0, 0, 1);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-family: inherit;
|
||||
line-height: normal; /* Restore value. See -webkit-media-text-track-container 'line-height' */
|
||||
}
|
||||
|
||||
.htmlvideoplayer-moveupsubtitles::-webkit-media-text-track-display {
|
||||
/* style the text itself */
|
||||
margin-top: -2em;
|
||||
.htmlvideoplayer::-webkit-media-text-track-container {
|
||||
font-size: 170% !important; /* Override element inline style */
|
||||
line-height: 50%; /* Child element cannot set line height smaller than its parent has. This allow smaller values for children */
|
||||
}
|
||||
|
||||
.htmlvideoplayer::-webkit-media-text-track-display {
|
||||
max-width: 70%;
|
||||
margin-left: 15%;
|
||||
}
|
||||
|
||||
.videoSubtitles {
|
||||
position: fixed;
|
||||
bottom: 10%;
|
||||
bottom: 0;
|
||||
text-align: center;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
@ -53,7 +59,6 @@ video::-webkit-media-controls {
|
|||
.videoSubtitlesInner {
|
||||
max-width: 70%;
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
padding: 0.25em;
|
||||
margin: auto;
|
||||
display: inline-block;
|
||||
}
|
||||
|
|
|
@ -1,165 +1,165 @@
|
|||
define(['pluginManager'], function (pluginManager) {
|
||||
return function () {
|
||||
var self = this;
|
||||
import pluginManager from 'pluginManager';
|
||||
|
||||
self.name = 'Logo ScreenSaver';
|
||||
self.type = 'screensaver';
|
||||
self.id = 'logoscreensaver';
|
||||
self.supportsAnonymous = true;
|
||||
export default function () {
|
||||
const self = this;
|
||||
|
||||
var interval;
|
||||
self.name = 'Logo ScreenSaver';
|
||||
self.type = 'screensaver';
|
||||
self.id = 'logoscreensaver';
|
||||
self.supportsAnonymous = true;
|
||||
|
||||
function animate() {
|
||||
var animations = [
|
||||
let interval;
|
||||
|
||||
bounceInLeft,
|
||||
bounceInRight,
|
||||
swing,
|
||||
tada,
|
||||
wobble,
|
||||
rotateIn,
|
||||
rotateOut
|
||||
];
|
||||
function animate() {
|
||||
const animations = [
|
||||
|
||||
var elem = document.querySelector('.logoScreenSaverImage');
|
||||
bounceInLeft,
|
||||
bounceInRight,
|
||||
swing,
|
||||
tada,
|
||||
wobble,
|
||||
rotateIn,
|
||||
rotateOut
|
||||
];
|
||||
|
||||
if (elem && elem.animate) {
|
||||
var random = getRandomInt(0, animations.length - 1);
|
||||
const elem = document.querySelector('.logoScreenSaverImage');
|
||||
|
||||
animations[random](elem, 1);
|
||||
if (elem && elem.animate) {
|
||||
const random = getRandomInt(0, animations.length - 1);
|
||||
|
||||
animations[random](elem, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function getRandomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function bounceInLeft(elem, iterations) {
|
||||
const keyframes = [
|
||||
{ transform: 'translate3d(-3000px, 0, 0)', opacity: '0', offset: 0 },
|
||||
{ transform: 'translate3d(25px, 0, 0)', opacity: '1', offset: 0.6 },
|
||||
{ transform: 'translate3d(-100px, 0, 0)', offset: 0.75 },
|
||||
{ transform: 'translate3d(5px, 0, 0)', offset: 0.9 },
|
||||
{ transform: 'none', opacity: '1', offset: 1 }];
|
||||
const timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function bounceInRight(elem, iterations) {
|
||||
const keyframes = [
|
||||
{ transform: 'translate3d(3000px, 0, 0)', opacity: '0', offset: 0 },
|
||||
{ transform: 'translate3d(-25px, 0, 0)', opacity: '1', offset: 0.6 },
|
||||
{ transform: 'translate3d(100px, 0, 0)', offset: 0.75 },
|
||||
{ transform: 'translate3d(-5px, 0, 0)', offset: 0.9 },
|
||||
{ transform: 'none', opacity: '1', offset: 1 }];
|
||||
const timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function swing(elem, iterations) {
|
||||
const keyframes = [
|
||||
{ transform: 'translate(0%)', offset: 0 },
|
||||
{ transform: 'rotate3d(0, 0, 1, 15deg)', offset: 0.2 },
|
||||
{ transform: 'rotate3d(0, 0, 1, -10deg)', offset: 0.4 },
|
||||
{ transform: 'rotate3d(0, 0, 1, 5deg)', offset: 0.6 },
|
||||
{ transform: 'rotate3d(0, 0, 1, -5deg)', offset: 0.8 },
|
||||
{ transform: 'rotate3d(0, 0, 1, 0deg)', offset: 1 }];
|
||||
const timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function tada(elem, iterations) {
|
||||
const keyframes = [
|
||||
{ transform: 'scale3d(1, 1, 1)', offset: 0 },
|
||||
{ transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.1 },
|
||||
{ transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.2 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.3 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.4 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.5 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.6 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.7 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.8 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.9 },
|
||||
{ transform: 'scale3d(1, 1, 1)', offset: 1 }];
|
||||
const timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function wobble(elem, iterations) {
|
||||
const keyframes = [
|
||||
{ transform: 'translate(0%)', offset: 0 },
|
||||
{ transform: 'translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg)', offset: 0.15 },
|
||||
{ transform: 'translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg)', offset: 0.45 },
|
||||
{ transform: 'translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg)', offset: 0.6 },
|
||||
{ transform: 'translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg)', offset: 0.75 },
|
||||
{ transform: 'translateX(0%)', offset: 1 }];
|
||||
const timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function rotateIn(elem, iterations) {
|
||||
const keyframes = [{ transform: 'rotate3d(0, 0, 1, -200deg)', opacity: '0', transformOrigin: 'center', offset: 0 },
|
||||
{ transform: 'none', opacity: '1', transformOrigin: 'center', offset: 1 }];
|
||||
const timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function rotateOut(elem, iterations) {
|
||||
const keyframes = [{ transform: 'none', opacity: '1', transformOrigin: 'center', offset: 0 },
|
||||
{ transform: 'rotate3d(0, 0, 1, 200deg)', opacity: '0', transformOrigin: 'center', offset: 1 }];
|
||||
const timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function fadeOut(elem, iterations) {
|
||||
const keyframes = [
|
||||
{ opacity: '1', offset: 0 },
|
||||
{ opacity: '0', offset: 1 }];
|
||||
const timing = { duration: 400, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function stopInterval() {
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
interval = null;
|
||||
}
|
||||
}
|
||||
|
||||
self.show = function () {
|
||||
import('css!' + pluginManager.mapPath(self, 'style.css')).then(() => {
|
||||
let elem = document.querySelector('.logoScreenSaver');
|
||||
|
||||
if (!elem) {
|
||||
elem = document.createElement('div');
|
||||
elem.classList.add('logoScreenSaver');
|
||||
document.body.appendChild(elem);
|
||||
|
||||
elem.innerHTML = '<img class="logoScreenSaverImage" src="assets/img/banner-light.png" />';
|
||||
}
|
||||
}
|
||||
|
||||
function getRandomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function bounceInLeft(elem, iterations) {
|
||||
var keyframes = [
|
||||
{ transform: 'translate3d(-3000px, 0, 0)', opacity: '0', offset: 0 },
|
||||
{ transform: 'translate3d(25px, 0, 0)', opacity: '1', offset: 0.6 },
|
||||
{ transform: 'translate3d(-100px, 0, 0)', offset: 0.75 },
|
||||
{ transform: 'translate3d(5px, 0, 0)', offset: 0.9 },
|
||||
{ transform: 'none', opacity: '1', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function bounceInRight(elem, iterations) {
|
||||
var keyframes = [
|
||||
{ transform: 'translate3d(3000px, 0, 0)', opacity: '0', offset: 0 },
|
||||
{ transform: 'translate3d(-25px, 0, 0)', opacity: '1', offset: 0.6 },
|
||||
{ transform: 'translate3d(100px, 0, 0)', offset: 0.75 },
|
||||
{ transform: 'translate3d(-5px, 0, 0)', offset: 0.9 },
|
||||
{ transform: 'none', opacity: '1', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function swing(elem, iterations) {
|
||||
var keyframes = [
|
||||
{ transform: 'translate(0%)', offset: 0 },
|
||||
{ transform: 'rotate3d(0, 0, 1, 15deg)', offset: 0.2 },
|
||||
{ transform: 'rotate3d(0, 0, 1, -10deg)', offset: 0.4 },
|
||||
{ transform: 'rotate3d(0, 0, 1, 5deg)', offset: 0.6 },
|
||||
{ transform: 'rotate3d(0, 0, 1, -5deg)', offset: 0.8 },
|
||||
{ transform: 'rotate3d(0, 0, 1, 0deg)', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function tada(elem, iterations) {
|
||||
var keyframes = [
|
||||
{ transform: 'scale3d(1, 1, 1)', offset: 0 },
|
||||
{ transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.1 },
|
||||
{ transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.2 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.3 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.4 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.5 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.6 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.7 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.8 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.9 },
|
||||
{ transform: 'scale3d(1, 1, 1)', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function wobble(elem, iterations) {
|
||||
var keyframes = [
|
||||
{ transform: 'translate(0%)', offset: 0 },
|
||||
{ transform: 'translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg)', offset: 0.15 },
|
||||
{ transform: 'translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg)', offset: 0.45 },
|
||||
{ transform: 'translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg)', offset: 0.6 },
|
||||
{ transform: 'translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg)', offset: 0.75 },
|
||||
{ transform: 'translateX(0%)', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function rotateIn(elem, iterations) {
|
||||
var keyframes = [{ transform: 'rotate3d(0, 0, 1, -200deg)', opacity: '0', transformOrigin: 'center', offset: 0 },
|
||||
{ transform: 'none', opacity: '1', transformOrigin: 'center', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function rotateOut(elem, iterations) {
|
||||
var keyframes = [{ transform: 'none', opacity: '1', transformOrigin: 'center', offset: 0 },
|
||||
{ transform: 'rotate3d(0, 0, 1, 200deg)', opacity: '0', transformOrigin: 'center', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function fadeOut(elem, iterations) {
|
||||
var keyframes = [
|
||||
{ opacity: '1', offset: 0 },
|
||||
{ opacity: '0', offset: 1 }];
|
||||
var timing = { duration: 400, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function stopInterval() {
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
interval = null;
|
||||
}
|
||||
}
|
||||
|
||||
self.show = function () {
|
||||
require(['css!' + pluginManager.mapPath(self, 'style.css')], function () {
|
||||
var elem = document.querySelector('.logoScreenSaver');
|
||||
|
||||
if (!elem) {
|
||||
elem = document.createElement('div');
|
||||
elem.classList.add('logoScreenSaver');
|
||||
document.body.appendChild(elem);
|
||||
|
||||
elem.innerHTML = '<img class="logoScreenSaverImage" src="assets/img/banner-light.png" />';
|
||||
}
|
||||
|
||||
stopInterval();
|
||||
interval = setInterval(animate, 3000);
|
||||
});
|
||||
};
|
||||
|
||||
self.hide = function () {
|
||||
stopInterval();
|
||||
|
||||
var elem = document.querySelector('.logoScreenSaver');
|
||||
|
||||
if (elem) {
|
||||
var onAnimationFinish = function () {
|
||||
elem.parentNode.removeChild(elem);
|
||||
};
|
||||
|
||||
if (elem.animate) {
|
||||
var animation = fadeOut(elem, 1);
|
||||
animation.onfinish = onAnimationFinish;
|
||||
} else {
|
||||
onAnimationFinish();
|
||||
}
|
||||
}
|
||||
};
|
||||
interval = setInterval(animate, 3000);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
self.hide = function () {
|
||||
stopInterval();
|
||||
|
||||
const elem = document.querySelector('.logoScreenSaver');
|
||||
|
||||
if (elem) {
|
||||
const onAnimationFinish = function () {
|
||||
elem.parentNode.removeChild(elem);
|
||||
};
|
||||
|
||||
if (elem.animate) {
|
||||
const animation = fadeOut(elem, 1);
|
||||
animation.onfinish = onAnimationFinish;
|
||||
} else {
|
||||
onAnimationFinish();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,33 +1,26 @@
|
|||
define(['connectionManager', 'globalize'], function (connectionManager, globalize) {
|
||||
'use strict';
|
||||
import connectionManager from 'connectionManager';
|
||||
import globalize from 'globalize';
|
||||
|
||||
function getRequirePromise(deps) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(deps, resolve);
|
||||
});
|
||||
}
|
||||
function showErrorMessage() {
|
||||
return import('alert').then(({default: alert}) => {
|
||||
return alert(globalize.translate('MessagePlayAccessRestricted'));
|
||||
});
|
||||
}
|
||||
|
||||
function showErrorMessage() {
|
||||
return getRequirePromise(['alert']).then(function (alert) {
|
||||
return alert(globalize.translate('MessagePlayAccessRestricted')).then(function () {
|
||||
return Promise.reject();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function PlayAccessValidation() {
|
||||
class PlayAccessValidation {
|
||||
constructor() {
|
||||
this.name = 'Playback validation';
|
||||
this.type = 'preplayintercept';
|
||||
this.id = 'playaccessvalidation';
|
||||
this.order = -2;
|
||||
}
|
||||
|
||||
PlayAccessValidation.prototype.intercept = function (options) {
|
||||
var item = options.item;
|
||||
intercept(options) {
|
||||
const item = options.item;
|
||||
if (!item) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
var serverId = item.ServerId;
|
||||
const serverId = item.ServerId;
|
||||
if (!serverId) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
@ -44,7 +37,7 @@ define(['connectionManager', 'globalize'], function (connectionManager, globaliz
|
|||
|
||||
return showErrorMessage();
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return PlayAccessValidation;
|
||||
});
|
||||
export default PlayAccessValidation;
|
||||
|
|
|
@ -1,129 +1,123 @@
|
|||
define(['playbackManager', 'events', 'serverNotifications', 'connectionManager'], function (playbackManager, events, serverNotifications, connectionManager) {
|
||||
'use strict';
|
||||
import playbackManager from 'playbackManager';
|
||||
import events from 'events';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import connectionManager from 'connectionManager';
|
||||
|
||||
function getActivePlayerId() {
|
||||
var info = playbackManager.getPlayerInfo();
|
||||
return info ? info.id : null;
|
||||
function getActivePlayerId() {
|
||||
const info = playbackManager.getPlayerInfo();
|
||||
return info ? info.id : null;
|
||||
}
|
||||
|
||||
function sendPlayCommand(apiClient, options, playType) {
|
||||
const sessionId = getActivePlayerId();
|
||||
|
||||
const ids = options.ids || options.items.map(function (i) {
|
||||
return i.Id;
|
||||
});
|
||||
|
||||
const remoteOptions = {
|
||||
ItemIds: ids.join(','),
|
||||
|
||||
PlayCommand: playType
|
||||
};
|
||||
|
||||
if (options.startPositionTicks) {
|
||||
remoteOptions.StartPositionTicks = options.startPositionTicks;
|
||||
}
|
||||
|
||||
function sendPlayCommand(apiClient, options, playType) {
|
||||
var sessionId = getActivePlayerId();
|
||||
|
||||
var ids = options.ids || options.items.map(function (i) {
|
||||
return i.Id;
|
||||
});
|
||||
|
||||
var remoteOptions = {
|
||||
ItemIds: ids.join(','),
|
||||
|
||||
PlayCommand: playType
|
||||
};
|
||||
|
||||
if (options.startPositionTicks) {
|
||||
remoteOptions.StartPositionTicks = options.startPositionTicks;
|
||||
}
|
||||
|
||||
if (options.mediaSourceId) {
|
||||
remoteOptions.MediaSourceId = options.mediaSourceId;
|
||||
}
|
||||
|
||||
if (options.audioStreamIndex != null) {
|
||||
remoteOptions.AudioStreamIndex = options.audioStreamIndex;
|
||||
}
|
||||
|
||||
if (options.subtitleStreamIndex != null) {
|
||||
remoteOptions.SubtitleStreamIndex = options.subtitleStreamIndex;
|
||||
}
|
||||
|
||||
if (options.startIndex != null) {
|
||||
remoteOptions.StartIndex = options.startIndex;
|
||||
}
|
||||
|
||||
return apiClient.sendPlayCommand(sessionId, remoteOptions);
|
||||
if (options.mediaSourceId) {
|
||||
remoteOptions.MediaSourceId = options.mediaSourceId;
|
||||
}
|
||||
|
||||
function sendPlayStateCommand(apiClient, command, options) {
|
||||
var sessionId = getActivePlayerId();
|
||||
|
||||
apiClient.sendPlayStateCommand(sessionId, command, options);
|
||||
if (options.audioStreamIndex != null) {
|
||||
remoteOptions.AudioStreamIndex = options.audioStreamIndex;
|
||||
}
|
||||
|
||||
function getCurrentApiClient(instance) {
|
||||
var currentServerId = instance.currentServerId;
|
||||
|
||||
if (currentServerId) {
|
||||
return connectionManager.getApiClient(currentServerId);
|
||||
}
|
||||
|
||||
return connectionManager.currentApiClient();
|
||||
if (options.subtitleStreamIndex != null) {
|
||||
remoteOptions.SubtitleStreamIndex = options.subtitleStreamIndex;
|
||||
}
|
||||
|
||||
function sendCommandByName(instance, name, options) {
|
||||
var command = {
|
||||
Name: name
|
||||
};
|
||||
|
||||
if (options) {
|
||||
command.Arguments = options;
|
||||
}
|
||||
|
||||
instance.sendCommand(command);
|
||||
if (options.startIndex != null) {
|
||||
remoteOptions.StartIndex = options.startIndex;
|
||||
}
|
||||
|
||||
function unsubscribeFromPlayerUpdates(instance) {
|
||||
instance.isUpdating = true;
|
||||
return apiClient.sendPlayCommand(sessionId, remoteOptions);
|
||||
}
|
||||
|
||||
var apiClient = getCurrentApiClient(instance);
|
||||
apiClient.sendMessage('SessionsStop');
|
||||
if (instance.pollInterval) {
|
||||
clearInterval(instance.pollInterval);
|
||||
instance.pollInterval = null;
|
||||
}
|
||||
function sendPlayStateCommand(apiClient, command, options) {
|
||||
const sessionId = getActivePlayerId();
|
||||
|
||||
apiClient.sendPlayStateCommand(sessionId, command, options);
|
||||
}
|
||||
|
||||
function getCurrentApiClient(instance) {
|
||||
const currentServerId = instance.currentServerId;
|
||||
|
||||
if (currentServerId) {
|
||||
return connectionManager.getApiClient(currentServerId);
|
||||
}
|
||||
|
||||
function processUpdatedSessions(instance, sessions, apiClient) {
|
||||
var serverId = apiClient.serverId();
|
||||
return connectionManager.currentApiClient();
|
||||
}
|
||||
|
||||
sessions.map(function (s) {
|
||||
if (s.NowPlayingItem) {
|
||||
s.NowPlayingItem.ServerId = serverId;
|
||||
}
|
||||
});
|
||||
function sendCommandByName(instance, name, options) {
|
||||
const command = {
|
||||
Name: name
|
||||
};
|
||||
|
||||
var currentTargetId = getActivePlayerId();
|
||||
|
||||
var session = sessions.filter(function (s) {
|
||||
return s.Id === currentTargetId;
|
||||
})[0];
|
||||
|
||||
if (session) {
|
||||
normalizeImages(session, apiClient);
|
||||
|
||||
var eventNames = getChangedEvents(instance.lastPlayerData, session);
|
||||
instance.lastPlayerData = session;
|
||||
|
||||
for (var i = 0, length = eventNames.length; i < length; i++) {
|
||||
events.trigger(instance, eventNames[i], [session]);
|
||||
}
|
||||
} else {
|
||||
instance.lastPlayerData = session;
|
||||
|
||||
playbackManager.setDefaultPlayerActive();
|
||||
}
|
||||
if (options) {
|
||||
command.Arguments = options;
|
||||
}
|
||||
|
||||
function getChangedEvents(state1, state2) {
|
||||
var names = [];
|
||||
instance.sendCommand(command);
|
||||
}
|
||||
|
||||
if (!state1) {
|
||||
names.push('statechange');
|
||||
names.push('timeupdate');
|
||||
names.push('pause');
|
||||
function unsubscribeFromPlayerUpdates(instance) {
|
||||
instance.isUpdating = true;
|
||||
|
||||
return names;
|
||||
const apiClient = getCurrentApiClient(instance);
|
||||
apiClient.sendMessage('SessionsStop');
|
||||
if (instance.pollInterval) {
|
||||
clearInterval(instance.pollInterval);
|
||||
instance.pollInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
function processUpdatedSessions(instance, sessions, apiClient) {
|
||||
const serverId = apiClient.serverId();
|
||||
|
||||
sessions.map(function (s) {
|
||||
if (s.NowPlayingItem) {
|
||||
s.NowPlayingItem.ServerId = serverId;
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: Trim these down to prevent the UI from over-refreshing
|
||||
const currentTargetId = getActivePlayerId();
|
||||
|
||||
const session = sessions.filter(function (s) {
|
||||
return s.Id === currentTargetId;
|
||||
})[0];
|
||||
|
||||
if (session) {
|
||||
normalizeImages(session, apiClient);
|
||||
|
||||
const eventNames = getChangedEvents(instance.lastPlayerData, session);
|
||||
instance.lastPlayerData = session;
|
||||
|
||||
for (let i = 0, length = eventNames.length; i < length; i++) {
|
||||
events.trigger(instance, eventNames[i], [session]);
|
||||
}
|
||||
} else {
|
||||
instance.lastPlayerData = session;
|
||||
|
||||
playbackManager.setDefaultPlayerActive();
|
||||
}
|
||||
}
|
||||
|
||||
function getChangedEvents(state1, state2) {
|
||||
const names = [];
|
||||
|
||||
if (!state1) {
|
||||
names.push('statechange');
|
||||
names.push('timeupdate');
|
||||
names.push('pause');
|
||||
|
@ -131,53 +125,62 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
|
|||
return names;
|
||||
}
|
||||
|
||||
function onPollIntervalFired() {
|
||||
var instance = this;
|
||||
var apiClient = getCurrentApiClient(instance);
|
||||
if (!apiClient.isMessageChannelOpen()) {
|
||||
apiClient.getSessions().then(function (sessions) {
|
||||
processUpdatedSessions(instance, sessions, apiClient);
|
||||
});
|
||||
}
|
||||
// TODO: Trim these down to prevent the UI from over-refreshing
|
||||
names.push('statechange');
|
||||
names.push('timeupdate');
|
||||
names.push('pause');
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
function onPollIntervalFired() {
|
||||
const instance = this;
|
||||
const apiClient = getCurrentApiClient(instance);
|
||||
if (!apiClient.isMessageChannelOpen()) {
|
||||
apiClient.getSessions().then(function (sessions) {
|
||||
processUpdatedSessions(instance, sessions, apiClient);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function subscribeToPlayerUpdates(instance) {
|
||||
instance.isUpdating = true;
|
||||
function subscribeToPlayerUpdates(instance) {
|
||||
instance.isUpdating = true;
|
||||
|
||||
var apiClient = getCurrentApiClient(instance);
|
||||
apiClient.sendMessage('SessionsStart', '100,800');
|
||||
if (instance.pollInterval) {
|
||||
clearInterval(instance.pollInterval);
|
||||
instance.pollInterval = null;
|
||||
}
|
||||
instance.pollInterval = setInterval(onPollIntervalFired.bind(instance), 5000);
|
||||
const apiClient = getCurrentApiClient(instance);
|
||||
apiClient.sendMessage('SessionsStart', '100,800');
|
||||
if (instance.pollInterval) {
|
||||
clearInterval(instance.pollInterval);
|
||||
instance.pollInterval = null;
|
||||
}
|
||||
instance.pollInterval = setInterval(onPollIntervalFired.bind(instance), 5000);
|
||||
}
|
||||
|
||||
function normalizeImages(state, apiClient) {
|
||||
if (state && state.NowPlayingItem) {
|
||||
var item = state.NowPlayingItem;
|
||||
function normalizeImages(state, apiClient) {
|
||||
if (state && state.NowPlayingItem) {
|
||||
const item = state.NowPlayingItem;
|
||||
|
||||
if (!item.ImageTags || !item.ImageTags.Primary) {
|
||||
if (item.PrimaryImageTag) {
|
||||
item.ImageTags = item.ImageTags || {};
|
||||
item.ImageTags.Primary = item.PrimaryImageTag;
|
||||
}
|
||||
}
|
||||
if (item.BackdropImageTag && item.BackdropItemId === item.Id) {
|
||||
item.BackdropImageTags = [item.BackdropImageTag];
|
||||
}
|
||||
if (item.BackdropImageTag && item.BackdropItemId !== item.Id) {
|
||||
item.ParentBackdropImageTags = [item.BackdropImageTag];
|
||||
item.ParentBackdropItemId = item.BackdropItemId;
|
||||
}
|
||||
if (!item.ServerId) {
|
||||
item.ServerId = apiClient.serverId();
|
||||
if (!item.ImageTags || !item.ImageTags.Primary) {
|
||||
if (item.PrimaryImageTag) {
|
||||
item.ImageTags = item.ImageTags || {};
|
||||
item.ImageTags.Primary = item.PrimaryImageTag;
|
||||
}
|
||||
}
|
||||
if (item.BackdropImageTag && item.BackdropItemId === item.Id) {
|
||||
item.BackdropImageTags = [item.BackdropImageTag];
|
||||
}
|
||||
if (item.BackdropImageTag && item.BackdropItemId !== item.Id) {
|
||||
item.ParentBackdropImageTags = [item.BackdropImageTag];
|
||||
item.ParentBackdropItemId = item.BackdropItemId;
|
||||
}
|
||||
if (!item.ServerId) {
|
||||
item.ServerId = apiClient.serverId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function SessionPlayer() {
|
||||
var self = this;
|
||||
class SessionPlayer {
|
||||
constructor() {
|
||||
const self = this;
|
||||
|
||||
this.name = 'Remote Control';
|
||||
this.type = 'mediaplayer';
|
||||
|
@ -189,7 +192,7 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
|
|||
});
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.beginPlayerUpdates = function () {
|
||||
beginPlayerUpdates() {
|
||||
this.playerListenerCount = this.playerListenerCount || 0;
|
||||
|
||||
if (this.playerListenerCount <= 0) {
|
||||
|
@ -199,9 +202,9 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
|
|||
}
|
||||
|
||||
this.playerListenerCount++;
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.endPlayerUpdates = function () {
|
||||
endPlayerUpdates() {
|
||||
this.playerListenerCount = this.playerListenerCount || 0;
|
||||
this.playerListenerCount--;
|
||||
|
||||
|
@ -209,21 +212,21 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
|
|||
unsubscribeFromPlayerUpdates(this);
|
||||
this.playerListenerCount = 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.getPlayerState = function () {
|
||||
getPlayerState() {
|
||||
return this.lastPlayerData || {};
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.getTargets = function () {
|
||||
var apiClient = getCurrentApiClient(this);
|
||||
getTargets() {
|
||||
const apiClient = getCurrentApiClient(this);
|
||||
|
||||
var sessionQuery = {
|
||||
const sessionQuery = {
|
||||
ControllableByUserId: apiClient.getCurrentUserId()
|
||||
};
|
||||
|
||||
if (apiClient) {
|
||||
var name = this.name;
|
||||
const name = this.name;
|
||||
|
||||
return apiClient.getSessions(sessionQuery).then(function (sessions) {
|
||||
return sessions.filter(function (s) {
|
||||
|
@ -240,11 +243,9 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
|
|||
isLocalPlayer: false,
|
||||
supportedCommands: s.Capabilities.SupportedCommands,
|
||||
user: s.UserId ? {
|
||||
|
||||
Id: s.UserId,
|
||||
Name: s.UserName,
|
||||
PrimaryImageTag: s.UserPrimaryImageTag
|
||||
|
||||
} : null
|
||||
};
|
||||
});
|
||||
|
@ -252,16 +253,16 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
|
|||
} else {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.sendCommand = function (command) {
|
||||
var sessionId = getActivePlayerId();
|
||||
sendCommand(command) {
|
||||
const sessionId = getActivePlayerId();
|
||||
|
||||
var apiClient = getCurrentApiClient(this);
|
||||
const apiClient = getCurrentApiClient(this);
|
||||
apiClient.sendCommand(sessionId, command);
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.play = function (options) {
|
||||
play(options) {
|
||||
options = Object.assign({}, options);
|
||||
|
||||
if (options.items) {
|
||||
|
@ -273,251 +274,233 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
|
|||
}
|
||||
|
||||
return sendPlayCommand(getCurrentApiClient(this), options, 'PlayNow');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.shuffle = function (item) {
|
||||
shuffle(item) {
|
||||
sendPlayCommand(getCurrentApiClient(this), { ids: [item.Id] }, 'PlayShuffle');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.instantMix = function (item) {
|
||||
instantMix(item) {
|
||||
sendPlayCommand(getCurrentApiClient(this), { ids: [item.Id] }, 'PlayInstantMix');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.queue = function (options) {
|
||||
queue(options) {
|
||||
sendPlayCommand(getCurrentApiClient(this), options, 'PlayNext');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.queueNext = function (options) {
|
||||
queueNext(options) {
|
||||
sendPlayCommand(getCurrentApiClient(this), options, 'PlayLast');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.canPlayMediaType = function (mediaType) {
|
||||
canPlayMediaType(mediaType) {
|
||||
mediaType = (mediaType || '').toLowerCase();
|
||||
return mediaType === 'audio' || mediaType === 'video';
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.canQueueMediaType = function (mediaType) {
|
||||
canQueueMediaType(mediaType) {
|
||||
return this.canPlayMediaType(mediaType);
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.stop = function () {
|
||||
stop() {
|
||||
sendPlayStateCommand(getCurrentApiClient(this), 'stop');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.nextTrack = function () {
|
||||
nextTrack() {
|
||||
sendPlayStateCommand(getCurrentApiClient(this), 'nextTrack');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.previousTrack = function () {
|
||||
previousTrack() {
|
||||
sendPlayStateCommand(getCurrentApiClient(this), 'previousTrack');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.seek = function (positionTicks) {
|
||||
seek(positionTicks) {
|
||||
sendPlayStateCommand(getCurrentApiClient(this), 'seek',
|
||||
{
|
||||
SeekPositionTicks: positionTicks
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.currentTime = function (val) {
|
||||
currentTime(val) {
|
||||
if (val != null) {
|
||||
return this.seek(val);
|
||||
}
|
||||
|
||||
var state = this.lastPlayerData || {};
|
||||
let state = this.lastPlayerData || {};
|
||||
state = state.PlayState || {};
|
||||
return state.PositionTicks;
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.duration = function () {
|
||||
var state = this.lastPlayerData || {};
|
||||
duration() {
|
||||
let state = this.lastPlayerData || {};
|
||||
state = state.NowPlayingItem || {};
|
||||
return state.RunTimeTicks;
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.paused = function () {
|
||||
var state = this.lastPlayerData || {};
|
||||
paused() {
|
||||
let state = this.lastPlayerData || {};
|
||||
state = state.PlayState || {};
|
||||
return state.IsPaused;
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.getVolume = function () {
|
||||
var state = this.lastPlayerData || {};
|
||||
getVolume() {
|
||||
let state = this.lastPlayerData || {};
|
||||
state = state.PlayState || {};
|
||||
return state.VolumeLevel;
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.isMuted = function () {
|
||||
var state = this.lastPlayerData || {};
|
||||
isMuted() {
|
||||
let state = this.lastPlayerData || {};
|
||||
state = state.PlayState || {};
|
||||
return state.IsMuted;
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.pause = function () {
|
||||
pause() {
|
||||
sendPlayStateCommand(getCurrentApiClient(this), 'Pause');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.unpause = function () {
|
||||
unpause() {
|
||||
sendPlayStateCommand(getCurrentApiClient(this), 'Unpause');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.playPause = function () {
|
||||
playPause() {
|
||||
sendPlayStateCommand(getCurrentApiClient(this), 'PlayPause');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.setMute = function (isMuted) {
|
||||
setMute(isMuted) {
|
||||
if (isMuted) {
|
||||
sendCommandByName(this, 'Mute');
|
||||
} else {
|
||||
sendCommandByName(this, 'Unmute');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.toggleMute = function () {
|
||||
toggleMute() {
|
||||
sendCommandByName(this, 'ToggleMute');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.setVolume = function (vol) {
|
||||
setVolume(vol) {
|
||||
sendCommandByName(this, 'SetVolume', {
|
||||
Volume: vol
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.volumeUp = function () {
|
||||
volumeUp() {
|
||||
sendCommandByName(this, 'VolumeUp');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.volumeDown = function () {
|
||||
volumeDown() {
|
||||
sendCommandByName(this, 'VolumeDown');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.toggleFullscreen = function () {
|
||||
toggleFullscreen() {
|
||||
sendCommandByName(this, 'ToggleFullscreen');
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.audioTracks = function () {
|
||||
var state = this.lastPlayerData || {};
|
||||
audioTracks() {
|
||||
let state = this.lastPlayerData || {};
|
||||
state = state.NowPlayingItem || {};
|
||||
var streams = state.MediaStreams || [];
|
||||
const streams = state.MediaStreams || [];
|
||||
return streams.filter(function (s) {
|
||||
return s.Type === 'Audio';
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.getAudioStreamIndex = function () {
|
||||
var state = this.lastPlayerData || {};
|
||||
getAudioStreamIndex() {
|
||||
let state = this.lastPlayerData || {};
|
||||
state = state.PlayState || {};
|
||||
return state.AudioStreamIndex;
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.playTrailers = function (item) {
|
||||
playTrailers(item) {
|
||||
sendCommandByName(this, 'PlayTrailers', {
|
||||
ItemId: item.Id
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.setAudioStreamIndex = function (index) {
|
||||
setAudioStreamIndex(index) {
|
||||
sendCommandByName(this, 'SetAudioStreamIndex', {
|
||||
Index: index
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.subtitleTracks = function () {
|
||||
var state = this.lastPlayerData || {};
|
||||
subtitleTracks() {
|
||||
let state = this.lastPlayerData || {};
|
||||
state = state.NowPlayingItem || {};
|
||||
var streams = state.MediaStreams || [];
|
||||
const streams = state.MediaStreams || [];
|
||||
return streams.filter(function (s) {
|
||||
return s.Type === 'Subtitle';
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.getSubtitleStreamIndex = function () {
|
||||
var state = this.lastPlayerData || {};
|
||||
getSubtitleStreamIndex() {
|
||||
let state = this.lastPlayerData || {};
|
||||
state = state.PlayState || {};
|
||||
return state.SubtitleStreamIndex;
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.setSubtitleStreamIndex = function (index) {
|
||||
setSubtitleStreamIndex(index) {
|
||||
sendCommandByName(this, 'SetSubtitleStreamIndex', {
|
||||
Index: index
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.getMaxStreamingBitrate = function () {
|
||||
|
||||
};
|
||||
|
||||
SessionPlayer.prototype.setMaxStreamingBitrate = function (options) {
|
||||
|
||||
};
|
||||
|
||||
SessionPlayer.prototype.isFullscreen = function () {
|
||||
|
||||
};
|
||||
|
||||
SessionPlayer.prototype.toggleFullscreen = function () {
|
||||
|
||||
};
|
||||
|
||||
SessionPlayer.prototype.getRepeatMode = function () {
|
||||
|
||||
};
|
||||
|
||||
SessionPlayer.prototype.setRepeatMode = function (mode) {
|
||||
setRepeatMode(mode) {
|
||||
sendCommandByName(this, 'SetRepeatMode', {
|
||||
RepeatMode: mode
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.setQueueShuffleMode = function (mode) {
|
||||
getRepeatMode() {
|
||||
}
|
||||
|
||||
setQueueShuffleMode(mode) {
|
||||
sendCommandByName(this, 'SetShuffleQueue', {
|
||||
ShuffleMode: mode
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.getQueueShuffleMode = function () {
|
||||
getQueueShuffleMode() {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
SessionPlayer.prototype.displayContent = function (options) {
|
||||
displayContent(options) {
|
||||
sendCommandByName(this, 'DisplayContent', options);
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.isPlaying = function () {
|
||||
var state = this.lastPlayerData || {};
|
||||
isPlaying() {
|
||||
const state = this.lastPlayerData || {};
|
||||
return state.NowPlayingItem != null;
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.isPlayingVideo = function () {
|
||||
var state = this.lastPlayerData || {};
|
||||
isPlayingVideo() {
|
||||
let state = this.lastPlayerData || {};
|
||||
state = state.NowPlayingItem || {};
|
||||
return state.MediaType === 'Video';
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.isPlayingAudio = function () {
|
||||
var state = this.lastPlayerData || {};
|
||||
isPlayingAudio() {
|
||||
let state = this.lastPlayerData || {};
|
||||
state = state.NowPlayingItem || {};
|
||||
return state.MediaType === 'Audio';
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.getPlaylist = function () {
|
||||
getPlaylist() {
|
||||
return Promise.resolve([]);
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.getCurrentPlaylistItemId = function () {
|
||||
};
|
||||
getCurrentPlaylistItemId() {
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.setCurrentPlaylistItem = function (playlistItemId) {
|
||||
setCurrentPlaylistItem(playlistItemId) {
|
||||
return Promise.resolve();
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.removeFromPlaylist = function (playlistItemIds) {
|
||||
removeFromPlaylist(playlistItemIds) {
|
||||
return Promise.resolve();
|
||||
};
|
||||
}
|
||||
|
||||
SessionPlayer.prototype.tryPair = function (target) {
|
||||
tryPair(target) {
|
||||
return Promise.resolve();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return SessionPlayer;
|
||||
});
|
||||
export default SessionPlayer;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue