1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Merge remote-tracking branch 'upstream/master' into fix-subtitle-line-spacing

Conflicts:
	src/components/subtitlesettings/subtitleappearancehelper.js
	src/plugins/htmlVideoPlayer/plugin.js
This commit is contained in:
Dmitry Lyzo 2020-07-30 17:49:07 +03:00
commit 48886918d3
278 changed files with 2125 additions and 5109 deletions

View file

@ -6,7 +6,6 @@ let currentDisplayText = '';
let currentDisplayTextContainer;
function onKeyDown(e) {
if (e.ctrlKey) {
return;
}
@ -21,7 +20,6 @@ function onKeyDown(e) {
let chr = key ? alphanumeric(key) : null;
if (chr) {
chr = chr.toString().toUpperCase();
if (chr.length === 1) {
@ -82,12 +80,10 @@ function onAlphanumericShortcutTimeout() {
}
function selectByShortcutValue(container, value) {
value = value.toUpperCase();
let focusElem;
if (value === '#') {
focusElem = container.querySelector('*[data-prefix]');
}
@ -102,7 +98,6 @@ function selectByShortcutValue(container, value) {
class AlphaNumericShortcuts {
constructor(options) {
this.options = options;
const keyDownHandler = onKeyDown.bind(this);
@ -114,7 +109,6 @@ class AlphaNumericShortcuts {
this.keyDownHandler = keyDownHandler;
}
destroy() {
const keyDownHandler = this.keyDownHandler;
if (keyDownHandler) {

View file

@ -2,7 +2,6 @@ define([], function () {
'use strict';
function isTv() {
// This is going to be really difficult to get right
var userAgent = navigator.userAgent.toLowerCase();
@ -50,7 +49,6 @@ define([], function () {
}
function hasKeyboard(browser) {
if (browser.touch) {
return true;
}
@ -101,10 +99,7 @@ define([], function () {
}
var animation = false;
var animationstring = 'animation';
var keyframeprefix = '';
var domPrefixes = ['Webkit', 'O', 'Moz'];
var pfx = '';
var elm = document.createElement('div');
if (elm.style.animationName !== undefined) {
@ -114,9 +109,6 @@ define([], function () {
if (animation === false && allowPrefix) {
for (var i = 0; i < domPrefixes.length; i++) {
if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) {
pfx = domPrefixes[i];
animationstring = pfx + 'Animation';
keyframeprefix = '-' + pfx.toLowerCase() + '-';
animation = true;
break;
}
@ -135,7 +127,10 @@ define([], function () {
var uaMatch = function (ua) {
ua = ua.toLowerCase();
var match = /(edge)[ \/]([\w.]+)/.exec(ua) ||
var match = /(edg)[ \/]([\w.]+)/.exec(ua) ||
/(edga)[ \/]([\w.]+)/.exec(ua) ||
/(edgios)[ \/]([\w.]+)/.exec(ua) ||
/(edge)[ \/]([\w.]+)/.exec(ua) ||
/(opera)[ \/]([\w.]+)/.exec(ua) ||
/(opr)[ \/]([\w.]+)/.exec(ua) ||
/(chrome)[ \/]([\w.]+)/.exec(ua) ||
@ -198,7 +193,9 @@ define([], function () {
browser[matched.platform] = true;
}
if (!browser.chrome && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf('webkit') !== -1) {
browser.edgeChromium = browser.edg || browser.edga || browser.edgios;
if (!browser.chrome && !browser.edgeChromium && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf('webkit') !== -1) {
browser.safari = true;
}
@ -259,7 +256,5 @@ define([], function () {
}
}
browser.chromecast = browser.chrome && userAgent.toLowerCase().indexOf('crkey') !== -1;
return browser;
});

View file

@ -144,6 +144,10 @@ define(['browser'], function (browser) {
return true;
}
if (browser.edgeChromium && browser.windows) {
return true;
}
if (browser.edgeUwp) {
return true;
}
@ -210,7 +214,7 @@ define(['browser'], function (browser) {
supported = browser.tizen;
break;
case 'mov':
supported = browser.tizen || browser.web0s || browser.chrome || browser.edgeUwp;
supported = browser.tizen || browser.web0s || browser.chrome || browser.edgeChromium || browser.edgeUwp;
videoCodecs.push('h264');
break;
case 'm2ts':
@ -323,7 +327,6 @@ define(['browser'], function (browser) {
// Otherwise with HLS and mp3 audio we're seeing some browsers
// safari is lying
if (supportsAc3(videoTestElement)) {
videoAudioCodecs.push('ac3');
var eAc3 = supportsEac3(videoTestElement);
@ -505,7 +508,6 @@ define(['browser'], function (browser) {
});
['opus', 'mp3', 'mp2', 'aac', 'flac', 'alac', 'webma', 'wma', 'wav', 'ogg', 'oga'].filter(canPlayAudioFormat).forEach(function (audioFormat) {
if (audioFormat === 'mp2') {
profile.DirectPlayProfiles.push({
Container: 'mp2,mp3',
@ -703,40 +705,35 @@ define(['browser'], function (browser) {
if (browser.tizen ||
videoTestElement.canPlayType('video/mp4; codecs="avc1.6e0033"').replace(/no/, '')) {
// These tests are passing in safari, but playback is failing
if (!browser.safari && !browser.iOS && !browser.web0s && !browser.edge && !browser.mobile) {
h264Profiles += '|high 10';
}
}
profile.CodecProfiles.push({
Type: 'Video',
Codec: 'h264',
Conditions: [
{
Condition: 'NotEquals',
Property: 'IsAnamorphic',
Value: 'true',
IsRequired: false
},
{
Condition: 'EqualsAny',
Property: 'VideoProfile',
Value: h264Profiles,
IsRequired: false
},
{
Condition: 'LessThanEqual',
Property: 'VideoLevel',
Value: maxH264Level.toString(),
IsRequired: false
}
]
});
const h264CodecProfileConditions = [
{
Condition: 'NotEquals',
Property: 'IsAnamorphic',
Value: 'true',
IsRequired: false
},
{
Condition: 'EqualsAny',
Property: 'VideoProfile',
Value: h264Profiles,
IsRequired: false
},
{
Condition: 'LessThanEqual',
Property: 'VideoLevel',
Value: maxH264Level.toString(),
IsRequired: false
}
];
if (!browser.edgeUwp && !browser.tizen && !browser.web0s) {
profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({
h264CodecProfileConditions.push({
Condition: 'NotEquals',
Property: 'IsInterlaced',
Value: 'true',
@ -745,7 +742,7 @@ define(['browser'], function (browser) {
}
if (maxVideoWidth) {
profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({
h264CodecProfileConditions.push({
Condition: 'LessThanEqual',
Property: 'Width',
Value: maxVideoWidth.toString(),
@ -758,7 +755,7 @@ define(['browser'], function (browser) {
var h264MaxVideoBitrate = globalMaxVideoBitrate;
if (h264MaxVideoBitrate) {
profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({
h264CodecProfileConditions.push({
Condition: 'LessThanEqual',
Property: 'VideoBitrate',
Value: h264MaxVideoBitrate,
@ -766,6 +763,33 @@ define(['browser'], function (browser) {
});
}
// On iOS 12.x, for TS container max h264 level is 4.2
if (browser.iOS && browser.iOSVersion < 13) {
const codecProfile = {
Type: 'Video',
Codec: 'h264',
Container: 'ts',
Conditions: h264CodecProfileConditions.filter((condition) => {
return condition.Property !== 'VideoLevel';
})
};
codecProfile.Conditions.push({
Condition: 'LessThanEqual',
Property: 'VideoLevel',
Value: '42',
IsRequired: false
});
profile.CodecProfiles.push(codecProfile);
}
profile.CodecProfiles.push({
Type: 'Video',
Codec: 'h264',
Conditions: h264CodecProfileConditions
});
var globalVideoConditions = [];
if (globalMaxVideoBitrate) {

View file

@ -3,7 +3,6 @@ import globalize from 'globalize';
/* eslint-disable indent */
export function parseISO8601Date(s, toLocal) {
// parenthese matches:
// year month day hours minutes seconds
// dotmilliseconds
@ -20,7 +19,6 @@ import globalize from 'globalize';
// "00", "00", ".000", "Z", undefined, undefined, undefined]
if (!d) {
throw "Couldn't parse ISO 8601 date string '" + s + "'";
}
@ -106,7 +104,6 @@ import globalize from 'globalize';
}();
function getOptionList(options) {
const list = [];
for (const i in options) {
@ -120,7 +117,6 @@ import globalize from 'globalize';
}
export function toLocaleString(date, options) {
if (!date) {
throw new Error('date cannot be null');
}
@ -128,7 +124,6 @@ import globalize from 'globalize';
options = options || {};
if (toLocaleTimeStringSupportsLocales) {
const currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) {
@ -140,7 +135,6 @@ import globalize from 'globalize';
}
export function toLocaleDateString(date, options) {
if (!date) {
throw new Error('date cannot be null');
}
@ -148,7 +142,6 @@ import globalize from 'globalize';
options = options || {};
if (toLocaleTimeStringSupportsLocales) {
const currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) {
@ -174,7 +167,6 @@ import globalize from 'globalize';
}
export function toLocaleTimeString(date, options) {
if (!date) {
throw new Error('date cannot be null');
}
@ -182,7 +174,6 @@ import globalize from 'globalize';
options = options || {};
if (toLocaleTimeStringSupportsLocales) {
const currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) {
@ -194,16 +185,13 @@ import globalize from 'globalize';
}
export function getDisplayTime(date) {
if (!date) {
throw new Error('date cannot be null');
}
if ((typeof date).toString().toLowerCase() === 'string') {
try {
date = parseISO8601Date(date, true);
} catch (err) {
return date;
}
@ -223,7 +211,6 @@ import globalize from 'globalize';
const timeLower = time.toLowerCase();
if (timeLower.indexOf('am') !== -1 || timeLower.indexOf('pm') !== -1) {
time = timeLower;
let hour = date.getHours() % 12;
const suffix = date.getHours() > 11 ? 'pm' : 'am';
@ -239,12 +226,10 @@ import globalize from 'globalize';
minutes = ':' + minutes;
time = hour + minutes + suffix;
} else {
const timeParts = time.split(':');
// Trim off seconds
if (timeParts.length > 2) {
// setting to 2 also handles '21:00:28 GMT+9:30'
timeParts.length = 2;
time = timeParts.join(':');
@ -255,7 +240,6 @@ import globalize from 'globalize';
}
export function isRelativeDay(date, offsetInDays) {
if (!date) {
throw new Error('date cannot be null');
}

View file

@ -4,9 +4,7 @@ import appRouter from 'appRouter';
import globalize from 'globalize';
function alertText(options) {
return new Promise(function (resolve, reject) {
import('alert').then(({default: alert}) => {
alert(options).then(resolve, resolve);
});
@ -14,7 +12,6 @@ function alertText(options) {
}
export function deleteItem(options) {
const item = options.item;
const parentId = item.SeasonId || item.SeriesId || item.ParentId;
@ -28,9 +25,7 @@ export function deleteItem(options) {
primary: 'delete'
}).then(function () {
return apiClient.deleteItem(item.Id).then(function () {
if (options.navigate) {
if (parentId) {
appRouter.showItem(parentId, item.ServerId);
@ -39,7 +34,6 @@ export function deleteItem(options) {
}
}
}, function (err) {
let result = function () {
return Promise.reject(err);
};

View file

@ -1,4 +1,3 @@
import datetime from 'datetime';
import $ from 'jQuery';
import globalize from 'globalize';
import 'material-icons';
@ -303,6 +302,7 @@ import 'material-icons';
$(document).on('itemsaved', '.metadataEditorPage', function (e, item) {
updateEditorNode(this, item);
}).on('pagebeforeshow', '.metadataEditorPage', function () {
/* eslint-disable-next-line no-unused-expressions */
import('css!assets/css/metadataeditor.css');
}).on('pagebeforeshow', '.metadataEditorPage', function () {
var page = this;

View file

@ -1,7 +1,6 @@
import multiDownload from 'multi-download';
export function download(items) {
if (window.NativeShell) {
items.map(function (item) {
window.NativeShell.downloadFile(item);

View file

@ -182,7 +182,6 @@ require(['apphost'], function (appHost) {
var isElectron = navigator.userAgent.toLowerCase().indexOf('electron') !== -1;
function allowInput() {
// This would be nice but always seems to return true with electron
if (!isElectron && document.hidden) { /* eslint-disable-line compat/compat */
return false;
@ -196,7 +195,6 @@ require(['apphost'], function (appHost) {
}
function raiseEvent(name, key, keyCode) {
if (!allowInput()) {
return;
}
@ -209,7 +207,6 @@ require(['apphost'], function (appHost) {
}
function clickElement(elem) {
if (!allowInput()) {
return;
}
@ -218,10 +215,8 @@ require(['apphost'], function (appHost) {
}
function raiseKeyEvent(oldPressedState, newPressedState, key, keyCode, enableRepeatKeyDown, clickonKeyUp) {
// No-op if oldPressedState === newPressedState
if (newPressedState === true) {
// button down
var fire = false;
@ -236,9 +231,7 @@ require(['apphost'], function (appHost) {
if (fire && keyCode) {
raiseEvent('keydown', key, keyCode);
}
} else if (newPressedState === false && oldPressedState === true) {
resetThrottle(key);
// button up
@ -406,5 +399,4 @@ require(['apphost'], function (appHost) {
// and provide input to the DOM navigator.getGamepads API.
window.navigator.gamepadInputEmulation = 'gamepad';
}
});

View file

@ -1,6 +1,5 @@
/* eslint-disable indent */
import browser from 'browser';
/* eslint-disable indent */
export function getDeviceIcon(device) {
var baseUrl = 'assets/img/devices/';
@ -32,6 +31,11 @@ import browser from 'browser';
case 'Safari iPad':
case 'Safari iPhone':
return baseUrl + 'safari.svg';
case 'Edge Chromium':
case 'Edge Chromium Android':
case 'Edge Chromium iPad':
case 'Edge Chromium iPhone':
return baseUrl + 'edgechromium.svg';
case 'Edge':
return baseUrl + 'edge.svg';
case 'Internet Explorer':

View file

@ -41,7 +41,6 @@ import appHost from 'apphost';
let commandTimes = {};
function checkCommandTime(command) {
const last = commandTimes[command] || 0;
const now = new Date().getTime();
@ -54,7 +53,6 @@ import appHost from 'apphost';
}
export function handleCommand(commandName, options) {
lastInputTime = new Date().getTime();
let sourceElement = (options ? options.sourceElement : null);

View file

@ -155,6 +155,7 @@ export function enable() {
function attachGamepadScript(e) {
console.log('Gamepad connected! Attaching gamepadtokey.js script');
window.removeEventListener('gamepadconnected', attachGamepadScript);
/* eslint-disable-next-line no-unused-expressions */
import('scripts/gamepadtokey');
}

View file

@ -1,199 +1,216 @@
define(['userSettings', 'globalize'], function (userSettings, globalize) {
'use strict';
import * as userSettings from 'userSettings';
import globalize from 'globalize';
var libraryBrowser = {
getSavedQueryKey: function (modifier) {
return window.location.href.split('#')[0] + (modifier || '');
},
loadSavedQueryValues: function (key, query) {
var values = userSettings.get(key);
export function getSavedQueryKey(modifier) {
return window.location.href.split('#')[0] + (modifier || '');
}
if (values) {
values = JSON.parse(values);
return Object.assign(query, values);
}
export function loadSavedQueryValues(key, query) {
var values = userSettings.get(key);
return query;
},
saveQueryValues: function (key, query) {
var values = {};
if (values) {
values = JSON.parse(values);
return Object.assign(query, values);
}
if (query.SortBy) {
values.SortBy = query.SortBy;
}
return query;
}
if (query.SortOrder) {
values.SortOrder = query.SortOrder;
}
export function saveQueryValues(key, query) {
var values = {};
userSettings.set(key, JSON.stringify(values));
},
saveViewSetting: function (key, value) {
userSettings.set(key + '-_view', value);
},
getSavedView: function (key) {
return userSettings.get(key + '-_view');
},
showLayoutMenu: function (button, currentLayout, views) {
var dispatchEvent = true;
if (query.SortBy) {
values.SortBy = query.SortBy;
}
if (!views) {
dispatchEvent = false;
views = button.getAttribute('data-layouts');
views = views ? views.split(',') : ['List', 'Poster', 'PosterCard', 'Thumb', 'ThumbCard'];
}
if (query.SortOrder) {
values.SortOrder = query.SortOrder;
}
var menuItems = views.map(function (v) {
return {
name: globalize.translate('Option' + v),
id: v,
selected: currentLayout == v
};
});
userSettings.set(key, JSON.stringify(values));
}
require(['actionsheet'], function (actionsheet) {
actionsheet.show({
items: menuItems,
positionTo: button,
callback: function (id) {
button.dispatchEvent(new CustomEvent('layoutchange', {
detail: {
viewStyle: id
},
bubbles: true,
cancelable: false
}));
export function saveViewSetting (key, value) {
userSettings.set(key + '-_view', value);
}
if (!dispatchEvent) {
if (window.$) {
$(button).trigger('layoutchange', [id]);
}
}
}
});
});
},
getQueryPagingHtml: function (options) {
var startIndex = options.startIndex;
var limit = options.limit;
var totalRecordCount = options.totalRecordCount;
var html = '';
var recordsEnd = Math.min(startIndex + limit, totalRecordCount);
var showControls = limit < totalRecordCount;
export function getSavedView (key) {
return userSettings.get(key + '-_view');
}
if (html += '<div class="listPaging">', showControls) {
html += '<span style="vertical-align:middle;">';
html += globalize.translate('ListPaging', (totalRecordCount ? startIndex + 1 : 0), recordsEnd, totalRecordCount);
html += '</span>';
}
export function showLayoutMenu (button, currentLayout, views) {
var dispatchEvent = true;
if (showControls || options.viewButton || options.filterButton || options.sortButton || options.addLayoutButton) {
html += '<div style="display:inline-block;">';
if (!views) {
dispatchEvent = false;
views = button.getAttribute('data-layouts');
views = views ? views.split(',') : ['List', 'Poster', 'PosterCard', 'Thumb', 'ThumbCard'];
}
if (showControls) {
html += '<button is="paper-icon-button-light" class="btnPreviousPage autoSize" ' + (startIndex ? '' : 'disabled') + '><span class="material-icons arrow_back"></span></button>';
html += '<button is="paper-icon-button-light" class="btnNextPage autoSize" ' + (startIndex + limit >= totalRecordCount ? 'disabled' : '') + '><span class="material-icons arrow_forward"></span></button>';
}
var menuItems = views.map(function (v) {
return {
name: globalize.translate('Option' + v),
id: v,
selected: currentLayout == v
};
});
if (options.addLayoutButton) {
html += '<button is="paper-icon-button-light" title="' + globalize.translate('ButtonSelectView') + '" class="btnChangeLayout autoSize" data-layouts="' + (options.layouts || '') + '" onclick="LibraryBrowser.showLayoutMenu(this, \'' + (options.currentLayout || '') + '\');"><span class="material-icons view_comfy"></span></button>';
}
import('actionsheet').then(({default: actionsheet}) => {
actionsheet.show({
items: menuItems,
positionTo: button,
callback: function (id) {
button.dispatchEvent(new CustomEvent('layoutchange', {
detail: {
viewStyle: id
},
bubbles: true,
cancelable: false
}));
if (options.sortButton) {
html += '<button is="paper-icon-button-light" class="btnSort autoSize" title="' + globalize.translate('ButtonSort') + '"><span class="material-icons sort_by_alpha"></span></button>';
}
if (options.filterButton) {
html += '<button is="paper-icon-button-light" class="btnFilter autoSize" title="' + globalize.translate('ButtonFilter') + '"><span class="material-icons filter_list"></span></button>';
}
html += '</div>';
}
return html += '</div>';
},
showSortMenu: function (options) {
require(['dialogHelper', 'emby-radio'], function (dialogHelper) {
function onSortByChange() {
var newValue = this.value;
if (this.checked) {
var changed = options.query.SortBy != newValue;
options.query.SortBy = newValue.replace('_', ',');
options.query.StartIndex = 0;
if (options.callback && changed) {
options.callback();
}
if (!dispatchEvent) {
if (window.$) {
$(button).trigger('layoutchange', [id]);
}
}
}
});
});
}
function onSortOrderChange() {
var newValue = this.value;
export function getQueryPagingHtml (options) {
var startIndex = options.startIndex;
var limit = options.limit;
var totalRecordCount = options.totalRecordCount;
var html = '';
var recordsEnd = Math.min(startIndex + limit, totalRecordCount);
var showControls = limit < totalRecordCount;
if (this.checked) {
var changed = options.query.SortOrder != newValue;
options.query.SortOrder = newValue;
options.query.StartIndex = 0;
if (html += '<div class="listPaging">', showControls) {
html += '<span style="vertical-align:middle;">';
html += globalize.translate('ListPaging', (totalRecordCount ? startIndex + 1 : 0), recordsEnd, totalRecordCount);
html += '</span>';
}
if (options.callback && changed) {
options.callback();
}
}
}
if (showControls || options.viewButton || options.filterButton || options.sortButton || options.addLayoutButton) {
html += '<div style="display:inline-block;">';
var dlg = dialogHelper.createDialog({
removeOnClose: true,
modal: false,
entryAnimationDuration: 160,
exitAnimationDuration: 200
});
dlg.classList.add('ui-body-a');
dlg.classList.add('background-theme-a');
dlg.classList.add('formDialog');
var html = '';
html += '<div style="margin:0;padding:1.25em 1.5em 1.5em;">';
html += '<h2 style="margin:0 0 .5em;">';
html += globalize.translate('HeaderSortBy');
html += '</h2>';
var i;
var length;
var isChecked;
html += '<div>';
for (i = 0, length = options.items.length; i < length; i++) {
var option = options.items[i];
var radioValue = option.id.replace(',', '_');
isChecked = (options.query.SortBy || '').replace(',', '_') == radioValue ? ' checked' : '';
html += '<label class="radio-label-block"><input type="radio" is="emby-radio" name="SortBy" data-id="' + option.id + '" value="' + radioValue + '" class="menuSortBy" ' + isChecked + ' /><span>' + option.name + '</span></label>';
}
html += '</div>';
html += '<h2 style="margin: 1em 0 .5em;">';
html += globalize.translate('HeaderSortOrder');
html += '</h2>';
html += '<div>';
isChecked = 'Ascending' == options.query.SortOrder ? ' checked' : '';
html += '<label class="radio-label-block"><input type="radio" is="emby-radio" name="SortOrder" value="Ascending" class="menuSortOrder" ' + isChecked + ' /><span>' + globalize.translate('OptionAscending') + '</span></label>';
isChecked = 'Descending' == options.query.SortOrder ? ' checked' : '';
html += '<label class="radio-label-block"><input type="radio" is="emby-radio" name="SortOrder" value="Descending" class="menuSortOrder" ' + isChecked + ' /><span>' + globalize.translate('OptionDescending') + '</span></label>';
html += '</div>';
html += '</div>';
dlg.innerHTML = html;
dialogHelper.open(dlg);
var sortBys = dlg.querySelectorAll('.menuSortBy');
for (i = 0, length = sortBys.length; i < length; i++) {
sortBys[i].addEventListener('change', onSortByChange);
}
var sortOrders = dlg.querySelectorAll('.menuSortOrder');
for (i = 0, length = sortOrders.length; i < length; i++) {
sortOrders[i].addEventListener('change', onSortOrderChange);
}
});
if (showControls) {
html += '<button is="paper-icon-button-light" class="btnPreviousPage autoSize" ' + (startIndex ? '' : 'disabled') + '><span class="material-icons arrow_back"></span></button>';
html += '<button is="paper-icon-button-light" class="btnNextPage autoSize" ' + (startIndex + limit >= totalRecordCount ? 'disabled' : '') + '><span class="material-icons arrow_forward"></span></button>';
}
};
window.LibraryBrowser = libraryBrowser;
return libraryBrowser;
});
if (options.addLayoutButton) {
html += '<button is="paper-icon-button-light" title="' + globalize.translate('ButtonSelectView') + '" class="btnChangeLayout autoSize" data-layouts="' + (options.layouts || '') + '" onclick="LibraryBrowser.showLayoutMenu(this, \'' + (options.currentLayout || '') + '\');"><span class="material-icons view_comfy"></span></button>';
}
if (options.sortButton) {
html += '<button is="paper-icon-button-light" class="btnSort autoSize" title="' + globalize.translate('ButtonSort') + '"><span class="material-icons sort_by_alpha"></span></button>';
}
if (options.filterButton) {
html += '<button is="paper-icon-button-light" class="btnFilter autoSize" title="' + globalize.translate('ButtonFilter') + '"><span class="material-icons filter_list"></span></button>';
}
html += '</div>';
}
return html += '</div>';
}
export function showSortMenu (options) {
require(['dialogHelper', 'emby-radio'], function (dialogHelper) {
function onSortByChange() {
var newValue = this.value;
if (this.checked) {
var changed = options.query.SortBy != newValue;
options.query.SortBy = newValue.replace('_', ',');
options.query.StartIndex = 0;
if (options.callback && changed) {
options.callback();
}
}
}
function onSortOrderChange() {
var newValue = this.value;
if (this.checked) {
var changed = options.query.SortOrder != newValue;
options.query.SortOrder = newValue;
options.query.StartIndex = 0;
if (options.callback && changed) {
options.callback();
}
}
}
var dlg = dialogHelper.createDialog({
removeOnClose: true,
modal: false,
entryAnimationDuration: 160,
exitAnimationDuration: 200
});
dlg.classList.add('ui-body-a');
dlg.classList.add('background-theme-a');
dlg.classList.add('formDialog');
var html = '';
html += '<div style="margin:0;padding:1.25em 1.5em 1.5em;">';
html += '<h2 style="margin:0 0 .5em;">';
html += globalize.translate('HeaderSortBy');
html += '</h2>';
var i;
var length;
var isChecked;
html += '<div>';
for (i = 0, length = options.items.length; i < length; i++) {
var option = options.items[i];
var radioValue = option.id.replace(',', '_');
isChecked = (options.query.SortBy || '').replace(',', '_') == radioValue ? ' checked' : '';
html += '<label class="radio-label-block"><input type="radio" is="emby-radio" name="SortBy" data-id="' + option.id + '" value="' + radioValue + '" class="menuSortBy" ' + isChecked + ' /><span>' + option.name + '</span></label>';
}
html += '</div>';
html += '<h2 style="margin: 1em 0 .5em;">';
html += globalize.translate('HeaderSortOrder');
html += '</h2>';
html += '<div>';
isChecked = 'Ascending' == options.query.SortOrder ? ' checked' : '';
html += '<label class="radio-label-block"><input type="radio" is="emby-radio" name="SortOrder" value="Ascending" class="menuSortOrder" ' + isChecked + ' /><span>' + globalize.translate('OptionAscending') + '</span></label>';
isChecked = 'Descending' == options.query.SortOrder ? ' checked' : '';
html += '<label class="radio-label-block"><input type="radio" is="emby-radio" name="SortOrder" value="Descending" class="menuSortOrder" ' + isChecked + ' /><span>' + globalize.translate('OptionDescending') + '</span></label>';
html += '</div>';
html += '</div>';
dlg.innerHTML = html;
dialogHelper.open(dlg);
var sortBys = dlg.querySelectorAll('.menuSortBy');
for (i = 0, length = sortBys.length; i < length; i++) {
sortBys[i].addEventListener('change', onSortByChange);
}
var sortOrders = dlg.querySelectorAll('.menuSortOrder');
for (i = 0, length = sortOrders.length; i < length; i++) {
sortOrders[i].addEventListener('change', onSortOrderChange);
}
});
}
const libraryBrowser = {
getSavedQueryKey,
loadSavedQueryValues,
saveQueryValues,
saveViewSetting,
getSavedView,
showLayoutMenu,
getQueryPagingHtml,
showSortMenu
};
window.LibraryBrowser = libraryBrowser;
export default libraryBrowser;

View file

@ -229,7 +229,6 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
function openMainDrawer() {
navDrawerInstance.open();
lastOpenTime = new Date().getTime();
}
function onMainDrawerOpened() {
@ -575,15 +574,12 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
}
function updateLibraryMenu(user) {
// FIXME: Potential equivalent might be
// showBySelector(".lnkSyncToOtherDevices", !!user.Policy.EnableContentDownloading);
if (!user) {
showBySelector('.libraryMenuDownloads', false);
showBySelector('.lnkSyncToOtherDevices', false);
return void showBySelector('.userMenuOptions', false);
}
// FIXME: Potentially the same as above
if (user.Policy.EnableContentDownloading) {
showBySelector('.lnkSyncToOtherDevices', true);
} else {
@ -838,7 +834,6 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
var enableLibraryNavDrawerHome = !layoutManager.tv;
var skinHeader = document.querySelector('.skinHeader');
var requiresUserRefresh = true;
var lastOpenTime = new Date().getTime();
window.LibraryMenu = {
getTopParentId: getTopParentId,
onHardwareMenuButtonClick: function () {

View file

@ -64,10 +64,7 @@ define(['layoutManager', 'datetime', 'cardBuilder', 'apphost'], function (layout
for (i = 0, length = groups.length; i < length; i++) {
var group = groups[i];
var supportsImageAnalysis = appHost.supports('imageanalysis');
var cardLayout = appHost.preferVisualCards || supportsImageAnalysis;
cardLayout = true;
if (group.name) {
html += '<div class="verticalSection">';
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + group.name + '</h2>';
@ -86,21 +83,21 @@ define(['layoutManager', 'datetime', 'cardBuilder', 'apphost'], function (layout
html += cardBuilder.getCardsHtml({
items: group.items,
shape: cardLayout ? getBackdropShape() : enableScrollX() ? 'autoOverflow' : 'autoVertical',
shape: getBackdropShape(),
showParentTitleOrTitle: true,
showAirTime: true,
showAirEndTime: true,
showChannelName: !cardLayout,
cardLayout: cardLayout,
centerText: !cardLayout,
showChannelName: false,
cardLayout: true,
centerText: false,
action: 'edit',
cardFooterAside: 'none',
preferThumb: !!cardLayout || 'auto',
defaultShape: cardLayout ? null : 'portrait',
preferThumb: true,
defaultShape: null,
coverImage: true,
allowBottomPadding: false,
overlayText: false,
showChannelLogo: cardLayout
showChannelLogo: true
});
html += '</div>';

View file

@ -11,12 +11,10 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
}
function notifyApp() {
inputManager.notifyMouseMove();
}
function removeIdleClasses() {
var classList = document.body.classList;
classList.remove('mouseIdle');
@ -24,7 +22,6 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
}
function addIdleClasses() {
var classList = document.body.classList;
classList.add('mouseIdle');
@ -36,7 +33,6 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
var lastPointerMoveData;
function onPointerMove(e) {
var eventX = e.screenX;
var eventY = e.screenY;
@ -73,7 +69,6 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
}
function onPointerEnter(e) {
var pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse');
if (pointerType === 'mouse') {
@ -87,7 +82,6 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
}
function enableFocusWithMouse() {
if (!layoutManager.tv) {
return false;
}
@ -104,7 +98,6 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
}
function onMouseInterval() {
if (!isMouseIdle && mouseIdleTime() >= 5000) {
isMouseIdle = true;
addIdleClasses();
@ -114,14 +107,12 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
var mouseInterval;
function startMouseInterval() {
if (!mouseInterval) {
mouseInterval = setInterval(onMouseInterval, 5000);
}
}
function stopMouseInterval() {
var interval = mouseInterval;
if (interval) {
@ -133,7 +124,6 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
}
function initMouse() {
stopMouseInterval();
/* eslint-disable-next-line compat/compat */

View file

@ -1,66 +1,65 @@
define(['browser'], function (browser) {
'use strict';
import browser from 'browser';
function fallback(urls) {
var i = 0;
function fallback(urls) {
var i = 0;
(function createIframe() {
var frame = document.createElement('iframe');
frame.style.display = 'none';
frame.src = urls[i++];
document.documentElement.appendChild(frame);
(function createIframe() {
var frame = document.createElement('iframe');
frame.style.display = 'none';
frame.src = urls[i++];
document.documentElement.appendChild(frame);
// the download init has to be sequential otherwise IE only use the first
var interval = setInterval(function () {
if (frame.contentWindow.document.readyState === 'complete' || frame.contentWindow.document.readyState === 'interactive') {
clearInterval(interval);
// the download init has to be sequential otherwise IE only use the first
var interval = setInterval(function () {
if (frame.contentWindow.document.readyState === 'complete' || frame.contentWindow.document.readyState === 'interactive') {
clearInterval(interval);
// Safari needs a timeout
setTimeout(function () {
frame.parentNode.removeChild(frame);
}, 1000);
// Safari needs a timeout
setTimeout(function () {
frame.parentNode.removeChild(frame);
}, 1000);
if (i < urls.length) {
createIframe();
}
if (i < urls.length) {
createIframe();
}
}, 100);
})();
}
function sameDomain(url) {
var a = document.createElement('a');
a.href = url;
return location.hostname === a.hostname && location.protocol === a.protocol;
}
function download(url) {
var a = document.createElement('a');
a.download = '';
a.href = url;
// firefox doesn't support `a.click()`...
a.dispatchEvent(new MouseEvent('click'));
}
return function (urls) {
if (!urls) {
throw new Error('`urls` required');
}
if (typeof document.createElement('a').download === 'undefined') {
return fallback(urls);
}
var delay = 0;
urls.forEach(function (url) {
// the download init has to be sequential for firefox if the urls are not on the same domain
if (browser.firefox && !sameDomain(url)) {
return setTimeout(download.bind(null, url), 100 * ++delay);
}
}, 100);
})();
}
function sameDomain(url) {
var a = document.createElement('a');
a.href = url;
return location.hostname === a.hostname && location.protocol === a.protocol;
}
function download(url) {
var a = document.createElement('a');
a.download = '';
a.href = url;
// firefox doesn't support `a.click()`...
a.dispatchEvent(new MouseEvent('click'));
}
export default function (urls) {
if (!urls) {
throw new Error('`urls` required');
}
if (typeof document.createElement('a').download === 'undefined') {
return fallback(urls);
}
var delay = 0;
urls.forEach(function (url) {
// the download init has to be sequential for firefox if the urls are not on the same domain
if (browser.firefox && !sameDomain(url)) {
return setTimeout(download.bind(null, url), 100 * ++delay);
}
download(url);
});
}
download(url);
});
};
});

View file

@ -3,7 +3,6 @@ import listView from 'listView';
import cardBuilder from 'cardBuilder';
import libraryMenu from 'libraryMenu';
import libraryBrowser from 'libraryBrowser';
import appHost from 'apphost';
import imageLoader from 'imageLoader';
import userSettings from 'userSettings';
import 'emby-itemscontainer';

View file

@ -13,7 +13,6 @@ define([
'listViewStyle',
'dashboardcss',
'detailtablecss'], function () {
function defineRoute(newRoute) {
var path = newRoute.alias ? newRoute.alias : newRoute.path;
console.debug('defining route: ' + path);
@ -24,77 +23,88 @@ define([
console.debug('defining core routes');
defineRoute({
path: '/addserver.html',
alias: '/addserver.html',
path: '/controllers/session/addServer/index.html',
autoFocus: false,
anonymous: true,
startup: true,
controller: 'auth/addserver'
controller: 'session/addServer/index'
});
defineRoute({
path: '/selectserver.html',
alias: '/selectserver.html',
path: '/controllers/session/selectServer/index.html',
autoFocus: false,
anonymous: true,
startup: true,
controller: 'auth/selectserver',
controller: 'session/selectServer/index',
type: 'selectserver'
});
defineRoute({
path: '/login.html',
alias: '/login.html',
path: '/controllers/session/login/index.html',
autoFocus: false,
anonymous: true,
startup: true,
controller: 'auth/login',
controller: 'session/login/index',
type: 'login'
});
defineRoute({
path: '/forgotpassword.html',
alias: '/forgotpassword.html',
path: '/controllers/session/forgotPassword/index.html',
anonymous: true,
startup: true,
controller: 'auth/forgotpassword'
controller: 'session/forgotPassword/index'
});
defineRoute({
path: '/forgotpasswordpin.html',
alias: '/forgotpasswordpin.html',
path: '/controllers/session/redeemPassword/index.html',
autoFocus: false,
anonymous: true,
startup: true,
controller: 'auth/forgotpasswordpin'
controller: 'session/redeemPassword/index'
});
defineRoute({
path: '/mypreferencesmenu.html',
alias: '/mypreferencesmenu.html',
path: '/controllers/user/menu/index.html',
autoFocus: false,
transition: 'fade',
controller: 'user/menu'
controller: 'user/menu/index'
});
defineRoute({
path: '/myprofile.html',
alias: '/myprofile.html',
path: '/controllers/user/profile/index.html',
autoFocus: false,
transition: 'fade',
controller: 'user/profile'
controller: 'user/profile/index'
});
defineRoute({
path: '/mypreferencesdisplay.html',
alias: '/mypreferencesdisplay.html',
path: '/controllers/user/display/index.html',
autoFocus: false,
transition: 'fade',
controller: 'user/display'
controller: 'user/display/index'
});
defineRoute({
path: '/mypreferenceshome.html',
alias: '/mypreferenceshome.html',
path: '/controllers/user/home/index.html',
autoFocus: false,
transition: 'fade',
controller: 'user/home'
controller: 'user/home/index'
});
defineRoute({
path: '/mypreferencesplayback.html',
alias: '/mypreferencesplayback.html',
path: '/controllers/user/playback/index.html',
autoFocus: false,
transition: 'fade',
controller: 'user/playback'
controller: 'user/playback/index'
});
defineRoute({
path: '/mypreferencessubtitles.html',
alias: '/mypreferencessubtitles.html',
path: '/controllers/user/subtitles/index.html',
autoFocus: false,
transition: 'fade',
controller: 'user/subtitles'
controller: 'user/subtitles/index'
});
defineRoute({
@ -140,10 +150,11 @@ define([
controller: 'dashboard/dlna/profiles'
});
defineRoute({
path: '/addplugin.html',
alias: '/addplugin.html',
path: '/controllers/dashboard/plugins/add/index.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/plugins/add'
controller: 'dashboard/plugins/add/index'
});
defineRoute({
path: '/library.html',
@ -192,14 +203,16 @@ define([
controller: 'dashboard/metadatanfo'
});
defineRoute({
path: '/notificationsetting.html',
alias: '/notificationsetting.html',
path: '/controllers/dashboard/notifications/notification/index.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/notifications/notification'
controller: 'dashboard/notifications/notification/index'
});
defineRoute({
path: '/notificationsettings.html',
controller: 'dashboard/notifications/notifications',
alias: '/notificationsettings.html',
path: '/controllers/dashboard/notifications/notifications/index.html',
controller: 'dashboard/notifications/notifications/index',
autoFocus: false,
roles: 'admin'
});
@ -210,16 +223,18 @@ define([
controller: 'dashboard/playback'
});
defineRoute({
path: '/availableplugins.html',
alias: '/availableplugins.html',
path: '/controllers/dashboard/plugins/available/index.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/plugins/available'
controller: 'dashboard/plugins/available/index'
});
defineRoute({
path: '/repositories.html',
alias: '/repositories.html',
path: '/controllers/dashboard/plugins/repositories/index.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/plugins/repositories'
controller: 'dashboard/plugins/repositories/index'
});
defineRoute({
@ -288,10 +303,11 @@ define([
transition: 'fade'
});
defineRoute({
path: '/installedplugins.html',
alias: '/installedplugins.html',
path: '/controllers/dashboard/plugins/installed/index.html',
autoFocus: false,
roles: 'admin',
controller: 'dashboard/plugins/installed'
controller: 'dashboard/plugins/installed/index'
});
defineRoute({
path: '/scheduledtask.html',
@ -367,16 +383,18 @@ define([
});
defineRoute({
path: '/wizardremoteaccess.html',
alias: '/wizardremoteaccess.html',
path: '/controllers/wizard/remote/index.html',
autoFocus: false,
anonymous: true,
controller: 'wizard/remoteaccess'
controller: 'wizard/remote/index'
});
defineRoute({
path: '/wizardfinish.html',
alias: '/wizardfinish.html',
path: '/controllers/wizard/finish/index.html',
autoFocus: false,
anonymous: true,
controller: 'wizard/finish'
controller: 'wizard/finish/index'
});
defineRoute({
path: '/wizardlibrary.html',
@ -385,28 +403,32 @@ define([
controller: 'dashboard/mediaLibrary'
});
defineRoute({
path: '/wizardsettings.html',
alias: '/wizardsettings.html',
path: '/controllers/wizard/settings/index.html',
autoFocus: false,
anonymous: true,
controller: 'wizard/settings'
controller: 'wizard/settings/index'
});
defineRoute({
path: '/wizardstart.html',
alias: '/wizardstart.html',
path: '/controllers/wizard/start/index.html',
autoFocus: false,
anonymous: true,
controller: 'wizard/start'
controller: 'wizard/start/index'
});
defineRoute({
path: '/wizarduser.html',
controller: 'wizard/user',
alias: '/wizarduser.html',
path: '/controllers/wizard/user/index.html',
controller: 'wizard/user/index',
autoFocus: false,
anonymous: true
});
defineRoute({
path: '/videoosd.html',
alias: '/video',
path: '/controllers/playback/video/index.html',
transition: 'fade',
controller: 'playback/videoosd',
controller: 'playback/video/index',
autoFocus: false,
type: 'video-osd',
supportsThemeMedia: true,
@ -414,8 +436,9 @@ define([
enableMediaControl: false
});
defineRoute({
path: '/nowplaying.html',
controller: 'playback/nowplaying',
alias: '/queue',
path: '/controllers/playback/queue/index.html',
controller: 'playback/queue/index',
autoFocus: false,
transition: 'fade',
fullscreen: true,

View file

@ -2,7 +2,6 @@ define(['focusManager', 'dom', 'scrollStyles'], function (focusManager, dom) {
'use strict';
function getBoundingClientRect(elem) {
// Support: BlackBerry 5, iOS 3 (original iPhone)
// If we don't have gBCR, just use 0,0 rather than error
if (elem.getBoundingClientRect) {
@ -13,7 +12,6 @@ define(['focusManager', 'dom', 'scrollStyles'], function (focusManager, dom) {
}
function getPosition(scrollContainer, item, horizontal) {
var slideeOffset = getBoundingClientRect(scrollContainer);
var itemOffset = getBoundingClientRect(item);

View file

@ -8,7 +8,6 @@ define([], function () {
} else {
window.open(url, target || '_blank');
}
},
enableFullscreen: function () {
if (window.NativeShell) {

View file

@ -14,7 +14,7 @@ function getWindowLocationSearch(win) {
return search || '';
}
function getParameterByName(name, url) {
window.getParameterByName = function (name, url) {
'use strict';
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
@ -27,7 +27,7 @@ function getParameterByName(name, url) {
}
return decodeURIComponent(results[1].replace(/\+/g, ' '));
}
};
function pageClassOn(eventName, className, fn) {
'use strict';
@ -41,7 +41,7 @@ function pageClassOn(eventName, className, fn) {
});
}
function pageIdOn(eventName, id, fn) {
window.pageIdOn = function(eventName, id, fn) {
'use strict';
document.addEventListener(eventName, function (event) {
@ -51,7 +51,7 @@ function pageIdOn(eventName, id, fn) {
fn.call(target, event);
}
});
}
};
var Dashboard = {
getCurrentUser: function () {
@ -236,9 +236,7 @@ var Dashboard = {
var AppInfo = {};
!function () {
'use strict';
function initClient() {
function defineConnectionManager(connectionManager) {
window.ConnectionManager = connectionManager;
define('connectionManager', [], function () {
@ -494,7 +492,7 @@ var AppInfo = {};
if (appHost.supports('remotecontrol')) {
list.push('plugins/sessionPlayer/plugin');
if (browser.chrome || browser.opera) {
if (browser.chrome || browser.edgeChromium || browser.opera) {
list.push('plugins/chromecastPlayer/plugin');
}
}
@ -679,7 +677,6 @@ var AppInfo = {};
'howler',
'native-promise-only',
'resize-observer-polyfill',
'shaka',
'swiper',
'queryString',
'sortable',
@ -785,7 +782,6 @@ var AppInfo = {};
define('multiSelect', [componentsPath + '/multiSelect/multiSelect'], returnFirstDependency);
define('alphaPicker', [componentsPath + '/alphaPicker/alphaPicker'], returnFirstDependency);
define('tabbedView', [componentsPath + '/tabbedview/tabbedview'], returnFirstDependency);
define('itemsTab', [componentsPath + '/tabbedview/itemstab'], returnFirstDependency);
define('collectionEditor', [componentsPath + '/collectionEditor/collectionEditor'], returnFirstDependency);
define('playlistEditor', [componentsPath + '/playlisteditor/playlisteditor'], returnFirstDependency);
define('recordingCreator', [componentsPath + '/recordingcreator/recordingcreator'], returnFirstDependency);
@ -890,7 +886,7 @@ var AppInfo = {};
};
appRouter.showVideoOsd = function () {
return Dashboard.navigate('videoosd.html');
return Dashboard.navigate('video');
};
appRouter.showSelectServer = function () {
@ -1127,7 +1123,9 @@ var AppInfo = {};
})();
return onWebComponentsReady();
}();
}
initClient();
pageClassOn('viewshow', 'standalonePage', function () {
document.querySelector('.skinHeader').classList.add('noHeaderRight');

View file

@ -1,5 +1,5 @@
import events from 'events';
import * as userSettings from 'userSettings';
import serverNotifications from 'serverNotifications';
import connectionManager from 'connectionManager';
import globalize from 'globalize';

View file

@ -7,7 +7,6 @@ function getTouches(e) {
class TouchHelper {
constructor(elem, options) {
options = options || {};
let touchTarget;
let touchStartX;
@ -24,7 +23,6 @@ class TouchHelper {
const excludeTagNames = options.ignoreTagNames || [];
const touchStart = function (e) {
const touch = getTouches(e)[0];
touchTarget = null;
touchStartX = 0;
@ -34,7 +32,6 @@ class TouchHelper {
thresholdYMet = false;
if (touch) {
const currentTouchTarget = touch.target;
if (dom.parentWithTag(currentTouchTarget, excludeTagNames)) {
@ -48,7 +45,6 @@ class TouchHelper {
};
const touchEnd = function (e) {
const isTouchMove = e.type === 'touchmove';
if (touchTarget) {
@ -81,7 +77,6 @@ class TouchHelper {
} else if (deltaX < (0 - swipeXThreshold) && Math.abs(deltaY) < swipeXMaxY) {
events.trigger(self, 'swipeleft', [touchTarget]);
} else if ((deltaY < (0 - swipeYThreshold) || thresholdYMet) && Math.abs(deltaX) < swipeXMaxY) {
thresholdYMet = true;
events.trigger(self, 'swipeup', [touchTarget, {
@ -139,7 +134,6 @@ class TouchHelper {
});
}
destroy() {
const elem = this.elem;
if (elem) {