Merge remote-tracking branch 'upstream/master' into quickconnect
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
html {
|
||||
font-family: "Noto Sans", sans-serif;
|
||||
font-size: 93%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
text-size-adjust: 100%;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
@@ -29,7 +27,9 @@ h3 {
|
||||
}
|
||||
|
||||
.layout-tv {
|
||||
font-size: 130%;
|
||||
/* Per WebOS and Tizen guidelines, fonts must be 20px minimum.
|
||||
This takes the 16px baseline and multiplies it by 1.25 to get 20px. */
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
.layout-mobile {
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
.layout-tv .itemDetailPage {
|
||||
padding-top: 4.2em !important;
|
||||
}
|
||||
|
||||
.standalonePage {
|
||||
padding-top: 4.5em !important;
|
||||
}
|
||||
@@ -163,6 +167,12 @@
|
||||
transition: background ease-in-out 0.5s;
|
||||
}
|
||||
|
||||
.layout-tv .skinHeader {
|
||||
/* In TV layout, it makes more sense to keep the top bar at the top of the page
|
||||
Having it follow the view only makes us lose vertical space, while not being focusable */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hiddenViewMenuBar .skinHeader {
|
||||
display: none;
|
||||
}
|
||||
@@ -236,12 +246,6 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.layout-desktop .searchTabButton,
|
||||
.layout-mobile .searchTabButton,
|
||||
.layout-tv .headerSearchButton {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mainDrawer-scrollContainer {
|
||||
padding-bottom: 10vh;
|
||||
}
|
||||
@@ -453,8 +457,7 @@
|
||||
height: 26.5vh;
|
||||
}
|
||||
|
||||
.layout-desktop .itemBackdrop::after,
|
||||
.layout-tv .itemBackdrop::after {
|
||||
.layout-desktop .itemBackdrop::after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -462,8 +465,8 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
.layout-desktop .noBackdrop .itemBackdrop,
|
||||
.layout-tv .noBackdrop .itemBackdrop {
|
||||
.layout-tv .itemBackdrop,
|
||||
.layout-desktop .noBackdrop .itemBackdrop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -630,6 +633,10 @@
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.layout-tv .detailPagePrimaryContainer {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.layout-mobile .detailPagePrimaryContainer {
|
||||
display: block;
|
||||
position: relative;
|
||||
@@ -643,10 +650,14 @@
|
||||
padding-left: 32.45vw;
|
||||
}
|
||||
|
||||
.layout-desktop .detailRibbon,
|
||||
.layout-tv .detailRibbon {
|
||||
.layout-desktop .detailRibbon {
|
||||
margin-top: -7.2em;
|
||||
height: 7.18em;
|
||||
height: 7.2em;
|
||||
}
|
||||
|
||||
.layout-tv .detailRibbon {
|
||||
margin-top: 0;
|
||||
height: inherit;
|
||||
}
|
||||
|
||||
.layout-desktop .noBackdrop .detailRibbon,
|
||||
@@ -754,8 +765,7 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.layout-desktop .itemBackdrop,
|
||||
.layout-tv .itemBackdrop {
|
||||
.layout-desktop .itemBackdrop {
|
||||
height: 40vh;
|
||||
}
|
||||
|
||||
@@ -781,13 +791,8 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
}
|
||||
|
||||
.emby-button.detailFloatingButton {
|
||||
position: absolute;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 3;
|
||||
top: 100%;
|
||||
left: 90%;
|
||||
margin: -2.2em 0 0 -2.2em;
|
||||
padding: 0.4em;
|
||||
font-size: 1.4em;
|
||||
margin-right: 0.5em !important;
|
||||
color: rgba(255, 255, 255, 0.76);
|
||||
}
|
||||
|
||||
@@ -850,7 +855,7 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
margin: 0 !important;
|
||||
padding: 0.5em 0.7em !important;
|
||||
padding: 0.7em 0.7em !important;
|
||||
}
|
||||
|
||||
@media all and (min-width: 29em) {
|
||||
@@ -919,10 +924,6 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
}
|
||||
|
||||
@media all and (min-width: 100em) {
|
||||
.detailFloatingButton {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.personBackdrop {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -931,6 +932,11 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
font-size: 108%;
|
||||
margin: 1.25em 0;
|
||||
}
|
||||
|
||||
.layout-tv .mainDetailButtons {
|
||||
font-size: 108%;
|
||||
margin: 1em 0 1.25em;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 50em) {
|
||||
@@ -1146,13 +1152,13 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards {
|
||||
}
|
||||
|
||||
.layout-tv .padded-top-focusscale {
|
||||
padding-top: 1em;
|
||||
margin-top: -1em;
|
||||
padding-top: 1.5em;
|
||||
margin-top: -1.5em;
|
||||
}
|
||||
|
||||
.layout-tv .padded-bottom-focusscale {
|
||||
padding-bottom: 1em;
|
||||
margin-bottom: -1em;
|
||||
padding-bottom: 1.5em;
|
||||
margin-bottom: -1.5em;
|
||||
}
|
||||
|
||||
@media all and (min-height: 31.25em) {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
}
|
||||
|
||||
.osdPoster img,
|
||||
.pageContainer,
|
||||
.videoOsdBottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
@@ -248,14 +247,7 @@
|
||||
animation: spin 4s linear infinite;
|
||||
}
|
||||
|
||||
.pageContainer {
|
||||
top: 0;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
@media all and (max-width: 30em) {
|
||||
.btnFastForward,
|
||||
.btnRewind,
|
||||
.osdMediaInfo,
|
||||
.osdPoster {
|
||||
display: none !important;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24"><title>Microsoft Edge icon</title><path d="M21.86 17.86q.14 0 .25.12.1.13.1.25t-.11.33l-.32.46-.43.53-.44.5q-.21.25-.38.42l-.22.23q-.58.53-1.34 1.04-.76.51-1.6.91-.86.4-1.74.64t-1.67.24q-.9 0-1.69-.28-.8-.28-1.48-.78-.68-.5-1.22-1.17-.53-.66-.92-1.44-.38-.77-.58-1.6-.2-.83-.2-1.67 0-1 .32-1.96.33-.97.87-1.8.14.95.55 1.77.41.82 1.02 1.5.6.68 1.38 1.21.78.54 1.64.9.86.36 1.77.56.92.2 1.8.2 1.12 0 2.18-.24 1.06-.23 2.06-.72l.2-.1.2-.05zm-15.5-1.27q0 1.1.27 2.15.27 1.06.78 2.03.51.96 1.24 1.77.74.82 1.66 1.4-1.47-.2-2.8-.74-1.33-.55-2.48-1.37-1.15-.83-2.08-1.9-.92-1.07-1.58-2.33T.36 14.94Q0 13.54 0 12.06q0-.81.32-1.49.31-.68.83-1.23.53-.55 1.2-.96.66-.4 1.35-.66.74-.27 1.5-.39.78-.12 1.55-.12.7 0 1.42.1.72.12 1.4.35.68.23 1.32.57.63.35 1.16.83-.35 0-.7.07-.33.07-.65.23v-.02q-.63.28-1.2.74-.57.46-1.05 1.04-.48.58-.87 1.26-.38.67-.65 1.39-.27.71-.42 1.44-.15.72-.15 1.38zM11.96.06q1.7 0 3.33.39 1.63.38 3.07 1.15 1.43.77 2.62 1.93 1.18 1.16 1.98 2.7.49.94.76 1.96.28 1 .28 2.08 0 .89-.23 1.7-.24.8-.69 1.48-.45.68-1.1 1.22-.64.53-1.45.88-.54.24-1.11.36-.58.13-1.16.13-.42 0-.97-.03-.54-.03-1.1-.12-.55-.1-1.05-.28-.5-.19-.84-.5-.12-.09-.23-.24-.1-.16-.1-.33 0-.15.16-.35.16-.2.35-.5.2-.28.36-.68.16-.4.16-.95 0-1.06-.4-1.96-.4-.91-1.06-1.64-.66-.74-1.52-1.28-.86-.55-1.79-.89-.84-.3-1.72-.44-.87-.14-1.76-.14-1.55 0-3.06.45T.94 7.55q.71-1.74 1.81-3.13 1.1-1.38 2.52-2.35Q6.68 1.1 8.37.58q1.7-.52 3.58-.52Z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
+34
-34
@@ -2,165 +2,159 @@
|
||||
* require.js module definitions bundled by webpack
|
||||
*/
|
||||
// Use define from require.js not webpack's define
|
||||
var _define = window.define;
|
||||
const _define = window.define;
|
||||
|
||||
// fetch
|
||||
var fetch = require('whatwg-fetch');
|
||||
const fetch = require('whatwg-fetch');
|
||||
_define('fetch', function() {
|
||||
return fetch;
|
||||
});
|
||||
|
||||
// Blurhash
|
||||
var blurhash = require('blurhash');
|
||||
const blurhash = require('blurhash');
|
||||
_define('blurhash', function() {
|
||||
return blurhash;
|
||||
});
|
||||
|
||||
// query-string
|
||||
var query = require('query-string');
|
||||
const query = require('query-string');
|
||||
_define('queryString', function() {
|
||||
return query;
|
||||
});
|
||||
|
||||
// flvjs
|
||||
var flvjs = require('flv.js/dist/flv').default;
|
||||
const flvjs = require('flv.js/dist/flv').default;
|
||||
_define('flvjs', function() {
|
||||
return flvjs;
|
||||
});
|
||||
|
||||
// jstree
|
||||
var jstree = require('jstree');
|
||||
const jstree = require('jstree');
|
||||
require('jstree/dist/themes/default/style.css');
|
||||
_define('jstree', function() {
|
||||
return jstree;
|
||||
});
|
||||
|
||||
// jquery
|
||||
var jquery = require('jquery');
|
||||
const jquery = require('jquery');
|
||||
_define('jQuery', function() {
|
||||
return jquery;
|
||||
});
|
||||
|
||||
// hlsjs
|
||||
var hlsjs = require('hls.js');
|
||||
const hlsjs = require('hls.js');
|
||||
_define('hlsjs', function() {
|
||||
return hlsjs;
|
||||
});
|
||||
|
||||
// howler
|
||||
var howler = require('howler');
|
||||
const howler = require('howler');
|
||||
_define('howler', function() {
|
||||
return howler;
|
||||
});
|
||||
|
||||
// resize-observer-polyfill
|
||||
var resize = require('resize-observer-polyfill').default;
|
||||
const resize = require('resize-observer-polyfill').default;
|
||||
_define('resize-observer-polyfill', function() {
|
||||
return resize;
|
||||
});
|
||||
|
||||
// swiper
|
||||
var swiper = require('swiper/js/swiper');
|
||||
require('swiper/css/swiper.min.css');
|
||||
const swiper = require('swiper/swiper-bundle');
|
||||
require('swiper/swiper-bundle.css');
|
||||
_define('swiper', function() {
|
||||
return swiper;
|
||||
});
|
||||
|
||||
// sortable
|
||||
var sortable = require('sortablejs').default;
|
||||
const sortable = require('sortablejs').default;
|
||||
_define('sortable', function() {
|
||||
return sortable;
|
||||
});
|
||||
|
||||
// webcomponents
|
||||
var webcomponents = require('webcomponents.js/webcomponents-lite');
|
||||
const webcomponents = require('webcomponents.js/webcomponents-lite');
|
||||
_define('webcomponents', function() {
|
||||
return webcomponents;
|
||||
});
|
||||
|
||||
// shaka
|
||||
var shaka = require('shaka-player');
|
||||
_define('shaka', function() {
|
||||
return shaka;
|
||||
});
|
||||
|
||||
// libass-wasm
|
||||
var libassWasm = require('libass-wasm');
|
||||
const libassWasm = require('libass-wasm');
|
||||
_define('JavascriptSubtitlesOctopus', function() {
|
||||
return libassWasm;
|
||||
});
|
||||
|
||||
// material-icons
|
||||
var materialIcons = require('material-design-icons-iconfont/dist/material-design-icons.css');
|
||||
const materialIcons = require('material-design-icons-iconfont/dist/material-design-icons.css');
|
||||
_define('material-icons', function() {
|
||||
return materialIcons;
|
||||
});
|
||||
|
||||
// noto font
|
||||
var noto = require('jellyfin-noto');
|
||||
const noto = require('jellyfin-noto');
|
||||
_define('jellyfin-noto', function () {
|
||||
return noto;
|
||||
});
|
||||
|
||||
var epubjs = require('epubjs');
|
||||
const epubjs = require('epubjs');
|
||||
_define('epubjs', function () {
|
||||
return epubjs;
|
||||
});
|
||||
|
||||
// page.js
|
||||
var page = require('page');
|
||||
const page = require('page');
|
||||
_define('page', function() {
|
||||
return page;
|
||||
});
|
||||
|
||||
// core-js
|
||||
var polyfill = require('@babel/polyfill/dist/polyfill');
|
||||
const polyfill = require('@babel/polyfill/dist/polyfill');
|
||||
_define('polyfill', function () {
|
||||
return polyfill;
|
||||
});
|
||||
|
||||
// domtokenlist-shim
|
||||
var classlist = require('classlist.js');
|
||||
const classlist = require('classlist.js');
|
||||
_define('classlist-polyfill', function () {
|
||||
return classlist;
|
||||
});
|
||||
|
||||
// Date-FNS
|
||||
var dateFns = require('date-fns');
|
||||
const dateFns = require('date-fns');
|
||||
_define('date-fns', function () {
|
||||
return dateFns;
|
||||
});
|
||||
|
||||
var dateFnsLocale = require('date-fns/locale');
|
||||
const dateFnsLocale = require('date-fns/locale');
|
||||
_define('date-fns/locale', function () {
|
||||
return dateFnsLocale;
|
||||
});
|
||||
|
||||
var fast_text_encoding = require('fast-text-encoding');
|
||||
const fast_text_encoding = require('fast-text-encoding');
|
||||
_define('fast-text-encoding', function () {
|
||||
return fast_text_encoding;
|
||||
});
|
||||
|
||||
// intersection-observer
|
||||
var intersection_observer = require('intersection-observer');
|
||||
const intersection_observer = require('intersection-observer');
|
||||
_define('intersection-observer', function () {
|
||||
return intersection_observer;
|
||||
});
|
||||
|
||||
// screenfull
|
||||
var screenfull = require('screenfull');
|
||||
const screenfull = require('screenfull');
|
||||
_define('screenfull', function () {
|
||||
return screenfull;
|
||||
});
|
||||
|
||||
// headroom.js
|
||||
var headroom = require('headroom.js/dist/headroom');
|
||||
const headroom = require('headroom.js/dist/headroom');
|
||||
_define('headroom', function () {
|
||||
return headroom;
|
||||
});
|
||||
|
||||
// apiclient
|
||||
var apiclient = require('jellyfin-apiclient');
|
||||
const apiclient = require('jellyfin-apiclient');
|
||||
|
||||
_define('apiclient', function () {
|
||||
return apiclient.ApiClient;
|
||||
@@ -181,3 +175,9 @@ _define('connectionManagerFactory', function () {
|
||||
_define('appStorage', function () {
|
||||
return apiclient.AppStorage;
|
||||
});
|
||||
|
||||
// libarchive.js
|
||||
var libarchive = require('libarchive.js');
|
||||
_define('libarchive', function () {
|
||||
return libarchive;
|
||||
});
|
||||
|
||||
@@ -49,7 +49,7 @@ import 'formDialogStyle';
|
||||
};
|
||||
|
||||
if (parseFloat(updatedSchedule.StartHour) >= parseFloat(updatedSchedule.EndHour)) {
|
||||
return void alert(globalize.translate('ErrorMessageStartHourGreaterThanEnd'));
|
||||
return void alert(globalize.translate('ErrorStartHourGreaterThanEnd'));
|
||||
}
|
||||
|
||||
context.submitted = true;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="formDialogHeader">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${LabelPrevious}" tabindex="-1">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${Previous}" tabindex="-1">
|
||||
<span class="material-icons arrow_back" aria-hidden="true"></span>
|
||||
</button>
|
||||
<h3 class="formDialogHeaderTitle">
|
||||
@@ -12,13 +12,13 @@
|
||||
|
||||
<div class="selectContainer">
|
||||
<select is="emby-select" id="selectDay" label="${LabelAccessDay}">
|
||||
<option value="Sunday">${OptionSunday}</option>
|
||||
<option value="Monday">${OptionMonday}</option>
|
||||
<option value="Tuesday">${OptionTuesday}</option>
|
||||
<option value="Wednesday">${OptionWednesday}</option>
|
||||
<option value="Thursday">${OptionThursday}</option>
|
||||
<option value="Friday">${OptionFriday}</option>
|
||||
<option value="Saturday">${OptionSaturday}</option>
|
||||
<option value="Sunday">${Sunday}</option>
|
||||
<option value="Monday">${Monday}</option>
|
||||
<option value="Tuesday">${Tuesday}</option>
|
||||
<option value="Wednesday">${Wednesday}</option>
|
||||
<option value="Thursday">${Thursday}</option>
|
||||
<option value="Friday">${Friday}</option>
|
||||
<option value="Saturday">${Saturday}</option>
|
||||
<option value="Everyday">${OptionEveryday}</option>
|
||||
<option value="Weekday">${OptionWeekdays}</option>
|
||||
<option value="Weekend">${OptionWeekends}</option>
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
<div class="formDialogFooter">
|
||||
<button is="emby-button" type="submit" class="raised button-submit block formDialogFooterItem">
|
||||
<span>${ButtonAdd}</span>
|
||||
<span>${Add}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -9,15 +9,14 @@ import 'scrollStyles';
|
||||
import 'listViewStyle';
|
||||
|
||||
function getOffsets(elems) {
|
||||
|
||||
let results = [];
|
||||
const results = [];
|
||||
|
||||
if (!document) {
|
||||
return results;
|
||||
}
|
||||
|
||||
for (const elem of elems) {
|
||||
let box = elem.getBoundingClientRect();
|
||||
const box = elem.getBoundingClientRect();
|
||||
|
||||
results.push({
|
||||
top: box.top,
|
||||
@@ -31,12 +30,11 @@ function getOffsets(elems) {
|
||||
}
|
||||
|
||||
function getPosition(options, dlg) {
|
||||
|
||||
const windowSize = dom.getWindowSize();
|
||||
const windowHeight = windowSize.innerHeight;
|
||||
const windowWidth = windowSize.innerWidth;
|
||||
|
||||
let pos = getOffsets([options.positionTo])[0];
|
||||
const pos = getOffsets([options.positionTo])[0];
|
||||
|
||||
if (options.positionY !== 'top') {
|
||||
pos.top += (pos.height || 0) / 2;
|
||||
@@ -80,12 +78,11 @@ function centerFocus(elem, horiz, on) {
|
||||
}
|
||||
|
||||
export function show(options) {
|
||||
|
||||
// items
|
||||
// positionTo
|
||||
// showCancel
|
||||
// title
|
||||
let dialogOptions = {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
enableHistory: options.enableHistory,
|
||||
scrollY: false
|
||||
@@ -98,7 +95,6 @@ export function show(options) {
|
||||
isFullscreen = true;
|
||||
dialogOptions.autoFocus = true;
|
||||
} else {
|
||||
|
||||
dialogOptions.modal = false;
|
||||
dialogOptions.entryAnimation = options.entryAnimation;
|
||||
dialogOptions.exitAnimation = options.exitAnimation;
|
||||
@@ -107,7 +103,7 @@ export function show(options) {
|
||||
dialogOptions.autoFocus = false;
|
||||
}
|
||||
|
||||
let dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
if (isFullscreen) {
|
||||
dlg.classList.add('actionsheet-fullscreen');
|
||||
@@ -133,10 +129,9 @@ export function show(options) {
|
||||
}
|
||||
|
||||
let renderIcon = false;
|
||||
let icons = [];
|
||||
const icons = [];
|
||||
let itemIcon;
|
||||
for (const item of options.items) {
|
||||
|
||||
itemIcon = item.icon || (item.selected ? 'check' : null);
|
||||
|
||||
if (itemIcon) {
|
||||
@@ -161,7 +156,6 @@ export function show(options) {
|
||||
}
|
||||
|
||||
if (options.title) {
|
||||
|
||||
html += '<h1 class="actionSheetTitle">' + options.title + '</h1>';
|
||||
}
|
||||
if (options.text) {
|
||||
@@ -197,7 +191,6 @@ export function show(options) {
|
||||
const item = options.items[i];
|
||||
|
||||
if (item.divider) {
|
||||
|
||||
html += '<div class="actionsheetDivider"></div>';
|
||||
continue;
|
||||
}
|
||||
@@ -248,15 +241,13 @@ export function show(options) {
|
||||
centerFocus(dlg.querySelector('.actionSheetScroller'), false, true);
|
||||
}
|
||||
|
||||
let btnCloseActionSheet = dlg.querySelector('.btnCloseActionSheet');
|
||||
const btnCloseActionSheet = dlg.querySelector('.btnCloseActionSheet');
|
||||
if (btnCloseActionSheet) {
|
||||
btnCloseActionSheet.addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
}
|
||||
|
||||
// Seeing an issue in some non-chrome browsers where this is requiring a double click
|
||||
//var eventName = browser.firefox ? 'mousedown' : 'click';
|
||||
let selectedId;
|
||||
|
||||
let timeout;
|
||||
@@ -267,26 +258,20 @@ export function show(options) {
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
let isResolved;
|
||||
|
||||
dlg.addEventListener('click', function (e) {
|
||||
|
||||
const actionSheetMenuItem = dom.parentWithClass(e.target, 'actionSheetMenuItem');
|
||||
|
||||
if (actionSheetMenuItem) {
|
||||
selectedId = actionSheetMenuItem.getAttribute('data-id');
|
||||
|
||||
if (options.resolveOnClick) {
|
||||
|
||||
if (options.resolveOnClick.indexOf) {
|
||||
|
||||
if (options.resolveOnClick.indexOf(selectedId) !== -1) {
|
||||
|
||||
resolve(selectedId);
|
||||
isResolved = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
resolve(selectedId);
|
||||
isResolved = true;
|
||||
@@ -295,11 +280,9 @@ export function show(options) {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.actionSheetScroller'), false, false);
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@ import globalize from 'globalize';
|
||||
import dom from 'dom';
|
||||
import * as datefns from 'date-fns';
|
||||
import dfnshelper from 'dfnshelper';
|
||||
import userSettings from 'userSettings';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import connectionManager from 'connectionManager';
|
||||
import 'emby-button';
|
||||
import 'listViewStyle';
|
||||
|
||||
@@ -17,7 +15,7 @@ import 'listViewStyle';
|
||||
let color = '#00a4dc';
|
||||
let icon = 'notifications';
|
||||
|
||||
if ('Error' == entry.Severity || 'Fatal' == entry.Severity || 'Warn' == entry.Severity) {
|
||||
if (entry.Severity == 'Error' || entry.Severity == 'Fatal' || entry.Severity == 'Warn') {
|
||||
color = '#cc0000';
|
||||
icon = 'notification_important';
|
||||
}
|
||||
@@ -61,14 +59,15 @@ import 'listViewStyle';
|
||||
}
|
||||
|
||||
function reloadData(instance, elem, apiClient, startIndex, limit) {
|
||||
if (null == startIndex) {
|
||||
if (startIndex == null) {
|
||||
startIndex = parseInt(elem.getAttribute('data-activitystartindex') || '0');
|
||||
}
|
||||
|
||||
limit = limit || parseInt(elem.getAttribute('data-activitylimit') || '7');
|
||||
const minDate = new Date();
|
||||
const hasUserId = 'false' !== elem.getAttribute('data-useractivity');
|
||||
const hasUserId = elem.getAttribute('data-useractivity') !== 'false';
|
||||
|
||||
// TODO: Use date-fns
|
||||
if (hasUserId) {
|
||||
minDate.setTime(minDate.getTime() - 24 * 60 * 60 * 1000); // one day back
|
||||
} else {
|
||||
@@ -141,7 +140,7 @@ class ActivityLog {
|
||||
const element = options.element;
|
||||
element.classList.add('activityLogListWidget');
|
||||
element.addEventListener('click', onListClick.bind(this));
|
||||
const apiClient = connectionManager.getApiClient(options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(options.serverId);
|
||||
reloadData(this, element, apiClient);
|
||||
const onUpdate = onActivityLogUpdate.bind(this);
|
||||
this.updateFn = onUpdate;
|
||||
@@ -153,7 +152,7 @@ class ActivityLog {
|
||||
|
||||
if (options) {
|
||||
options.element.classList.remove('activityLogListWidget');
|
||||
connectionManager.getApiClient(options.serverId).sendMessage('ActivityLogEntryStop', '0,1500');
|
||||
window.connectionManager.getApiClient(options.serverId).sendMessage('ActivityLogEntryStop', '0,1500');
|
||||
}
|
||||
|
||||
const onUpdate = this.updateFn;
|
||||
|
||||
@@ -10,7 +10,6 @@ import globalize from 'globalize';
|
||||
}
|
||||
|
||||
export default function (text, title) {
|
||||
|
||||
let options;
|
||||
if (typeof text === 'string') {
|
||||
options = {
|
||||
|
||||
@@ -26,7 +26,6 @@ import 'material-icons';
|
||||
}
|
||||
|
||||
function getAlphaPickerButtonClassName(vertical) {
|
||||
|
||||
let alphaPickerButtonClassName = 'alphaPickerButton';
|
||||
|
||||
if (layoutManager.tv) {
|
||||
@@ -45,14 +44,12 @@ import 'material-icons';
|
||||
}
|
||||
|
||||
function mapLetters(letters, vertical) {
|
||||
|
||||
return letters.map(l => {
|
||||
return getLetterButton(l, vertical);
|
||||
});
|
||||
}
|
||||
|
||||
function render(element, options) {
|
||||
|
||||
element.classList.add('alphaPicker');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
@@ -137,7 +134,6 @@ import 'material-icons';
|
||||
}
|
||||
|
||||
function onAlphaPickerInKeyboardModeClick(e) {
|
||||
|
||||
const alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
|
||||
|
||||
if (alphaPickerButton) {
|
||||
@@ -153,7 +149,6 @@ import 'material-icons';
|
||||
}
|
||||
|
||||
function onAlphaPickerClick(e) {
|
||||
|
||||
const alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
|
||||
|
||||
if (alphaPickerButton) {
|
||||
@@ -167,7 +162,6 @@ import 'material-icons';
|
||||
}
|
||||
|
||||
function onAlphaPickerFocusIn(e) {
|
||||
|
||||
if (alphaFocusTimeout) {
|
||||
clearTimeout(alphaFocusTimeout);
|
||||
alphaFocusTimeout = null;
|
||||
@@ -182,13 +176,11 @@ import 'material-icons';
|
||||
}
|
||||
|
||||
function onItemsFocusIn(e) {
|
||||
|
||||
const item = dom.parentWithClass(e.target, itemClass);
|
||||
|
||||
if (item) {
|
||||
const prefix = item.getAttribute('data-prefix');
|
||||
if (prefix && prefix.length) {
|
||||
|
||||
itemFocusValue = prefix[0];
|
||||
if (itemFocusTimeout) {
|
||||
clearTimeout(itemFocusTimeout);
|
||||
@@ -199,9 +191,7 @@ import 'material-icons';
|
||||
}
|
||||
|
||||
this.enabled = function (enabled) {
|
||||
|
||||
if (enabled) {
|
||||
|
||||
if (itemsContainer) {
|
||||
itemsContainer.addEventListener('focus', onItemsFocusIn, true);
|
||||
}
|
||||
@@ -215,9 +205,7 @@ import 'material-icons';
|
||||
} else {
|
||||
element.addEventListener('click', onAlphaPickerClick.bind(this));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (itemsContainer) {
|
||||
itemsContainer.removeEventListener('focus', onItemsFocusIn, true);
|
||||
}
|
||||
@@ -235,14 +223,12 @@ import 'material-icons';
|
||||
}
|
||||
|
||||
value(value, applyValue) {
|
||||
|
||||
const element = this.options.element;
|
||||
let btn;
|
||||
let selected;
|
||||
|
||||
if (value !== undefined) {
|
||||
if (value != null) {
|
||||
|
||||
value = value.toUpperCase();
|
||||
this._currentValue = value;
|
||||
|
||||
@@ -295,33 +281,27 @@ import 'material-icons';
|
||||
}
|
||||
|
||||
visible(visible) {
|
||||
|
||||
const element = this.options.element;
|
||||
element.style.visibility = visible ? 'visible' : 'hidden';
|
||||
}
|
||||
|
||||
values() {
|
||||
|
||||
const element = this.options.element;
|
||||
const elems = element.querySelectorAll('.alphaPickerButton');
|
||||
const values = [];
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
values.push(elems[i].getAttribute('data-value'));
|
||||
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
focus() {
|
||||
|
||||
const element = this.options.element;
|
||||
focusManager.autoFocus(element, true);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
||||
const element = this.options.element;
|
||||
this.enabled(false);
|
||||
element.classList.remove('focuscontainer-x');
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import browser from 'browser';
|
||||
import 'css!./appFooter';
|
||||
|
||||
function render(options) {
|
||||
|
||||
+556
-412
File diff suppressed because it is too large
Load Diff
+361
-405
@@ -1,456 +1,412 @@
|
||||
define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'globalize'], function (appSettings, browser, events, htmlMediaHelper, webSettings, globalize) {
|
||||
'use strict';
|
||||
import appSettings from 'appSettings';
|
||||
import browser from 'browser';
|
||||
import events from 'events';
|
||||
import * as htmlMediaHelper from 'htmlMediaHelper';
|
||||
import * as webSettings from 'webSettings';
|
||||
import globalize from 'globalize';
|
||||
|
||||
function getBaseProfileOptions(item) {
|
||||
var disableHlsVideoAudioCodecs = [];
|
||||
function getBaseProfileOptions(item) {
|
||||
const disableHlsVideoAudioCodecs = [];
|
||||
|
||||
if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) {
|
||||
if (browser.edge) {
|
||||
disableHlsVideoAudioCodecs.push('mp3');
|
||||
if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) {
|
||||
if (browser.edge) {
|
||||
disableHlsVideoAudioCodecs.push('mp3');
|
||||
}
|
||||
|
||||
disableHlsVideoAudioCodecs.push('ac3');
|
||||
disableHlsVideoAudioCodecs.push('eac3');
|
||||
disableHlsVideoAudioCodecs.push('opus');
|
||||
}
|
||||
|
||||
return {
|
||||
enableMkvProgressive: false,
|
||||
disableHlsVideoAudioCodecs: disableHlsVideoAudioCodecs
|
||||
};
|
||||
}
|
||||
|
||||
function getDeviceProfile(item, options = {}) {
|
||||
return new Promise(function (resolve) {
|
||||
import('browserdeviceprofile').then(({default: profileBuilder}) => {
|
||||
let profile;
|
||||
|
||||
if (window.NativeShell) {
|
||||
profile = window.NativeShell.AppHost.getDeviceProfile(profileBuilder);
|
||||
} else {
|
||||
const builderOpts = getBaseProfileOptions(item);
|
||||
builderOpts.enableSsaRender = (item && !options.isRetry && appSettings.get('subtitleburnin') !== 'allcomplexformats');
|
||||
profile = profileBuilder(builderOpts);
|
||||
}
|
||||
|
||||
disableHlsVideoAudioCodecs.push('ac3');
|
||||
disableHlsVideoAudioCodecs.push('eac3');
|
||||
disableHlsVideoAudioCodecs.push('opus');
|
||||
}
|
||||
|
||||
return {
|
||||
enableMkvProgressive: false,
|
||||
disableHlsVideoAudioCodecs: disableHlsVideoAudioCodecs
|
||||
};
|
||||
}
|
||||
|
||||
function getDeviceProfileForWindowsUwp(item) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(['browserdeviceprofile', 'environments/windows-uwp/mediacaps'], function (profileBuilder, uwpMediaCaps) {
|
||||
var profileOptions = getBaseProfileOptions(item);
|
||||
profileOptions.supportsDts = uwpMediaCaps.supportsDTS();
|
||||
profileOptions.supportsTrueHd = uwpMediaCaps.supportsDolby();
|
||||
profileOptions.audioChannels = uwpMediaCaps.getAudioChannels();
|
||||
resolve(profileBuilder(profileOptions));
|
||||
});
|
||||
resolve(profile);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1');
|
||||
}
|
||||
|
||||
function replaceAll(originalString, strReplace, strWith) {
|
||||
const strReplace2 = escapeRegExp(strReplace);
|
||||
const reg = new RegExp(strReplace2, 'ig');
|
||||
return originalString.replace(reg, strWith);
|
||||
}
|
||||
|
||||
function generateDeviceId() {
|
||||
const keys = [];
|
||||
|
||||
if (keys.push(navigator.userAgent), keys.push(new Date().getTime()), window.btoa) {
|
||||
const result = replaceAll(btoa(keys.join('|')), '=', '1');
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
function getDeviceProfile(item, options) {
|
||||
options = options || {};
|
||||
return Promise.resolve(new Date().getTime());
|
||||
}
|
||||
|
||||
if (self.Windows) {
|
||||
return getDeviceProfileForWindowsUwp(item);
|
||||
}
|
||||
function getDeviceId() {
|
||||
const key = '_deviceId2';
|
||||
const deviceId = appSettings.get(key);
|
||||
|
||||
return new Promise(function (resolve) {
|
||||
require(['browserdeviceprofile'], function (profileBuilder) {
|
||||
var profile;
|
||||
|
||||
if (window.NativeShell) {
|
||||
profile = window.NativeShell.AppHost.getDeviceProfile(profileBuilder);
|
||||
} else {
|
||||
var builderOpts = getBaseProfileOptions(item);
|
||||
builderOpts.enableSsaRender = (item && !options.isRetry && 'allcomplexformats' !== appSettings.get('subtitleburnin'));
|
||||
profile = profileBuilder(builderOpts);
|
||||
}
|
||||
|
||||
resolve(profile);
|
||||
});
|
||||
});
|
||||
if (deviceId) {
|
||||
return Promise.resolve(deviceId);
|
||||
}
|
||||
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
|
||||
return generateDeviceId().then(function (deviceId) {
|
||||
appSettings.set(key, deviceId);
|
||||
return deviceId;
|
||||
});
|
||||
}
|
||||
|
||||
function getDeviceName() {
|
||||
var deviceName;
|
||||
if (browser.tizen) {
|
||||
deviceName = 'Samsung Smart TV';
|
||||
} else if (browser.web0s) {
|
||||
deviceName = 'LG Smart TV';
|
||||
} else if (browser.operaTv) {
|
||||
deviceName = 'Opera TV';
|
||||
} else if (browser.xboxOne) {
|
||||
deviceName = 'Xbox One';
|
||||
} else if (browser.ps4) {
|
||||
deviceName = 'Sony PS4';
|
||||
} else if (browser.chrome) {
|
||||
deviceName = 'Chrome';
|
||||
} else if (browser.edgeChromium) {
|
||||
deviceName = 'Edge Chromium';
|
||||
} else if (browser.edge) {
|
||||
deviceName = 'Edge';
|
||||
} else if (browser.firefox) {
|
||||
deviceName = 'Firefox';
|
||||
} else if (browser.opera) {
|
||||
deviceName = 'Opera';
|
||||
} else if (browser.safari) {
|
||||
deviceName = 'Safari';
|
||||
} else {
|
||||
deviceName = 'Web Browser';
|
||||
}
|
||||
|
||||
function replaceAll(originalString, strReplace, strWith) {
|
||||
var strReplace2 = escapeRegExp(strReplace);
|
||||
var reg = new RegExp(strReplace2, 'ig');
|
||||
return originalString.replace(reg, strWith);
|
||||
if (browser.ipad) {
|
||||
deviceName += ' iPad';
|
||||
} else if (browser.iphone) {
|
||||
deviceName += ' iPhone';
|
||||
} else if (browser.android) {
|
||||
deviceName += ' Android';
|
||||
}
|
||||
|
||||
function generateDeviceId() {
|
||||
var keys = [];
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
if (keys.push(navigator.userAgent), keys.push(new Date().getTime()), self.btoa) {
|
||||
var result = replaceAll(btoa(keys.join('|')), '=', '1');
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
return Promise.resolve(new Date().getTime());
|
||||
function supportsVoiceInput() {
|
||||
if (!browser.tv) {
|
||||
return window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.oSpeechRecognition || window.msSpeechRecognition;
|
||||
}
|
||||
|
||||
function getDeviceId() {
|
||||
var key = '_deviceId2';
|
||||
var deviceId = appSettings.get(key);
|
||||
|
||||
if (deviceId) {
|
||||
return Promise.resolve(deviceId);
|
||||
}
|
||||
|
||||
return generateDeviceId().then(function (deviceId) {
|
||||
appSettings.set(key, deviceId);
|
||||
return deviceId;
|
||||
});
|
||||
}
|
||||
|
||||
function getDeviceName() {
|
||||
var deviceName;
|
||||
if (browser.tizen) {
|
||||
deviceName = 'Samsung Smart TV';
|
||||
} else if (browser.web0s) {
|
||||
deviceName = 'LG Smart TV';
|
||||
} else if (browser.operaTv) {
|
||||
deviceName = 'Opera TV';
|
||||
} else if (browser.xboxOne) {
|
||||
deviceName = 'Xbox One';
|
||||
} else if (browser.ps4) {
|
||||
deviceName = 'Sony PS4';
|
||||
} else if (browser.chrome) {
|
||||
deviceName = 'Chrome';
|
||||
} else if (browser.edge) {
|
||||
deviceName = 'Edge';
|
||||
} else if (browser.firefox) {
|
||||
deviceName = 'Firefox';
|
||||
} else if (browser.opera) {
|
||||
deviceName = 'Opera';
|
||||
} else if (browser.safari) {
|
||||
deviceName = 'Safari';
|
||||
} else {
|
||||
deviceName = 'Web Browser';
|
||||
}
|
||||
|
||||
if (browser.ipad) {
|
||||
deviceName += ' iPad';
|
||||
} else if (browser.iphone) {
|
||||
deviceName += ' iPhone';
|
||||
} else if (browser.android) {
|
||||
deviceName += ' Android';
|
||||
}
|
||||
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
function supportsVoiceInput() {
|
||||
if (!browser.tv) {
|
||||
return window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.oSpeechRecognition || window.msSpeechRecognition;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function supportsFullscreen() {
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function supportsFullscreen() {
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
}
|
||||
const element = document.documentElement;
|
||||
return (element.requestFullscreen || element.mozRequestFullScreen || element.webkitRequestFullscreen || element.msRequestFullscreen) || document.createElement('video').webkitEnterFullscreen;
|
||||
}
|
||||
|
||||
var element = document.documentElement;
|
||||
return (element.requestFullscreen || element.mozRequestFullScreen || element.webkitRequestFullscreen || element.msRequestFullscreen) || document.createElement('video').webkitEnterFullscreen;
|
||||
}
|
||||
|
||||
function getSyncProfile() {
|
||||
return new Promise(function (resolve) {
|
||||
require(['browserdeviceprofile', 'appSettings'], function (profileBuilder, appSettings) {
|
||||
var profile;
|
||||
|
||||
if (window.NativeShell) {
|
||||
profile = window.NativeShell.AppHost.getSyncProfile(profileBuilder, appSettings);
|
||||
} else {
|
||||
profile = profileBuilder();
|
||||
profile.MaxStaticMusicBitrate = appSettings.maxStaticMusicBitrate();
|
||||
}
|
||||
|
||||
resolve(profile);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getDefaultLayout() {
|
||||
return 'desktop';
|
||||
}
|
||||
|
||||
function supportsHtmlMediaAutoplay() {
|
||||
if (browser.edgeUwp || browser.tizen || browser.web0s || browser.orsay || browser.operaTv || browser.ps4 || browser.xboxOne) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.mobile) {
|
||||
return false;
|
||||
}
|
||||
function getDefaultLayout() {
|
||||
return 'desktop';
|
||||
}
|
||||
|
||||
function supportsHtmlMediaAutoplay() {
|
||||
if (browser.edgeUwp || browser.tizen || browser.web0s || browser.orsay || browser.operaTv || browser.ps4 || browser.xboxOne) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function supportsCue() {
|
||||
try {
|
||||
var video = document.createElement('video');
|
||||
var style = document.createElement('style');
|
||||
|
||||
style.textContent = 'video::cue {background: inherit}';
|
||||
document.body.appendChild(style);
|
||||
document.body.appendChild(video);
|
||||
|
||||
var cue = window.getComputedStyle(video, '::cue').background;
|
||||
document.body.removeChild(style);
|
||||
document.body.removeChild(video);
|
||||
|
||||
return !!cue.length;
|
||||
} catch (err) {
|
||||
console.error('error detecting cue support: ' + err);
|
||||
return false;
|
||||
}
|
||||
if (browser.mobile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function onAppVisible() {
|
||||
if (isHidden) {
|
||||
isHidden = false;
|
||||
console.debug('triggering app resume event');
|
||||
events.trigger(appHost, 'resume');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function supportsCue() {
|
||||
try {
|
||||
const video = document.createElement('video');
|
||||
const style = document.createElement('style');
|
||||
|
||||
style.textContent = 'video::cue {background: inherit}';
|
||||
document.body.appendChild(style);
|
||||
document.body.appendChild(video);
|
||||
|
||||
const cue = window.getComputedStyle(video, '::cue').background;
|
||||
document.body.removeChild(style);
|
||||
document.body.removeChild(video);
|
||||
|
||||
return !!cue.length;
|
||||
} catch (err) {
|
||||
console.error('error detecting cue support: ' + err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function onAppVisible() {
|
||||
if (isHidden) {
|
||||
isHidden = false;
|
||||
console.debug('triggering app resume event');
|
||||
events.trigger(appHost, 'resume');
|
||||
}
|
||||
}
|
||||
|
||||
function onAppHidden() {
|
||||
if (!isHidden) {
|
||||
isHidden = true;
|
||||
console.debug('app is hidden');
|
||||
}
|
||||
}
|
||||
|
||||
const supportedFeatures = function () {
|
||||
const features = [];
|
||||
|
||||
if (navigator.share) {
|
||||
features.push('sharing');
|
||||
}
|
||||
|
||||
function onAppHidden() {
|
||||
if (!isHidden) {
|
||||
isHidden = true;
|
||||
console.debug('app is hidden');
|
||||
}
|
||||
if (!browser.edgeUwp && !browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
features.push('filedownload');
|
||||
}
|
||||
|
||||
var supportedFeatures = function () {
|
||||
var features = [];
|
||||
if (browser.operaTv || browser.tizen || browser.orsay || browser.web0s) {
|
||||
features.push('exit');
|
||||
} else {
|
||||
features.push('exitmenu');
|
||||
features.push('plugins');
|
||||
}
|
||||
|
||||
if (navigator.share) {
|
||||
features.push('sharing');
|
||||
}
|
||||
if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.ps4) {
|
||||
features.push('externallinks');
|
||||
features.push('externalpremium');
|
||||
}
|
||||
|
||||
if (!browser.edgeUwp && !browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
features.push('filedownload');
|
||||
}
|
||||
if (!browser.operaTv) {
|
||||
features.push('externallinkdisplay');
|
||||
}
|
||||
|
||||
if (browser.operaTv || browser.tizen || browser.orsay || browser.web0s) {
|
||||
features.push('exit');
|
||||
if (supportsVoiceInput()) {
|
||||
features.push('voiceinput');
|
||||
}
|
||||
|
||||
if (supportsHtmlMediaAutoplay()) {
|
||||
features.push('htmlaudioautoplay');
|
||||
features.push('htmlvideoautoplay');
|
||||
}
|
||||
|
||||
if (browser.edgeUwp) {
|
||||
features.push('sync');
|
||||
}
|
||||
|
||||
if (supportsFullscreen()) {
|
||||
features.push('fullscreenchange');
|
||||
}
|
||||
|
||||
if (browser.tv || browser.xboxOne || browser.ps4 || browser.mobile) {
|
||||
features.push('physicalvolumecontrol');
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
features.push('remotecontrol');
|
||||
}
|
||||
|
||||
if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.edgeUwp) {
|
||||
features.push('remotevideo');
|
||||
}
|
||||
|
||||
features.push('displaylanguage');
|
||||
features.push('otherapppromotions');
|
||||
features.push('displaymode');
|
||||
features.push('targetblank');
|
||||
features.push('screensaver');
|
||||
|
||||
webSettings.getMultiServer().then(enabled => {
|
||||
if (enabled) features.push('multiserver');
|
||||
});
|
||||
|
||||
if (!browser.orsay && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) {
|
||||
features.push('subtitleappearancesettings');
|
||||
}
|
||||
|
||||
if (!browser.orsay) {
|
||||
features.push('subtitleburnsettings');
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.ps4 && !browser.xboxOne) {
|
||||
features.push('fileinput');
|
||||
}
|
||||
|
||||
if (browser.chrome || browser.edgeChromium) {
|
||||
features.push('chromecast');
|
||||
}
|
||||
|
||||
return features;
|
||||
}();
|
||||
|
||||
/**
|
||||
* Do exit according to platform
|
||||
*/
|
||||
function doExit() {
|
||||
try {
|
||||
if (window.NativeShell) {
|
||||
window.NativeShell.AppHost.exit();
|
||||
} else if (browser.tizen) {
|
||||
tizen.application.getCurrentApplication().exit();
|
||||
} else if (browser.web0s) {
|
||||
webOS.platformBack();
|
||||
} else {
|
||||
features.push('exitmenu');
|
||||
features.push('plugins');
|
||||
window.close();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('error closing application: ' + err);
|
||||
}
|
||||
}
|
||||
|
||||
if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.ps4) {
|
||||
features.push('externallinks');
|
||||
features.push('externalpremium');
|
||||
}
|
||||
let exitPromise;
|
||||
|
||||
if (!browser.operaTv) {
|
||||
features.push('externallinkdisplay');
|
||||
}
|
||||
|
||||
if (supportsVoiceInput()) {
|
||||
features.push('voiceinput');
|
||||
}
|
||||
|
||||
if (supportsHtmlMediaAutoplay()) {
|
||||
features.push('htmlaudioautoplay');
|
||||
features.push('htmlvideoautoplay');
|
||||
}
|
||||
|
||||
if (browser.edgeUwp) {
|
||||
features.push('sync');
|
||||
}
|
||||
|
||||
if (supportsFullscreen()) {
|
||||
features.push('fullscreenchange');
|
||||
}
|
||||
|
||||
if (browser.chrome || browser.edge && !browser.slow) {
|
||||
if (!browser.noAnimation && !browser.edgeUwp && !browser.xboxOne) {
|
||||
features.push('imageanalysis');
|
||||
}
|
||||
}
|
||||
|
||||
if (browser.tv || browser.xboxOne || browser.ps4 || browser.mobile) {
|
||||
features.push('physicalvolumecontrol');
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
features.push('remotecontrol');
|
||||
}
|
||||
|
||||
if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.edgeUwp) {
|
||||
features.push('remotevideo');
|
||||
}
|
||||
|
||||
features.push('displaylanguage');
|
||||
features.push('otherapppromotions');
|
||||
features.push('displaymode');
|
||||
features.push('targetblank');
|
||||
features.push('screensaver');
|
||||
|
||||
webSettings.enableMultiServer().then(enabled => {
|
||||
if (enabled) features.push('multiserver');
|
||||
});
|
||||
|
||||
if (!browser.orsay && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) {
|
||||
features.push('subtitleappearancesettings');
|
||||
}
|
||||
|
||||
if (!browser.orsay) {
|
||||
features.push('subtitleburnsettings');
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.ps4 && !browser.xboxOne) {
|
||||
features.push('fileinput');
|
||||
}
|
||||
|
||||
if (browser.chrome) {
|
||||
features.push('chromecast');
|
||||
}
|
||||
|
||||
return features;
|
||||
}();
|
||||
|
||||
/**
|
||||
* Do exit according to platform
|
||||
*/
|
||||
function doExit() {
|
||||
try {
|
||||
if (window.NativeShell) {
|
||||
window.NativeShell.AppHost.exit();
|
||||
} else if (browser.tizen) {
|
||||
tizen.application.getCurrentApplication().exit();
|
||||
} else if (browser.web0s) {
|
||||
webOS.platformBack();
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('error closing application: ' + err);
|
||||
}
|
||||
/**
|
||||
* Ask user for exit
|
||||
*/
|
||||
function askForExit() {
|
||||
if (exitPromise) {
|
||||
return;
|
||||
}
|
||||
|
||||
var exitPromise;
|
||||
|
||||
/**
|
||||
* Ask user for exit
|
||||
*/
|
||||
function askForExit() {
|
||||
if (exitPromise) {
|
||||
return;
|
||||
}
|
||||
|
||||
require(['actionsheet'], function (actionsheet) {
|
||||
exitPromise = actionsheet.show({
|
||||
title: globalize.translate('MessageConfirmAppExit'),
|
||||
items: [
|
||||
{id: 'yes', name: globalize.translate('Yes')},
|
||||
{id: 'no', name: globalize.translate('No')}
|
||||
]
|
||||
}).then(function (value) {
|
||||
if (value === 'yes') {
|
||||
doExit();
|
||||
}
|
||||
}).finally(function () {
|
||||
exitPromise = null;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var deviceId;
|
||||
var deviceName;
|
||||
var appName = 'Jellyfin Web';
|
||||
var appVersion = '10.6.0';
|
||||
|
||||
var appHost = {
|
||||
getWindowState: function () {
|
||||
return document.windowState || 'Normal';
|
||||
},
|
||||
setWindowState: function (state) {
|
||||
alert('setWindowState is not supported and should not be called');
|
||||
},
|
||||
exit: function () {
|
||||
if (!!window.appMode && browser.tizen) {
|
||||
askForExit();
|
||||
} else {
|
||||
import('actionsheet').then(({default: actionsheet}) => {
|
||||
exitPromise = actionsheet.show({
|
||||
title: globalize.translate('MessageConfirmAppExit'),
|
||||
items: [
|
||||
{id: 'yes', name: globalize.translate('Yes')},
|
||||
{id: 'no', name: globalize.translate('No')}
|
||||
]
|
||||
}).then(function (value) {
|
||||
if (value === 'yes') {
|
||||
doExit();
|
||||
}
|
||||
},
|
||||
supports: function (command) {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.supports(command);
|
||||
}
|
||||
}).finally(function () {
|
||||
exitPromise = null;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return -1 !== supportedFeatures.indexOf(command.toLowerCase());
|
||||
},
|
||||
preferVisualCards: browser.android || browser.chrome,
|
||||
getSyncProfile: getSyncProfile,
|
||||
getDefaultLayout: function () {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.getDefaultLayout();
|
||||
}
|
||||
let deviceId;
|
||||
let deviceName;
|
||||
const appName = 'Jellyfin Web';
|
||||
const appVersion = '10.7.0';
|
||||
|
||||
return getDefaultLayout();
|
||||
},
|
||||
getDeviceProfile: getDeviceProfile,
|
||||
init: function () {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.init();
|
||||
}
|
||||
|
||||
deviceName = getDeviceName();
|
||||
getDeviceId().then(function (id) {
|
||||
deviceId = id;
|
||||
});
|
||||
},
|
||||
deviceName: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.deviceName() : deviceName;
|
||||
},
|
||||
deviceId: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.deviceId() : deviceId;
|
||||
},
|
||||
appName: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.appName() : appName;
|
||||
},
|
||||
appVersion: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.appVersion() : appVersion;
|
||||
},
|
||||
getPushTokenInfo: function () {
|
||||
return {};
|
||||
},
|
||||
setThemeColor: function (color) {
|
||||
var metaThemeColor = document.querySelector('meta[name=theme-color]');
|
||||
|
||||
if (metaThemeColor) {
|
||||
metaThemeColor.setAttribute('content', color);
|
||||
}
|
||||
},
|
||||
setUserScalable: function (scalable) {
|
||||
if (!browser.tv) {
|
||||
var att = scalable ? 'width=device-width, initial-scale=1, minimum-scale=1, user-scalable=yes' : 'width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no';
|
||||
document.querySelector('meta[name=viewport]').setAttribute('content', att);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var isHidden = false;
|
||||
var hidden;
|
||||
var visibilityChange;
|
||||
|
||||
if (typeof document.hidden !== 'undefined') { /* eslint-disable-line compat/compat */
|
||||
hidden = 'hidden';
|
||||
visibilityChange = 'visibilitychange';
|
||||
} else if (typeof document.webkitHidden !== 'undefined') {
|
||||
hidden = 'webkitHidden';
|
||||
visibilityChange = 'webkitvisibilitychange';
|
||||
}
|
||||
|
||||
document.addEventListener(visibilityChange, function () {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (document[hidden]) {
|
||||
onAppHidden();
|
||||
const appHost = {
|
||||
getWindowState: function () {
|
||||
return document.windowState || 'Normal';
|
||||
},
|
||||
setWindowState: function () {
|
||||
alert('setWindowState is not supported and should not be called');
|
||||
},
|
||||
exit: function () {
|
||||
if (!!window.appMode && browser.tizen) {
|
||||
askForExit();
|
||||
} else {
|
||||
onAppVisible();
|
||||
doExit();
|
||||
}
|
||||
},
|
||||
supports: function (command) {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.supports(command);
|
||||
}
|
||||
}, false);
|
||||
|
||||
if (self.addEventListener) {
|
||||
self.addEventListener('focus', onAppVisible);
|
||||
self.addEventListener('blur', onAppHidden);
|
||||
return supportedFeatures.indexOf(command.toLowerCase()) !== -1;
|
||||
},
|
||||
preferVisualCards: browser.android || browser.chrome,
|
||||
getDefaultLayout: function () {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.getDefaultLayout();
|
||||
}
|
||||
|
||||
return getDefaultLayout();
|
||||
},
|
||||
getDeviceProfile: getDeviceProfile,
|
||||
init: function () {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.init();
|
||||
}
|
||||
|
||||
deviceName = getDeviceName();
|
||||
getDeviceId().then(function (id) {
|
||||
deviceId = id;
|
||||
});
|
||||
},
|
||||
deviceName: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.deviceName() : deviceName;
|
||||
},
|
||||
deviceId: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.deviceId() : deviceId;
|
||||
},
|
||||
appName: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.appName() : appName;
|
||||
},
|
||||
appVersion: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.appVersion() : appVersion;
|
||||
},
|
||||
getPushTokenInfo: function () {
|
||||
return {};
|
||||
},
|
||||
setUserScalable: function (scalable) {
|
||||
if (!browser.tv) {
|
||||
const att = scalable ? 'width=device-width, initial-scale=1, minimum-scale=1, user-scalable=yes' : 'width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no';
|
||||
document.querySelector('meta[name=viewport]').setAttribute('content', att);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return appHost;
|
||||
});
|
||||
let isHidden = false;
|
||||
let hidden;
|
||||
let visibilityChange;
|
||||
|
||||
if (typeof document.hidden !== 'undefined') { /* eslint-disable-line compat/compat */
|
||||
hidden = 'hidden';
|
||||
visibilityChange = 'visibilitychange';
|
||||
} else if (typeof document.webkitHidden !== 'undefined') {
|
||||
hidden = 'webkitHidden';
|
||||
visibilityChange = 'webkitvisibilitychange';
|
||||
}
|
||||
|
||||
document.addEventListener(visibilityChange, function () {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (document[hidden]) {
|
||||
onAppHidden();
|
||||
} else {
|
||||
onAppVisible();
|
||||
}
|
||||
}, false);
|
||||
|
||||
if (window.addEventListener) {
|
||||
window.addEventListener('focus', onAppVisible);
|
||||
window.addEventListener('blur', onAppHidden);
|
||||
}
|
||||
|
||||
export default appHost;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import browser from 'browser';
|
||||
import connectionManager from 'connectionManager';
|
||||
import playbackManager from 'playbackManager';
|
||||
import dom from 'dom';
|
||||
import * as userSettings from 'userSettings';
|
||||
@@ -177,7 +176,7 @@ import 'css!./backdrop';
|
||||
function getItemImageUrls(item, imageOptions) {
|
||||
imageOptions = imageOptions || {};
|
||||
|
||||
const apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
if (item.BackdropImageTags && item.BackdropImageTags.length > 0) {
|
||||
return item.BackdropImageTags.map((imgTag, index) => {
|
||||
return apiClient.getScaledImageUrl(item.BackdropItemId || item.Id, Object.assign(imageOptions, {
|
||||
|
||||
@@ -209,6 +209,10 @@ button::-moz-focus-inner {
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
.defaultCardBackground {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.cardContent:not(.defaultCardBackground) {
|
||||
background-color: transparent;
|
||||
}
|
||||
@@ -239,33 +243,13 @@ button::-moz-focus-inner {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.cardImage-img {
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
|
||||
/* This is simply for lazy image purposes, to ensure the image is visible sooner when scrolling */
|
||||
min-height: 70%;
|
||||
min-width: 70%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.coveredImage-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.coveredImage-noscale-img {
|
||||
max-height: none;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.coveredImage {
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
.coveredImage-noScale {
|
||||
background-size: cover;
|
||||
.coveredImage.coveredImage-contain {
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.cardFooter {
|
||||
@@ -372,6 +356,8 @@ button::-moz-focus-inner {
|
||||
.cardDefaultText {
|
||||
white-space: normal;
|
||||
text-align: center;
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cardImageContainer .cardImageIcon {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
import datetime from 'datetime';
|
||||
import imageLoader from 'imageLoader';
|
||||
import connectionManager from 'connectionManager';
|
||||
import itemHelper from 'itemHelper';
|
||||
import focusManager from 'focusManager';
|
||||
import indicators from 'indicators';
|
||||
@@ -277,7 +276,7 @@ import 'programStyles';
|
||||
*/
|
||||
function getImageWidth(shape, screenWidth, isOrientationLandscape) {
|
||||
const imagesPerRow = getPostersPerRow(shape, screenWidth, isOrientationLandscape);
|
||||
return Math.round(screenWidth / imagesPerRow) * 2;
|
||||
return Math.round(screenWidth / imagesPerRow);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -291,12 +290,10 @@ import 'programStyles';
|
||||
const primaryImageAspectRatio = imageLoader.getPrimaryImageAspectRatio(items);
|
||||
|
||||
if (['auto', 'autohome', 'autooverflow', 'autoVertical'].includes(options.shape)) {
|
||||
|
||||
const requestedShape = options.shape;
|
||||
options.shape = null;
|
||||
|
||||
if (primaryImageAspectRatio) {
|
||||
|
||||
if (primaryImageAspectRatio >= 3) {
|
||||
options.shape = 'banner';
|
||||
options.coverImage = true;
|
||||
@@ -364,16 +361,16 @@ import 'programStyles';
|
||||
let hasOpenRow;
|
||||
let hasOpenSection;
|
||||
|
||||
let sectionTitleTagName = options.sectionTitleTagName || 'div';
|
||||
const sectionTitleTagName = options.sectionTitleTagName || 'div';
|
||||
let apiClient;
|
||||
let lastServerId;
|
||||
|
||||
for (const [i, item] of items.entries()) {
|
||||
let serverId = item.ServerId || options.serverId;
|
||||
const serverId = item.ServerId || options.serverId;
|
||||
|
||||
if (serverId !== lastServerId) {
|
||||
lastServerId = serverId;
|
||||
apiClient = connectionManager.getApiClient(lastServerId);
|
||||
apiClient = window.connectionManager.getApiClient(lastServerId);
|
||||
}
|
||||
|
||||
if (options.indexBy) {
|
||||
@@ -394,7 +391,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (newIndexValue !== currentIndexValue) {
|
||||
|
||||
if (hasOpenRow) {
|
||||
html += '</div>';
|
||||
hasOpenRow = false;
|
||||
@@ -402,7 +398,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (hasOpenSection) {
|
||||
|
||||
html += '</div>';
|
||||
|
||||
if (isVertical) {
|
||||
@@ -426,7 +421,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (options.rows && itemsInRow === 0) {
|
||||
|
||||
if (hasOpenRow) {
|
||||
html += '</div>';
|
||||
hasOpenRow = false;
|
||||
@@ -626,7 +620,7 @@ import 'programStyles';
|
||||
});
|
||||
}
|
||||
|
||||
let blurHashes = options.imageBlurhashes || item.ImageBlurHashes || {};
|
||||
const blurHashes = options.imageBlurhashes || item.ImageBlurHashes || {};
|
||||
|
||||
return {
|
||||
imgUrl: imgUrl,
|
||||
@@ -661,7 +655,7 @@ import 'programStyles';
|
||||
for (let i = 0; i < character.length; i++) {
|
||||
sum += parseInt(character.charAt(i));
|
||||
}
|
||||
let index = String(sum).substr(-1);
|
||||
const index = String(sum).substr(-1);
|
||||
|
||||
return (index % numRandomColors) + 1;
|
||||
} else {
|
||||
@@ -686,9 +680,8 @@ import 'programStyles';
|
||||
let valid = 0;
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
|
||||
let currentCssClass = cssClass;
|
||||
let text = lines[i];
|
||||
const text = lines[i];
|
||||
|
||||
if (valid > 0 && isOuterFooter) {
|
||||
currentCssClass += ' cardText-secondary';
|
||||
@@ -713,8 +706,7 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (forceLines) {
|
||||
|
||||
let linesLength = maxLines || Math.min(lines.length, maxLines || lines.length);
|
||||
const linesLength = maxLines || Math.min(lines.length, maxLines || lines.length);
|
||||
|
||||
while (valid < linesLength) {
|
||||
html += "<div class='" + cssClass + "'> </div>";
|
||||
@@ -745,7 +737,6 @@ import 'programStyles';
|
||||
let airTimeText = '';
|
||||
|
||||
if (item.StartDate) {
|
||||
|
||||
try {
|
||||
let date = datetime.parseISO8601Date(item.StartDate);
|
||||
|
||||
@@ -792,7 +783,6 @@ import 'programStyles';
|
||||
const showOtherText = isOuterFooter ? !overlayText : overlayText;
|
||||
|
||||
if (isOuterFooter && options.cardLayout && layoutManager.mobile) {
|
||||
|
||||
if (options.cardFooterAside !== 'none') {
|
||||
html += '<button is="paper-icon-button-light" class="itemAction btnCardOptions cardText-secondary" data-action="menu"><span class="material-icons more_vert"></span></button>';
|
||||
}
|
||||
@@ -807,9 +797,7 @@ import 'programStyles';
|
||||
|
||||
if (showOtherText) {
|
||||
if ((options.showParentTitle || options.showParentTitleOrTitle) && !parentTitleUnderneath) {
|
||||
|
||||
if (isOuterFooter && item.Type === 'Episode' && item.SeriesName) {
|
||||
|
||||
if (item.SeriesId) {
|
||||
lines.push(getTextActionButton({
|
||||
Id: item.SeriesId,
|
||||
@@ -822,15 +810,12 @@ import 'programStyles';
|
||||
lines.push(item.SeriesName);
|
||||
}
|
||||
} else {
|
||||
|
||||
if (isUsingLiveTvNaming(item)) {
|
||||
|
||||
lines.push(item.Name);
|
||||
|
||||
if (!item.EpisodeTitle) {
|
||||
titleAdded = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
const parentTitle = item.SeriesName || item.Series || item.Album || item.AlbumArtist || '';
|
||||
|
||||
@@ -848,7 +833,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (showMediaTitle) {
|
||||
|
||||
const name = options.showTitle === 'auto' && !item.IsFolder && item.MediaType === 'Photo' ? '' : itemHelper.getDisplayName(item, {
|
||||
includeParentInfo: options.includeParentInfoInTitle
|
||||
});
|
||||
@@ -865,7 +849,6 @@ import 'programStyles';
|
||||
|
||||
if (showOtherText) {
|
||||
if (options.showParentTitle && parentTitleUnderneath) {
|
||||
|
||||
if (isOuterFooter && item.AlbumArtists && item.AlbumArtists.length) {
|
||||
item.AlbumArtists[0].Type = 'MusicArtist';
|
||||
item.AlbumArtists[0].IsFolder = true;
|
||||
@@ -899,7 +882,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (options.showPremiereDate) {
|
||||
|
||||
if (item.PremiereDate) {
|
||||
try {
|
||||
lines.push(datetime.toLocaleDateString(
|
||||
@@ -908,7 +890,6 @@ import 'programStyles';
|
||||
));
|
||||
} catch (err) {
|
||||
lines.push('');
|
||||
|
||||
}
|
||||
} else {
|
||||
lines.push('');
|
||||
@@ -916,14 +897,10 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (options.showYear || options.showSeriesYear) {
|
||||
|
||||
if (item.Type === 'Series') {
|
||||
if (item.Status === 'Continuing') {
|
||||
|
||||
lines.push(globalize.translate('SeriesYearToPresent', item.ProductionYear || ''));
|
||||
|
||||
} else {
|
||||
|
||||
if (item.EndDate && item.ProductionYear) {
|
||||
const endYear = datetime.parseISO8601Date(item.EndDate).getFullYear();
|
||||
lines.push(item.ProductionYear + ((endYear === item.ProductionYear) ? '' : (' - ' + endYear)));
|
||||
@@ -937,9 +914,7 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (options.showRuntime) {
|
||||
|
||||
if (item.RunTimeTicks) {
|
||||
|
||||
lines.push(datetime.getDisplayRunningTime(item.RunTimeTicks));
|
||||
} else {
|
||||
lines.push('');
|
||||
@@ -947,14 +922,11 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (options.showAirTime) {
|
||||
|
||||
lines.push(getAirTimeText(item, options.showAirDateTime, options.showAirEndTime) || '');
|
||||
}
|
||||
|
||||
if (options.showChannelName) {
|
||||
|
||||
if (item.ChannelId) {
|
||||
|
||||
lines.push(getTextActionButton({
|
||||
|
||||
Id: item.ChannelId,
|
||||
@@ -971,7 +943,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (options.showCurrentProgram && item.Type === 'TvChannel') {
|
||||
|
||||
if (item.CurrentProgram) {
|
||||
lines.push(item.CurrentProgram.Name);
|
||||
} else {
|
||||
@@ -980,7 +951,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (options.showCurrentProgramTime && item.Type === 'TvChannel') {
|
||||
|
||||
if (item.CurrentProgram) {
|
||||
lines.push(getAirTimeText(item.CurrentProgram, false, true) || '');
|
||||
} else {
|
||||
@@ -990,7 +960,6 @@ import 'programStyles';
|
||||
|
||||
if (options.showSeriesTimerTime) {
|
||||
if (item.RecordAnyTime) {
|
||||
|
||||
lines.push(globalize.translate('Anytime'));
|
||||
} else {
|
||||
lines.push(datetime.getDisplayTime(item.StartDate));
|
||||
@@ -1016,6 +985,10 @@ import 'programStyles';
|
||||
lines = [];
|
||||
}
|
||||
|
||||
if (overlayText && showTitle) {
|
||||
lines = [item.Name];
|
||||
}
|
||||
|
||||
const addRightTextMargin = isOuterFooter && options.cardLayout && !options.centerText && options.cardFooterAside !== 'none' && layoutManager.mobile;
|
||||
|
||||
html += getCardTextLines(lines, cssClass, !options.overlayText, isOuterFooter, options.cardLayout, addRightTextMargin, options.lines);
|
||||
@@ -1025,7 +998,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (html) {
|
||||
|
||||
if (!isOuterFooter || logoUrl || options.cardLayout) {
|
||||
html = '<div class="' + footerClass + '">' + html;
|
||||
|
||||
@@ -1067,31 +1039,25 @@ import 'programStyles';
|
||||
* @returns {string} HTML markup for the item count indicator.
|
||||
*/
|
||||
function getItemCountsHtml(options, item) {
|
||||
let counts = [];
|
||||
const counts = [];
|
||||
let childText;
|
||||
|
||||
if (item.Type === 'Playlist') {
|
||||
|
||||
childText = '';
|
||||
|
||||
if (item.RunTimeTicks) {
|
||||
|
||||
let minutes = item.RunTimeTicks / 600000000;
|
||||
|
||||
minutes = minutes || 1;
|
||||
|
||||
childText += globalize.translate('ValueMinutes', Math.round(minutes));
|
||||
|
||||
} else {
|
||||
childText += globalize.translate('ValueMinutes', 0);
|
||||
}
|
||||
|
||||
counts.push(childText);
|
||||
|
||||
} else if (item.Type === 'Genre' || item.Type === 'Studio') {
|
||||
|
||||
if (item.MovieCount) {
|
||||
|
||||
childText = item.MovieCount === 1 ?
|
||||
globalize.translate('ValueOneMovie') :
|
||||
globalize.translate('ValueMovieCount', item.MovieCount);
|
||||
@@ -1100,7 +1066,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (item.SeriesCount) {
|
||||
|
||||
childText = item.SeriesCount === 1 ?
|
||||
globalize.translate('ValueOneSeries') :
|
||||
globalize.translate('ValueSeriesCount', item.SeriesCount);
|
||||
@@ -1108,18 +1073,14 @@ import 'programStyles';
|
||||
counts.push(childText);
|
||||
}
|
||||
if (item.EpisodeCount) {
|
||||
|
||||
childText = item.EpisodeCount === 1 ?
|
||||
globalize.translate('ValueOneEpisode') :
|
||||
globalize.translate('ValueEpisodeCount', item.EpisodeCount);
|
||||
|
||||
counts.push(childText);
|
||||
}
|
||||
|
||||
} else if (item.Type === 'MusicGenre' || options.context === 'MusicArtist') {
|
||||
|
||||
if (item.AlbumCount) {
|
||||
|
||||
childText = item.AlbumCount === 1 ?
|
||||
globalize.translate('ValueOneAlbum') :
|
||||
globalize.translate('ValueAlbumCount', item.AlbumCount);
|
||||
@@ -1127,7 +1088,6 @@ import 'programStyles';
|
||||
counts.push(childText);
|
||||
}
|
||||
if (item.SongCount) {
|
||||
|
||||
childText = item.SongCount === 1 ?
|
||||
globalize.translate('ValueOneSong') :
|
||||
globalize.translate('ValueSongCount', item.SongCount);
|
||||
@@ -1135,16 +1095,13 @@ import 'programStyles';
|
||||
counts.push(childText);
|
||||
}
|
||||
if (item.MusicVideoCount) {
|
||||
|
||||
childText = item.MusicVideoCount === 1 ?
|
||||
globalize.translate('ValueOneMusicVideo') :
|
||||
globalize.translate('ValueMusicVideoCount', item.MusicVideoCount);
|
||||
|
||||
counts.push(childText);
|
||||
}
|
||||
|
||||
} else if (item.Type === 'Series') {
|
||||
|
||||
childText = item.RecursiveItemCount === 1 ?
|
||||
globalize.translate('ValueOneEpisode') :
|
||||
globalize.translate('ValueEpisodeCount', item.RecursiveItemCount);
|
||||
@@ -1163,6 +1120,7 @@ import 'programStyles';
|
||||
function importRefreshIndicator() {
|
||||
if (!refreshIndicatorLoaded) {
|
||||
refreshIndicatorLoaded = true;
|
||||
/* eslint-disable-next-line @babel/no-unused-expressions */
|
||||
import('emby-itemrefreshindicator');
|
||||
}
|
||||
}
|
||||
@@ -1197,13 +1155,11 @@ import 'programStyles';
|
||||
let shape = options.shape;
|
||||
|
||||
if (shape === 'mixed') {
|
||||
|
||||
shape = null;
|
||||
|
||||
const primaryImageAspectRatio = item.PrimaryImageAspectRatio;
|
||||
|
||||
if (primaryImageAspectRatio) {
|
||||
|
||||
if (primaryImageAspectRatio >= 1.33) {
|
||||
shape = 'mixedBackdrop';
|
||||
} else if (primaryImageAspectRatio > 0.71) {
|
||||
@@ -1259,8 +1215,8 @@ import 'programStyles';
|
||||
if (coveredImage) {
|
||||
cardImageContainerClass += ' coveredImage';
|
||||
|
||||
if (item.MediaType === 'Photo' || item.Type === 'PhotoAlbum' || item.Type === 'Folder' || item.ProgramInfo || item.Type === 'Program' || item.Type === 'Recording') {
|
||||
cardImageContainerClass += ' coveredImage-noScale';
|
||||
if (item.Type === 'TvChannel') {
|
||||
cardImageContainerClass += ' coveredImage-contain';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1295,7 +1251,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (overlayText) {
|
||||
|
||||
logoUrl = null;
|
||||
|
||||
footerCssClass = progressHtml ? 'innerCardFooter fullInnerCardFooter' : 'innerCardFooter';
|
||||
@@ -1366,7 +1321,7 @@ import 'programStyles';
|
||||
let cardBoxClose = '';
|
||||
let cardScalableClose = '';
|
||||
|
||||
let cardContentClass = 'cardContent';
|
||||
const cardContentClass = 'cardContent';
|
||||
|
||||
let blurhashAttrib = '';
|
||||
if (blurhash && blurhash.length > 0) {
|
||||
@@ -1385,7 +1340,7 @@ import 'programStyles';
|
||||
cardImageContainerClose = '</button>';
|
||||
}
|
||||
|
||||
let cardScalableClass = 'cardScalable';
|
||||
const cardScalableClass = 'cardScalable';
|
||||
|
||||
cardImageContainerOpen = '<div class="' + cardBoxClass + '"><div class="' + cardScalableClass + '"><div class="cardPadder cardPadder-' + shape + '"></div>' + cardImageContainerOpen;
|
||||
cardBoxClose = '</div>';
|
||||
@@ -1404,7 +1359,6 @@ import 'programStyles';
|
||||
indicatorsHtml += indicators.getTypeIndicator(item);
|
||||
|
||||
if (options.showGroupCount) {
|
||||
|
||||
indicatorsHtml += indicators.getChildCountIndicatorHtml(item, {
|
||||
minCount: 1
|
||||
});
|
||||
@@ -1498,14 +1452,15 @@ import 'programStyles';
|
||||
const userData = item.UserData || {};
|
||||
|
||||
if (itemHelper.canMarkPlayed(item)) {
|
||||
/* eslint-disable-next-line @babel/no-unused-expressions */
|
||||
import('emby-playstatebutton');
|
||||
html += '<button is="emby-playstatebutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-played="' + (userData.Played) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover check"></span></button>';
|
||||
}
|
||||
|
||||
if (itemHelper.canRate(item)) {
|
||||
|
||||
const likes = userData.Likes == null ? '' : userData.Likes;
|
||||
|
||||
/* eslint-disable-next-line @babel/no-unused-expressions */
|
||||
import('emby-ratingbutton');
|
||||
html += '<button is="emby-ratingbutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-likes="' + likes + '" data-isfavorite="' + (userData.IsFavorite) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover favorite"></span></button>';
|
||||
}
|
||||
@@ -1583,7 +1538,6 @@ import 'programStyles';
|
||||
const html = buildCardsHtmlInternal(items, options);
|
||||
|
||||
if (html) {
|
||||
|
||||
if (options.itemsContainer.cardBuilderHtml !== html) {
|
||||
options.itemsContainer.innerHTML = html;
|
||||
|
||||
@@ -1596,7 +1550,6 @@ import 'programStyles';
|
||||
|
||||
imageLoader.lazyChildren(options.itemsContainer);
|
||||
} else {
|
||||
|
||||
options.itemsContainer.innerHTML = html;
|
||||
options.itemsContainer.cardBuilderHtml = null;
|
||||
}
|
||||
@@ -1620,7 +1573,6 @@ import 'programStyles';
|
||||
indicatorsElem = card.querySelector('.cardIndicators');
|
||||
|
||||
if (!indicatorsElem) {
|
||||
|
||||
const cardImageContainer = card.querySelector('.cardImageContainer');
|
||||
indicatorsElem = document.createElement('div');
|
||||
indicatorsElem.classList.add('cardIndicators');
|
||||
@@ -1644,11 +1596,9 @@ import 'programStyles';
|
||||
let itemProgressBar = null;
|
||||
|
||||
if (userData.Played) {
|
||||
|
||||
playedIndicator = card.querySelector('.playedIndicator');
|
||||
|
||||
if (!playedIndicator) {
|
||||
|
||||
playedIndicator = document.createElement('div');
|
||||
playedIndicator.classList.add('playedIndicator');
|
||||
playedIndicator.classList.add('indicator');
|
||||
@@ -1657,10 +1607,8 @@ import 'programStyles';
|
||||
}
|
||||
playedIndicator.innerHTML = '<span class="material-icons indicatorIcon check"></span>';
|
||||
} else {
|
||||
|
||||
playedIndicator = card.querySelector('.playedIndicator');
|
||||
if (playedIndicator) {
|
||||
|
||||
playedIndicator.parentNode.removeChild(playedIndicator);
|
||||
}
|
||||
}
|
||||
@@ -1668,7 +1616,6 @@ import 'programStyles';
|
||||
countIndicator = card.querySelector('.countIndicator');
|
||||
|
||||
if (!countIndicator) {
|
||||
|
||||
countIndicator = document.createElement('div');
|
||||
countIndicator.classList.add('countIndicator');
|
||||
indicatorsElem = ensureIndicators(card, indicatorsElem);
|
||||
@@ -1676,10 +1623,8 @@ import 'programStyles';
|
||||
}
|
||||
countIndicator.innerHTML = userData.UnplayedItemCount;
|
||||
} else if (enableCountIndicator) {
|
||||
|
||||
countIndicator = card.querySelector('.countIndicator');
|
||||
if (countIndicator) {
|
||||
|
||||
countIndicator.parentNode.removeChild(countIndicator);
|
||||
}
|
||||
}
|
||||
@@ -1691,7 +1636,6 @@ import 'programStyles';
|
||||
});
|
||||
|
||||
if (progressHtml) {
|
||||
|
||||
itemProgressBar = card.querySelector('.itemProgressBar');
|
||||
|
||||
if (!itemProgressBar) {
|
||||
@@ -1710,7 +1654,6 @@ import 'programStyles';
|
||||
|
||||
itemProgressBar.innerHTML = progressHtml;
|
||||
} else {
|
||||
|
||||
itemProgressBar = card.querySelector('.itemProgressBar');
|
||||
if (itemProgressBar) {
|
||||
itemProgressBar.parentNode.removeChild(itemProgressBar);
|
||||
@@ -1741,7 +1684,7 @@ import 'programStyles';
|
||||
const cells = itemsContainer.querySelectorAll('.card[data-id="' + programId + '"]');
|
||||
|
||||
for (let i = 0, length = cells.length; i < length; i++) {
|
||||
let cell = cells[i];
|
||||
const cell = cells[i];
|
||||
const icon = cell.querySelector('.timerIndicator');
|
||||
if (!icon) {
|
||||
const indicatorsElem = ensureIndicators(cell);
|
||||
@@ -1760,8 +1703,8 @@ import 'programStyles';
|
||||
const cells = itemsContainer.querySelectorAll('.card[data-timerid="' + timerId + '"]');
|
||||
|
||||
for (let i = 0; i < cells.length; i++) {
|
||||
let cell = cells[i];
|
||||
let icon = cell.querySelector('.timerIndicator');
|
||||
const cell = cells[i];
|
||||
const icon = cell.querySelector('.timerIndicator');
|
||||
if (icon) {
|
||||
icon.parentNode.removeChild(icon);
|
||||
}
|
||||
@@ -1778,8 +1721,8 @@ import 'programStyles';
|
||||
const cells = itemsContainer.querySelectorAll('.card[data-seriestimerid="' + cancelledTimerId + '"]');
|
||||
|
||||
for (let i = 0; i < cells.length; i++) {
|
||||
let cell = cells[i];
|
||||
let icon = cell.querySelector('.timerIndicator');
|
||||
const cell = cells[i];
|
||||
const icon = cell.querySelector('.timerIndicator');
|
||||
if (icon) {
|
||||
icon.parentNode.removeChild(icon);
|
||||
}
|
||||
|
||||
@@ -7,14 +7,12 @@
|
||||
|
||||
import datetime from 'datetime';
|
||||
import imageLoader from 'imageLoader';
|
||||
import connectionManager from 'connectionManager';
|
||||
import layoutManager from 'layoutManager';
|
||||
import browser from 'browser';
|
||||
|
||||
const enableFocusTransform = !browser.slow && !browser.edge;
|
||||
|
||||
function buildChapterCardsHtml(item, chapters, options) {
|
||||
|
||||
// TODO move card creation code to Card component
|
||||
|
||||
let className = 'card itemAction chapterCard';
|
||||
@@ -35,7 +33,6 @@ import browser from 'browser';
|
||||
let shape = (options.backdropShape || 'backdrop');
|
||||
|
||||
if (videoStream.Width && videoStream.Height) {
|
||||
|
||||
if ((videoStream.Width / videoStream.Height) <= 1.2) {
|
||||
shape = (options.squareShape || 'square');
|
||||
}
|
||||
@@ -50,10 +47,9 @@ import browser from 'browser';
|
||||
let html = '';
|
||||
let itemsInRow = 0;
|
||||
|
||||
const apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
for (let i = 0, length = chapters.length; i < length; i++) {
|
||||
|
||||
if (options.rows && itemsInRow === 0) {
|
||||
html += '<div class="cardColumn">';
|
||||
}
|
||||
@@ -73,12 +69,10 @@ import browser from 'browser';
|
||||
}
|
||||
|
||||
function getImgUrl({Id}, {ImageTag}, index, maxWidth, apiClient) {
|
||||
|
||||
if (ImageTag) {
|
||||
|
||||
return apiClient.getScaledImageUrl(Id, {
|
||||
|
||||
maxWidth: maxWidth * 2,
|
||||
maxWidth: maxWidth,
|
||||
tag: ImageTag,
|
||||
type: 'Chapter',
|
||||
index
|
||||
@@ -89,7 +83,6 @@ import browser from 'browser';
|
||||
}
|
||||
|
||||
function buildChapterCard(item, apiClient, chapter, index, {width, coverImage}, className, shape) {
|
||||
|
||||
const imgUrl = getImgUrl(item, chapter, index, width || 400, apiClient);
|
||||
|
||||
let cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer';
|
||||
@@ -110,13 +103,10 @@ import browser from 'browser';
|
||||
const cardBoxCssClass = 'cardBox';
|
||||
const cardScalableClass = 'cardScalable';
|
||||
|
||||
const html = `<button type="button" class="${className}"${dataAttributes}><div class="${cardBoxCssClass}"><div class="${cardScalableClass}"><div class="cardPadder-${shape}"></div>${cardImageContainer}</div><div class="innerCardFooter">${nameHtml}</div></div></div></button>`;
|
||||
|
||||
return html;
|
||||
return `<button type="button" class="${className}"${dataAttributes}><div class="${cardBoxCssClass}"><div class="${cardScalableClass}"><div class="cardPadder-${shape}"></div>${cardImageContainer}</div><div class="innerCardFooter">${nameHtml}</div></div></div></button>`;
|
||||
}
|
||||
|
||||
export function buildChapterCards(item, chapters, options) {
|
||||
|
||||
if (options.parentContainer) {
|
||||
// Abort if the container has been disposed
|
||||
if (!document.body.contains(options.parentContainer)) {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
import cardBuilder from 'cardBuilder';
|
||||
|
||||
export function buildPeopleCards(items, options) {
|
||||
|
||||
options = Object.assign(options || {}, {
|
||||
cardLayout: false,
|
||||
centerText: true,
|
||||
|
||||
@@ -1,34 +1,28 @@
|
||||
define([], function() {
|
||||
'use strict';
|
||||
|
||||
if (window.appMode === 'cordova' || window.appMode === 'android') {
|
||||
return {
|
||||
load: function () {
|
||||
window.chrome = window.chrome || {};
|
||||
class CastSenderApi {
|
||||
load() {
|
||||
if (window.appMode === 'cordova' || window.appMode === 'android') {
|
||||
window.chrome = window.chrome || {};
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
let ccLoaded = false;
|
||||
if (ccLoaded) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
var ccLoaded = false;
|
||||
return {
|
||||
load: function () {
|
||||
if (ccLoaded) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
var fileref = document.createElement('script');
|
||||
fileref.setAttribute('type', 'text/javascript');
|
||||
return new Promise(function (resolve) {
|
||||
const fileref = document.createElement('script');
|
||||
fileref.setAttribute('type', 'text/javascript');
|
||||
|
||||
fileref.onload = function () {
|
||||
ccLoaded = true;
|
||||
resolve();
|
||||
};
|
||||
fileref.onload = function () {
|
||||
ccLoaded = true;
|
||||
resolve();
|
||||
};
|
||||
|
||||
fileref.setAttribute('src', 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js');
|
||||
document.querySelector('head').appendChild(fileref);
|
||||
});
|
||||
}
|
||||
};
|
||||
fileref.setAttribute('src', 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js');
|
||||
document.querySelector('head').appendChild(fileref);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default CastSenderApi;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import dom from 'dom';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import loading from 'loading';
|
||||
import connectionManager from 'connectionManager';
|
||||
import globalize from 'globalize';
|
||||
import actionsheet from 'actionsheet';
|
||||
import 'emby-input';
|
||||
@@ -16,14 +15,15 @@ export default class channelMapper {
|
||||
function mapChannel(button, channelId, providerChannelId) {
|
||||
loading.show();
|
||||
const providerId = options.providerId;
|
||||
connectionManager.getApiClient(options.serverId).ajax({
|
||||
window.connectionManager.getApiClient(options.serverId).ajax({
|
||||
type: 'POST',
|
||||
url: ApiClient.getUrl('LiveTv/ChannelMappings'),
|
||||
data: {
|
||||
data: JSON.stringify({
|
||||
providerId: providerId,
|
||||
tunerChannelId: channelId,
|
||||
providerChannelId: providerChannelId
|
||||
},
|
||||
}),
|
||||
contentType: 'application/json',
|
||||
dataType: 'json'
|
||||
}).then(mapping => {
|
||||
const listItem = dom.parentWithClass(button, 'listItem');
|
||||
@@ -58,7 +58,7 @@ export default class channelMapper {
|
||||
}
|
||||
|
||||
function getChannelMappingOptions(serverId, providerId) {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getJSON(apiClient.getUrl('LiveTv/ChannelMappingOptions', {
|
||||
providerId: providerId
|
||||
}));
|
||||
@@ -93,7 +93,7 @@ export default class channelMapper {
|
||||
html += '<div class="formDialogContent smoothScrollY">';
|
||||
html += '<div class="dialogContentInner dialog-content-centered">';
|
||||
html += '<form style="margin:auto;">';
|
||||
html += `<h1>${globalize.translate('HeaderChannels')}</h1>`;
|
||||
html += `<h1>${globalize.translate('Channels')}</h1>`;
|
||||
html += '<div class="channels paperList">';
|
||||
html += '</div>';
|
||||
html += '</form>';
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import dom from 'dom';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import loading from 'loading';
|
||||
import appHost from 'apphost';
|
||||
import layoutManager from 'layoutManager';
|
||||
import connectionManager from 'connectionManager';
|
||||
import appRouter from 'appRouter';
|
||||
import globalize from 'globalize';
|
||||
import 'emby-checkbox';
|
||||
@@ -26,7 +24,7 @@ import 'flexStyles';
|
||||
|
||||
const collectionId = panel.querySelector('#selectCollectionToAddTo').value;
|
||||
|
||||
const apiClient = connectionManager.getApiClient(currentServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(currentServerId);
|
||||
|
||||
if (collectionId) {
|
||||
addToCollection(apiClient, panel, collectionId);
|
||||
@@ -39,7 +37,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function createCollection(apiClient, dlg) {
|
||||
|
||||
const url = apiClient.getUrl('Collections', {
|
||||
|
||||
Name: dlg.querySelector('#txtNewCollectionName').value,
|
||||
@@ -53,7 +50,6 @@ import 'flexStyles';
|
||||
dataType: 'json'
|
||||
|
||||
}).then(result => {
|
||||
|
||||
loading.hide();
|
||||
|
||||
const id = result.Id;
|
||||
@@ -61,17 +57,14 @@ import 'flexStyles';
|
||||
dlg.submitted = true;
|
||||
dialogHelper.close(dlg);
|
||||
redirectToCollection(apiClient, id);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function redirectToCollection(apiClient, id) {
|
||||
|
||||
appRouter.showItem(id, apiClient.serverId());
|
||||
}
|
||||
|
||||
function addToCollection(apiClient, dlg, id) {
|
||||
|
||||
const url = apiClient.getUrl(`Collections/${id}/Items`, {
|
||||
|
||||
Ids: dlg.querySelector('.fldSelectedItemIds').value || ''
|
||||
@@ -82,7 +75,6 @@ import 'flexStyles';
|
||||
url: url
|
||||
|
||||
}).then(() => {
|
||||
|
||||
loading.hide();
|
||||
|
||||
dlg.submitted = true;
|
||||
@@ -99,7 +91,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function populateCollections(panel) {
|
||||
|
||||
loading.show();
|
||||
|
||||
const select = panel.querySelector('#selectCollectionToAddTo');
|
||||
@@ -114,15 +105,13 @@ import 'flexStyles';
|
||||
EnableTotalRecordCount: false
|
||||
};
|
||||
|
||||
const apiClient = connectionManager.getApiClient(currentServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(currentServerId);
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), options).then(result => {
|
||||
|
||||
let html = '';
|
||||
|
||||
html += `<option value="">${globalize.translate('OptionNew')}</option>`;
|
||||
|
||||
html += result.Items.map(i => {
|
||||
|
||||
return `<option value="${i.Id}">${i.Name}</option>`;
|
||||
});
|
||||
|
||||
@@ -135,7 +124,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function getEditorHtml() {
|
||||
|
||||
let html = '';
|
||||
|
||||
html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">';
|
||||
@@ -183,7 +171,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function initEditor(content, items) {
|
||||
|
||||
content.querySelector('#selectCollectionToAddTo').addEventListener('change', function () {
|
||||
if (this.value) {
|
||||
content.querySelector('.newCollectionInfo').classList.add('hide');
|
||||
@@ -212,7 +199,7 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
import('scrollHelper').then(scrollHelper => {
|
||||
import('scrollHelper').then((scrollHelper) => {
|
||||
const fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
@@ -220,7 +207,6 @@ import 'flexStyles';
|
||||
|
||||
export class showEditor {
|
||||
constructor(options) {
|
||||
|
||||
const items = options.items || {};
|
||||
currentServerId = options.serverId;
|
||||
|
||||
@@ -248,10 +234,6 @@ import 'flexStyles';
|
||||
html += title;
|
||||
html += '</h3>';
|
||||
|
||||
if (appHost.supports('externallinks')) {
|
||||
html += `<a is="emby-linkbutton" class="button-link btnHelp flex align-items-center" href="https://web.archive.org/web/20181216120305/https://github.com/MediaBrowser/Wiki/wiki/Collections" target="_blank" style="margin-left:auto;margin-right:.5em;padding:.25em;" title="${globalize.translate('Help')}"><span class="material-icons info"></span><span style="margin-left:.25em;">${globalize.translate('Help')}</span></a>`;
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
html += getEditorHtml();
|
||||
@@ -261,7 +243,6 @@ import 'flexStyles';
|
||||
initEditor(dlg, items);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
@@ -270,7 +251,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
return dialogHelper.open(dlg).then(() => {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import globalize from 'globalize';
|
||||
|
||||
/* eslint-disable indent */
|
||||
export default (() => {
|
||||
|
||||
function replaceAll(str, find, replace) {
|
||||
return str.split(find).join(replace);
|
||||
}
|
||||
@@ -20,7 +19,7 @@ export default (() => {
|
||||
}
|
||||
|
||||
const text = replaceAll(options.text || '', '<br/>', '\n');
|
||||
const result = confirm(text);
|
||||
const result = window.confirm(text);
|
||||
|
||||
if (result) {
|
||||
return Promise.resolve();
|
||||
|
||||
@@ -13,7 +13,6 @@ import 'flexStyles';
|
||||
/* eslint-disable indent */
|
||||
|
||||
function showDialog(options, template) {
|
||||
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
@@ -45,10 +44,6 @@ import 'flexStyles';
|
||||
dlg.classList.add('dialog-fullscreen-lowres');
|
||||
}
|
||||
|
||||
//dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
|
||||
// dialogHelper.close(dlg);
|
||||
//});
|
||||
|
||||
if (options.title) {
|
||||
dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.title || '';
|
||||
} else {
|
||||
@@ -68,7 +63,6 @@ import 'flexStyles';
|
||||
let hasDescriptions = false;
|
||||
|
||||
for (i = 0, length = options.buttons.length; i < length; i++) {
|
||||
|
||||
const item = options.buttons[i];
|
||||
const autoFocus = i === 0 ? ' autofocus' : '';
|
||||
|
||||
@@ -111,7 +105,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
return dialogHelper.open(dlg).then(() => {
|
||||
|
||||
if (enableTvLayout) {
|
||||
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
@@ -125,7 +118,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
export async function show(text, title) {
|
||||
|
||||
let options;
|
||||
if (typeof text === 'string') {
|
||||
options = {
|
||||
|
||||
@@ -12,7 +12,6 @@ import 'scrollStyles';
|
||||
let globalOnOpenCallback;
|
||||
|
||||
function enableAnimation() {
|
||||
|
||||
// too slow
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
@@ -22,7 +21,6 @@ import 'scrollStyles';
|
||||
}
|
||||
|
||||
function removeCenterFocus(dlg) {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
if (dlg.classList.contains('scrollX')) {
|
||||
centerFocus(dlg, true, false);
|
||||
@@ -35,7 +33,6 @@ import 'scrollStyles';
|
||||
function tryRemoveElement(elem) {
|
||||
const parentNode = elem.parentNode;
|
||||
if (parentNode) {
|
||||
|
||||
// Seeing crashes in edge webview
|
||||
try {
|
||||
parentNode.removeChild(elem);
|
||||
@@ -46,14 +43,12 @@ import 'scrollStyles';
|
||||
}
|
||||
|
||||
function DialogHashHandler(dlg, hash, resolve) {
|
||||
|
||||
const self = this;
|
||||
self.originalUrl = window.location.href;
|
||||
const activeElement = document.activeElement;
|
||||
let removeScrollLockOnClose = false;
|
||||
|
||||
function onHashChange(e) {
|
||||
|
||||
const isBack = self.originalUrl === window.location.href;
|
||||
|
||||
if (isBack || !isOpened(dlg)) {
|
||||
@@ -67,7 +62,6 @@ import 'scrollStyles';
|
||||
}
|
||||
|
||||
function onBackCommand(e) {
|
||||
|
||||
if (e.detail.command === 'back') {
|
||||
self.closedByBack = true;
|
||||
e.preventDefault();
|
||||
@@ -77,7 +71,6 @@ import 'scrollStyles';
|
||||
}
|
||||
|
||||
function onDialogClosed() {
|
||||
|
||||
if (!isHistoryEnabled(dlg)) {
|
||||
inputManager.off(dlg, onBackCommand);
|
||||
}
|
||||
@@ -92,9 +85,9 @@ import 'scrollStyles';
|
||||
}
|
||||
|
||||
if (!self.closedByBack && isHistoryEnabled(dlg)) {
|
||||
const state = history.state || {};
|
||||
const state = window.history.state || {};
|
||||
if (state.dialogId === hash) {
|
||||
history.back();
|
||||
window.history.back();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +151,6 @@ import 'scrollStyles';
|
||||
}
|
||||
|
||||
function addBackdropOverlay(dlg) {
|
||||
|
||||
const backdrop = document.createElement('div');
|
||||
backdrop.classList.add('dialogBackdrop');
|
||||
|
||||
@@ -193,7 +185,6 @@ import 'scrollStyles';
|
||||
}
|
||||
|
||||
export function open(dlg) {
|
||||
|
||||
if (globalOnOpenCallback) {
|
||||
globalOnOpenCallback(dlg);
|
||||
}
|
||||
@@ -210,22 +201,19 @@ import 'scrollStyles';
|
||||
document.body.appendChild(dialogContainer);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
new DialogHashHandler(dlg, `dlg${new Date().getTime()}`, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function isOpened(dlg) {
|
||||
|
||||
//return dlg.opened;
|
||||
return !dlg.classList.contains('hide');
|
||||
}
|
||||
|
||||
export function close(dlg) {
|
||||
|
||||
if (isOpened(dlg)) {
|
||||
if (isHistoryEnabled(dlg)) {
|
||||
history.back();
|
||||
window.history.back();
|
||||
} else {
|
||||
closeDialog(dlg);
|
||||
}
|
||||
@@ -233,9 +221,7 @@ import 'scrollStyles';
|
||||
}
|
||||
|
||||
function closeDialog(dlg) {
|
||||
|
||||
if (!dlg.classList.contains('hide')) {
|
||||
|
||||
dlg.dispatchEvent(new CustomEvent('closing', {
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
@@ -256,7 +242,6 @@ import 'scrollStyles';
|
||||
}
|
||||
|
||||
function animateDialogOpen(dlg) {
|
||||
|
||||
const onAnimationFinish = () => {
|
||||
focusManager.pushScope(dlg);
|
||||
|
||||
@@ -271,7 +256,6 @@ import 'scrollStyles';
|
||||
};
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
const onFinish = () => {
|
||||
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
|
||||
once: true
|
||||
@@ -288,13 +272,10 @@ import 'scrollStyles';
|
||||
}
|
||||
|
||||
function animateDialogClose(dlg, onAnimationFinish) {
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
let animated = true;
|
||||
|
||||
switch (dlg.animationConfig.exit.name) {
|
||||
|
||||
case 'fadeout':
|
||||
dlg.style.animation = `fadeout ${dlg.animationConfig.exit.timing.duration}ms ease-out normal both`;
|
||||
break;
|
||||
@@ -329,7 +310,6 @@ import 'scrollStyles';
|
||||
const supportsOverscrollBehavior = 'overscroll-behavior-y' in document.body.style;
|
||||
|
||||
function shouldLockDocumentScroll(options) {
|
||||
|
||||
if (supportsOverscrollBehavior && (options.size || !browser.touch)) {
|
||||
return false;
|
||||
}
|
||||
@@ -350,7 +330,6 @@ import 'scrollStyles';
|
||||
}
|
||||
|
||||
function removeBackdrop(dlg) {
|
||||
|
||||
const backdrop = dlg.backdrop;
|
||||
|
||||
if (!backdrop) {
|
||||
@@ -364,7 +343,6 @@ import 'scrollStyles';
|
||||
};
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
backdrop.classList.remove('dialogBackdropOpened');
|
||||
|
||||
// this is not firing animatonend
|
||||
@@ -376,14 +354,13 @@ import 'scrollStyles';
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
import('scrollHelper').then(scrollHelper => {
|
||||
import('scrollHelper').then((scrollHelper) => {
|
||||
const fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
export function createDialog(options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
// If there's no native dialog support, use a plain div
|
||||
@@ -398,7 +375,7 @@ import 'scrollStyles';
|
||||
dlg.setAttribute('data-lockscroll', 'true');
|
||||
}
|
||||
|
||||
if (options.enableHistory !== false && appRouter.enableNativeHistory()) {
|
||||
if (options.enableHistory === true) {
|
||||
dlg.setAttribute('data-history', 'true');
|
||||
}
|
||||
|
||||
@@ -414,11 +391,8 @@ import 'scrollStyles';
|
||||
dlg.setAttribute('data-autofocus', 'true');
|
||||
}
|
||||
|
||||
let defaultEntryAnimation;
|
||||
let defaultExitAnimation;
|
||||
|
||||
defaultEntryAnimation = 'scaleup';
|
||||
defaultExitAnimation = 'scaledown';
|
||||
const defaultEntryAnimation = 'scaleup';
|
||||
const defaultExitAnimation = 'scaledown';
|
||||
const entryAnimation = options.entryAnimation || defaultEntryAnimation;
|
||||
const exitAnimation = options.exitAnimation || defaultExitAnimation;
|
||||
|
||||
@@ -473,9 +447,7 @@ import 'scrollStyles';
|
||||
}
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
switch (dlg.animationConfig.entry.name) {
|
||||
|
||||
case 'fadein':
|
||||
dlg.style.animation = `fadein ${entryAnimationDuration}ms ease-out normal`;
|
||||
break;
|
||||
|
||||
@@ -125,7 +125,7 @@ import 'emby-button';
|
||||
html += `<input is="emby-input" id="txtDirectoryPickerPath" type="text" required="required" ${readOnlyAttribute} label="${globalize.translate(labelKey)}"/>`;
|
||||
html += '</div>';
|
||||
if (!readOnlyAttribute) {
|
||||
html += `<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="${globalize.translate('ButtonRefresh')}"><span class="material-icons search"></span></button>`;
|
||||
html += `<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="${globalize.translate('Refresh')}"><span class="material-icons search"></span></button>`;
|
||||
}
|
||||
html += '</div>';
|
||||
if (!readOnlyAttribute) {
|
||||
@@ -166,10 +166,11 @@ import 'emby-button';
|
||||
return apiClient.ajax({
|
||||
type: 'POST',
|
||||
url: apiClient.getUrl('Environment/ValidatePath'),
|
||||
data: {
|
||||
data: JSON.stringify({
|
||||
ValidateWriteable: validateWriteable,
|
||||
Path: path
|
||||
}
|
||||
}),
|
||||
contentType: 'application/json'
|
||||
}).catch(response => {
|
||||
if (response) {
|
||||
if (response.status === 404) {
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import browser from 'browser';
|
||||
import layoutManager from 'layoutManager';
|
||||
import appSettings from 'appSettings';
|
||||
import pluginManager from 'pluginManager';
|
||||
import appHost from 'apphost';
|
||||
import focusManager from 'focusManager';
|
||||
import datetime from 'datetime';
|
||||
import globalize from 'globalize';
|
||||
import loading from 'loading';
|
||||
import connectionManager from 'connectionManager';
|
||||
import skinManager from 'skinManager';
|
||||
import events from 'events';
|
||||
import 'emby-select';
|
||||
@@ -16,17 +14,22 @@ import 'emby-button';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function fillThemes(select, isDashboard) {
|
||||
select.innerHTML = skinManager.getThemes().map(t => {
|
||||
let value = t.id;
|
||||
if (t.isDefault && !isDashboard) {
|
||||
value = '';
|
||||
} else if (t.isDefaultServerDashboard && isDashboard) {
|
||||
value = '';
|
||||
}
|
||||
function fillThemes(context, userSettings) {
|
||||
const select = context.querySelector('#selectTheme');
|
||||
|
||||
return `<option value="${value}">${t.name}</option>`;
|
||||
}).join('');
|
||||
skinManager.getThemes().then(themes => {
|
||||
select.innerHTML = themes.map(t => {
|
||||
return `<option value="${t.id}">${t.name}</option>`;
|
||||
}).join('');
|
||||
|
||||
// get default theme
|
||||
var defaultTheme = themes.find(theme => {
|
||||
return theme.default;
|
||||
});
|
||||
|
||||
// set the current theme
|
||||
select.value = userSettings.theme() || defaultTheme.id;
|
||||
});
|
||||
}
|
||||
|
||||
function loadScreensavers(context, userSettings) {
|
||||
@@ -46,6 +49,7 @@ import 'emby-button';
|
||||
selectScreensaver.innerHTML = options.map(o => {
|
||||
return `<option value="${o.value}">${o.name}</option>`;
|
||||
}).join('');
|
||||
|
||||
selectScreensaver.value = userSettings.screensaver();
|
||||
|
||||
if (!selectScreensaver.value) {
|
||||
@@ -54,61 +58,7 @@ import 'emby-button';
|
||||
}
|
||||
}
|
||||
|
||||
function loadSoundEffects(context, userSettings) {
|
||||
|
||||
const selectSoundEffects = context.querySelector('.selectSoundEffects');
|
||||
const options = pluginManager.ofType('soundeffects').map(plugin => {
|
||||
return {
|
||||
name: plugin.name,
|
||||
value: plugin.id
|
||||
};
|
||||
});
|
||||
|
||||
options.unshift({
|
||||
name: globalize.translate('None'),
|
||||
value: 'none'
|
||||
});
|
||||
|
||||
selectSoundEffects.innerHTML = options.map(o => {
|
||||
return `<option value="${o.value}">${o.name}</option>`;
|
||||
}).join('');
|
||||
selectSoundEffects.value = userSettings.soundEffects();
|
||||
|
||||
if (!selectSoundEffects.value) {
|
||||
// TODO: set the default instead of none
|
||||
selectSoundEffects.value = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function loadSkins(context, userSettings) {
|
||||
|
||||
const selectSkin = context.querySelector('.selectSkin');
|
||||
|
||||
const options = pluginManager.ofType('skin').map(plugin => {
|
||||
return {
|
||||
name: plugin.name,
|
||||
value: plugin.id
|
||||
};
|
||||
});
|
||||
|
||||
selectSkin.innerHTML = options.map(o => {
|
||||
return `<option value="${o.value}">${o.name}</option>`;
|
||||
}).join('');
|
||||
selectSkin.value = userSettings.skin();
|
||||
|
||||
if (!selectSkin.value && options.length) {
|
||||
selectSkin.value = options[0].value;
|
||||
}
|
||||
|
||||
if (options.length > 1 && appHost.supports('skins')) {
|
||||
context.querySelector('.selectSkinContainer').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.selectSkinContainer').classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function showOrHideMissingEpisodesField(context) {
|
||||
|
||||
if (browser.tizen || browser.web0s) {
|
||||
context.querySelector('.fldDisplayMissingEpisodes').classList.add('hide');
|
||||
return;
|
||||
@@ -118,13 +68,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
function loadForm(context, user, userSettings) {
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
context.querySelector('.selectDashboardThemeContainer').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.selectDashboardThemeContainer').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('displaylanguage')) {
|
||||
context.querySelector('.languageSection').classList.remove('hide');
|
||||
} else {
|
||||
@@ -143,18 +86,6 @@ import 'emby-button';
|
||||
context.querySelector('.learnHowToContributeContainer').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('runatstartup')) {
|
||||
context.querySelector('.fldAutorun').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.fldAutorun').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('soundeffects')) {
|
||||
context.querySelector('.fldSoundEffects').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.fldSoundEffects').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('screensaver')) {
|
||||
context.querySelector('.selectScreensaverContainer').classList.remove('hide');
|
||||
} else {
|
||||
@@ -177,16 +108,8 @@ import 'emby-button';
|
||||
context.querySelector('.fldThemeVideo').classList.add('hide');
|
||||
}
|
||||
|
||||
context.querySelector('.chkRunAtStartup').checked = appSettings.runAtStartup();
|
||||
|
||||
const selectTheme = context.querySelector('#selectTheme');
|
||||
const selectDashboardTheme = context.querySelector('#selectDashboardTheme');
|
||||
|
||||
fillThemes(selectTheme);
|
||||
fillThemes(selectDashboardTheme, true);
|
||||
fillThemes(context, userSettings);
|
||||
loadScreensavers(context, userSettings);
|
||||
loadSoundEffects(context, userSettings);
|
||||
loadSkins(context, userSettings);
|
||||
|
||||
context.querySelector('.chkDisplayMissingEpisodes').checked = user.Configuration.DisplayMissingEpisodes || false;
|
||||
|
||||
@@ -202,9 +125,6 @@ import 'emby-button';
|
||||
|
||||
context.querySelector('#txtLibraryPageSize').value = userSettings.libraryPageSize();
|
||||
|
||||
selectDashboardTheme.value = userSettings.dashboardTheme() || '';
|
||||
selectTheme.value = userSettings.theme() || '';
|
||||
|
||||
context.querySelector('.selectLayout').value = layoutManager.getSavedLayout() || '';
|
||||
|
||||
showOrHideMissingEpisodesField(context);
|
||||
@@ -213,9 +133,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
function saveUser(context, user, userSettingsInstance, apiClient) {
|
||||
|
||||
appSettings.runAtStartup(context.querySelector('.chkRunAtStartup').checked);
|
||||
|
||||
user.Configuration.DisplayMissingEpisodes = context.querySelector('.chkDisplayMissingEpisodes').checked;
|
||||
|
||||
if (appHost.supports('displaylanguage')) {
|
||||
@@ -226,15 +143,11 @@ import 'emby-button';
|
||||
|
||||
userSettingsInstance.enableThemeSongs(context.querySelector('#chkThemeSong').checked);
|
||||
userSettingsInstance.enableThemeVideos(context.querySelector('#chkThemeVideo').checked);
|
||||
userSettingsInstance.dashboardTheme(context.querySelector('#selectDashboardTheme').value);
|
||||
userSettingsInstance.theme(context.querySelector('#selectTheme').value);
|
||||
userSettingsInstance.soundEffects(context.querySelector('.selectSoundEffects').value);
|
||||
userSettingsInstance.screensaver(context.querySelector('.selectScreensaver').value);
|
||||
|
||||
userSettingsInstance.libraryPageSize(context.querySelector('#txtLibraryPageSize').value);
|
||||
|
||||
userSettingsInstance.skin(context.querySelector('.selectSkin').value);
|
||||
|
||||
userSettingsInstance.enableFastFadein(context.querySelector('#chkFadein').checked);
|
||||
userSettingsInstance.enableBlurhash(context.querySelector('#chkBlurhash').checked);
|
||||
userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked);
|
||||
@@ -268,7 +181,7 @@ import 'emby-button';
|
||||
|
||||
function onSubmit(e) {
|
||||
const self = this;
|
||||
const apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userId = self.options.userId;
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
@@ -307,7 +220,7 @@ import 'emby-button';
|
||||
loading.show();
|
||||
|
||||
const userId = self.options.userId;
|
||||
const apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
return apiClient.getUser(userId).then(user => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<form style="margin: 0 auto;">
|
||||
|
||||
<h2 class="sectionTitle">
|
||||
${Display}
|
||||
</h2>
|
||||
@@ -123,26 +122,14 @@
|
||||
<div class="fieldDescription">${LabelPleaseRestart}</div>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer hide selectSkinContainer">
|
||||
<select is="emby-select" class="selectSkin" label="${LabelSkin}"></select>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer">
|
||||
<select id="selectTheme" is="emby-select" label="${LabelTheme}"></select>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer selectDashboardThemeContainer hide">
|
||||
<select id="selectDashboardTheme" is="emby-select" label="${LabelDashboardTheme}"></select>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer hide selectScreensaverContainer">
|
||||
<select is="emby-select" class="selectScreensaver" label="${LabelScreensaver}"></select>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer fldSoundEffects hide">
|
||||
<select is="emby-select" class="selectSoundEffects" label="${LabelSoundEffects}"></select>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer inputContainer-withDescription">
|
||||
<input is="emby-input" type="number" id="txtLibraryPageSize" pattern="[0-9]*" required="required" min="0" max="1000" step="1" label="${LabelLibraryPageSize}" />
|
||||
<div class="fieldDescription">${LabelLibraryPageSizeHelp}</div>
|
||||
@@ -159,9 +146,9 @@
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkBlurhash" />
|
||||
<span>${EnableBlurhash}</span>
|
||||
<span>${EnableBlurHash}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableBlurhashHelp}</div>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableBlurHashHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
@@ -175,7 +162,7 @@
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldBackdrops hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkBackdrops" />
|
||||
<span>${EnableBackdrops}</span>
|
||||
<span>${Backdrops}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableBackdropsHelp}</div>
|
||||
</div>
|
||||
@@ -183,7 +170,7 @@
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldThemeSong hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkThemeSong" />
|
||||
<span>${EnableThemeSongs}</span>
|
||||
<span>${ThemeSongs}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableThemeSongsHelp}</div>
|
||||
</div>
|
||||
@@ -191,18 +178,11 @@
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldThemeVideo hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkThemeVideo" />
|
||||
<span>${EnableThemeVideos}</span>
|
||||
<span>${ThemeVideos}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableThemeVideosHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer hide fldAutorun">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkRunAtStartup" />
|
||||
<span>${RunAtStartup}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldDisplayMissingEpisodes hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkDisplayMissingEpisodes" />
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoader', 'globalize', 'layoutManager', 'scrollStyles', 'emby-itemscontainer'], function (loading, libraryBrowser, cardBuilder, dom, appHost, imageLoader, globalize, layoutManager) {
|
||||
'use strict';
|
||||
import loading from 'loading';
|
||||
import cardBuilder from 'cardBuilder';
|
||||
import dom from 'dom';
|
||||
import appHost from 'apphost';
|
||||
import imageLoader from 'imageLoader';
|
||||
import globalize from 'globalize';
|
||||
import layoutManager from 'layoutManager';
|
||||
import 'scrollStyles';
|
||||
import 'emby-itemscontainer';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function enableScrollX() {
|
||||
return !layoutManager.desktop;
|
||||
@@ -19,21 +28,21 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
|
||||
function getSections() {
|
||||
return [{
|
||||
name: 'HeaderFavoriteMovies',
|
||||
name: 'Movies',
|
||||
types: 'Movie',
|
||||
id: 'favoriteMovies',
|
||||
shape: getPosterShape(),
|
||||
showTitle: false,
|
||||
overlayPlayButton: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteShows',
|
||||
name: 'Shows',
|
||||
types: 'Series',
|
||||
id: 'favoriteShows',
|
||||
shape: getPosterShape(),
|
||||
showTitle: false,
|
||||
overlayPlayButton: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteEpisodes',
|
||||
name: 'Episodes',
|
||||
types: 'Episode',
|
||||
id: 'favoriteEpisode',
|
||||
shape: getThumbShape(),
|
||||
@@ -44,7 +53,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
overlayText: false,
|
||||
centerText: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteVideos',
|
||||
name: 'Videos',
|
||||
types: 'Video,MusicVideo',
|
||||
id: 'favoriteVideos',
|
||||
shape: getThumbShape(),
|
||||
@@ -54,7 +63,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
overlayText: false,
|
||||
centerText: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteArtists',
|
||||
name: 'Artists',
|
||||
types: 'MusicArtist',
|
||||
id: 'favoriteArtists',
|
||||
shape: getSquareShape(),
|
||||
@@ -66,7 +75,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
overlayPlayButton: true,
|
||||
coverImage: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteAlbums',
|
||||
name: 'Albums',
|
||||
types: 'MusicAlbum',
|
||||
id: 'favoriteAlbums',
|
||||
shape: getSquareShape(),
|
||||
@@ -78,7 +87,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
overlayPlayButton: true,
|
||||
coverImage: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteSongs',
|
||||
name: 'Songs',
|
||||
types: 'Audio',
|
||||
id: 'favoriteSongs',
|
||||
shape: getSquareShape(),
|
||||
@@ -94,8 +103,8 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
}
|
||||
|
||||
function loadSection(elem, userId, topParentId, section, isSingleSection) {
|
||||
var screenWidth = dom.getWindowSize().innerWidth;
|
||||
var options = {
|
||||
const screenWidth = dom.getWindowSize().innerWidth;
|
||||
const options = {
|
||||
SortBy: 'SortName',
|
||||
SortOrder: 'Ascending',
|
||||
Filters: 'IsFavorite',
|
||||
@@ -118,9 +127,9 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
}
|
||||
}
|
||||
|
||||
var promise;
|
||||
let promise;
|
||||
|
||||
if ('MusicArtist' === section.types) {
|
||||
if (section.types === 'MusicArtist') {
|
||||
promise = ApiClient.getArtists(userId, options);
|
||||
} else {
|
||||
options.IncludeItemTypes = section.types;
|
||||
@@ -128,7 +137,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
}
|
||||
|
||||
return promise.then(function (result) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
if (result.Items.length) {
|
||||
if (html += '<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">', !layoutManager.tv && options.Limit && result.Items.length >= options.Limit) {
|
||||
@@ -144,7 +153,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
|
||||
html += '</div>';
|
||||
if (enableScrollX()) {
|
||||
var scrollXClass = 'scrollX hiddenScrollX';
|
||||
let scrollXClass = 'scrollX hiddenScrollX';
|
||||
if (layoutManager.tv) {
|
||||
scrollXClass += ' smoothScrollX';
|
||||
}
|
||||
@@ -154,14 +163,13 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
html += '<div is="emby-itemscontainer" class="itemsContainer vertical-wrap padded-left padded-right">';
|
||||
}
|
||||
|
||||
var supportsImageAnalysis = appHost.supports('imageanalysis');
|
||||
var cardLayout = (appHost.preferVisualCards || supportsImageAnalysis) && section.autoCardLayout && section.showTitle;
|
||||
let cardLayout = appHost.preferVisualCards && section.autoCardLayout && section.showTitle;
|
||||
cardLayout = false;
|
||||
html += cardBuilder.getCardsHtml(result.Items, {
|
||||
preferThumb: section.preferThumb,
|
||||
shape: section.shape,
|
||||
centerText: section.centerText && !cardLayout,
|
||||
overlayText: false !== section.overlayText,
|
||||
overlayText: section.overlayText !== false,
|
||||
showTitle: section.showTitle,
|
||||
showParentTitle: section.showParentTitle,
|
||||
scalable: true,
|
||||
@@ -180,10 +188,10 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
});
|
||||
}
|
||||
|
||||
function loadSections(page, userId, topParentId, types) {
|
||||
export function loadSections(page, userId, topParentId, types) {
|
||||
loading.show();
|
||||
var sections = getSections();
|
||||
var sectionid = getParameterByName('sectionid');
|
||||
let sections = getSections();
|
||||
const sectionid = getParameterByName('sectionid');
|
||||
|
||||
if (sectionid) {
|
||||
sections = sections.filter(function (s) {
|
||||
@@ -193,30 +201,28 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
|
||||
if (types) {
|
||||
sections = sections.filter(function (s) {
|
||||
return -1 !== types.indexOf(s.id);
|
||||
return types.indexOf(s.id) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
var i;
|
||||
var length;
|
||||
var elem = page.querySelector('.favoriteSections');
|
||||
let elem = page.querySelector('.favoriteSections');
|
||||
|
||||
if (!elem.innerHTML) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
for (i = 0, length = sections.length; i < length; i++) {
|
||||
for (let i = 0, length = sections.length; i < length; i++) {
|
||||
html += '<div class="verticalSection section' + sections[i].id + '"></div>';
|
||||
}
|
||||
|
||||
elem.innerHTML = html;
|
||||
}
|
||||
|
||||
var promises = [];
|
||||
const promises = [];
|
||||
|
||||
for (i = 0, length = sections.length; i < length; i++) {
|
||||
var section = sections[i];
|
||||
for (let i = 0, length = sections.length; i < length; i++) {
|
||||
const section = sections[i];
|
||||
elem = page.querySelector('.section' + section.id);
|
||||
promises.push(loadSection(elem, userId, topParentId, section, 1 === sections.length));
|
||||
promises.push(loadSection(elem, userId, topParentId, section, sections.length === 1));
|
||||
}
|
||||
|
||||
Promise.all(promises).then(function () {
|
||||
@@ -224,7 +230,8 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
render: loadSections
|
||||
};
|
||||
});
|
||||
export default {
|
||||
render: loadSections
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* eslint-disable indent */
|
||||
export function getFetchPromise(request) {
|
||||
|
||||
const headers = request.headers || {};
|
||||
|
||||
if (request.dataType === 'json') {
|
||||
@@ -16,7 +15,6 @@
|
||||
let contentType = request.contentType;
|
||||
|
||||
if (request.data) {
|
||||
|
||||
if (typeof request.data === 'string') {
|
||||
fetchRequest.body = request.data;
|
||||
} else {
|
||||
@@ -27,7 +25,6 @@
|
||||
}
|
||||
|
||||
if (contentType) {
|
||||
|
||||
headers['Content-Type'] = contentType;
|
||||
}
|
||||
|
||||
@@ -48,11 +45,9 @@
|
||||
}
|
||||
|
||||
function fetchWithTimeout(url, options, timeoutMs) {
|
||||
|
||||
console.debug(`fetchWithTimeout: timeoutMs: ${timeoutMs}, url: ${url}`);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
const timeout = setTimeout(reject, timeoutMs);
|
||||
|
||||
options = options || {};
|
||||
@@ -65,7 +60,6 @@
|
||||
|
||||
resolve(response);
|
||||
}, function (error) {
|
||||
|
||||
clearTimeout(timeout);
|
||||
|
||||
console.debug(`fetchWithTimeout: timed out connecting to url: ${url}`);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import dom from 'dom';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import globalize from 'globalize';
|
||||
import connectionManager from 'connectionManager';
|
||||
import events from 'events';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-collapse';
|
||||
@@ -420,7 +419,7 @@ import 'css!./style.css';
|
||||
this.bindEvents(dlg);
|
||||
if (enableDynamicFilters(this.options.mode)) {
|
||||
dlg.classList.add('dynamicFilterDialog');
|
||||
const apiClient = connectionManager.getApiClient(this.options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(this.options.serverId);
|
||||
loadDynamicFilters(dlg, apiClient, apiClient.getCurrentUserId(), this.options.query);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<div style="margin: 0;padding:1.5em 2em;" class="filterDialogContent">
|
||||
|
||||
<div is="emby-collapse" title="${HeaderFilters}">
|
||||
<div is="emby-collapse" title="${Filters}">
|
||||
<div class="collapseContent">
|
||||
<div class="checkboxList">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter videoStandard"
|
||||
data-filter="IsPlayed" />
|
||||
<span>${OptionPlayed}</span>
|
||||
<span>${Played}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter videoStandard"
|
||||
data-filter="IsUnPlayed" />
|
||||
<span>${OptionUnplayed}</span>
|
||||
<span>${Unplayed}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter videoStandard"
|
||||
@@ -21,7 +21,7 @@
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter chkFavorite"
|
||||
data-filter="IsFavorite" />
|
||||
<span>${OptionFavorite}</span>
|
||||
<span>${Favorites}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter chkLikes" data-filter="Likes" />
|
||||
@@ -53,30 +53,30 @@
|
||||
<div class="checkboxList">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStatus" data-filter="Continuing" />
|
||||
<span>${OptionContinuing}</span>
|
||||
<span>${Continuing}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStatus" data-filter="Ended" />
|
||||
<span>${OptionEnded}</span>
|
||||
<span>${Ended}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div is="emby-collapse" title="${HeaderFeatures}" class="features hide">
|
||||
<div is="emby-collapse" title="${Features}" class="features hide">
|
||||
<div class="collapseContent">
|
||||
<div class="checkboxList">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkFeatureFilter" id="chkSubtitle" />
|
||||
<span>${OptionHasSubtitles}</span>
|
||||
<span>${Subtitles}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkFeatureFilter" id="chkTrailer" />
|
||||
<span>${OptionHasTrailer}</span>
|
||||
<span>${ButtonTrailer}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkFeatureFilter" id="chkSpecialFeature" />
|
||||
<span>${OptionHasSpecialFeatures}</span>
|
||||
<span>${SpecialFeatures}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkFeatureFilter" id="chkThemeSong" />
|
||||
@@ -90,7 +90,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div is="emby-collapse" title="${HeaderGenres}" class="genreFilters hide">
|
||||
<div is="emby-collapse" title="${Genres}" class="genreFilters hide">
|
||||
<div class="collapseContent filterOptions">
|
||||
</div>
|
||||
</div>
|
||||
@@ -100,7 +100,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div is="emby-collapse" title="${HeaderTags}" class="tagFilters hide">
|
||||
<div is="emby-collapse" title="${Tags}" class="tagFilters hide">
|
||||
<div class="collapseContent filterOptions">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,271 +1,219 @@
|
||||
define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost', 'inputManager', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'userSettings', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (require, dom, focusManager, dialogHelper, loading, appHost, inputManager, layoutManager, connectionManager, appRouter, globalize, userSettings) {
|
||||
'use strict';
|
||||
import dom from 'dom';
|
||||
import focusManager from 'focusManager';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import inputManager from 'inputManager';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import * as userSettings from 'userSettings';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-input';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-select';
|
||||
import 'material-icons';
|
||||
import 'css!./../formdialog';
|
||||
import 'emby-button';
|
||||
import 'flexStyles';
|
||||
|
||||
function onSubmit(e) {
|
||||
function onSubmit(e) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
function renderOptions(context, selector, cssClass, items, isCheckedFn) {
|
||||
var elem = context.querySelector(selector);
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
if (items.length) {
|
||||
elem.classList.remove('hide');
|
||||
} else {
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
|
||||
function renderOptions(context, selector, cssClass, items, isCheckedFn) {
|
||||
var html = '';
|
||||
|
||||
var elem = context.querySelector(selector);
|
||||
html += items.map(function (filter) {
|
||||
var itemHtml = '';
|
||||
|
||||
if (items.length) {
|
||||
var checkedHtml = isCheckedFn(filter) ? ' checked' : '';
|
||||
itemHtml += '<label>';
|
||||
itemHtml += '<input is="emby-checkbox" type="checkbox"' + checkedHtml + ' data-filter="' + filter.Id + '" class="' + cssClass + '"/>';
|
||||
itemHtml += '<span>' + filter.Name + '</span>';
|
||||
itemHtml += '</label>';
|
||||
|
||||
elem.classList.remove('hide');
|
||||
return itemHtml;
|
||||
}).join('');
|
||||
|
||||
elem.querySelector('.filterOptions').innerHTML = html;
|
||||
}
|
||||
|
||||
function renderDynamicFilters(context, result, options) {
|
||||
renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) {
|
||||
// Switching from | to ,
|
||||
var delimeter = (options.settings.GenreIds || '').indexOf('|') === -1 ? ',' : '|';
|
||||
return (delimeter + (options.settings.GenreIds || '') + delimeter).indexOf(delimeter + i.Id + delimeter) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
function setBasicFilter(context, key, elem) {
|
||||
var value = elem.checked;
|
||||
value = value ? value : null;
|
||||
userSettings.setFilter(key, value);
|
||||
}
|
||||
function moveCheckboxFocus(elem, offset) {
|
||||
var parent = dom.parentWithClass(elem, 'checkboxList-verticalwrap');
|
||||
var elems = focusManager.getFocusableElements(parent);
|
||||
|
||||
var index = -1;
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i] === elem) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
index += offset;
|
||||
|
||||
index = Math.min(elems.length - 1, index);
|
||||
index = Math.max(0, index);
|
||||
|
||||
var newElem = elems[index];
|
||||
if (newElem) {
|
||||
focusManager.focus(newElem);
|
||||
}
|
||||
}
|
||||
function centerFocus(elem, horiz, on) {
|
||||
import('scrollHelper').then(({ default: scrollHelper }) => {
|
||||
var fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
function onInputCommand(e) {
|
||||
switch (e.detail.command) {
|
||||
case 'left':
|
||||
moveCheckboxFocus(e.target, -1);
|
||||
e.preventDefault();
|
||||
break;
|
||||
case 'right':
|
||||
moveCheckboxFocus(e.target, 1);
|
||||
e.preventDefault();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
function saveValues(context, settings, settingsKey) {
|
||||
var elems = context.querySelectorAll('.simpleFilter');
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].tagName === 'INPUT') {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i]);
|
||||
} else {
|
||||
elem.classList.add('hide');
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i].querySelector('input'));
|
||||
}
|
||||
|
||||
var html = '';
|
||||
|
||||
html += items.map(function (filter) {
|
||||
|
||||
var itemHtml = '';
|
||||
|
||||
var checkedHtml = isCheckedFn(filter) ? ' checked' : '';
|
||||
itemHtml += '<label>';
|
||||
itemHtml += '<input is="emby-checkbox" type="checkbox"' + checkedHtml + ' data-filter="' + filter.Id + '" class="' + cssClass + '"/>';
|
||||
itemHtml += '<span>' + filter.Name + '</span>';
|
||||
itemHtml += '</label>';
|
||||
|
||||
return itemHtml;
|
||||
|
||||
}).join('');
|
||||
|
||||
elem.querySelector('.filterOptions').innerHTML = html;
|
||||
}
|
||||
|
||||
function renderDynamicFilters(context, result, options) {
|
||||
// Video type
|
||||
var videoTypes = [];
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
|
||||
// If there's a huge number of these they will be really show to render
|
||||
//if (result.Tags) {
|
||||
// result.Tags.length = Math.min(result.Tags.length, 50);
|
||||
//}
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].checked) {
|
||||
videoTypes.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
userSettings.setFilter(settingsKey + '-filter-VideoTypes', videoTypes.join(','));
|
||||
|
||||
renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) {
|
||||
// Series status
|
||||
var seriesStatuses = [];
|
||||
elems = context.querySelectorAll('.chkSeriesStatus');
|
||||
|
||||
// Switching from | to ,
|
||||
var delimeter = (options.settings.GenreIds || '').indexOf('|') === -1 ? ',' : '|';
|
||||
return (delimeter + (options.settings.GenreIds || '') + delimeter).indexOf(delimeter + i.Id + delimeter) !== -1;
|
||||
});
|
||||
|
||||
//renderOptions(context, '.officialRatingFilters', 'chkOfficialRatingFilter', result.OfficialRatings, function (i) {
|
||||
// var delimeter = '|';
|
||||
// return (delimeter + (query.OfficialRatings || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
//});
|
||||
|
||||
//renderOptions(context, '.tagFilters', 'chkTagFilter', result.Tags, function (i) {
|
||||
// var delimeter = '|';
|
||||
// return (delimeter + (query.Tags || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
//});
|
||||
|
||||
//renderOptions(context, '.yearFilters', 'chkYearFilter', result.Years, function (i) {
|
||||
|
||||
// var delimeter = ',';
|
||||
// return (delimeter + (query.Years || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
//});
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].checked) {
|
||||
seriesStatuses.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
|
||||
function loadDynamicFilters(context, options) {
|
||||
// Genres
|
||||
var genres = [];
|
||||
elems = context.querySelectorAll('.chkGenreFilter');
|
||||
|
||||
var apiClient = connectionManager.getApiClient(options.serverId);
|
||||
|
||||
var filterMenuOptions = Object.assign(options.filterMenuOptions, {
|
||||
|
||||
UserId: apiClient.getCurrentUserId(),
|
||||
ParentId: options.parentId,
|
||||
IncludeItemTypes: options.itemTypes.join(',')
|
||||
});
|
||||
|
||||
apiClient.getFilters(filterMenuOptions).then(function (result) {
|
||||
|
||||
renderDynamicFilters(context, result, options);
|
||||
}, function () {
|
||||
|
||||
// older server
|
||||
});
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].checked) {
|
||||
genres.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
|
||||
function initEditor(context, settings) {
|
||||
|
||||
context.querySelector('form').addEventListener('submit', onSubmit);
|
||||
|
||||
var elems = context.querySelectorAll('.simpleFilter');
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].tagName === 'INPUT') {
|
||||
elems[i].checked = settings[elems[i].getAttribute('data-settingname')] || false;
|
||||
} else {
|
||||
elems[i].querySelector('input').checked = settings[elems[i].getAttribute('data-settingname')] || false;
|
||||
}
|
||||
}
|
||||
|
||||
var videoTypes = settings.VideoTypes ? settings.VideoTypes.split(',') : [];
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
elems[i].checked = videoTypes.indexOf(elems[i].getAttribute('data-filter')) !== -1;
|
||||
}
|
||||
|
||||
var seriesStatuses = settings.SeriesStatus ? settings.SeriesStatus.split(',') : [];
|
||||
elems = context.querySelectorAll('.chkSeriesStatus');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
elems[i].checked = seriesStatuses.indexOf(elems[i].getAttribute('data-filter')) !== -1;
|
||||
}
|
||||
|
||||
if (context.querySelector('.basicFilterSection .viewSetting:not(.hide)')) {
|
||||
context.querySelector('.basicFilterSection').classList.remove('hide');
|
||||
userSettings.setFilter(settingsKey + '-filter-GenreIds', genres.join(','));
|
||||
}
|
||||
function bindCheckboxInput(context, on) {
|
||||
var elems = context.querySelectorAll('.checkboxList-verticalwrap');
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (on) {
|
||||
inputManager.on(elems[i], onInputCommand);
|
||||
} else {
|
||||
context.querySelector('.basicFilterSection').classList.add('hide');
|
||||
inputManager.off(elems[i], onInputCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
function initEditor(context, settings) {
|
||||
context.querySelector('form').addEventListener('submit', onSubmit);
|
||||
|
||||
if (context.querySelector('.featureSection .viewSetting:not(.hide)')) {
|
||||
context.querySelector('.featureSection').classList.remove('hide');
|
||||
var elems = context.querySelectorAll('.simpleFilter');
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].tagName === 'INPUT') {
|
||||
elems[i].checked = settings[elems[i].getAttribute('data-settingname')] || false;
|
||||
} else {
|
||||
context.querySelector('.featureSection').classList.add('hide');
|
||||
elems[i].querySelector('input').checked = settings[elems[i].getAttribute('data-settingname')] || false;
|
||||
}
|
||||
}
|
||||
|
||||
function saveValues(context, settings, settingsKey) {
|
||||
var videoTypes = settings.VideoTypes ? settings.VideoTypes.split(',') : [];
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
|
||||
var elems = context.querySelectorAll('.simpleFilter');
|
||||
var i;
|
||||
var length;
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].tagName === 'INPUT') {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i]);
|
||||
} else {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i].querySelector('input'));
|
||||
}
|
||||
}
|
||||
|
||||
// Video type
|
||||
var videoTypes = [];
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].checked) {
|
||||
videoTypes.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
userSettings.setFilter(settingsKey + '-filter-VideoTypes', videoTypes.join(','));
|
||||
|
||||
// Series status
|
||||
var seriesStatuses = [];
|
||||
elems = context.querySelectorAll('.chkSeriesStatus');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].checked) {
|
||||
seriesStatuses.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
|
||||
// Genres
|
||||
var genres = [];
|
||||
elems = context.querySelectorAll('.chkGenreFilter');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].checked) {
|
||||
genres.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
userSettings.setFilter(settingsKey + '-filter-GenreIds', genres.join(','));
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].checked = videoTypes.indexOf(elems[i].getAttribute('data-filter')) !== -1;
|
||||
}
|
||||
|
||||
function setBasicFilter(context, key, elem) {
|
||||
var seriesStatuses = settings.SeriesStatus ? settings.SeriesStatus.split(',') : [];
|
||||
elems = context.querySelectorAll('.chkSeriesStatus');
|
||||
|
||||
var value = elem.checked;
|
||||
value = value ? value : null;
|
||||
userSettings.setFilter(key, value);
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].checked = seriesStatuses.indexOf(elems[i].getAttribute('data-filter')) !== -1;
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
var fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
if (context.querySelector('.basicFilterSection .viewSetting:not(.hide)')) {
|
||||
context.querySelector('.basicFilterSection').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.basicFilterSection').classList.add('hide');
|
||||
}
|
||||
|
||||
function moveCheckboxFocus(elem, offset) {
|
||||
|
||||
var parent = dom.parentWithClass(elem, 'checkboxList-verticalwrap');
|
||||
var elems = focusManager.getFocusableElements(parent);
|
||||
|
||||
var index = -1;
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i] === elem) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
index += offset;
|
||||
|
||||
index = Math.min(elems.length - 1, index);
|
||||
index = Math.max(0, index);
|
||||
|
||||
var newElem = elems[index];
|
||||
if (newElem) {
|
||||
focusManager.focus(newElem);
|
||||
}
|
||||
if (context.querySelector('.featureSection .viewSetting:not(.hide)')) {
|
||||
context.querySelector('.featureSection').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.featureSection').classList.add('hide');
|
||||
}
|
||||
}
|
||||
function loadDynamicFilters(context, options) {
|
||||
var apiClient = window.connectionManager.getApiClient(options.serverId);
|
||||
|
||||
function onInputCommand(e) {
|
||||
switch (e.detail.command) {
|
||||
var filterMenuOptions = Object.assign(options.filterMenuOptions, {
|
||||
|
||||
case 'left':
|
||||
moveCheckboxFocus(e.target, -1);
|
||||
e.preventDefault();
|
||||
break;
|
||||
case 'right':
|
||||
moveCheckboxFocus(e.target, 1);
|
||||
e.preventDefault();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function FilterMenu() {
|
||||
|
||||
}
|
||||
|
||||
function bindCheckboxInput(context, on) {
|
||||
|
||||
var elems = context.querySelectorAll('.checkboxList-verticalwrap');
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
if (on) {
|
||||
inputManager.on(elems[i], onInputCommand);
|
||||
} else {
|
||||
inputManager.off(elems[i], onInputCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FilterMenu.prototype.show = function (options) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['text!./filtermenu.template.html'], function (template) {
|
||||
UserId: apiClient.getCurrentUserId(),
|
||||
ParentId: options.parentId,
|
||||
IncludeItemTypes: options.itemTypes.join(',')
|
||||
});
|
||||
|
||||
apiClient.getFilters(filterMenuOptions).then((result) => {
|
||||
renderDynamicFilters(context, result, options);
|
||||
});
|
||||
}
|
||||
class FilterMenu {
|
||||
show(options) {
|
||||
return new Promise( (resolve, reject) => {
|
||||
import('text!./filtermenu.template.html').then(({ default: template }) => {
|
||||
var dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
@@ -289,7 +237,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
||||
dlg.innerHTML = globalize.translateHtml(html, 'core');
|
||||
|
||||
var settingElements = dlg.querySelectorAll('.viewSetting');
|
||||
for (var i = 0, length = settingElements.length; i < length; i++) {
|
||||
for (let i = 0, length = settingElements.length; i < length; i++) {
|
||||
if (options.visibleSettings.indexOf(settingElements[i].getAttribute('data-settingname')) === -1) {
|
||||
settingElements[i].classList.add('hide');
|
||||
} else {
|
||||
@@ -301,9 +249,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
||||
loadDynamicFilters(dlg, options);
|
||||
|
||||
bindCheckboxInput(dlg, true);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
@@ -314,17 +260,10 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
||||
var submitted;
|
||||
|
||||
dlg.querySelector('form').addEventListener('change', function () {
|
||||
|
||||
submitted = true;
|
||||
//if (options.onChange) {
|
||||
// saveValues(dlg, options.settings, options.settingsKey);
|
||||
// options.onChange();
|
||||
//}
|
||||
|
||||
}, true);
|
||||
|
||||
dialogHelper.open(dlg).then(function () {
|
||||
|
||||
dialogHelper.open(dlg).then( function() {
|
||||
bindCheckboxInput(dlg, false);
|
||||
|
||||
if (layoutManager.tv) {
|
||||
@@ -332,19 +271,16 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
||||
}
|
||||
|
||||
if (submitted) {
|
||||
|
||||
//if (!options.onChange) {
|
||||
saveValues(dlg, options.settings, options.settingsKey);
|
||||
resolve();
|
||||
return resolve();
|
||||
//}
|
||||
return;
|
||||
}
|
||||
|
||||
reject();
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return FilterMenu;
|
||||
});
|
||||
export default FilterMenu;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
import dom from 'dom';
|
||||
import scrollManager from 'scrollManager';
|
||||
|
||||
var scopes = [];
|
||||
function pushScope(elem) {
|
||||
@@ -7,14 +9,12 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function popScope(elem) {
|
||||
|
||||
if (scopes.length) {
|
||||
scopes.length -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
function autoFocus(view, defaultToFirst, findAutoFocusElement) {
|
||||
|
||||
var element;
|
||||
if (findAutoFocusElement !== false) {
|
||||
element = view.querySelector('*[autofocus]');
|
||||
@@ -37,7 +37,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function focus(element) {
|
||||
|
||||
try {
|
||||
element.focus({
|
||||
preventScroll: scrollManager.isEnabled()
|
||||
@@ -50,16 +49,13 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
var focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A'];
|
||||
var focusableContainerTagNames = ['BODY', 'DIALOG'];
|
||||
var focusableQuery = focusableTagNames.map(function (t) {
|
||||
|
||||
if (t === 'INPUT') {
|
||||
t += ':not([type="range"]):not([type="file"])';
|
||||
}
|
||||
return t + ':not([tabindex="-1"]):not(:disabled)';
|
||||
|
||||
}).join(',') + ',.focusable';
|
||||
|
||||
function isFocusable(elem) {
|
||||
|
||||
if (focusableTagNames.indexOf(elem.tagName) !== -1) {
|
||||
return true;
|
||||
}
|
||||
@@ -83,7 +79,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function focusableParent(elem) {
|
||||
|
||||
var originalElement = elem;
|
||||
|
||||
while (!isFocusable(elem)) {
|
||||
@@ -101,7 +96,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
|
||||
// Determines if a focusable element can be focused at a given point in time
|
||||
function isCurrentlyFocusableInternal(elem) {
|
||||
|
||||
// http://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom
|
||||
if (elem.offsetParent === null) {
|
||||
return false;
|
||||
@@ -112,7 +106,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
|
||||
// Determines if a focusable element can be focused at a given point in time
|
||||
function isCurrentlyFocusable(elem) {
|
||||
|
||||
if (elem.disabled) {
|
||||
return false;
|
||||
}
|
||||
@@ -143,7 +136,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
var focusableElements = [];
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elem = elems[i];
|
||||
|
||||
if (excludeClass && elem.classList.contains(excludeClass)) {
|
||||
@@ -163,7 +155,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function isFocusContainer(elem, direction) {
|
||||
|
||||
if (focusableContainerTagNames.indexOf(elem.tagName) !== -1) {
|
||||
return true;
|
||||
}
|
||||
@@ -217,7 +208,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function getOffset(elem) {
|
||||
|
||||
var box;
|
||||
|
||||
// Support: BlackBerry 5, iOS 3 (original iPhone)
|
||||
@@ -234,7 +224,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
if (box.right === null) {
|
||||
|
||||
// Create a new object because some browsers will throw an error when trying to set data onto the Rect object
|
||||
var newBox = {
|
||||
top: box.top,
|
||||
@@ -253,7 +242,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function nav(activeElement, direction, container, focusableElements) {
|
||||
|
||||
activeElement = activeElement || document.activeElement;
|
||||
|
||||
if (activeElement) {
|
||||
@@ -272,14 +260,10 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
var rect = getOffset(activeElement);
|
||||
|
||||
// Get elements and work out x/y points
|
||||
var cache = [];
|
||||
var point1x = parseFloat(rect.left) || 0;
|
||||
var point1y = parseFloat(rect.top) || 0;
|
||||
var point2x = parseFloat(point1x + rect.width - 1) || point1x;
|
||||
var point2y = parseFloat(point1y + rect.height - 1) || point1y;
|
||||
// Shortcuts to help with compression
|
||||
var min = Math.min;
|
||||
var max = Math.max;
|
||||
|
||||
var sourceMidX = rect.left + (rect.width / 2);
|
||||
var sourceMidY = rect.top + (rect.height / 2);
|
||||
@@ -301,10 +285,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//if (!isCurrentlyFocusableInternal(curr)) {
|
||||
// continue;
|
||||
//}
|
||||
|
||||
var elementRect = getOffset(curr);
|
||||
|
||||
// not currently visible
|
||||
@@ -313,7 +293,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
switch (direction) {
|
||||
|
||||
case 0:
|
||||
// left
|
||||
if (elementRect.left >= rect.left) {
|
||||
@@ -369,7 +348,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
var distY;
|
||||
|
||||
switch (direction) {
|
||||
|
||||
case 0:
|
||||
// left
|
||||
distX = Math.abs(point1x - Math.min(point1x, x2));
|
||||
@@ -403,7 +381,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
if (nearestElement) {
|
||||
|
||||
// See if there's a focusable container, and if so, send the focus command to that
|
||||
if (activeElement) {
|
||||
var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable');
|
||||
@@ -418,12 +395,10 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function intersectsInternal(a1, a2, b1, b2) {
|
||||
|
||||
return (b1 >= a1 && b1 <= a2) || (b2 >= a1 && b2 <= a2);
|
||||
}
|
||||
|
||||
function intersects(a1, a2, b1, b2) {
|
||||
|
||||
return intersectsInternal(a1, a2, b1, b2) || intersectsInternal(b1, b2, a1, a2);
|
||||
}
|
||||
|
||||
@@ -434,11 +409,9 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function focusFirst(container, focusableSelector) {
|
||||
|
||||
var elems = container.querySelectorAll(focusableSelector);
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elem = elems[i];
|
||||
|
||||
if (isCurrentlyFocusableInternal(elem)) {
|
||||
@@ -449,11 +422,9 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function focusLast(container, focusableSelector) {
|
||||
|
||||
var elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse();
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elem = elems[i];
|
||||
|
||||
if (isCurrentlyFocusableInternal(elem)) {
|
||||
@@ -464,7 +435,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function moveFocus(sourceElement, container, focusableSelector, offset) {
|
||||
|
||||
var elems = container.querySelectorAll(focusableSelector);
|
||||
var list = [];
|
||||
var i;
|
||||
@@ -472,7 +442,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
var elem;
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
elem = elems[i];
|
||||
|
||||
if (isCurrentlyFocusableInternal(elem)) {
|
||||
@@ -483,7 +452,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
var currentIndex = -1;
|
||||
|
||||
for (i = 0, length = list.length; i < length; i++) {
|
||||
|
||||
elem = list[i];
|
||||
|
||||
if (sourceElement === elem || elem.contains(sourceElement)) {
|
||||
@@ -506,37 +474,38 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
autoFocus: autoFocus,
|
||||
focus: focus,
|
||||
focusableParent: focusableParent,
|
||||
getFocusableElements: getFocusableElements,
|
||||
moveLeft: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 0, container, focusableElements);
|
||||
},
|
||||
moveRight: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 1, container, focusableElements);
|
||||
},
|
||||
moveUp: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 2, container, focusableElements);
|
||||
},
|
||||
moveDown: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 3, container, focusableElements);
|
||||
},
|
||||
sendText: sendText,
|
||||
isCurrentlyFocusable: isCurrentlyFocusable,
|
||||
pushScope: pushScope,
|
||||
popScope: popScope,
|
||||
focusFirst: focusFirst,
|
||||
focusLast: focusLast,
|
||||
moveFocus: moveFocus
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
autoFocus: autoFocus,
|
||||
focus: focus,
|
||||
focusableParent: focusableParent,
|
||||
getFocusableElements: getFocusableElements,
|
||||
moveLeft: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 0, container, focusableElements);
|
||||
},
|
||||
moveRight: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 1, container, focusableElements);
|
||||
},
|
||||
moveUp: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 2, container, focusableElements);
|
||||
},
|
||||
moveDown: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 3, container, focusableElements);
|
||||
},
|
||||
sendText: sendText,
|
||||
isCurrentlyFocusable: isCurrentlyFocusable,
|
||||
pushScope: pushScope,
|
||||
popScope: popScope,
|
||||
focusFirst: focusFirst,
|
||||
focusLast: focusLast,
|
||||
moveFocus: moveFocus
|
||||
};
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
import dom from 'dom';
|
||||
import appRouter from 'appRouter';
|
||||
import connectionManager from 'connectionManager';
|
||||
|
||||
function onGroupedCardClick(e, card) {
|
||||
var itemId = card.getAttribute('data-id');
|
||||
var serverId = card.getAttribute('data-serverid');
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
var apiClient = window.connectionManager.getApiClient(serverId);
|
||||
var userId = apiClient.getCurrentUserId();
|
||||
var playedIndicator = card.querySelector('.playedIndicator');
|
||||
var playedIndicatorHtml = playedIndicator ? playedIndicator.innerHTML : null;
|
||||
@@ -21,7 +20,7 @@ import connectionManager from 'connectionManager';
|
||||
|
||||
if (!actionableParent || actionableParent.classList.contains('cardContent')) {
|
||||
apiClient.getJSON(apiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) {
|
||||
if (1 === items.length) {
|
||||
if (items.length === 1) {
|
||||
return void appRouter.showItem(items[0]);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,160 +1,149 @@
|
||||
define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectionManager', 'require', 'loading', 'scrollHelper', 'emby-checkbox', 'emby-radio', 'css!./../formdialog', 'material-icons'], function (dialogHelper, globalize, userSettings, layoutManager, connectionManager, require, loading, scrollHelper) {
|
||||
'use strict';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import globalize from 'globalize';
|
||||
import * as userSettings from 'userSettings';
|
||||
import layoutManager from 'layoutManager';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-radio';
|
||||
import 'css!./../formdialog';
|
||||
import 'material-icons';
|
||||
|
||||
function saveCategories(context, options) {
|
||||
function saveCategories(context, options) {
|
||||
const categories = [];
|
||||
|
||||
var categories = [];
|
||||
const chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (const chkCategory of chkCategorys) {
|
||||
const type = chkCategory.getAttribute('data-type');
|
||||
|
||||
var chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (var i = 0, length = chkCategorys.length; i < length; i++) {
|
||||
|
||||
var type = chkCategorys[i].getAttribute('data-type');
|
||||
|
||||
if (chkCategorys[i].checked) {
|
||||
categories.push(type);
|
||||
}
|
||||
}
|
||||
|
||||
if (categories.length >= 4) {
|
||||
categories.push('series');
|
||||
}
|
||||
|
||||
// differentiate between none and all
|
||||
categories.push('all');
|
||||
options.categories = categories;
|
||||
}
|
||||
|
||||
function loadCategories(context, options) {
|
||||
|
||||
var selectedCategories = options.categories || [];
|
||||
|
||||
var chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (var i = 0, length = chkCategorys.length; i < length; i++) {
|
||||
|
||||
var type = chkCategorys[i].getAttribute('data-type');
|
||||
|
||||
chkCategorys[i].checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1;
|
||||
if (chkCategory.checked) {
|
||||
categories.push(type);
|
||||
}
|
||||
}
|
||||
|
||||
function save(context) {
|
||||
if (categories.length >= 4) {
|
||||
categories.push('series');
|
||||
}
|
||||
|
||||
var i;
|
||||
var length;
|
||||
// differentiate between none and all
|
||||
categories.push('all');
|
||||
options.categories = categories;
|
||||
}
|
||||
|
||||
var chkIndicators = context.querySelectorAll('.chkIndicator');
|
||||
for (i = 0, length = chkIndicators.length; i < length; i++) {
|
||||
function loadCategories(context, options) {
|
||||
const selectedCategories = options.categories || [];
|
||||
|
||||
var type = chkIndicators[i].getAttribute('data-type');
|
||||
userSettings.set('guide-indicator-' + type, chkIndicators[i].checked);
|
||||
const chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (const chkCategory of chkCategorys) {
|
||||
const type = chkCategory.getAttribute('data-type');
|
||||
|
||||
chkCategory.checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1;
|
||||
}
|
||||
}
|
||||
|
||||
function save(context) {
|
||||
const chkIndicators = context.querySelectorAll('.chkIndicator');
|
||||
|
||||
for (const chkIndicator of chkIndicators) {
|
||||
const type = chkIndicator.getAttribute('data-type');
|
||||
userSettings.set('guide-indicator-' + type, chkIndicator.checked);
|
||||
}
|
||||
|
||||
userSettings.set('guide-colorcodedbackgrounds', context.querySelector('.chkColorCodedBackgrounds').checked);
|
||||
userSettings.set('livetv-favoritechannelsattop', context.querySelector('.chkFavoriteChannelsAtTop').checked);
|
||||
|
||||
const sortBys = context.querySelectorAll('.chkSortOrder');
|
||||
for (const sortBy of sortBys) {
|
||||
if (sortBy.checked) {
|
||||
userSettings.set('livetv-channelorder', sortBy.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
userSettings.set('guide-colorcodedbackgrounds', context.querySelector('.chkColorCodedBackgrounds').checked);
|
||||
userSettings.set('livetv-favoritechannelsattop', context.querySelector('.chkFavoriteChannelsAtTop').checked);
|
||||
function load(context) {
|
||||
const chkIndicators = context.querySelectorAll('.chkIndicator');
|
||||
|
||||
var sortBys = context.querySelectorAll('.chkSortOrder');
|
||||
for (i = 0, length = sortBys.length; i < length; i++) {
|
||||
if (sortBys[i].checked) {
|
||||
userSettings.set('livetv-channelorder', sortBys[i].value);
|
||||
break;
|
||||
}
|
||||
for (const chkIndicator of chkIndicators) {
|
||||
const type = chkIndicator.getAttribute('data-type');
|
||||
|
||||
if (chkIndicator.getAttribute('data-default') === 'true') {
|
||||
chkIndicator.checked = userSettings.get('guide-indicator-' + type) !== 'false';
|
||||
} else {
|
||||
chkIndicator.checked = userSettings.get('guide-indicator-' + type) === 'true';
|
||||
}
|
||||
}
|
||||
|
||||
function load(context) {
|
||||
context.querySelector('.chkColorCodedBackgrounds').checked = userSettings.get('guide-colorcodedbackgrounds') === 'true';
|
||||
context.querySelector('.chkFavoriteChannelsAtTop').checked = userSettings.get('livetv-favoritechannelsattop') !== 'false';
|
||||
|
||||
var i;
|
||||
var length;
|
||||
const sortByValue = userSettings.get('livetv-channelorder') || 'Number';
|
||||
|
||||
var chkIndicators = context.querySelectorAll('.chkIndicator');
|
||||
for (i = 0, length = chkIndicators.length; i < length; i++) {
|
||||
const sortBys = context.querySelectorAll('.chkSortOrder');
|
||||
for (const sortBy of sortBys) {
|
||||
sortBy.checked = sortBy.value === sortByValue;
|
||||
}
|
||||
}
|
||||
|
||||
var type = chkIndicators[i].getAttribute('data-type');
|
||||
function showEditor(options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
let settingsChanged = false;
|
||||
|
||||
if (chkIndicators[i].getAttribute('data-default') === 'true') {
|
||||
chkIndicators[i].checked = userSettings.get('guide-indicator-' + type) !== 'false';
|
||||
import('text!./guide-settings.template.html').then(({ default: template }) => {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
chkIndicators[i].checked = userSettings.get('guide-indicator-' + type) === 'true';
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
}
|
||||
|
||||
context.querySelector('.chkColorCodedBackgrounds').checked = userSettings.get('guide-colorcodedbackgrounds') === 'true';
|
||||
context.querySelector('.chkFavoriteChannelsAtTop').checked = userSettings.get('livetv-favoritechannelsattop') !== 'false';
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
var sortByValue = userSettings.get('livetv-channelorder') || 'Number';
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var sortBys = context.querySelectorAll('.chkSortOrder');
|
||||
for (i = 0, length = sortBys.length; i < length; i++) {
|
||||
sortBys[i].checked = sortBys[i].value === sortByValue;
|
||||
}
|
||||
}
|
||||
let html = '';
|
||||
|
||||
function showEditor(options) {
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
dlg.innerHTML = html;
|
||||
|
||||
var settingsChanged = false;
|
||||
|
||||
require(['text!./guide-settings.template.html'], function (template) {
|
||||
|
||||
var dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var html = '';
|
||||
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
dlg.addEventListener('change', function () {
|
||||
|
||||
settingsChanged = true;
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
save(dlg);
|
||||
saveCategories(dlg, options);
|
||||
|
||||
if (settingsChanged) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
load(dlg);
|
||||
loadCategories(dlg, options);
|
||||
dialogHelper.open(dlg);
|
||||
dlg.addEventListener('change', function () {
|
||||
settingsChanged = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: showEditor
|
||||
};
|
||||
});
|
||||
dlg.addEventListener('close', function () {
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
save(dlg);
|
||||
saveCategories(dlg, options);
|
||||
|
||||
if (settingsChanged) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
load(dlg);
|
||||
loadCategories(dlg, options);
|
||||
dialogHelper.open(dlg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
show: showEditor
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="formDialogHeader">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${LabelPrevious}" tabindex="-1">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${Previous}" tabindex="-1">
|
||||
<span class="material-icons arrow_back" aria-hidden="true"></span>
|
||||
</button>
|
||||
<h3 class="formDialogHeaderTitle">
|
||||
|
||||
@@ -70,6 +70,10 @@
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
.programContainer.emby-scroller {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.channelPrograms {
|
||||
height: 4.42em;
|
||||
contain: strict;
|
||||
|
||||
+1162
-1221
File diff suppressed because it is too large
Load Diff
@@ -29,10 +29,10 @@
|
||||
</div>
|
||||
|
||||
<div class="guideOptions hide">
|
||||
<button is="paper-icon-button-light" type="button" class="btnPreviousPage" title="${LabelPrevious}">
|
||||
<button is="paper-icon-button-light" type="button" class="btnPreviousPage" title="${Previous}">
|
||||
<span class="material-icons arrow_back" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" type="button" class="btnNextPage" title="${LabelNext}">
|
||||
<button is="paper-icon-button-light" type="button" class="btnNextPage" title="${Next}">
|
||||
<span class="material-icons arrow_forward" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,6 @@ import layoutManager from 'layoutManager';
|
||||
import focusManager from 'focusManager';
|
||||
import globalize from 'globalize';
|
||||
import loading from 'loading';
|
||||
import connectionManager from 'connectionManager';
|
||||
import homeSections from 'homeSections';
|
||||
import dom from 'dom';
|
||||
import events from 'events';
|
||||
@@ -15,12 +14,10 @@ import 'emby-checkbox';
|
||||
const numConfigurableSections = 7;
|
||||
|
||||
function renderViews(page, user, result) {
|
||||
|
||||
let folderHtml = '';
|
||||
|
||||
folderHtml += '<div class="checkboxList">';
|
||||
folderHtml += result.map(i => {
|
||||
|
||||
let currentHtml = '';
|
||||
|
||||
const id = `chkGroupFolder${i.Id}`;
|
||||
@@ -35,7 +32,6 @@ import 'emby-checkbox';
|
||||
currentHtml += '</label>';
|
||||
|
||||
return currentHtml;
|
||||
|
||||
}).join('');
|
||||
|
||||
folderHtml += '</div>';
|
||||
@@ -44,7 +40,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function getLandingScreenOptions(type) {
|
||||
|
||||
const list = [];
|
||||
|
||||
if (type === 'movies') {
|
||||
@@ -133,9 +128,7 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function getLandingScreenOptionsHtml(type, userValue) {
|
||||
|
||||
return getLandingScreenOptions(type).map(o => {
|
||||
|
||||
const selected = userValue === o.value || (o.isDefault && !userValue);
|
||||
const selectedHtml = selected ? ' selected' : '';
|
||||
const optionValue = o.isDefault ? '' : o.value;
|
||||
@@ -145,13 +138,9 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function renderViewOrder(context, user, result) {
|
||||
|
||||
let html = '';
|
||||
|
||||
let index = 0;
|
||||
|
||||
html += result.Items.map(view => {
|
||||
|
||||
html += result.Items.map((view) => {
|
||||
let currentHtml = '';
|
||||
|
||||
currentHtml += `<div class="listItem viewItem" data-viewid="${view.Id}">`;
|
||||
@@ -171,18 +160,14 @@ import 'emby-checkbox';
|
||||
|
||||
currentHtml += '</div>';
|
||||
|
||||
index++;
|
||||
return currentHtml;
|
||||
|
||||
}).join('');
|
||||
|
||||
context.querySelector('.viewOrderList').innerHTML = html;
|
||||
}
|
||||
|
||||
function updateHomeSectionValues(context, userSettings) {
|
||||
|
||||
for (let i = 1; i <= 7; i++) {
|
||||
|
||||
const select = context.querySelector(`#selectHomeSection${i}`);
|
||||
const defaultValue = homeSections.getDefaultSection(i - 1);
|
||||
|
||||
@@ -203,7 +188,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function getPerLibrarySettingsHtml(item, user, userSettings, apiClient) {
|
||||
|
||||
let html = '';
|
||||
|
||||
let isChecked;
|
||||
@@ -220,7 +204,6 @@ import 'emby-checkbox';
|
||||
|
||||
const excludeFromLatest = ['playlists', 'livetv', 'boxsets', 'channels'];
|
||||
if (!excludeFromLatest.includes(item.CollectionType || '')) {
|
||||
|
||||
isChecked = !user.Configuration.LatestItemsExcludes.includes(item.Id);
|
||||
html += '<label class="fldIncludeInLatest">';
|
||||
html += `<input type="checkbox" is="emby-checkbox" class="chkIncludeInLatest" data-folderid="${item.Id}"${isChecked ? ' checked="checked"' : ''}/>`;
|
||||
@@ -229,12 +212,10 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
if (html) {
|
||||
|
||||
html = `<div class="checkboxListContainer">${html}</div>`;
|
||||
}
|
||||
|
||||
if (item.CollectionType === 'movies' || item.CollectionType === 'tvshows' || item.CollectionType === 'music' || item.CollectionType === 'livetv') {
|
||||
|
||||
const idForLanding = item.CollectionType === 'livetv' ? item.CollectionType : item.Id;
|
||||
html += '<div class="selectContainer">';
|
||||
html += `<select is="emby-select" class="selectLanding" data-folderid="${idForLanding}" label="${globalize.translate('LabelDefaultScreen')}">`;
|
||||
@@ -248,7 +229,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
if (html) {
|
||||
|
||||
let prefix = '';
|
||||
prefix += '<div class="verticalSection">';
|
||||
|
||||
@@ -264,12 +244,10 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function renderPerLibrarySettings(context, user, userViews, userSettings, apiClient) {
|
||||
|
||||
const elem = context.querySelector('.perLibrarySettings');
|
||||
let html = '';
|
||||
|
||||
for (let i = 0, length = userViews.length; i < length; i++) {
|
||||
|
||||
html += getPerLibrarySettingsHtml(userViews[i], user, userSettings, apiClient);
|
||||
}
|
||||
|
||||
@@ -277,7 +255,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function loadForm(context, user, userSettings, apiClient) {
|
||||
|
||||
context.querySelector('.chkHidePlayedFromLatest').checked = user.Configuration.HidePlayedInLatest || false;
|
||||
|
||||
updateHomeSectionValues(context, userSettings);
|
||||
@@ -286,7 +263,6 @@ import 'emby-checkbox';
|
||||
const promise2 = apiClient.getJSON(apiClient.getUrl(`Users/${user.Id}/GroupingOptions`));
|
||||
|
||||
Promise.all([promise1, promise2]).then(responses => {
|
||||
|
||||
renderViewOrder(context, user, responses[0]);
|
||||
|
||||
renderPerLibrarySettings(context, user, responses[0].Items, userSettings, apiClient);
|
||||
@@ -298,17 +274,13 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function onSectionOrderListClick(e) {
|
||||
|
||||
const target = dom.parentWithClass(e.target, 'btnViewItemMove');
|
||||
|
||||
if (target) {
|
||||
const viewItem = dom.parentWithClass(target, 'viewItem');
|
||||
|
||||
if (viewItem) {
|
||||
const ul = dom.parentWithClass(viewItem, 'paperList');
|
||||
|
||||
if (target.classList.contains('btnViewItemDown')) {
|
||||
|
||||
const next = viewItem.nextSibling;
|
||||
|
||||
if (next) {
|
||||
@@ -316,9 +288,7 @@ import 'emby-checkbox';
|
||||
next.parentNode.insertBefore(viewItem, next.nextSibling);
|
||||
focusManager.focus(e.target);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
const prev = viewItem.previousSibling;
|
||||
|
||||
if (prev) {
|
||||
@@ -332,37 +302,30 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function getCheckboxItems(selector, context, isChecked) {
|
||||
|
||||
const inputs = context.querySelectorAll(selector);
|
||||
const list = [];
|
||||
|
||||
for (let i = 0, length = inputs.length; i < length; i++) {
|
||||
|
||||
if (inputs[i].checked === isChecked) {
|
||||
list.push(inputs[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
function saveUser(context, user, userSettingsInstance, apiClient) {
|
||||
|
||||
user.Configuration.HidePlayedInLatest = context.querySelector('.chkHidePlayedFromLatest').checked;
|
||||
|
||||
user.Configuration.LatestItemsExcludes = getCheckboxItems('.chkIncludeInLatest', context, false).map(i => {
|
||||
|
||||
return i.getAttribute('data-folderid');
|
||||
});
|
||||
|
||||
user.Configuration.MyMediaExcludes = getCheckboxItems('.chkIncludeInMyMedia', context, false).map(i => {
|
||||
|
||||
return i.getAttribute('data-folderid');
|
||||
});
|
||||
|
||||
user.Configuration.GroupedFolders = getCheckboxItems('.chkGroupFolder', context, true).map(i => {
|
||||
|
||||
return i.getAttribute('data-folderid');
|
||||
});
|
||||
|
||||
@@ -396,13 +359,10 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
|
||||
|
||||
loading.show();
|
||||
|
||||
apiClient.getUser(userId).then(user => {
|
||||
|
||||
saveUser(context, user, userSettings, apiClient).then(() => {
|
||||
|
||||
loading.hide();
|
||||
if (enableSaveConfirmation) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
@@ -411,7 +371,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
events.trigger(instance, 'saved');
|
||||
|
||||
}, () => {
|
||||
loading.hide();
|
||||
});
|
||||
@@ -419,14 +378,12 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
|
||||
const self = this;
|
||||
const apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userId = self.options.userId;
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(() => {
|
||||
|
||||
const enableSaveConfirmation = self.options.enableSaveConfirmation;
|
||||
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
|
||||
});
|
||||
@@ -439,7 +396,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function onChange(e) {
|
||||
|
||||
const chkIncludeInMyMedia = dom.parentWithClass(e.target, 'chkIncludeInMyMedia');
|
||||
if (!chkIncludeInMyMedia) {
|
||||
return;
|
||||
@@ -457,9 +413,7 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function embed(options, self) {
|
||||
|
||||
return import('text!./homeScreenSettings.template.html').then(({default: template}) => {
|
||||
|
||||
for (let i = 1; i <= numConfigurableSections; i++) {
|
||||
template = template.replace(`{section${i}label}`, globalize.translate('LabelHomeScreenSectionValue', i));
|
||||
}
|
||||
@@ -491,20 +445,17 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
loadData(autoFocus) {
|
||||
|
||||
const self = this;
|
||||
const context = self.options.element;
|
||||
|
||||
loading.show();
|
||||
|
||||
const userId = self.options.userId;
|
||||
const apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
apiClient.getUser(userId).then(user => {
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(() => {
|
||||
|
||||
self.dataLoaded = true;
|
||||
|
||||
loadForm(context, user, userSettings, apiClient);
|
||||
@@ -521,7 +472,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
||||
this.options = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<form style="margin:0 auto;">
|
||||
<div class="verticalSection verticalSection-extrabottompadding">
|
||||
<h2 class="sectionTitle">${HeaderHome}</h2>
|
||||
<h2 class="sectionTitle">${Home}</h2>
|
||||
|
||||
<div class="selectContainer hide selectTVHomeScreenContainer">
|
||||
<select is="emby-select" class="selectTVHomeScreen" label="${LabelTVHomeScreen}">
|
||||
@@ -25,7 +25,7 @@
|
||||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
@@ -38,7 +38,7 @@
|
||||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
@@ -51,7 +51,7 @@
|
||||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
@@ -64,7 +64,7 @@
|
||||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
@@ -77,7 +77,7 @@
|
||||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
@@ -90,7 +90,7 @@
|
||||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
@@ -103,7 +103,7 @@
|
||||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import connectionManager from 'connectionManager';
|
||||
import cardBuilder from 'cardBuilder';
|
||||
import appSettings from 'appSettings';
|
||||
import dom from 'dom';
|
||||
import appHost from 'apphost';
|
||||
import layoutManager from 'layoutManager';
|
||||
import imageLoader from 'imageLoader';
|
||||
import globalize from 'globalize';
|
||||
import itemShortcuts from 'itemShortcuts';
|
||||
import itemHelper from 'itemHelper';
|
||||
import appRouter from 'appRouter';
|
||||
import imageHelper from 'scripts/imagehelper';
|
||||
import 'paper-icon-button-light';
|
||||
@@ -135,7 +130,6 @@ import 'css!./homesections';
|
||||
}
|
||||
|
||||
function loadSection(page, apiClient, user, userSettings, userViews, allSections, index) {
|
||||
|
||||
const section = allSections[index];
|
||||
const userId = user.Id;
|
||||
|
||||
@@ -215,17 +209,9 @@ import 'css!./homesections';
|
||||
imageLoader.lazyChildren(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random integer between min (inclusive) and max (inclusive)
|
||||
* Using Math.round() will give you a non-uniform distribution!
|
||||
*/
|
||||
function getRandomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function getFetchLatestItemsFn(serverId, parentId, collectionType) {
|
||||
return function () {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
let limit = 16;
|
||||
|
||||
if (enableScrollX()) {
|
||||
@@ -347,14 +333,6 @@ import 'css!./homesections';
|
||||
}
|
||||
}
|
||||
|
||||
function getRequirePromise(deps) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
import(deps).then(() => {
|
||||
return resolve;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function loadLibraryTiles(elem, apiClient, user, userSettings, shape, userViews, allSections) {
|
||||
let html = '';
|
||||
if (userViews.length) {
|
||||
@@ -389,7 +367,7 @@ import 'css!./homesections';
|
||||
|
||||
function getContinueWatchingFetchFn(serverId) {
|
||||
return function () {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
const screenWidth = dom.getWindowSize().innerWidth;
|
||||
|
||||
let limit;
|
||||
@@ -462,7 +440,7 @@ import 'css!./homesections';
|
||||
|
||||
function getContinueListeningFetchFn(serverId) {
|
||||
return function () {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
const screenWidth = dom.getWindowSize().innerWidth;
|
||||
|
||||
let limit;
|
||||
@@ -535,7 +513,7 @@ import 'css!./homesections';
|
||||
|
||||
function getOnNowFetchFn(serverId) {
|
||||
return function () {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getLiveTvRecommendedPrograms({
|
||||
userId: apiClient.getCurrentUserId(),
|
||||
IsAiring: true,
|
||||
@@ -549,7 +527,6 @@ import 'css!./homesections';
|
||||
}
|
||||
|
||||
function getOnNowItemsHtml(items) {
|
||||
const cardLayout = false;
|
||||
return cardBuilder.getCardsHtml({
|
||||
items: items,
|
||||
preferThumb: 'auto',
|
||||
@@ -576,7 +553,6 @@ import 'css!./homesections';
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const userId = user.Id;
|
||||
return apiClient.getLiveTvRecommendedPrograms({
|
||||
userId: apiClient.getCurrentUserId(),
|
||||
IsAiring: true,
|
||||
@@ -649,7 +625,6 @@ import 'css!./homesections';
|
||||
html += '</h2>';
|
||||
html += '<span class="material-icons chevron_right"></span>';
|
||||
html += '</a>';
|
||||
|
||||
} else {
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards">' + globalize.translate('HeaderOnNow') + '</h2>';
|
||||
}
|
||||
@@ -681,7 +656,7 @@ import 'css!./homesections';
|
||||
|
||||
function getNextUpFetchFn(serverId) {
|
||||
return function () {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getNextUpEpisodes({
|
||||
Limit: enableScrollX() ? 24 : 15,
|
||||
Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo,Path',
|
||||
@@ -720,12 +695,12 @@ import 'css!./homesections';
|
||||
serverId: apiClient.serverId()
|
||||
}) + '" class="button-flat button-flat-mini sectionTitleTextButton">';
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards">';
|
||||
html += globalize.translate('HeaderNextUp');
|
||||
html += globalize.translate('NextUp');
|
||||
html += '</h2>';
|
||||
html += '<span class="material-icons chevron_right"></span>';
|
||||
html += '</a>';
|
||||
} else {
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards">' + globalize.translate('HeaderNextUp') + '</h2>';
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards">' + globalize.translate('NextUp') + '</h2>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
@@ -752,7 +727,7 @@ import 'css!./homesections';
|
||||
|
||||
function getLatestRecordingsFetchFn(serverId, activeRecordingsOnly) {
|
||||
return function () {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getLiveTvRecordings({
|
||||
userId: apiClient.getCurrentUserId(),
|
||||
Limit: enableScrollX() ? 12 : 5,
|
||||
@@ -766,7 +741,6 @@ import 'css!./homesections';
|
||||
|
||||
function getLatestRecordingItemsHtml(activeRecordingsOnly) {
|
||||
return function (items) {
|
||||
const cardLayout = false;
|
||||
return cardBuilder.getCardsHtml({
|
||||
items: items,
|
||||
shape: enableScrollX() ? 'autooverflow' : 'auto',
|
||||
|
||||
@@ -33,34 +33,7 @@ import events from 'events';
|
||||
return false;
|
||||
}
|
||||
|
||||
export function enableHlsShakaPlayer(item, mediaSource, mediaType) {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (!!window.MediaSource && !!MediaSource.isTypeSupported) {
|
||||
|
||||
if (canPlayNativeHls()) {
|
||||
|
||||
if (browser.edge && mediaType === 'Video') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// simple playback should use the native support
|
||||
if (mediaSource.RunTimeTicks) {
|
||||
//if (!browser.edge) {
|
||||
//return false;
|
||||
//}
|
||||
}
|
||||
|
||||
//return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function enableHlsJsPlayer(runTimeTicks, mediaType) {
|
||||
|
||||
if (window.MediaSource == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -76,7 +49,6 @@ import events from 'events';
|
||||
}
|
||||
|
||||
if (canPlayNativeHls()) {
|
||||
|
||||
// Having trouble with chrome's native support and transcoded music
|
||||
if (browser.android && mediaType === 'Audio') {
|
||||
return true;
|
||||
@@ -102,7 +74,6 @@ import events from 'events';
|
||||
var recoverDecodingErrorDate;
|
||||
var recoverSwapAudioCodecDate;
|
||||
export function handleHlsJsMediaError(instance, reject) {
|
||||
|
||||
var hlsPlayer = instance._hlsPlayer;
|
||||
|
||||
if (!hlsPlayer) {
|
||||
@@ -138,7 +109,6 @@ import events from 'events';
|
||||
}
|
||||
|
||||
export function onErrorInternal(instance, type) {
|
||||
|
||||
// Needed for video
|
||||
if (instance.destroyCustomTrack) {
|
||||
instance.destroyCustomTrack(instance._mediaElement);
|
||||
@@ -166,12 +136,9 @@ import events from 'events';
|
||||
}
|
||||
|
||||
export function seekOnPlaybackStart(instance, element, ticks, onMediaReady) {
|
||||
|
||||
var seconds = (ticks || 0) / 10000000;
|
||||
|
||||
if (seconds) {
|
||||
var src = (instance.currentSrc() || '').toLowerCase();
|
||||
|
||||
// Appending #t=xxx to the query string doesn't seem to work with HLS
|
||||
// For plain video files, not all browsers support it either
|
||||
|
||||
@@ -204,11 +171,8 @@ import events from 'events';
|
||||
}
|
||||
|
||||
export function applySrc(elem, src, options) {
|
||||
|
||||
if (window.Windows && options.mediaSource && options.mediaSource.IsLocal) {
|
||||
|
||||
return Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function (file) {
|
||||
|
||||
var playlist = new Windows.Media.Playback.MediaPlaybackList();
|
||||
|
||||
var source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file);
|
||||
@@ -217,9 +181,7 @@ import events from 'events';
|
||||
elem.src = URL.createObjectURL(playlist, { oneTimeOnly: true });
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
elem.src = src;
|
||||
}
|
||||
|
||||
@@ -227,18 +189,15 @@ import events from 'events';
|
||||
}
|
||||
|
||||
function onSuccessfulPlay(elem, onErrorFn) {
|
||||
|
||||
elem.addEventListener('error', onErrorFn);
|
||||
}
|
||||
|
||||
export function playWithPromise(elem, onErrorFn) {
|
||||
|
||||
try {
|
||||
var promise = elem.play();
|
||||
if (promise && promise.then) {
|
||||
// Chrome now returns a promise
|
||||
return promise.catch(function (e) {
|
||||
|
||||
var errorName = (e.name || '').toLowerCase();
|
||||
// safari uses aborterror
|
||||
if (errorName === 'notallowederror' ||
|
||||
@@ -260,7 +219,6 @@ import events from 'events';
|
||||
}
|
||||
|
||||
export function destroyCastPlayer(instance) {
|
||||
|
||||
var player = instance._castPlayer;
|
||||
if (player) {
|
||||
try {
|
||||
@@ -273,19 +231,6 @@ import events from 'events';
|
||||
}
|
||||
}
|
||||
|
||||
export function destroyShakaPlayer(instance) {
|
||||
var player = instance._shakaPlayer;
|
||||
if (player) {
|
||||
try {
|
||||
player.destroy();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
instance._shakaPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
export function destroyHlsPlayer(instance) {
|
||||
var player = instance._hlsPlayer;
|
||||
if (player) {
|
||||
@@ -315,10 +260,8 @@ import events from 'events';
|
||||
}
|
||||
|
||||
export function bindEventsToHlsPlayer(instance, hls, elem, onErrorFn, resolve, reject) {
|
||||
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, function () {
|
||||
playWithPromise(elem, onErrorFn).then(resolve, function () {
|
||||
|
||||
if (reject) {
|
||||
reject();
|
||||
reject = null;
|
||||
@@ -327,14 +270,12 @@ import events from 'events';
|
||||
});
|
||||
|
||||
hls.on(Hls.Events.ERROR, function (event, data) {
|
||||
|
||||
console.error('HLS Error: Type: ' + data.type + ' Details: ' + (data.details || '') + ' Fatal: ' + (data.fatal || false));
|
||||
|
||||
switch (data.type) {
|
||||
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||
// try to recover network error
|
||||
if (data.response && data.response.code && data.response.code >= 400) {
|
||||
|
||||
console.debug('hls.js response error code: ' + data.response.code);
|
||||
|
||||
// Trigger failure differently depending on whether this is prior to start of playback, or after
|
||||
@@ -348,7 +289,6 @@ import events from 'events';
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -361,7 +301,6 @@ import events from 'events';
|
||||
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||
|
||||
if (data.response && data.response.code === 0) {
|
||||
|
||||
// This could be a CORS error related to access control response headers
|
||||
|
||||
console.debug('hls.js response error code: ' + data.response.code);
|
||||
@@ -407,7 +346,6 @@ import events from 'events';
|
||||
}
|
||||
|
||||
export function onEndedInternal(instance, elem, onErrorFn) {
|
||||
|
||||
elem.removeEventListener('error', onErrorFn);
|
||||
|
||||
elem.src = '';
|
||||
@@ -416,7 +354,6 @@ import events from 'events';
|
||||
|
||||
destroyHlsPlayer(instance);
|
||||
destroyFlvPlayer(instance);
|
||||
destroyShakaPlayer(instance);
|
||||
destroyCastPlayer(instance);
|
||||
|
||||
var stopInfo = {
|
||||
@@ -431,7 +368,6 @@ import events from 'events';
|
||||
}
|
||||
|
||||
export function getBufferedRanges(instance, elem) {
|
||||
|
||||
var ranges = [];
|
||||
var seekable = elem.buffered || [];
|
||||
|
||||
@@ -444,7 +380,6 @@ import events from 'events';
|
||||
offset = offset || 0;
|
||||
|
||||
for (var i = 0, length = seekable.length; i < length; i++) {
|
||||
|
||||
var start = seekable.start(i);
|
||||
var end = seekable.end(i);
|
||||
|
||||
|
||||
@@ -1,24 +1,37 @@
|
||||
define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'imageLoader', 'browser', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'emby-checkbox', 'paper-icon-button-light', 'emby-button', 'formDialogStyle', 'cardStyle'], function (dom, loading, appHost, dialogHelper, connectionManager, imageLoader, browser, layoutManager, scrollHelper, globalize, require) {
|
||||
'use strict';
|
||||
import dom from 'dom';
|
||||
import loading from 'loading';
|
||||
import appHost from 'apphost';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import imageLoader from 'imageLoader';
|
||||
import browser from 'browser';
|
||||
import layoutManager from 'layoutManager';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import globalize from 'globalize';
|
||||
import 'emby-checkbox';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-button';
|
||||
import 'formDialogStyle';
|
||||
import 'cardStyle';
|
||||
|
||||
var enableFocusTransform = !browser.slow && !browser.edge;
|
||||
/* eslint-disable indent */
|
||||
|
||||
var currentItemId;
|
||||
var currentItemType;
|
||||
var currentResolve;
|
||||
var currentReject;
|
||||
var hasChanges = false;
|
||||
const enableFocusTransform = !browser.slow && !browser.edge;
|
||||
|
||||
let currentItemId;
|
||||
let currentItemType;
|
||||
let currentResolve;
|
||||
let currentReject;
|
||||
let hasChanges = false;
|
||||
|
||||
// These images can be large and we're seeing memory problems in safari
|
||||
var browsableImagePageSize = browser.slow ? 6 : 30;
|
||||
const browsableImagePageSize = browser.slow ? 6 : 30;
|
||||
|
||||
var browsableImageStartIndex = 0;
|
||||
var browsableImageType = 'Primary';
|
||||
var selectedProvider;
|
||||
let browsableImageStartIndex = 0;
|
||||
let browsableImageType = 'Primary';
|
||||
let selectedProvider;
|
||||
|
||||
function getBaseRemoteOptions() {
|
||||
|
||||
var options = {};
|
||||
const options = {};
|
||||
|
||||
options.itemId = currentItemId;
|
||||
|
||||
@@ -26,58 +39,53 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
}
|
||||
|
||||
function reloadBrowsableImages(page, apiClient) {
|
||||
|
||||
loading.show();
|
||||
|
||||
var options = getBaseRemoteOptions();
|
||||
const options = getBaseRemoteOptions();
|
||||
|
||||
options.type = browsableImageType;
|
||||
options.startIndex = browsableImageStartIndex;
|
||||
options.limit = browsableImagePageSize;
|
||||
options.IncludeAllLanguages = page.querySelector('#chkAllLanguages').checked;
|
||||
|
||||
var provider = selectedProvider || '';
|
||||
const provider = selectedProvider || '';
|
||||
|
||||
if (provider) {
|
||||
options.ProviderName = provider;
|
||||
}
|
||||
|
||||
apiClient.getAvailableRemoteImages(options).then(function (result) {
|
||||
|
||||
renderRemoteImages(page, apiClient, result, browsableImageType, options.startIndex, options.limit);
|
||||
|
||||
page.querySelector('#selectBrowsableImageType').value = browsableImageType;
|
||||
|
||||
var providersHtml = result.Providers.map(function (p) {
|
||||
const providersHtml = result.Providers.map(function (p) {
|
||||
return '<option value="' + p + '">' + p + '</option>';
|
||||
});
|
||||
|
||||
var selectImageProvider = page.querySelector('#selectImageProvider');
|
||||
const selectImageProvider = page.querySelector('#selectImageProvider');
|
||||
selectImageProvider.innerHTML = '<option value="">' + globalize.translate('All') + '</option>' + providersHtml;
|
||||
selectImageProvider.value = provider;
|
||||
|
||||
loading.hide();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function renderRemoteImages(page, apiClient, imagesResult, imageType, startIndex, limit) {
|
||||
|
||||
page.querySelector('.availableImagesPaging').innerHTML = getPagingHtml(startIndex, limit, imagesResult.TotalRecordCount);
|
||||
|
||||
var html = '';
|
||||
|
||||
for (var i = 0, length = imagesResult.Images.length; i < length; i++) {
|
||||
let html = '';
|
||||
|
||||
for (let i = 0, length = imagesResult.Images.length; i < length; i++) {
|
||||
html += getRemoteImageHtml(imagesResult.Images[i], imageType, apiClient);
|
||||
}
|
||||
|
||||
var availableImagesList = page.querySelector('.availableImagesList');
|
||||
const availableImagesList = page.querySelector('.availableImagesList');
|
||||
availableImagesList.innerHTML = html;
|
||||
imageLoader.lazyChildren(availableImagesList);
|
||||
|
||||
var btnNextPage = page.querySelector('.btnNextPage');
|
||||
var btnPreviousPage = page.querySelector('.btnPreviousPage');
|
||||
const btnNextPage = page.querySelector('.btnNextPage');
|
||||
const btnPreviousPage = page.querySelector('.btnPreviousPage');
|
||||
|
||||
if (btnNextPage) {
|
||||
btnNextPage.addEventListener('click', function () {
|
||||
@@ -92,23 +100,21 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
reloadBrowsableImages(page, apiClient);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getPagingHtml(startIndex, limit, totalRecordCount) {
|
||||
let html = '';
|
||||
|
||||
var html = '';
|
||||
|
||||
var recordsEnd = Math.min(startIndex + limit, totalRecordCount);
|
||||
const recordsEnd = Math.min(startIndex + limit, totalRecordCount);
|
||||
|
||||
// 20 is the minimum page size
|
||||
var showControls = totalRecordCount > limit;
|
||||
const showControls = totalRecordCount > limit;
|
||||
|
||||
html += '<div class="listPaging">';
|
||||
|
||||
html += '<span style="margin-right: 10px;">';
|
||||
|
||||
var startAtDisplay = totalRecordCount ? startIndex + 1 : 0;
|
||||
const startAtDisplay = totalRecordCount ? startIndex + 1 : 0;
|
||||
html += globalize.translate('ListPaging', startAtDisplay, recordsEnd, totalRecordCount);
|
||||
|
||||
html += '</span>';
|
||||
@@ -127,7 +133,7 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
}
|
||||
|
||||
function downloadRemoteImage(page, apiClient, url, type, provider) {
|
||||
var options = getBaseRemoteOptions();
|
||||
const options = getBaseRemoteOptions();
|
||||
|
||||
options.Type = type;
|
||||
options.ImageUrl = url;
|
||||
@@ -136,9 +142,8 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
loading.show();
|
||||
|
||||
apiClient.downloadRemoteImage(options).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
var dlg = dom.parentWithClass(page, 'dialog');
|
||||
const dlg = dom.parentWithClass(page, 'dialog');
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
}
|
||||
@@ -148,17 +153,17 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
}
|
||||
|
||||
function getRemoteImageHtml(image, imageType, apiClient) {
|
||||
var tagName = layoutManager.tv ? 'button' : 'div';
|
||||
var enableFooterButtons = !layoutManager.tv;
|
||||
const tagName = layoutManager.tv ? 'button' : 'div';
|
||||
const enableFooterButtons = !layoutManager.tv;
|
||||
|
||||
// TODO move card creation code to Card component
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
var cssClass = 'card scalableCard imageEditorCard';
|
||||
var cardBoxCssClass = 'cardBox visualCardBox';
|
||||
let cssClass = 'card scalableCard imageEditorCard';
|
||||
const cardBoxCssClass = 'cardBox visualCardBox';
|
||||
|
||||
var shape = 'backdrop';
|
||||
let shape;
|
||||
if (imageType === 'Backdrop' || imageType === 'Art' || imageType === 'Thumb' || imageType === 'Logo') {
|
||||
shape = 'backdrop';
|
||||
} else if (imageType === 'Banner') {
|
||||
@@ -166,7 +171,6 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
} else if (imageType === 'Disc') {
|
||||
shape = 'square';
|
||||
} else {
|
||||
|
||||
if (currentItemType === 'Episode') {
|
||||
shape = 'backdrop';
|
||||
} else if (currentItemType === 'MusicAlbum' || currentItemType === 'MusicArtist') {
|
||||
@@ -217,19 +221,16 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
html += '<div class="cardText cardTextCentered">' + image.ProviderName + '</div>';
|
||||
|
||||
if (image.Width || image.Height || image.Language) {
|
||||
|
||||
html += '<div class="cardText cardText-secondary cardTextCentered">';
|
||||
|
||||
if (image.Width && image.Height) {
|
||||
html += image.Width + ' x ' + image.Height;
|
||||
|
||||
if (image.Language) {
|
||||
|
||||
html += ' • ' + image.Language;
|
||||
}
|
||||
} else {
|
||||
if (image.Language) {
|
||||
|
||||
html += image.Language;
|
||||
}
|
||||
}
|
||||
@@ -238,13 +239,11 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
}
|
||||
|
||||
if (image.CommunityRating != null) {
|
||||
|
||||
html += '<div class="cardText cardText-secondary cardTextCentered">';
|
||||
|
||||
if (image.RatingType === 'Likes') {
|
||||
html += image.CommunityRating + (image.CommunityRating === 1 ? ' like' : ' likes');
|
||||
} else {
|
||||
|
||||
if (image.CommunityRating) {
|
||||
html += image.CommunityRating.toFixed(1);
|
||||
|
||||
@@ -270,7 +269,6 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
// end footer
|
||||
|
||||
html += '</div>';
|
||||
//html += '</div>';
|
||||
|
||||
html += '</' + tagName + '>';
|
||||
|
||||
@@ -287,7 +285,6 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
});
|
||||
|
||||
page.querySelector('#selectImageProvider').addEventListener('change', function () {
|
||||
|
||||
browsableImageStartIndex = 0;
|
||||
selectedProvider = this.value;
|
||||
|
||||
@@ -295,22 +292,20 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
});
|
||||
|
||||
page.querySelector('#chkAllLanguages').addEventListener('change', function () {
|
||||
|
||||
browsableImageStartIndex = 0;
|
||||
|
||||
reloadBrowsableImages(page, apiClient);
|
||||
});
|
||||
|
||||
page.addEventListener('click', function (e) {
|
||||
|
||||
var btnDownloadRemoteImage = dom.parentWithClass(e.target, 'btnDownloadRemoteImage');
|
||||
const btnDownloadRemoteImage = dom.parentWithClass(e.target, 'btnDownloadRemoteImage');
|
||||
if (btnDownloadRemoteImage) {
|
||||
var card = dom.parentWithClass(btnDownloadRemoteImage, 'card');
|
||||
const card = dom.parentWithClass(btnDownloadRemoteImage, 'card');
|
||||
downloadRemoteImage(page, apiClient, card.getAttribute('data-imageurl'), card.getAttribute('data-imagetype'), card.getAttribute('data-imageprovider'));
|
||||
return;
|
||||
}
|
||||
|
||||
var btnImageCard = dom.parentWithClass(e.target, 'btnImageCard');
|
||||
const btnImageCard = dom.parentWithClass(e.target, 'btnImageCard');
|
||||
if (btnImageCard) {
|
||||
downloadRemoteImage(page, apiClient, btnImageCard.getAttribute('data-imageurl'), btnImageCard.getAttribute('data-imagetype'), btnImageCard.getAttribute('data-imageprovider'));
|
||||
}
|
||||
@@ -320,14 +315,13 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
function showEditor(itemId, serverId, itemType) {
|
||||
loading.show();
|
||||
|
||||
require(['text!./imageDownloader.template.html'], function (template) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
import('text!./imageDownloader.template.html').then(({default: template}) => {
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
currentItemId = itemId;
|
||||
currentItemType = itemType;
|
||||
|
||||
var dialogOptions = {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true
|
||||
};
|
||||
|
||||
@@ -337,7 +331,7 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.innerHTML = globalize.translateHtml(template, 'core');
|
||||
|
||||
@@ -350,11 +344,10 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
var editorContent = dlg.querySelector('.formDialogContent');
|
||||
const editorContent = dlg.querySelector('.formDialogContent');
|
||||
initEditor(editorContent, apiClient);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
@@ -363,7 +356,7 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
}
|
||||
|
||||
function onDialogClosed() {
|
||||
var dlg = this;
|
||||
const dlg = this;
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg, false);
|
||||
@@ -377,18 +370,20 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
show: function (itemId, serverId, itemType, imageType) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
currentResolve = resolve;
|
||||
currentReject = reject;
|
||||
hasChanges = false;
|
||||
browsableImageStartIndex = 0;
|
||||
browsableImageType = imageType || 'Primary';
|
||||
selectedProvider = null;
|
||||
export function show(itemId, serverId, itemType, imageType) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
currentResolve = resolve;
|
||||
currentReject = reject;
|
||||
hasChanges = false;
|
||||
browsableImageStartIndex = 0;
|
||||
browsableImageType = imageType || 'Primary';
|
||||
selectedProvider = null;
|
||||
showEditor(itemId, serverId, itemType);
|
||||
});
|
||||
}
|
||||
|
||||
showEditor(itemId, serverId, itemType);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -16,7 +16,7 @@ import 'emby-input';
|
||||
return {
|
||||
Type: type,
|
||||
MinWidth: 0,
|
||||
Limit: 'Primary' === type ? 1 : 0
|
||||
Limit: type === 'Primary' ? 1 : 0
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -15,41 +15,41 @@
|
||||
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Primary" />
|
||||
<span>${OptionDownloadPrimaryImage}</span>
|
||||
<span>${Primary}</span>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Art" />
|
||||
<span>${OptionDownloadArtImage}</span>
|
||||
<span>${Art}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="BoxRear" />
|
||||
<span>${OptionDownloadBackImage}</span>
|
||||
<span>${Back}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Banner" />
|
||||
<span>${OptionDownloadBannerImage}</span>
|
||||
<span>${Banner}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Box" />
|
||||
<span>${OptionDownloadBoxImage}</span>
|
||||
<span>${Box}</span>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Disc" />
|
||||
<span>${OptionDownloadDiscImage}</span>
|
||||
<span>${Disc}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Logo" />
|
||||
<span>${OptionDownloadLogoImage}</span>
|
||||
<span>${Logo}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Menu" />
|
||||
<span>${OptionDownloadMenuImage}</span>
|
||||
<span>${Menu}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Thumb" />
|
||||
<span>${OptionDownloadThumbImage}</span>
|
||||
<span>${Thumb}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
*/
|
||||
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import connectionManager from 'connectionManager';
|
||||
import dom from 'dom';
|
||||
import loading from 'loading';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
@@ -23,7 +22,6 @@ import 'css!./style';
|
||||
let hasChanges = false;
|
||||
|
||||
function onFileReaderError(evt) {
|
||||
|
||||
loading.hide();
|
||||
|
||||
switch (evt.target.error.code) {
|
||||
@@ -43,7 +41,6 @@ import 'css!./style';
|
||||
}
|
||||
|
||||
function setFiles(page, files) {
|
||||
|
||||
const file = files[0];
|
||||
|
||||
if (!file || !file.type.match('image.*')) {
|
||||
@@ -69,7 +66,6 @@ import 'css!./style';
|
||||
// Closure to capture the file information.
|
||||
reader.onload = (theFile => {
|
||||
return e => {
|
||||
|
||||
// Render thumbnail.
|
||||
const html = ['<img style="max-width:100%;max-height:100%;" src="', e.target.result, '" title="', escape(theFile.name), '"/>'].join('');
|
||||
|
||||
@@ -84,7 +80,6 @@ import 'css!./style';
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
|
||||
const file = currentFile;
|
||||
|
||||
if (!file) {
|
||||
@@ -112,8 +107,7 @@ import 'css!./style';
|
||||
return false;
|
||||
}
|
||||
|
||||
connectionManager.getApiClient(currentServerId).uploadItemImage(currentItemId, imageType, file).then(() => {
|
||||
|
||||
window.connectionManager.getApiClient(currentServerId).uploadItemImage(currentItemId, imageType, file).then(() => {
|
||||
dlg.querySelector('#uploadImage').value = '';
|
||||
|
||||
loading.hide();
|
||||
@@ -126,7 +120,6 @@ import 'css!./style';
|
||||
}
|
||||
|
||||
function initEditor(page) {
|
||||
|
||||
page.querySelector('form').addEventListener('submit', onSubmit);
|
||||
|
||||
page.querySelector('#uploadImage').addEventListener('change', function () {
|
||||
@@ -139,11 +132,9 @@ import 'css!./style';
|
||||
}
|
||||
|
||||
function showEditor(options, resolve) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
return import('text!./imageUploader.template.html').then(({default: template}) => {
|
||||
|
||||
currentItemId = options.itemId;
|
||||
currentServerId = options.serverId;
|
||||
|
||||
@@ -169,7 +160,6 @@ import 'css!./style';
|
||||
|
||||
// Has to be assigned a z-index after the call to .open()
|
||||
dlg.addEventListener('close', () => {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg, false);
|
||||
}
|
||||
@@ -185,16 +175,13 @@ import 'css!./style';
|
||||
dlg.querySelector('#selectImageType').value = options.imageType || 'Primary';
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function show(options) {
|
||||
|
||||
return new Promise(resolve => {
|
||||
|
||||
hasChanges = false;
|
||||
|
||||
showEditor(options, resolve);
|
||||
|
||||
@@ -1,14 +1,28 @@
|
||||
define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager', 'focusManager', 'globalize', 'scrollHelper', 'imageLoader', 'require', 'browser', 'apphost', 'cardStyle', 'formDialogStyle', 'emby-button', 'paper-icon-button-light', 'css!./imageeditor'], function (dialogHelper, connectionManager, loading, dom, layoutManager, focusManager, globalize, scrollHelper, imageLoader, require, browser, appHost) {
|
||||
'use strict';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import loading from 'loading';
|
||||
import dom from 'dom';
|
||||
import layoutManager from 'layoutManager';
|
||||
import focusManager from 'focusManager';
|
||||
import globalize from 'globalize';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import imageLoader from 'imageLoader';
|
||||
import browser from 'browser';
|
||||
import appHost from 'apphost';
|
||||
import 'cardStyle';
|
||||
import 'formDialogStyle';
|
||||
import 'emby-button';
|
||||
import 'paper-icon-button-light';
|
||||
import 'css!./imageeditor';
|
||||
|
||||
var enableFocusTransform = !browser.slow && !browser.edge;
|
||||
/* eslint-disable indent */
|
||||
|
||||
var currentItem;
|
||||
var hasChanges = false;
|
||||
const enableFocusTransform = !browser.slow && !browser.edge;
|
||||
|
||||
let currentItem;
|
||||
let hasChanges = false;
|
||||
|
||||
function getBaseRemoteOptions() {
|
||||
|
||||
var options = {};
|
||||
const options = {};
|
||||
|
||||
options.itemId = currentItem.Id;
|
||||
|
||||
@@ -16,17 +30,15 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function reload(page, item, focusContext) {
|
||||
|
||||
loading.show();
|
||||
|
||||
var apiClient;
|
||||
let apiClient;
|
||||
|
||||
if (item) {
|
||||
apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
reloadItem(page, item, apiClient, focusContext);
|
||||
} else {
|
||||
|
||||
apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
apiClient = window.connectionManager.getApiClient(currentItem.ServerId);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), currentItem.Id).then(function (item) {
|
||||
reloadItem(page, item, apiClient, focusContext);
|
||||
});
|
||||
@@ -34,9 +46,8 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function addListeners(container, className, eventName, fn) {
|
||||
|
||||
container.addEventListener(eventName, function (e) {
|
||||
var elem = dom.parentWithClass(e.target, className);
|
||||
const elem = dom.parentWithClass(e.target, className);
|
||||
if (elem) {
|
||||
fn.call(elem, e);
|
||||
}
|
||||
@@ -44,14 +55,11 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function reloadItem(page, item, apiClient, focusContext) {
|
||||
|
||||
currentItem = item;
|
||||
|
||||
apiClient.getRemoteImageProviders(getBaseRemoteOptions()).then(function (providers) {
|
||||
|
||||
var btnBrowseAllImages = page.querySelectorAll('.btnBrowseAllImages');
|
||||
for (var i = 0, length = btnBrowseAllImages.length; i < length; i++) {
|
||||
|
||||
if (providers.length) {
|
||||
btnBrowseAllImages[i].classList.remove('hide');
|
||||
} else {
|
||||
@@ -60,7 +68,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
apiClient.getItemImageInfos(currentItem.Id).then(function (imageInfos) {
|
||||
|
||||
renderStandardImages(page, apiClient, item, imageInfos, providers);
|
||||
renderBackdrops(page, apiClient, item, imageInfos, providers);
|
||||
renderScreenshots(page, apiClient, item, imageInfos, providers);
|
||||
@@ -74,7 +81,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function getImageUrl(item, apiClient, type, index, options) {
|
||||
|
||||
options = options || {};
|
||||
options.type = type;
|
||||
options.index = index;
|
||||
@@ -94,13 +100,12 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function getCardHtml(image, index, numImages, apiClient, imageProviders, imageSize, tagName, enableFooterButtons) {
|
||||
|
||||
// TODO move card creation code to Card component
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
var cssClass = 'card scalableCard imageEditorCard';
|
||||
var cardBoxCssClass = 'cardBox visualCardBox';
|
||||
let cssClass = 'card scalableCard imageEditorCard';
|
||||
const cardBoxCssClass = 'cardBox visualCardBox';
|
||||
|
||||
cssClass += ' backdropCard backdropCard-scalable';
|
||||
|
||||
@@ -130,7 +135,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
|
||||
html += '<div class="cardContent">';
|
||||
|
||||
var imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: imageSize });
|
||||
const imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: imageSize });
|
||||
|
||||
html += '<div class="cardImageContainer" style="background-image:url(\'' + imageUrl + '\');background-position:center center;background-size:contain;"></div>';
|
||||
|
||||
@@ -153,7 +158,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
html += '<div class="cardText cardTextCentered">';
|
||||
|
||||
if (image.ImageType === 'Backdrop' || image.ImageType === 'Screenshot') {
|
||||
|
||||
if (index > 0) {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex - 1) + '" title="' + globalize.translate('MoveLeft') + '"><span class="material-icons chevron_left"></span></button>';
|
||||
} else {
|
||||
@@ -183,13 +187,10 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function deleteImage(context, itemId, type, index, apiClient, enableConfirmation) {
|
||||
|
||||
var afterConfirm = function () {
|
||||
const afterConfirm = function () {
|
||||
apiClient.deleteItemImage(itemId, type, index).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
reload(context);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
@@ -198,9 +199,8 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
return;
|
||||
}
|
||||
|
||||
require(['confirm'], function (confirm) {
|
||||
|
||||
confirm.default({
|
||||
import('confirm').then(({default: confirm}) => {
|
||||
confirm({
|
||||
|
||||
text: globalize.translate('ConfirmDeleteImage'),
|
||||
confirmText: globalize.translate('Delete'),
|
||||
@@ -211,36 +211,30 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function moveImage(context, apiClient, itemId, type, index, newIndex, focusContext) {
|
||||
|
||||
apiClient.updateItemImageIndex(itemId, type, index, newIndex).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
reload(context, null, focusContext);
|
||||
}, function () {
|
||||
|
||||
require(['alert'], function (alert) {
|
||||
alert(globalize.translate('DefaultErrorMessage'));
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert(globalize.translate('ErrorDefault'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderImages(page, item, apiClient, images, imageProviders, elem) {
|
||||
let html = '';
|
||||
|
||||
var html = '';
|
||||
|
||||
var imageSize = 300;
|
||||
var windowSize = dom.getWindowSize();
|
||||
let imageSize = 300;
|
||||
const windowSize = dom.getWindowSize();
|
||||
if (windowSize.innerWidth >= 1280) {
|
||||
imageSize = Math.round(windowSize.innerWidth / 4);
|
||||
}
|
||||
|
||||
var tagName = layoutManager.tv ? 'button' : 'div';
|
||||
var enableFooterButtons = !layoutManager.tv;
|
||||
|
||||
for (var i = 0, length = images.length; i < length; i++) {
|
||||
|
||||
var image = images[i];
|
||||
const tagName = layoutManager.tv ? 'button' : 'div';
|
||||
const enableFooterButtons = !layoutManager.tv;
|
||||
|
||||
for (let i = 0, length = images.length; i < length; i++) {
|
||||
const image = images[i];
|
||||
html += getCardHtml(image, i, length, apiClient, imageProviders, imageSize, tagName, enableFooterButtons);
|
||||
}
|
||||
|
||||
@@ -249,8 +243,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function renderStandardImages(page, apiClient, item, imageInfos, imageProviders) {
|
||||
|
||||
var images = imageInfos.filter(function (i) {
|
||||
const images = imageInfos.filter(function (i) {
|
||||
return i.ImageType !== 'Screenshot' && i.ImageType !== 'Backdrop' && i.ImageType !== 'Chapter';
|
||||
});
|
||||
|
||||
@@ -258,10 +251,8 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function renderBackdrops(page, apiClient, item, imageInfos, imageProviders) {
|
||||
|
||||
var images = imageInfos.filter(function (i) {
|
||||
const images = imageInfos.filter(function (i) {
|
||||
return i.ImageType === 'Backdrop';
|
||||
|
||||
}).sort(function (a, b) {
|
||||
return a.ImageIndex - b.ImageIndex;
|
||||
});
|
||||
@@ -275,10 +266,8 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function renderScreenshots(page, apiClient, item, imageInfos, imageProviders) {
|
||||
|
||||
var images = imageInfos.filter(function (i) {
|
||||
const images = imageInfos.filter(function (i) {
|
||||
return i.ImageType === 'Screenshot';
|
||||
|
||||
}).sort(function (a, b) {
|
||||
return a.ImageIndex - b.ImageIndex;
|
||||
});
|
||||
@@ -292,32 +281,26 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function showImageDownloader(page, imageType) {
|
||||
|
||||
require(['imageDownloader'], function (ImageDownloader) {
|
||||
|
||||
import('imageDownloader').then(({default: ImageDownloader}) => {
|
||||
ImageDownloader.show(currentItem.Id, currentItem.ServerId, currentItem.Type, imageType).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
reload(page);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function showActionSheet(context, imageCard) {
|
||||
const itemId = imageCard.getAttribute('data-id');
|
||||
const serverId = imageCard.getAttribute('data-serverid');
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
var itemId = imageCard.getAttribute('data-id');
|
||||
var serverId = imageCard.getAttribute('data-serverid');
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
const type = imageCard.getAttribute('data-imagetype');
|
||||
const index = parseInt(imageCard.getAttribute('data-index'));
|
||||
const providerCount = parseInt(imageCard.getAttribute('data-providers'));
|
||||
const numImages = parseInt(imageCard.getAttribute('data-numimages'));
|
||||
|
||||
var type = imageCard.getAttribute('data-imagetype');
|
||||
var index = parseInt(imageCard.getAttribute('data-index'));
|
||||
var providerCount = parseInt(imageCard.getAttribute('data-providers'));
|
||||
var numImages = parseInt(imageCard.getAttribute('data-numimages'));
|
||||
|
||||
require(['actionsheet'], function (actionSheet) {
|
||||
|
||||
var commands = [];
|
||||
import('actionsheet').then(({default: actionSheet}) => {
|
||||
const commands = [];
|
||||
|
||||
commands.push({
|
||||
name: globalize.translate('Delete'),
|
||||
@@ -353,9 +336,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
positionTo: imageCard
|
||||
|
||||
}).then(function (id) {
|
||||
|
||||
switch (id) {
|
||||
|
||||
case 'delete':
|
||||
deleteImage(context, itemId, type, index, apiClient, false);
|
||||
break;
|
||||
@@ -371,16 +352,14 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initEditor(context, options) {
|
||||
|
||||
var uploadButtons = context.querySelectorAll('.btnOpenUploadMenu');
|
||||
var isFileInputSupported = appHost.supports('fileinput');
|
||||
for (var i = 0, length = uploadButtons.length; i < length; i++) {
|
||||
const uploadButtons = context.querySelectorAll('.btnOpenUploadMenu');
|
||||
const isFileInputSupported = appHost.supports('fileinput');
|
||||
for (let i = 0, length = uploadButtons.length; i < length; i++) {
|
||||
if (isFileInputSupported) {
|
||||
uploadButtons[i].classList.remove('hide');
|
||||
} else {
|
||||
@@ -389,10 +368,9 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
addListeners(context, 'btnOpenUploadMenu', 'click', function () {
|
||||
var imageType = this.getAttribute('data-imagetype');
|
||||
|
||||
require(['imageUploader'], function (imageUploader) {
|
||||
const imageType = this.getAttribute('data-imagetype');
|
||||
|
||||
import('imageUploader').then(({default: imageUploader}) => {
|
||||
imageUploader.show({
|
||||
|
||||
theme: options.theme,
|
||||
@@ -401,7 +379,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
serverId: currentItem.ServerId
|
||||
|
||||
}).then(function (hasChanged) {
|
||||
|
||||
if (hasChanged) {
|
||||
hasChanges = true;
|
||||
reload(context);
|
||||
@@ -423,34 +400,32 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
});
|
||||
|
||||
addListeners(context, 'btnDeleteImage', 'click', function () {
|
||||
var type = this.getAttribute('data-imagetype');
|
||||
var index = this.getAttribute('data-index');
|
||||
const type = this.getAttribute('data-imagetype');
|
||||
let index = this.getAttribute('data-index');
|
||||
index = index === 'null' ? null : parseInt(index);
|
||||
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(currentItem.ServerId);
|
||||
deleteImage(context, currentItem.Id, type, index, apiClient, true);
|
||||
});
|
||||
|
||||
addListeners(context, 'btnMoveImage', 'click', function () {
|
||||
var type = this.getAttribute('data-imagetype');
|
||||
var index = this.getAttribute('data-index');
|
||||
var newIndex = this.getAttribute('data-newindex');
|
||||
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
const type = this.getAttribute('data-imagetype');
|
||||
const index = this.getAttribute('data-index');
|
||||
const newIndex = this.getAttribute('data-newindex');
|
||||
const apiClient = window.connectionManager.getApiClient(currentItem.ServerId);
|
||||
moveImage(context, apiClient, currentItem.Id, type, index, newIndex, dom.parentWithClass(this, 'itemsContainer'));
|
||||
});
|
||||
}
|
||||
|
||||
function showEditor(options, resolve, reject) {
|
||||
|
||||
var itemId = options.itemId;
|
||||
var serverId = options.serverId;
|
||||
const itemId = options.itemId;
|
||||
const serverId = options.serverId;
|
||||
|
||||
loading.show();
|
||||
|
||||
require(['text!./imageeditor.template.html'], function (template) {
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
import('text!./imageeditor.template.html').then(({default: template}) => {
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
|
||||
|
||||
var dialogOptions = {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true
|
||||
};
|
||||
|
||||
@@ -460,7 +435,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
@@ -474,7 +449,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
|
||||
// Has to be assigned a z-index after the call to .open()
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg, false);
|
||||
}
|
||||
@@ -493,22 +467,21 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
reload(dlg, item);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: function (options) {
|
||||
export function show (options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
hasChanges = false;
|
||||
showEditor(options, resolve, reject);
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
export default {
|
||||
show
|
||||
};
|
||||
|
||||
hasChanges = false;
|
||||
|
||||
showEditor(options, resolve, reject);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -17,8 +17,8 @@ import 'css!./style';
|
||||
// Although the default values recommended by Blurhash developers is 32x32, a size of 18x18 seems to be the sweet spot for us,
|
||||
// improving the performance and reducing the memory usage, while retaining almost full blur quality.
|
||||
// Lower values had more visible pixelation
|
||||
let width = 18;
|
||||
let height = 18;
|
||||
const width = 18;
|
||||
const height = 18;
|
||||
let pixels;
|
||||
try {
|
||||
pixels = blurhash.decode(blurhashstr, width, height);
|
||||
@@ -27,11 +27,11 @@ import 'css!./style';
|
||||
target.classList.add('non-blurhashable');
|
||||
return;
|
||||
}
|
||||
let canvas = document.createElement('canvas');
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
let ctx = canvas.getContext('2d');
|
||||
let imgData = ctx.createImageData(width, height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
const imgData = ctx.createImageData(width, height);
|
||||
|
||||
imgData.data.set(pixels);
|
||||
ctx.putImageData(imgData, 0, 0);
|
||||
@@ -55,7 +55,7 @@ import 'css!./style';
|
||||
if (!entry) {
|
||||
throw new Error('entry cannot be null');
|
||||
}
|
||||
let target = entry.target;
|
||||
const target = entry.target;
|
||||
var source = undefined;
|
||||
|
||||
if (target) {
|
||||
@@ -78,7 +78,7 @@ import 'css!./style';
|
||||
throw new TypeError('url cannot be undefined');
|
||||
}
|
||||
|
||||
let preloaderImg = new Image();
|
||||
const preloaderImg = new Image();
|
||||
preloaderImg.src = url;
|
||||
|
||||
elem.classList.add('lazy-hidden');
|
||||
@@ -87,6 +87,9 @@ import 'css!./style';
|
||||
requestAnimationFrame(() => {
|
||||
if (elem.tagName !== 'IMG') {
|
||||
elem.style.backgroundImage = "url('" + url + "')";
|
||||
if (elem.classList.contains('blurhashed')) {
|
||||
elem.style.backgroundColor = '#fff';
|
||||
}
|
||||
} else {
|
||||
elem.setAttribute('src', url);
|
||||
}
|
||||
@@ -108,6 +111,7 @@ import 'css!./style';
|
||||
if (elem.tagName !== 'IMG') {
|
||||
url = elem.style.backgroundImage.slice(4, -1).replace(/"/g, '');
|
||||
elem.style.backgroundImage = 'none';
|
||||
elem.style.backgroundColor = null;
|
||||
} else {
|
||||
url = elem.getAttribute('src');
|
||||
elem.setAttribute('src', '');
|
||||
@@ -133,11 +137,9 @@ import 'css!./style';
|
||||
}
|
||||
|
||||
export function getPrimaryImageAspectRatio(items) {
|
||||
|
||||
var values = [];
|
||||
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
var ratio = items[i].PrimaryImageAspectRatio || 0;
|
||||
|
||||
if (!ratio) {
|
||||
@@ -193,7 +195,6 @@ import 'css!./style';
|
||||
}
|
||||
|
||||
export function fillImages(elems) {
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
var elem = elems[0];
|
||||
fillImage(elem);
|
||||
@@ -208,7 +209,7 @@ import 'css!./style';
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
serLazyImage: setLazyImage,
|
||||
setLazyImage: setLazyImage,
|
||||
fillImages: fillImages,
|
||||
fillImage: fillImage,
|
||||
lazyImage: lazyImage,
|
||||
|
||||
@@ -82,7 +82,7 @@ export function enablePlayedIndicator(item) {
|
||||
|
||||
export function getPlayedIndicatorHtml(item) {
|
||||
if (enablePlayedIndicator(item)) {
|
||||
let userData = item.UserData || {};
|
||||
const userData = item.UserData || {};
|
||||
if (userData.UnplayedItemCount) {
|
||||
return '<div class="countIndicator indicator">' + userData.UnplayedItemCount + '</div>';
|
||||
}
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
import appHost from 'apphost';
|
||||
import globalize from 'globalize';
|
||||
import connectionManager from 'connectionManager';
|
||||
import itemHelper from 'itemHelper';
|
||||
import appRouter from 'appRouter';
|
||||
import playbackManager from 'playbackManager';
|
||||
import loading from 'loading';
|
||||
import appSettings from 'appSettings';
|
||||
import browser from 'browser';
|
||||
import actionsheet from 'actionsheet';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
export function getCommands(options) {
|
||||
const item = options.item;
|
||||
const user = options.user;
|
||||
@@ -18,7 +14,7 @@ import actionsheet from 'actionsheet';
|
||||
const canPlay = playbackManager.canPlay(item);
|
||||
const restrictOptions = (browser.operaTv || browser.web0s) && !user.Policy.IsAdministrator;
|
||||
|
||||
let commands = [];
|
||||
const commands = [];
|
||||
|
||||
if (canPlay && item.MediaType !== 'Photo') {
|
||||
if (options.play !== false) {
|
||||
@@ -144,7 +140,6 @@ import actionsheet from 'actionsheet';
|
||||
}
|
||||
|
||||
if (item.CanDelete && options.deleteItem !== false) {
|
||||
|
||||
if (item.Type === 'Playlist' || item.Type === 'BoxSet') {
|
||||
commands.push({
|
||||
name: globalize.translate('Delete'),
|
||||
@@ -334,7 +329,7 @@ import actionsheet from 'actionsheet';
|
||||
function executeCommand(item, id, options) {
|
||||
const itemId = item.Id;
|
||||
const serverId = item.ServerId;
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
switch (id) {
|
||||
@@ -355,7 +350,7 @@ import actionsheet from 'actionsheet';
|
||||
});
|
||||
break;
|
||||
case 'download':
|
||||
import('fileDownloader').then(({default: fileDownloader}) => {
|
||||
import('fileDownloader').then((fileDownloader) => {
|
||||
const downloadHref = apiClient.getItemDownloadUrl(itemId);
|
||||
fileDownloader.download([{
|
||||
url: downloadHref,
|
||||
@@ -370,7 +365,7 @@ import actionsheet from 'actionsheet';
|
||||
case 'copy-stream': {
|
||||
const downloadHref = apiClient.getItemDownloadUrl(itemId);
|
||||
const textAreaCopy = function () {
|
||||
let textArea = document.createElement('textarea');
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = downloadHref;
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
|
||||
+311
-324
@@ -1,363 +1,350 @@
|
||||
define(['apphost', 'globalize'], function (appHost, globalize) {
|
||||
'use strict';
|
||||
import appHost from 'apphost';
|
||||
import globalize from 'globalize';
|
||||
|
||||
function getDisplayName(item, options = {}) {
|
||||
export function getDisplayName(item, options = {}) {
|
||||
if (!item) {
|
||||
throw new Error('null item passed into getDisplayName');
|
||||
}
|
||||
|
||||
if (!item) {
|
||||
throw new Error('null item passed into getDisplayName');
|
||||
if (item.Type === 'Timer') {
|
||||
item = item.ProgramInfo || item;
|
||||
}
|
||||
|
||||
let name = ((item.Type === 'Program' || item.Type === 'Recording') && (item.IsSeries || item.EpisodeTitle) ? item.EpisodeTitle : item.Name) || '';
|
||||
|
||||
if (item.Type === 'TvChannel') {
|
||||
if (item.ChannelNumber) {
|
||||
return item.ChannelNumber + ' ' + name;
|
||||
}
|
||||
|
||||
if (item.Type === 'Timer') {
|
||||
item = item.ProgramInfo || item;
|
||||
}
|
||||
|
||||
var name = ((item.Type === 'Program' || item.Type === 'Recording') && (item.IsSeries || item.EpisodeTitle) ? item.EpisodeTitle : item.Name) || '';
|
||||
|
||||
if (item.Type === 'TvChannel') {
|
||||
if (item.ChannelNumber) {
|
||||
return item.ChannelNumber + ' ' + name;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
if (item.Type === 'Episode' && item.ParentIndexNumber === 0) {
|
||||
name = globalize.translate('ValueSpecialEpisodeName', name);
|
||||
} else if ((item.Type === 'Episode' || item.Type === 'Program') && item.IndexNumber != null && item.ParentIndexNumber != null && options.includeIndexNumber !== false) {
|
||||
|
||||
var displayIndexNumber = item.IndexNumber;
|
||||
|
||||
var number = displayIndexNumber;
|
||||
var nameSeparator = ' - ';
|
||||
|
||||
if (options.includeParentInfo !== false) {
|
||||
number = 'S' + item.ParentIndexNumber + ':E' + number;
|
||||
} else {
|
||||
nameSeparator = '. ';
|
||||
}
|
||||
|
||||
if (item.IndexNumberEnd) {
|
||||
|
||||
displayIndexNumber = item.IndexNumberEnd;
|
||||
number += '-' + displayIndexNumber;
|
||||
}
|
||||
|
||||
if (number) {
|
||||
name = name ? (number + nameSeparator + name) : number;
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
if (item.Type === 'Episode' && item.ParentIndexNumber === 0) {
|
||||
name = globalize.translate('ValueSpecialEpisodeName', name);
|
||||
} else if ((item.Type === 'Episode' || item.Type === 'Program') && item.IndexNumber != null && item.ParentIndexNumber != null && options.includeIndexNumber !== false) {
|
||||
let displayIndexNumber = item.IndexNumber;
|
||||
|
||||
function supportsAddingToCollection(item) {
|
||||
let number = displayIndexNumber;
|
||||
let nameSeparator = ' - ';
|
||||
|
||||
var invalidTypes = ['Genre', 'MusicGenre', 'Studio', 'UserView', 'CollectionFolder', 'Audio', 'Program', 'Timer', 'SeriesTimer'];
|
||||
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
if (options.includeParentInfo !== false) {
|
||||
number = 'S' + item.ParentIndexNumber + ':E' + number;
|
||||
} else {
|
||||
nameSeparator = '. ';
|
||||
}
|
||||
|
||||
return !item.CollectionType && invalidTypes.indexOf(item.Type) === -1 && item.MediaType !== 'Photo' && !isLocalItem(item);
|
||||
if (item.IndexNumberEnd) {
|
||||
displayIndexNumber = item.IndexNumberEnd;
|
||||
number += '-' + displayIndexNumber;
|
||||
}
|
||||
|
||||
if (number) {
|
||||
name = name ? (number + nameSeparator + name) : number;
|
||||
}
|
||||
}
|
||||
|
||||
function supportsAddingToPlaylist(item) {
|
||||
return name;
|
||||
}
|
||||
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'TvChannel') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'Timer') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
if (item.MediaType === 'Photo') {
|
||||
return false;
|
||||
}
|
||||
export function supportsAddingToCollection(item) {
|
||||
const invalidTypes = ['Genre', 'MusicGenre', 'Studio', 'UserView', 'CollectionFolder', 'Audio', 'Program', 'Timer', 'SeriesTimer'];
|
||||
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLocalItem(item)) {
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
if (item.CollectionType === 'livetv') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return item.MediaType || item.IsFolder || item.Type === 'Genre' || item.Type === 'MusicGenre' || item.Type === 'MusicArtist';
|
||||
}
|
||||
|
||||
function canEdit(user, item) {
|
||||
return !item.CollectionType && invalidTypes.indexOf(item.Type) === -1 && item.MediaType !== 'Photo' && !isLocalItem(item);
|
||||
}
|
||||
|
||||
var itemType = item.Type;
|
||||
|
||||
if (itemType === 'UserRootFolder' || itemType === 'UserView') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'Program') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'Timer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return user.Policy.IsAdministrator;
|
||||
export function supportsAddingToPlaylist(item) {
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'TvChannel') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'Timer') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
if (item.MediaType === 'Photo') {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isLocalItem(item) {
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (item && item.Id && item.Id.indexOf('local') === 0) {
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
if (item.CollectionType === 'livetv') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return item.MediaType || item.IsFolder || item.Type === 'Genre' || item.Type === 'MusicGenre' || item.Type === 'MusicArtist';
|
||||
}
|
||||
|
||||
export function canEdit(user, item) {
|
||||
const itemType = item.Type;
|
||||
|
||||
if (itemType === 'UserRootFolder' || itemType === 'UserView') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'Program') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'Timer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return user.Policy.IsAdministrator;
|
||||
}
|
||||
|
||||
export function isLocalItem(item) {
|
||||
if (item && item.Id && item.Id.indexOf('local') === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function canIdentify (user, item) {
|
||||
const itemType = item.Type;
|
||||
|
||||
if (itemType === 'Movie' ||
|
||||
itemType === 'Trailer' ||
|
||||
itemType === 'Series' ||
|
||||
itemType === 'BoxSet' ||
|
||||
itemType === 'Person' ||
|
||||
itemType === 'Book' ||
|
||||
itemType === 'MusicAlbum' ||
|
||||
itemType === 'MusicArtist' ||
|
||||
itemType === 'MusicVideo') {
|
||||
if (user.Policy.IsAdministrator) {
|
||||
if (!isLocalItem(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function canEditImages (user, item) {
|
||||
const itemType = item.Type;
|
||||
|
||||
if (item.MediaType === 'Photo') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'UserView') {
|
||||
if (user.Policy.IsAdministrator) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return {
|
||||
getDisplayName: getDisplayName,
|
||||
supportsAddingToCollection: supportsAddingToCollection,
|
||||
supportsAddingToPlaylist: supportsAddingToPlaylist,
|
||||
isLocalItem: isLocalItem,
|
||||
|
||||
canIdentify: function (user, item) {
|
||||
|
||||
var itemType = item.Type;
|
||||
|
||||
if (itemType === 'Movie' ||
|
||||
itemType === 'Trailer' ||
|
||||
itemType === 'Series' ||
|
||||
itemType === 'BoxSet' ||
|
||||
itemType === 'Person' ||
|
||||
itemType === 'Book' ||
|
||||
itemType === 'MusicAlbum' ||
|
||||
itemType === 'MusicArtist' ||
|
||||
itemType === 'MusicVideo') {
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
|
||||
if (!isLocalItem(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
canEdit: canEdit,
|
||||
return itemType !== 'Timer' && itemType !== 'SeriesTimer' && canEdit(user, item) && !isLocalItem(item);
|
||||
}
|
||||
|
||||
canEditImages: function (user, item) {
|
||||
export function canSync (user, item) {
|
||||
if (user && !user.Policy.EnableContentDownloading) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var itemType = item.Type;
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.MediaType === 'Photo') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'UserView') {
|
||||
if (user.Policy.IsAdministrator) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return itemType !== 'Timer' && itemType !== 'SeriesTimer' && canEdit(user, item) && !isLocalItem(item);
|
||||
},
|
||||
|
||||
canSync: function (user, item) {
|
||||
|
||||
if (user && !user.Policy.EnableContentDownloading) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return item.SupportsSync;
|
||||
},
|
||||
|
||||
canShare: function (item, user) {
|
||||
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'TvChannel') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'Timer') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
return user.Policy.EnablePublicSharing && appHost.supports('sharing');
|
||||
},
|
||||
|
||||
enableDateAddedDisplay: function (item) {
|
||||
return !item.IsFolder && item.MediaType && item.Type !== 'Program' && item.Type !== 'TvChannel' && item.Type !== 'Trailer';
|
||||
},
|
||||
|
||||
canMarkPlayed: function (item) {
|
||||
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.MediaType === 'Video') {
|
||||
if (item.Type !== 'TvChannel') {
|
||||
return true;
|
||||
}
|
||||
} else if (item.MediaType === 'Audio') {
|
||||
if (item.Type === 'AudioPodcast') {
|
||||
return true;
|
||||
}
|
||||
if (item.Type === 'AudioBook') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Type === 'Series' ||
|
||||
item.Type === 'Season' ||
|
||||
item.Type === 'BoxSet' ||
|
||||
item.MediaType === 'Book' ||
|
||||
item.MediaType === 'Recording') {
|
||||
return true;
|
||||
}
|
||||
return item.SupportsSync;
|
||||
}
|
||||
|
||||
export function canShare (item, user) {
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'TvChannel') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'Timer') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
},
|
||||
}
|
||||
}
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
return user.Policy.EnablePublicSharing && appHost.supports('sharing');
|
||||
}
|
||||
|
||||
canRate: function (item) {
|
||||
export function enableDateAddedDisplay (item) {
|
||||
return !item.IsFolder && item.MediaType && item.Type !== 'Program' && item.Type !== 'TvChannel' && item.Type !== 'Trailer';
|
||||
}
|
||||
|
||||
if (item.Type === 'Program'
|
||||
|| item.Type === 'Timer'
|
||||
|| item.Type === 'SeriesTimer'
|
||||
|| item.Type === 'CollectionFolder'
|
||||
|| item.Type === 'UserView'
|
||||
|| item.Type === 'Channel'
|
||||
|| !item.UserData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
canConvert: function (item, user) {
|
||||
|
||||
if (!user.Policy.EnableMediaConversion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var mediaType = item.MediaType;
|
||||
if (mediaType === 'Book' || mediaType === 'Photo' || mediaType === 'Audio') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var collectionType = item.CollectionType;
|
||||
if (collectionType === 'livetv') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var type = item.Type;
|
||||
if (type === 'Channel' || type === 'Person' || type === 'Year' || type === 'Program' || type === 'Timer' || type === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.LocationType === 'Virtual' && !item.IsFolder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.IsPlaceHolder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
canRefreshMetadata: function (item, user) {
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
|
||||
var collectionType = item.CollectionType;
|
||||
if (collectionType === 'livetv') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.Type !== 'Timer' && item.Type !== 'SeriesTimer' && item.Type !== 'Program' && item.Type !== 'TvChannel' && !(item.Type === 'Recording' && item.Status !== 'Completed')) {
|
||||
|
||||
if (!isLocalItem(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
supportsMediaSourceSelection: function (item) {
|
||||
|
||||
if (item.MediaType !== 'Video') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'TvChannel') {
|
||||
return false;
|
||||
}
|
||||
if (!item.MediaSources || (item.MediaSources.length === 1 && item.MediaSources[0].Type === 'Placeholder')) {
|
||||
return false;
|
||||
}
|
||||
if (item.EnableMediaSourceDisplay === false) {
|
||||
return false;
|
||||
}
|
||||
if (item.EnableMediaSourceDisplay == null && item.SourceType && item.SourceType !== 'Library') {
|
||||
return false;
|
||||
}
|
||||
export function canMarkPlayed (item) {
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.MediaType === 'Video') {
|
||||
if (item.Type !== 'TvChannel') {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
});
|
||||
} else if (item.MediaType === 'Audio') {
|
||||
if (item.Type === 'AudioPodcast') {
|
||||
return true;
|
||||
}
|
||||
if (item.Type === 'AudioBook') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Type === 'Series' ||
|
||||
item.Type === 'Season' ||
|
||||
item.Type === 'BoxSet' ||
|
||||
item.MediaType === 'Book' ||
|
||||
item.MediaType === 'Recording') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function canRate (item) {
|
||||
if (item.Type === 'Program'
|
||||
|| item.Type === 'Timer'
|
||||
|| item.Type === 'SeriesTimer'
|
||||
|| item.Type === 'CollectionFolder'
|
||||
|| item.Type === 'UserView'
|
||||
|| item.Type === 'Channel'
|
||||
|| !item.UserData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function canConvert (item, user) {
|
||||
if (!user.Policy.EnableMediaConversion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const mediaType = item.MediaType;
|
||||
if (mediaType === 'Book' || mediaType === 'Photo' || mediaType === 'Audio') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const collectionType = item.CollectionType;
|
||||
if (collectionType === 'livetv') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const type = item.Type;
|
||||
if (type === 'Channel' || type === 'Person' || type === 'Year' || type === 'Program' || type === 'Timer' || type === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.LocationType === 'Virtual' && !item.IsFolder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.IsPlaceHolder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function canRefreshMetadata (item, user) {
|
||||
if (user.Policy.IsAdministrator) {
|
||||
const collectionType = item.CollectionType;
|
||||
if (collectionType === 'livetv') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.Type !== 'Timer' && item.Type !== 'SeriesTimer' && item.Type !== 'Program' && item.Type !== 'TvChannel' && !(item.Type === 'Recording' && item.Status !== 'Completed')) {
|
||||
if (!isLocalItem(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function supportsMediaSourceSelection (item) {
|
||||
if (item.MediaType !== 'Video') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'TvChannel') {
|
||||
return false;
|
||||
}
|
||||
if (!item.MediaSources || (item.MediaSources.length === 1 && item.MediaSources[0].Type === 'Placeholder')) {
|
||||
return false;
|
||||
}
|
||||
if (item.EnableMediaSourceDisplay === false) {
|
||||
return false;
|
||||
}
|
||||
if (item.EnableMediaSourceDisplay == null && item.SourceType && item.SourceType !== 'Library') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export default {
|
||||
getDisplayName: getDisplayName,
|
||||
supportsAddingToCollection: supportsAddingToCollection,
|
||||
supportsAddingToPlaylist: supportsAddingToPlaylist,
|
||||
isLocalItem: isLocalItem,
|
||||
canIdentify: canIdentify,
|
||||
canEdit: canEdit,
|
||||
canEditImages: canEditImages,
|
||||
canSync: canSync,
|
||||
canShare: canShare,
|
||||
enableDateAddedDisplay: enableDateAddedDisplay,
|
||||
canMarkPlayed: canMarkPlayed,
|
||||
canRate: canRate,
|
||||
canConvert: canConvert,
|
||||
canRefreshMetadata: canRefreshMetadata,
|
||||
supportsMediaSourceSelection: supportsMediaSourceSelection
|
||||
};
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import connectionManager from 'connectionManager';
|
||||
import loading from 'loading';
|
||||
import 'emby-select';
|
||||
import 'listViewStyle';
|
||||
@@ -52,8 +51,22 @@ import 'flexStyles';
|
||||
if (stream.Type === 'Data') {
|
||||
continue;
|
||||
}
|
||||
|
||||
html += '<div class="mediaInfoStream">';
|
||||
const displayType = globalize.translate(`MediaInfoStreamType${stream.Type}`);
|
||||
let translateString;
|
||||
switch (stream.Type) {
|
||||
case 'Audio':
|
||||
case 'Data':
|
||||
case 'Subtitle':
|
||||
case 'Video':
|
||||
translateString = stream.Type;
|
||||
break;
|
||||
case 'EmbeddedImage':
|
||||
translateString = 'Image';
|
||||
break;
|
||||
}
|
||||
|
||||
const displayType = globalize.translate(translateString);
|
||||
html += `<h2 class="mediaInfoStreamType">${displayType}</h2>`;
|
||||
const attributes = [];
|
||||
if (stream.DisplayTitle) {
|
||||
@@ -137,7 +150,7 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function loadMediaInfo(itemId, serverId, template) {
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(item => {
|
||||
const dialogOptions = {
|
||||
size: 'small',
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1">
|
||||
<span class="material-icons arrow_back"></span>
|
||||
</button>
|
||||
<h3 class="formDialogHeaderTitle">${HeaderMediaInfo}</h3>
|
||||
<h3 class="formDialogHeaderTitle">${MoreMediaInfo}</h3>
|
||||
</div>
|
||||
|
||||
<div class="formDialogContent smoothScrollY">
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import loading from 'loading';
|
||||
import connectionManager from 'connectionManager';
|
||||
import globalize from 'globalize';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import layoutManager from 'layoutManager';
|
||||
@@ -31,11 +30,10 @@ import 'cardStyle';
|
||||
let currentSearchResult;
|
||||
|
||||
function getApiClient() {
|
||||
return connectionManager.getApiClient(currentServerId);
|
||||
return window.connectionManager.getApiClient(currentServerId);
|
||||
}
|
||||
|
||||
function searchForIdentificationResults(page) {
|
||||
|
||||
let lookupInfo = {
|
||||
ProviderIds: {}
|
||||
};
|
||||
@@ -45,11 +43,9 @@ import 'cardStyle';
|
||||
const identifyField = page.querySelectorAll('.identifyField');
|
||||
let value;
|
||||
for (i = 0, length = identifyField.length; i < length; i++) {
|
||||
|
||||
value = identifyField[i].value;
|
||||
|
||||
if (value) {
|
||||
|
||||
if (identifyField[i].type === 'number') {
|
||||
value = parseInt(value);
|
||||
}
|
||||
@@ -62,7 +58,6 @@ import 'cardStyle';
|
||||
|
||||
const txtLookupId = page.querySelectorAll('.txtLookupId');
|
||||
for (i = 0, length = txtLookupId.length; i < length; i++) {
|
||||
|
||||
value = txtLookupId[i].value;
|
||||
|
||||
if (value) {
|
||||
@@ -100,14 +95,12 @@ import 'cardStyle';
|
||||
dataType: 'json'
|
||||
|
||||
}).then(results => {
|
||||
|
||||
loading.hide();
|
||||
showIdentificationSearchResults(page, results);
|
||||
});
|
||||
}
|
||||
|
||||
function showIdentificationSearchResults(page, results) {
|
||||
|
||||
const identificationSearchResults = page.querySelector('.identificationSearchResults');
|
||||
|
||||
page.querySelector('.popupIdentifyForm').classList.add('hide');
|
||||
@@ -119,7 +112,6 @@ import 'cardStyle';
|
||||
let i;
|
||||
let length;
|
||||
for (i = 0, length = results.length; i < length; i++) {
|
||||
|
||||
const result = results[i];
|
||||
html += getSearchResultHtml(result, i);
|
||||
}
|
||||
@@ -133,17 +125,14 @@ import 'cardStyle';
|
||||
const currentResult = results[index];
|
||||
|
||||
if (currentItem != null) {
|
||||
|
||||
showIdentifyOptions(page, currentResult);
|
||||
} else {
|
||||
|
||||
finishFindNewDialog(page, currentResult);
|
||||
}
|
||||
}
|
||||
|
||||
const searchImages = elem.querySelectorAll('.card');
|
||||
for (i = 0, length = searchImages.length; i < length; i++) {
|
||||
|
||||
searchImages[i].addEventListener('click', onSearchImageClick);
|
||||
}
|
||||
|
||||
@@ -161,7 +150,6 @@ import 'cardStyle';
|
||||
}
|
||||
|
||||
function showIdentifyOptions(page, identifyResult) {
|
||||
|
||||
const identifyOptionsForm = page.querySelector('.identifyOptionsForm');
|
||||
|
||||
page.querySelector('.popupIdentifyForm').classList.add('hide');
|
||||
@@ -193,7 +181,6 @@ import 'cardStyle';
|
||||
}
|
||||
|
||||
function getSearchResultHtml(result, index) {
|
||||
|
||||
// TODO move card creation code to Card component
|
||||
|
||||
let html = '';
|
||||
@@ -234,7 +221,6 @@ import 'cardStyle';
|
||||
|
||||
html += `<div class="cardImageContainer coveredImage" style="background-image:url('${displayUrl}');"></div>`;
|
||||
} else {
|
||||
|
||||
html += `<div class="cardImageContainer coveredImage defaultCardBackground defaultCardBackground1"><div class="cardText cardCenteredText">${result.Name}</div></div>`;
|
||||
}
|
||||
html += '</div>';
|
||||
@@ -257,7 +243,6 @@ import 'cardStyle';
|
||||
}
|
||||
|
||||
for (let i = 0; i < numLines; i++) {
|
||||
|
||||
if (i === 0) {
|
||||
html += '<div class="cardText cardText-first cardTextCentered">';
|
||||
} else {
|
||||
@@ -279,7 +264,6 @@ import 'cardStyle';
|
||||
}
|
||||
|
||||
function submitIdentficationResult(page) {
|
||||
|
||||
loading.show();
|
||||
|
||||
const options = {
|
||||
@@ -295,14 +279,11 @@ import 'cardStyle';
|
||||
contentType: 'application/json'
|
||||
|
||||
}).then(() => {
|
||||
|
||||
hasChanges = true;
|
||||
loading.hide();
|
||||
|
||||
dialogHelper.close(page);
|
||||
|
||||
}, () => {
|
||||
|
||||
loading.hide();
|
||||
|
||||
dialogHelper.close(page);
|
||||
@@ -310,15 +291,12 @@ import 'cardStyle';
|
||||
}
|
||||
|
||||
function showIdentificationForm(page, item) {
|
||||
|
||||
const apiClient = getApiClient();
|
||||
|
||||
apiClient.getJSON(apiClient.getUrl(`Items/${item.Id}/ExternalIdInfos`)).then(idList => {
|
||||
|
||||
let html = '';
|
||||
|
||||
for (let i = 0, length = idList.length; i < length; i++) {
|
||||
|
||||
const idInfo = idList[i];
|
||||
|
||||
const id = `txtLookup${idInfo.Key}`;
|
||||
@@ -340,11 +318,9 @@ import 'cardStyle';
|
||||
page.querySelector('#txtLookupName').value = '';
|
||||
|
||||
if (item.Type === 'Person' || item.Type === 'BoxSet') {
|
||||
|
||||
page.querySelector('.fldLookupYear').classList.add('hide');
|
||||
page.querySelector('#txtLookupYear').value = '';
|
||||
} else {
|
||||
|
||||
page.querySelector('.fldLookupYear').classList.remove('hide');
|
||||
page.querySelector('#txtLookupYear').value = '';
|
||||
}
|
||||
@@ -356,15 +332,12 @@ import 'cardStyle';
|
||||
}
|
||||
|
||||
function showEditor(itemId) {
|
||||
|
||||
loading.show();
|
||||
|
||||
return import('text!./itemidentifier.template.html').then(({default: template}) => {
|
||||
|
||||
const apiClient = getApiClient();
|
||||
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(item => {
|
||||
|
||||
currentItem = item;
|
||||
currentItemType = currentItem.Type;
|
||||
|
||||
@@ -406,21 +379,18 @@ import 'cardStyle';
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
dlg.querySelector('.popupIdentifyForm').addEventListener('submit', e => {
|
||||
|
||||
e.preventDefault();
|
||||
searchForIdentificationResults(dlg);
|
||||
return false;
|
||||
});
|
||||
|
||||
dlg.querySelector('.identifyOptionsForm').addEventListener('submit', e => {
|
||||
|
||||
e.preventDefault();
|
||||
submitIdentficationResult(dlg);
|
||||
return false;
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
@@ -433,7 +403,6 @@ import 'cardStyle';
|
||||
}
|
||||
|
||||
function onDialogClosed() {
|
||||
|
||||
loading.hide();
|
||||
if (hasChanges) {
|
||||
currentResolve();
|
||||
@@ -444,12 +413,10 @@ import 'cardStyle';
|
||||
|
||||
// TODO investigate where this was used
|
||||
function showEditorFindNew(itemName, itemYear, itemType, resolveFunc) {
|
||||
|
||||
currentItem = null;
|
||||
currentItemType = itemType;
|
||||
|
||||
return import('text!./itemidentifier.template.html').then(({default: template}) => {
|
||||
|
||||
const dialogOptions = {
|
||||
size: 'small',
|
||||
removeOnClose: true,
|
||||
@@ -477,19 +444,16 @@ import 'cardStyle';
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
dlg.querySelector('.popupIdentifyForm').addEventListener('submit', e => {
|
||||
|
||||
e.preventDefault();
|
||||
searchForIdentificationResults(dlg);
|
||||
return false;
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', () => {
|
||||
|
||||
loading.hide();
|
||||
const foundItem = hasChanges ? currentSearchResult : null;
|
||||
|
||||
@@ -503,16 +467,12 @@ import 'cardStyle';
|
||||
}
|
||||
|
||||
function showIdentificationFormFindNew(dlg, itemName, itemYear, itemType) {
|
||||
|
||||
dlg.querySelector('#txtLookupName').value = itemName;
|
||||
|
||||
if (itemType === 'Person' || itemType === 'BoxSet') {
|
||||
|
||||
dlg.querySelector('.fldLookupYear').classList.add('hide');
|
||||
dlg.querySelector('#txtLookupYear').value = '';
|
||||
|
||||
} else {
|
||||
|
||||
dlg.querySelector('.fldLookupYear').classList.remove('hide');
|
||||
dlg.querySelector('#txtLookupYear').value = itemYear;
|
||||
}
|
||||
@@ -521,9 +481,7 @@ import 'cardStyle';
|
||||
}
|
||||
|
||||
export function show(itemId, serverId) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
currentResolve = resolve;
|
||||
currentReject = reject;
|
||||
currentServerId = serverId;
|
||||
@@ -534,9 +492,7 @@ import 'cardStyle';
|
||||
}
|
||||
|
||||
export function showFindNew(itemName, itemYear, itemType, serverId) {
|
||||
|
||||
return new Promise((resolve) => {
|
||||
|
||||
currentServerId = serverId;
|
||||
|
||||
hasChanges = false;
|
||||
|
||||
+156
-187
@@ -1,149 +1,130 @@
|
||||
define(['playbackManager', 'serverNotifications', 'events'], function (playbackManager, serverNotifications, events) {
|
||||
'use strict';
|
||||
import playbackManager from 'playbackManager';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import events from 'events';
|
||||
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
const instance = this;
|
||||
|
||||
var instance = this;
|
||||
|
||||
var eventsToMonitor = getEventsToMonitor(instance);
|
||||
|
||||
// TODO: Check user data change reason?
|
||||
if (eventsToMonitor.indexOf('markfavorite') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
} else if (eventsToMonitor.indexOf('markplayed') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
function getEventsToMonitor(instance) {
|
||||
|
||||
var options = instance.options;
|
||||
var monitor = options ? options.monitorEvents : null;
|
||||
if (monitor) {
|
||||
return monitor.split(',');
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function onTimerCreated(e, apiClient, data) {
|
||||
|
||||
var instance = this;
|
||||
|
||||
if (getEventsToMonitor(instance).indexOf('timers') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onSeriesTimerCreated(e, apiClient, data) {
|
||||
|
||||
var instance = this;
|
||||
if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onTimerCancelled(e, apiClient, data) {
|
||||
var instance = this;
|
||||
|
||||
if (getEventsToMonitor(instance).indexOf('timers') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onSeriesTimerCancelled(e, apiClient, data) {
|
||||
|
||||
var instance = this;
|
||||
if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onLibraryChanged(e, apiClient, data) {
|
||||
|
||||
var instance = this;
|
||||
var eventsToMonitor = getEventsToMonitor(instance);
|
||||
if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) {
|
||||
|
||||
// yes this is an assumption
|
||||
return;
|
||||
}
|
||||
|
||||
var itemsAdded = data.ItemsAdded || [];
|
||||
var itemsRemoved = data.ItemsRemoved || [];
|
||||
if (!itemsAdded.length && !itemsRemoved.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var options = instance.options || {};
|
||||
var parentId = options.parentId;
|
||||
if (parentId) {
|
||||
var foldersAddedTo = data.FoldersAddedTo || [];
|
||||
var foldersRemovedFrom = data.FoldersRemovedFrom || [];
|
||||
var collectionFolders = data.CollectionFolders || [];
|
||||
|
||||
if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const eventsToMonitor = getEventsToMonitor(instance);
|
||||
|
||||
// TODO: Check user data change reason?
|
||||
if (eventsToMonitor.indexOf('markfavorite') !== -1) {
|
||||
instance.notifyRefreshNeeded();
|
||||
} else if (eventsToMonitor.indexOf('markplayed') !== -1) {
|
||||
instance.notifyRefreshNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
function onPlaybackStopped(e, stopInfo) {
|
||||
function getEventsToMonitor(instance) {
|
||||
const options = instance.options;
|
||||
const monitor = options ? options.monitorEvents : null;
|
||||
if (monitor) {
|
||||
return monitor.split(',');
|
||||
}
|
||||
|
||||
var instance = this;
|
||||
return [];
|
||||
}
|
||||
|
||||
var state = stopInfo.state;
|
||||
function onTimerCreated(e, apiClient, data) {
|
||||
const instance = this;
|
||||
|
||||
var eventsToMonitor = getEventsToMonitor(instance);
|
||||
if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') {
|
||||
if (getEventsToMonitor(instance).indexOf('timers') !== -1) {
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (eventsToMonitor.indexOf('videoplayback') !== -1) {
|
||||
function onSeriesTimerCreated(e, apiClient, data) {
|
||||
const instance = this;
|
||||
if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) {
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
instance.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
} else if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Audio') {
|
||||
function onTimerCancelled(e, apiClient, data) {
|
||||
const instance = this;
|
||||
|
||||
if (eventsToMonitor.indexOf('audioplayback') !== -1) {
|
||||
if (getEventsToMonitor(instance).indexOf('timers') !== -1) {
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
instance.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
function onSeriesTimerCancelled(e, apiClient, data) {
|
||||
const instance = this;
|
||||
if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) {
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onLibraryChanged(e, apiClient, data) {
|
||||
const instance = this;
|
||||
const eventsToMonitor = getEventsToMonitor(instance);
|
||||
if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) {
|
||||
// yes this is an assumption
|
||||
return;
|
||||
}
|
||||
|
||||
const itemsAdded = data.ItemsAdded || [];
|
||||
const itemsRemoved = data.ItemsRemoved || [];
|
||||
if (!itemsAdded.length && !itemsRemoved.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const options = instance.options || {};
|
||||
const parentId = options.parentId;
|
||||
if (parentId) {
|
||||
const foldersAddedTo = data.FoldersAddedTo || [];
|
||||
const foldersRemovedFrom = data.FoldersRemovedFrom || [];
|
||||
const collectionFolders = data.CollectionFolders || [];
|
||||
|
||||
if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function addNotificationEvent(instance, name, handler, owner) {
|
||||
instance.notifyRefreshNeeded();
|
||||
}
|
||||
|
||||
var localHandler = handler.bind(instance);
|
||||
function onPlaybackStopped(e, stopInfo) {
|
||||
const instance = this;
|
||||
|
||||
const state = stopInfo.state;
|
||||
|
||||
const eventsToMonitor = getEventsToMonitor(instance);
|
||||
if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') {
|
||||
if (eventsToMonitor.indexOf('videoplayback') !== -1) {
|
||||
instance.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
} else if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Audio') {
|
||||
if (eventsToMonitor.indexOf('audioplayback') !== -1) {
|
||||
instance.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addNotificationEvent(instance, name, handler, owner) {
|
||||
const localHandler = handler.bind(instance);
|
||||
owner = owner || serverNotifications;
|
||||
events.on(owner, name, localHandler);
|
||||
instance['event_' + name] = localHandler;
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name, owner) {
|
||||
const handler = instance['event_' + name];
|
||||
if (handler) {
|
||||
owner = owner || serverNotifications;
|
||||
events.on(owner, name, localHandler);
|
||||
instance['event_' + name] = localHandler;
|
||||
events.off(owner, name, handler);
|
||||
instance['event_' + name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name, owner) {
|
||||
|
||||
var handler = instance['event_' + name];
|
||||
if (handler) {
|
||||
owner = owner || serverNotifications;
|
||||
events.off(owner, name, handler);
|
||||
instance['event_' + name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
function ItemsRefresher(options) {
|
||||
|
||||
class ItemsRefresher {
|
||||
constructor(options) {
|
||||
this.options = options || {};
|
||||
|
||||
addNotificationEvent(this, 'UserDataChanged', onUserDataChanged);
|
||||
@@ -155,25 +136,20 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||
addNotificationEvent(this, 'playbackstop', onPlaybackStopped, playbackManager);
|
||||
}
|
||||
|
||||
ItemsRefresher.prototype.pause = function () {
|
||||
|
||||
pause() {
|
||||
clearRefreshInterval(this, true);
|
||||
|
||||
this.paused = true;
|
||||
};
|
||||
|
||||
ItemsRefresher.prototype.resume = function (options) {
|
||||
}
|
||||
|
||||
resume(options) {
|
||||
this.paused = false;
|
||||
|
||||
var refreshIntervalEndTime = this.refreshIntervalEndTime;
|
||||
const refreshIntervalEndTime = this.refreshIntervalEndTime;
|
||||
if (refreshIntervalEndTime) {
|
||||
|
||||
var remainingMs = refreshIntervalEndTime - new Date().getTime();
|
||||
const remainingMs = refreshIntervalEndTime - new Date().getTime();
|
||||
if (remainingMs > 0 && !this.needsRefresh) {
|
||||
|
||||
resetRefreshInterval(this, remainingMs);
|
||||
|
||||
} else {
|
||||
this.needsRefresh = true;
|
||||
this.refreshIntervalEndTime = null;
|
||||
@@ -185,10 +161,9 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
ItemsRefresher.prototype.refreshItems = function () {
|
||||
}
|
||||
|
||||
refreshItems() {
|
||||
if (!this.fetchData) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
@@ -201,16 +176,15 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||
this.needsRefresh = false;
|
||||
|
||||
return this.fetchData().then(onDataFetched.bind(this));
|
||||
};
|
||||
|
||||
ItemsRefresher.prototype.notifyRefreshNeeded = function (isInForeground) {
|
||||
}
|
||||
|
||||
notifyRefreshNeeded(isInForeground) {
|
||||
if (this.paused) {
|
||||
this.needsRefresh = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var timeout = this.refreshTimeout;
|
||||
const timeout = this.refreshTimeout;
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
@@ -220,49 +194,9 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||
} else {
|
||||
this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 10000);
|
||||
}
|
||||
};
|
||||
|
||||
function clearRefreshInterval(instance, isPausing) {
|
||||
|
||||
if (instance.refreshInterval) {
|
||||
|
||||
clearInterval(instance.refreshInterval);
|
||||
instance.refreshInterval = null;
|
||||
|
||||
if (!isPausing) {
|
||||
instance.refreshIntervalEndTime = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetRefreshInterval(instance, intervalMs) {
|
||||
|
||||
clearRefreshInterval(instance);
|
||||
|
||||
if (!intervalMs) {
|
||||
var options = instance.options;
|
||||
if (options) {
|
||||
intervalMs = options.refreshIntervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
if (intervalMs) {
|
||||
instance.refreshInterval = setInterval(instance.notifyRefreshNeeded.bind(instance), intervalMs);
|
||||
instance.refreshIntervalEndTime = new Date().getTime() + intervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
function onDataFetched(result) {
|
||||
|
||||
resetRefreshInterval(this);
|
||||
|
||||
if (this.afterRefresh) {
|
||||
this.afterRefresh(result);
|
||||
}
|
||||
}
|
||||
|
||||
ItemsRefresher.prototype.destroy = function () {
|
||||
|
||||
destroy() {
|
||||
clearRefreshInterval(this);
|
||||
|
||||
removeNotificationEvent(this, 'UserDataChanged');
|
||||
@@ -275,7 +209,42 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||
|
||||
this.fetchData = null;
|
||||
this.options = null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return ItemsRefresher;
|
||||
});
|
||||
function clearRefreshInterval(instance, isPausing) {
|
||||
if (instance.refreshInterval) {
|
||||
clearInterval(instance.refreshInterval);
|
||||
instance.refreshInterval = null;
|
||||
|
||||
if (!isPausing) {
|
||||
instance.refreshIntervalEndTime = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetRefreshInterval(instance, intervalMs) {
|
||||
clearRefreshInterval(instance);
|
||||
|
||||
if (!intervalMs) {
|
||||
const options = instance.options;
|
||||
if (options) {
|
||||
intervalMs = options.refreshIntervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
if (intervalMs) {
|
||||
instance.refreshInterval = setInterval(instance.notifyRefreshNeeded.bind(instance), intervalMs);
|
||||
instance.refreshIntervalEndTime = new Date().getTime() + intervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
function onDataFetched(result) {
|
||||
resetRefreshInterval(this);
|
||||
|
||||
if (this.afterRefresh) {
|
||||
this.afterRefresh(result);
|
||||
}
|
||||
}
|
||||
|
||||
export default ItemsRefresher;
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
define(['browser', 'appSettings', 'events'], function (browser, appSettings, events) {
|
||||
'use strict';
|
||||
import browser from 'browser';
|
||||
import appSettings from 'appSettings';
|
||||
import events from 'events';
|
||||
|
||||
function setLayout(instance, layout, selectedLayout) {
|
||||
if (layout === selectedLayout) {
|
||||
instance[layout] = true;
|
||||
document.documentElement.classList.add('layout-' + layout);
|
||||
} else {
|
||||
instance[layout] = false;
|
||||
document.documentElement.classList.remove('layout-' + layout);
|
||||
}
|
||||
function setLayout(instance, layout, selectedLayout) {
|
||||
if (layout === selectedLayout) {
|
||||
instance[layout] = true;
|
||||
document.documentElement.classList.add('layout-' + layout);
|
||||
} else {
|
||||
instance[layout] = false;
|
||||
document.documentElement.classList.remove('layout-' + layout);
|
||||
}
|
||||
}
|
||||
|
||||
function LayoutManager() {
|
||||
|
||||
}
|
||||
|
||||
LayoutManager.prototype.setLayout = function (layout, save) {
|
||||
|
||||
class LayoutManager {
|
||||
setLayout(layout, save) {
|
||||
if (!layout || layout === 'auto') {
|
||||
this.autoLayout();
|
||||
|
||||
@@ -34,14 +31,13 @@ define(['browser', 'appSettings', 'events'], function (browser, appSettings, eve
|
||||
}
|
||||
|
||||
events.trigger(this, 'modechange');
|
||||
};
|
||||
}
|
||||
|
||||
LayoutManager.prototype.getSavedLayout = function (layout) {
|
||||
getSavedLayout(layout) {
|
||||
return appSettings.get('layout');
|
||||
};
|
||||
|
||||
LayoutManager.prototype.autoLayout = function () {
|
||||
}
|
||||
|
||||
autoLayout() {
|
||||
// Take a guess at initial layout. The consuming app can override
|
||||
if (browser.mobile) {
|
||||
this.setLayout('mobile', false);
|
||||
@@ -50,16 +46,16 @@ define(['browser', 'appSettings', 'events'], function (browser, appSettings, eve
|
||||
} else {
|
||||
this.setLayout(this.defaultLayout || 'tv', false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
LayoutManager.prototype.init = function () {
|
||||
var saved = this.getSavedLayout();
|
||||
init() {
|
||||
const saved = this.getSavedLayout();
|
||||
if (saved) {
|
||||
this.setLayout(saved, false);
|
||||
} else {
|
||||
this.autoLayout();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return new LayoutManager();
|
||||
});
|
||||
export default new LayoutManager();
|
||||
|
||||
@@ -75,9 +75,9 @@ import 'emby-input';
|
||||
html += '</h3>';
|
||||
html += '</div>';
|
||||
if (i > 0) {
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('ButtonUp')}" class="btnSortableMoveUp btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_up"></span></button>`;
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Up')}" class="btnSortableMoveUp btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_up"></span></button>`;
|
||||
} else if (plugins.length > 1) {
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('ButtonDown')}" class="btnSortableMoveDown btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_down"></span></button>`;
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Down')}" class="btnSortableMoveDown btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_down"></span></button>`;
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
@@ -131,9 +131,9 @@ import 'emby-input';
|
||||
html += '</h3>';
|
||||
html += '</div>';
|
||||
if (index > 0) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonUp') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Up') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
} else if (plugins.length > 1) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonDown') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Down') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
}
|
||||
html += '</div>';
|
||||
});
|
||||
@@ -197,9 +197,9 @@ import 'emby-input';
|
||||
html += '</h3>';
|
||||
html += '</div>';
|
||||
if (i > 0) {
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('ButtonUp')}" class="btnSortableMoveUp btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_up"></span></button>`;
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Up')}" class="btnSortableMoveUp btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_up"></span></button>`;
|
||||
} else if (plugins.length > 1) {
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('ButtonDown')}" class="btnSortableMoveDown btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_down"></span></button>`;
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Down')}" class="btnSortableMoveDown btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_down"></span></button>`;
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
@@ -219,7 +219,7 @@ import 'emby-input';
|
||||
html += '<div class="flex align-items-center" style="margin:1.5em 0 .5em;">';
|
||||
html += '<h3 class="checkboxListLabel" style="margin:0;">' + globalize.translate('HeaderTypeImageFetchers', availableTypeOptions.Type) + '</h3>';
|
||||
const supportedImageTypes = availableTypeOptions.SupportedImageTypes || [];
|
||||
if (supportedImageTypes.length > 1 || 1 === supportedImageTypes.length && 'Primary' !== supportedImageTypes[0]) {
|
||||
if (supportedImageTypes.length > 1 || supportedImageTypes.length === 1 && supportedImageTypes[0] !== 'Primary') {
|
||||
html += '<button is="emby-button" class="raised btnImageOptionsForType" type="button" style="margin-left:1.5em;font-size:90%;"><span>' + globalize.translate('HeaderFetcherSettings') + '</span></button>';
|
||||
}
|
||||
html += '</div>';
|
||||
@@ -236,9 +236,9 @@ import 'emby-input';
|
||||
html += '</h3>';
|
||||
html += '</div>';
|
||||
if (i > 0) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonUp') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Up') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
} else if (plugins.length > 1) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonDown') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Down') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
@@ -291,13 +291,13 @@ import 'emby-input';
|
||||
const btnSortable = elem.querySelector('.btnSortable');
|
||||
const inner = btnSortable.querySelector('.material-icons');
|
||||
if (elem.previousSibling) {
|
||||
btnSortable.title = globalize.translate('ButtonUp');
|
||||
btnSortable.title = globalize.translate('Up');
|
||||
btnSortable.classList.add('btnSortableMoveUp');
|
||||
btnSortable.classList.remove('btnSortableMoveDown');
|
||||
inner.classList.remove('keyboard_arrow_down');
|
||||
inner.classList.add('keyboard_arrow_up');
|
||||
} else {
|
||||
btnSortable.title = globalize.translate('ButtonDown');
|
||||
btnSortable.title = globalize.translate('Down');
|
||||
btnSortable.classList.remove('btnSortableMoveUp');
|
||||
btnSortable.classList.add('btnSortableMoveDown');
|
||||
inner.classList.remove('keyboard_arrow_up');
|
||||
@@ -362,7 +362,7 @@ import 'emby-input';
|
||||
TypeOptions: []
|
||||
};
|
||||
currentAvailableOptions = null;
|
||||
const isNewLibrary = null === libraryOptions;
|
||||
const isNewLibrary = libraryOptions === null;
|
||||
isNewLibrary && parent.classList.add('newlibrary');
|
||||
const response = await fetch('components/libraryoptionseditor/libraryoptionseditor.template.html');
|
||||
const template = await response.text();
|
||||
@@ -578,7 +578,7 @@ import 'emby-input';
|
||||
parent.querySelector('#chkSkipIfAudioTrackPresent').checked = options.SkipSubtitlesIfAudioTrackMatches;
|
||||
parent.querySelector('#chkRequirePerfectMatch').checked = options.RequirePerfectSubtitleMatch;
|
||||
Array.prototype.forEach.call(parent.querySelectorAll('.chkMetadataSaver'), elem => {
|
||||
elem.checked = options.MetadataSavers ? options.MetadataSavers.includes(elem.getAttribute('data-pluginname')) : 'true' === elem.getAttribute('data-defaultenabled');
|
||||
elem.checked = options.MetadataSavers ? options.MetadataSavers.includes(elem.getAttribute('data-pluginname')) : elem.getAttribute('data-defaultenabled') === 'true';
|
||||
});
|
||||
Array.prototype.forEach.call(parent.querySelectorAll('.chkSubtitleLanguage'), elem => {
|
||||
elem.checked = !!options.SubtitleDownloadLanguages && options.SubtitleDownloadLanguages.includes(elem.getAttribute('data-lang'));
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
<div class="checkboxContainer checkboxContainer-withDescription hide chkImportMissingEpisodesContainer advanced">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="chkImportMissingEpisodes" />
|
||||
<span>${LabelDisplayMissingEpisodesWithinSeasons}</span>
|
||||
<span>${DisplayMissingEpisodesWithinSeasons}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${ImportMissingEpisodesHelp}</div>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
import itemHelper from 'itemHelper';
|
||||
import mediaInfo from 'mediaInfo';
|
||||
import indicators from 'indicators';
|
||||
import connectionManager from 'connectionManager';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import datetime from 'datetime';
|
||||
@@ -18,9 +17,7 @@ import 'emby-ratingbutton';
|
||||
import 'emby-playstatebutton';
|
||||
|
||||
function getIndex(item, options) {
|
||||
|
||||
if (options.index === 'disc') {
|
||||
|
||||
return item.ParentIndexNumber == null ? '' : globalize.translate('ValueDiscNumber', item.ParentIndexNumber);
|
||||
}
|
||||
|
||||
@@ -29,7 +26,6 @@ import 'emby-playstatebutton';
|
||||
let name;
|
||||
|
||||
if (sortBy.indexOf('sortname') === 0) {
|
||||
|
||||
if (item.Type === 'Episode') {
|
||||
return '';
|
||||
}
|
||||
@@ -45,11 +41,9 @@ import 'emby-playstatebutton';
|
||||
return name.toUpperCase();
|
||||
}
|
||||
if (sortBy.indexOf('officialrating') === 0) {
|
||||
|
||||
return item.OfficialRating || globalize.translate('Unrated');
|
||||
}
|
||||
if (sortBy.indexOf('communityrating') === 0) {
|
||||
|
||||
if (item.CommunityRating == null) {
|
||||
return globalize.translate('Unrated');
|
||||
}
|
||||
@@ -57,7 +51,6 @@ import 'emby-playstatebutton';
|
||||
return Math.floor(item.CommunityRating);
|
||||
}
|
||||
if (sortBy.indexOf('criticrating') === 0) {
|
||||
|
||||
if (item.CriticRating == null) {
|
||||
return globalize.translate('Unrated');
|
||||
}
|
||||
@@ -65,7 +58,6 @@ import 'emby-playstatebutton';
|
||||
return Math.floor(item.CriticRating);
|
||||
}
|
||||
if (sortBy.indexOf('albumartist') === 0) {
|
||||
|
||||
// SortName
|
||||
if (!item.AlbumArtist) {
|
||||
return '';
|
||||
@@ -84,12 +76,11 @@ import 'emby-playstatebutton';
|
||||
}
|
||||
|
||||
function getImageUrl(item, width) {
|
||||
|
||||
const apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
let itemId;
|
||||
|
||||
const options = {
|
||||
maxWidth: width * 2,
|
||||
maxWidth: width,
|
||||
type: 'Primary'
|
||||
};
|
||||
|
||||
@@ -114,10 +105,9 @@ import 'emby-playstatebutton';
|
||||
}
|
||||
|
||||
function getChannelImageUrl(item, width) {
|
||||
|
||||
const apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
const options = {
|
||||
maxWidth: width * 2,
|
||||
maxWidth: width,
|
||||
type: 'Primary'
|
||||
};
|
||||
|
||||
@@ -161,11 +151,9 @@ import 'emby-playstatebutton';
|
||||
}
|
||||
|
||||
function getRightButtonsHtml(options) {
|
||||
|
||||
let html = '';
|
||||
|
||||
for (let i = 0, length = options.rightButtons.length; i < length; i++) {
|
||||
|
||||
const button = options.rightButtons[i];
|
||||
|
||||
html += `<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="custom" data-customaction="${button.id}" title="${button.title}"><span class="material-icons ${button.icon}"></span></button>`;
|
||||
@@ -179,7 +167,6 @@ import 'emby-playstatebutton';
|
||||
}
|
||||
|
||||
export function getListViewHtml(options) {
|
||||
|
||||
const items = options.items;
|
||||
|
||||
let groupTitle = '';
|
||||
@@ -198,17 +185,14 @@ import 'emby-playstatebutton';
|
||||
const containerAlbumArtistIds = (options.containerAlbumArtists || []).map(getId);
|
||||
|
||||
for (let i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
const item = items[i];
|
||||
|
||||
let html = '';
|
||||
|
||||
if (options.showIndex) {
|
||||
|
||||
const itemGroupTitle = getIndex(item, options);
|
||||
|
||||
if (itemGroupTitle !== groupTitle) {
|
||||
|
||||
if (html) {
|
||||
html += '</div>';
|
||||
}
|
||||
@@ -258,20 +242,16 @@ import 'emby-playstatebutton';
|
||||
const channelIdData = item.ChannelId ? (` data-channelid="${item.ChannelId}"`) : '';
|
||||
|
||||
if (enableContentWrapper) {
|
||||
|
||||
cssClass += ' listItem-withContentWrapper';
|
||||
}
|
||||
|
||||
html += `<${outerTagName} class="${cssClass}"${playlistItemId} data-action="${action}" data-isfolder="${item.IsFolder}" data-id="${item.Id}" data-serverid="${item.ServerId}" data-type="${item.Type}"${mediaTypeData}${collectionTypeData}${channelIdData}${positionTicksData}${collectionIdData}${playlistIdData}>`;
|
||||
|
||||
if (enableContentWrapper) {
|
||||
|
||||
html += '<div class="listItem-content">';
|
||||
}
|
||||
|
||||
if (!clickEntireItem && options.dragHandle) {
|
||||
//html += '<button is="paper-icon-button-light" class="listViewDragHandle listItemButton"><span class="material-icons drag_handle"></span></button>';
|
||||
// Firefox and Edge are not allowing the button to be draggable
|
||||
html += '<span class="listViewDragHandle material-icons listItemIcon listItemIcon-transparent drag_handle"></span>';
|
||||
}
|
||||
|
||||
@@ -319,7 +299,6 @@ import 'emby-playstatebutton';
|
||||
}
|
||||
|
||||
if (options.showIndexNumberLeft) {
|
||||
|
||||
html += '<div class="listItem-indexnumberleft">';
|
||||
html += (item.IndexNumber || ' ');
|
||||
html += '</div>';
|
||||
@@ -367,9 +346,7 @@ import 'emby-playstatebutton';
|
||||
}
|
||||
|
||||
if (options.showParentTitle && options.parentTitleWithTitle) {
|
||||
|
||||
if (displayName) {
|
||||
|
||||
if (parentTitle) {
|
||||
parentTitle += ' - ';
|
||||
}
|
||||
@@ -387,27 +364,13 @@ import 'emby-playstatebutton';
|
||||
|
||||
if (item.IsFolder) {
|
||||
if (options.artist !== false) {
|
||||
|
||||
if (item.AlbumArtist && item.Type === 'MusicAlbum') {
|
||||
textlines.push(item.AlbumArtist);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
let showArtist = options.artist === true;
|
||||
const artistItems = item.ArtistItems;
|
||||
|
||||
if (!showArtist && options.artist !== false) {
|
||||
|
||||
if (!artistItems || !artistItems.length) {
|
||||
showArtist = true;
|
||||
} else if (artistItems.length > 1 || !containerAlbumArtistIds.includes(artistItems[0].Id)) {
|
||||
showArtist = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (showArtist) {
|
||||
|
||||
if (options.artist) {
|
||||
const artistItems = item.ArtistItems;
|
||||
if (artistItems && item.Type !== 'MusicAlbum') {
|
||||
textlines.push(artistItems.map(a => {
|
||||
return a.Name;
|
||||
@@ -417,7 +380,6 @@ import 'emby-playstatebutton';
|
||||
}
|
||||
|
||||
if (item.Type === 'TvChannel') {
|
||||
|
||||
if (item.CurrentProgram) {
|
||||
textlines.push(itemHelper.getDisplayName(item.CurrentProgram));
|
||||
}
|
||||
@@ -438,7 +400,6 @@ import 'emby-playstatebutton';
|
||||
|
||||
if (options.mediaInfo !== false) {
|
||||
if (!enableSideMediaInfo) {
|
||||
|
||||
const mediaInfoClass = 'secondary listItemMediaInfo listItemBodyText';
|
||||
|
||||
html += `<div class="${mediaInfoClass}">`;
|
||||
@@ -483,7 +444,6 @@ import 'emby-playstatebutton';
|
||||
html += '<div class="listViewUserDataButtons">';
|
||||
|
||||
if (!clickEntireItem) {
|
||||
|
||||
if (options.addToListButton) {
|
||||
html += '<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="addtoplaylist"><span class="material-icons playlist_add"></span></button>';
|
||||
}
|
||||
@@ -497,7 +457,6 @@ import 'emby-playstatebutton';
|
||||
}
|
||||
|
||||
if (options.enableUserDataButtons !== false) {
|
||||
|
||||
const userData = item.UserData || {};
|
||||
const likes = userData.Likes == null ? '' : userData.Likes;
|
||||
|
||||
|
||||
@@ -1,80 +1,74 @@
|
||||
define(['css!./loading'], function () {
|
||||
'use strict';
|
||||
import 'css!./loading';
|
||||
|
||||
var loadingElem;
|
||||
var layer1;
|
||||
var layer2;
|
||||
var layer3;
|
||||
var layer4;
|
||||
var circleLefts;
|
||||
var circleRights;
|
||||
let loadingElem;
|
||||
let layer1;
|
||||
let layer2;
|
||||
let layer3;
|
||||
let layer4;
|
||||
let circleLefts;
|
||||
let circleRights;
|
||||
|
||||
return {
|
||||
show: function () {
|
||||
var elem = loadingElem;
|
||||
export function show() {
|
||||
let elem = loadingElem;
|
||||
|
||||
if (!elem) {
|
||||
if (!elem) {
|
||||
elem = document.createElement('div');
|
||||
loadingElem = elem;
|
||||
|
||||
elem = document.createElement('div');
|
||||
loadingElem = elem;
|
||||
elem.classList.add('docspinner');
|
||||
elem.classList.add('mdl-spinner');
|
||||
|
||||
elem.classList.add('docspinner');
|
||||
elem.classList.add('mdl-spinner');
|
||||
elem.innerHTML = '<div class="mdl-spinner__layer mdl-spinner__layer-1"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div><div class="mdl-spinner__layer mdl-spinner__layer-2"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div><div class="mdl-spinner__layer mdl-spinner__layer-3"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div><div class="mdl-spinner__layer mdl-spinner__layer-4"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div>';
|
||||
|
||||
elem.innerHTML = '<div class="mdl-spinner__layer mdl-spinner__layer-1"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div><div class="mdl-spinner__layer mdl-spinner__layer-2"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div><div class="mdl-spinner__layer mdl-spinner__layer-3"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div><div class="mdl-spinner__layer mdl-spinner__layer-4"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div>';
|
||||
document.body.appendChild(elem);
|
||||
|
||||
document.body.appendChild(elem);
|
||||
layer1 = elem.querySelector('.mdl-spinner__layer-1');
|
||||
layer2 = elem.querySelector('.mdl-spinner__layer-2');
|
||||
layer3 = elem.querySelector('.mdl-spinner__layer-3');
|
||||
layer4 = elem.querySelector('.mdl-spinner__layer-4');
|
||||
|
||||
layer1 = elem.querySelector('.mdl-spinner__layer-1');
|
||||
layer2 = elem.querySelector('.mdl-spinner__layer-2');
|
||||
layer3 = elem.querySelector('.mdl-spinner__layer-3');
|
||||
layer4 = elem.querySelector('.mdl-spinner__layer-4');
|
||||
circleLefts = elem.querySelectorAll('.mdl-spinner__circleLeft');
|
||||
circleRights = elem.querySelectorAll('.mdl-spinner__circleRight');
|
||||
}
|
||||
|
||||
circleLefts = elem.querySelectorAll('.mdl-spinner__circleLeft');
|
||||
circleRights = elem.querySelectorAll('.mdl-spinner__circleRight');
|
||||
}
|
||||
elem.classList.add('mdlSpinnerActive');
|
||||
|
||||
elem.classList.add('mdlSpinnerActive');
|
||||
layer1.classList.add('mdl-spinner__layer-1-active');
|
||||
layer2.classList.add('mdl-spinner__layer-2-active');
|
||||
layer3.classList.add('mdl-spinner__layer-3-active');
|
||||
layer4.classList.add('mdl-spinner__layer-4-active');
|
||||
|
||||
layer1.classList.add('mdl-spinner__layer-1-active');
|
||||
layer2.classList.add('mdl-spinner__layer-2-active');
|
||||
layer3.classList.add('mdl-spinner__layer-3-active');
|
||||
layer4.classList.add('mdl-spinner__layer-4-active');
|
||||
for (let i = 0, length = circleLefts.length; i < length; i++) {
|
||||
circleLefts[i].classList.add('mdl-spinner__circleLeft-active');
|
||||
}
|
||||
|
||||
var i;
|
||||
var length;
|
||||
for (let i = 0, length = circleRights.length; i < length; i++) {
|
||||
circleRights[i].classList.add('mdl-spinner__circleRight-active');
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0, length = circleLefts.length; i < length; i++) {
|
||||
circleLefts[i].classList.add('mdl-spinner__circleLeft-active');
|
||||
}
|
||||
export function hide() {
|
||||
const elem = loadingElem;
|
||||
|
||||
for (i = 0, length = circleRights.length; i < length; i++) {
|
||||
circleRights[i].classList.add('mdl-spinner__circleRight-active');
|
||||
}
|
||||
},
|
||||
hide: function () {
|
||||
var elem = loadingElem;
|
||||
if (elem) {
|
||||
elem.classList.remove('mdlSpinnerActive');
|
||||
|
||||
if (elem) {
|
||||
elem.classList.remove('mdl-spinner__layer-1-active');
|
||||
elem.classList.remove('mdl-spinner__layer-2-active');
|
||||
elem.classList.remove('mdl-spinner__layer-3-active');
|
||||
elem.classList.remove('mdl-spinner__layer-4-active');
|
||||
|
||||
elem.classList.remove('mdlSpinnerActive');
|
||||
|
||||
elem.classList.remove('mdl-spinner__layer-1-active');
|
||||
elem.classList.remove('mdl-spinner__layer-2-active');
|
||||
elem.classList.remove('mdl-spinner__layer-3-active');
|
||||
elem.classList.remove('mdl-spinner__layer-4-active');
|
||||
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = circleLefts.length; i < length; i++) {
|
||||
circleLefts[i].classList.remove('mdl-spinner__circleLeft-active');
|
||||
}
|
||||
|
||||
for (i = 0, length = circleRights.length; i < length; i++) {
|
||||
circleRights[i].classList.remove('mdl-spinner__circleRight-active');
|
||||
}
|
||||
}
|
||||
for (let i = 0, length = circleLefts.length; i < length; i++) {
|
||||
circleLefts[i].classList.remove('mdl-spinner__circleLeft-active');
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
for (let i = 0, length = circleRights.length; i < length; i++) {
|
||||
circleRights[i].classList.remove('mdl-spinner__circleRight-active');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
show: show,
|
||||
hide: hide
|
||||
};
|
||||
|
||||
@@ -8,29 +8,10 @@ import 'emby-button';
|
||||
|
||||
let tabOwnerView;
|
||||
const queryScope = document.querySelector('.skinHeader');
|
||||
let footerTabsContainer;
|
||||
let headerTabsContainer;
|
||||
let tabsElem;
|
||||
|
||||
function enableTabsInFooter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getTabsContainerElem() {
|
||||
}
|
||||
|
||||
function ensureElements(enableInFooter) {
|
||||
|
||||
if (enableInFooter) {
|
||||
if (!footerTabsContainer) {
|
||||
footerTabsContainer = document.createElement('div');
|
||||
footerTabsContainer.classList.add('footerTabs');
|
||||
footerTabsContainer.classList.add('sectionTabs');
|
||||
footerTabsContainer.classList.add('hide');
|
||||
//appFooter.add(footerTabsContainer);
|
||||
}
|
||||
}
|
||||
|
||||
function ensureElements() {
|
||||
if (!headerTabsContainer) {
|
||||
headerTabsContainer = queryScope.querySelector('.headerTabs');
|
||||
}
|
||||
@@ -42,9 +23,7 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
function allowSwipe(target) {
|
||||
|
||||
function allowSwipeOn(elem) {
|
||||
|
||||
if (dom.parentWithTag(elem, 'input')) {
|
||||
return false;
|
||||
}
|
||||
@@ -69,13 +48,11 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
function configureSwipeTabs(view, tabsElem, getTabContainersFn) {
|
||||
|
||||
if (!browser.touch) {
|
||||
return;
|
||||
}
|
||||
|
||||
// implement without hammer
|
||||
const pageCount = getTabContainersFn().length;
|
||||
const onSwipeLeft = function (e, target) {
|
||||
if (allowSwipe(target) && view.contains(target)) {
|
||||
tabsElem.selectNext();
|
||||
@@ -89,7 +66,6 @@ import 'emby-button';
|
||||
};
|
||||
|
||||
import('touchHelper').then(({default: TouchHelper}) => {
|
||||
|
||||
const touchHelper = new TouchHelper(view.parentNode.parentNode);
|
||||
|
||||
events.on(touchHelper, 'swipeleft', onSwipeLeft);
|
||||
@@ -102,28 +78,19 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
export function setTabs(view, selectedIndex, getTabsFn, getTabContainersFn, onBeforeTabChange, onTabChange, setSelectedIndex) {
|
||||
|
||||
const enableInFooter = enableTabsInFooter();
|
||||
|
||||
if (!view) {
|
||||
if (tabOwnerView) {
|
||||
|
||||
if (!headerTabsContainer) {
|
||||
headerTabsContainer = queryScope.querySelector('.headerTabs');
|
||||
}
|
||||
|
||||
ensureElements(enableInFooter);
|
||||
ensureElements();
|
||||
|
||||
document.body.classList.remove('withSectionTabs');
|
||||
|
||||
headerTabsContainer.innerHTML = '';
|
||||
headerTabsContainer.classList.add('hide');
|
||||
|
||||
if (footerTabsContainer) {
|
||||
footerTabsContainer.innerHTML = '';
|
||||
footerTabsContainer.classList.add('hide');
|
||||
}
|
||||
|
||||
tabOwnerView = null;
|
||||
}
|
||||
return {
|
||||
@@ -132,21 +99,19 @@ import 'emby-button';
|
||||
};
|
||||
}
|
||||
|
||||
ensureElements(enableInFooter);
|
||||
ensureElements();
|
||||
|
||||
const tabsContainerElem = enableInFooter ? footerTabsContainer : headerTabsContainer;
|
||||
const tabsContainerElem = headerTabsContainer;
|
||||
|
||||
if (!tabOwnerView) {
|
||||
tabsContainerElem.classList.remove('hide');
|
||||
}
|
||||
|
||||
if (tabOwnerView !== view) {
|
||||
|
||||
let index = 0;
|
||||
|
||||
const indexAttribute = selectedIndex == null ? '' : (' data-index="' + selectedIndex + '"');
|
||||
const tabsHtml = '<div is="emby-tabs"' + indexAttribute + ' class="tabs-viewmenubar"><div class="emby-tabs-slider" style="white-space:nowrap;">' + getTabsFn().map(function (t) {
|
||||
|
||||
let tabClass = 'emby-tab-button';
|
||||
|
||||
if (t.enabled === false) {
|
||||
@@ -167,7 +132,6 @@ import 'emby-button';
|
||||
|
||||
index++;
|
||||
return tabHtml;
|
||||
|
||||
}).join('') + '</div></div>';
|
||||
|
||||
tabsContainerElem.innerHTML = tabsHtml;
|
||||
@@ -181,10 +145,8 @@ import 'emby-button';
|
||||
configureSwipeTabs(view, tabsElem, getTabContainersFn);
|
||||
|
||||
tabsElem.addEventListener('beforetabchange', function (e) {
|
||||
|
||||
const tabContainers = getTabContainersFn();
|
||||
if (e.detail.previousIndex != null) {
|
||||
|
||||
const previousPanel = tabContainers[e.detail.previousIndex];
|
||||
if (previousPanel) {
|
||||
previousPanel.classList.remove('is-active');
|
||||
@@ -193,12 +155,6 @@ import 'emby-button';
|
||||
|
||||
const newPanel = tabContainers[e.detail.selectedTabIndex];
|
||||
|
||||
//if (e.detail.previousIndex != null && e.detail.previousIndex != e.detail.selectedTabIndex) {
|
||||
// if (newPanel.animate && (animateTabs || []).indexOf(e.detail.selectedTabIndex) != -1) {
|
||||
// fadeInRight(newPanel);
|
||||
// }
|
||||
//}
|
||||
|
||||
if (newPanel) {
|
||||
newPanel.classList.add('is-active');
|
||||
}
|
||||
@@ -215,16 +171,11 @@ import 'emby-button';
|
||||
if (tabsElem.selectedIndex) {
|
||||
tabsElem.selectedIndex(selectedIndex);
|
||||
} else {
|
||||
|
||||
tabsElem.readySelectedIndex = selectedIndex;
|
||||
tabsElem.addEventListener('ready', onViewTabsReady);
|
||||
}
|
||||
}
|
||||
|
||||
//if (enableSwipe !== false) {
|
||||
// libraryBrowser.configureSwipeTabs(ownerpage, tabs);
|
||||
//}
|
||||
|
||||
return {
|
||||
tabsContainer: tabsContainerElem,
|
||||
tabs: tabsContainerElem.querySelector('[is="emby-tabs"]'),
|
||||
@@ -247,7 +198,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
export function selectedTabIndex(index) {
|
||||
|
||||
const tabsContainerElem = headerTabsContainer;
|
||||
|
||||
if (!tabsElem) {
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
<div class="folders">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<h1 style="margin: .5em 0;">${HeadersFolders}</h1>
|
||||
<button is="emby-button" type="button" class="fab btnAddFolder submit" style="margin-left:1em;" title="${ButtonAdd}">
|
||||
<h1 style="margin: .5em 0;">${Folders}</h1>
|
||||
<button is="emby-button" type="button" class="fab btnAddFolder submit" style="margin-left:1em;" title="${Add}">
|
||||
<span class="material-icons add"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -76,7 +76,7 @@ import 'flexStyles';
|
||||
confirm({
|
||||
title: globalize.translate('HeaderRemoveMediaLocation'),
|
||||
text: globalize.translate('MessageConfirmRemoveMediaLocation'),
|
||||
confirmText: globalize.translate('ButtonDelete'),
|
||||
confirmText: globalize.translate('Delete'),
|
||||
primary: 'delete'
|
||||
}).then(() => {
|
||||
const refreshAfterChange = currentOptions.refresh;
|
||||
@@ -85,7 +85,7 @@ import 'flexStyles';
|
||||
refreshLibraryFromServer(dom.parentWithClass(button, 'dlg-libraryeditor'));
|
||||
}, () => {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('DefaultErrorMessage'));
|
||||
toast(globalize.translate('ErrorDefault'));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -98,8 +98,8 @@ import 'flexStyles';
|
||||
if (listItem) {
|
||||
const index = parseInt(listItem.getAttribute('data-index'));
|
||||
const pathInfos = (currentOptions.library.LibraryOptions || {}).PathInfos || [];
|
||||
const pathInfo = null == index ? {} : pathInfos[index] || {};
|
||||
const originalPath = pathInfo.Path || (null == index ? null : currentOptions.library.Locations[index]);
|
||||
const pathInfo = index == null ? {} : pathInfos[index] || {};
|
||||
const originalPath = pathInfo.Path || (index == null ? null : currentOptions.library.Locations[index]);
|
||||
const btnRemovePath = dom.parentWithClass(e.target, 'btnRemovePath');
|
||||
|
||||
if (btnRemovePath) {
|
||||
@@ -171,7 +171,7 @@ import 'flexStyles';
|
||||
const picker = new directoryBrowser();
|
||||
picker.show({
|
||||
enableNetworkSharePath: true,
|
||||
pathReadOnly: null != originalPath,
|
||||
pathReadOnly: originalPath != null,
|
||||
path: originalPath,
|
||||
networkSharePath: networkPath,
|
||||
callback: function (path, networkSharePath) {
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
<div class="folders hide">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<h1 style="margin: .5em 0;">${HeadersFolders}</h1>
|
||||
<button is="emby-button" type="button" class="fab btnAddFolder submit" style="margin-left:1em;" title="${ButtonAdd}">
|
||||
<h1 style="margin: .5em 0;">${Folders}</h1>
|
||||
<button is="emby-button" type="button" class="fab btnAddFolder submit" style="margin-left:1em;" title="${Add}">
|
||||
<span class="material-icons add"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -9,25 +9,20 @@ import 'programStyles';
|
||||
import 'emby-button';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function getTimerIndicator(item) {
|
||||
|
||||
let status;
|
||||
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
return '<span class="material-icons mediaInfoItem mediaInfoIconItem mediaInfoTimerIcon fiber_smart_record"></span>';
|
||||
} else if (item.TimerId || item.SeriesTimerId) {
|
||||
|
||||
status = item.Status || 'Cancelled';
|
||||
} else if (item.Type === 'Timer') {
|
||||
|
||||
status = item.Status;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (item.SeriesTimerId) {
|
||||
|
||||
if (status !== 'Cancelled') {
|
||||
return '<span class="material-icons mediaInfoItem mediaInfoIconItem mediaInfoTimerIcon fiber_smart_record"></span>';
|
||||
}
|
||||
@@ -46,9 +41,7 @@ import 'emby-button';
|
||||
let date;
|
||||
|
||||
if (item.StartDate && options.programTime !== false) {
|
||||
|
||||
try {
|
||||
|
||||
text = '';
|
||||
|
||||
date = datetime.parseISO8601Date(item.StartDate);
|
||||
@@ -75,7 +68,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
if (item.ChannelName) {
|
||||
|
||||
if (options.interactive && item.ChannelId) {
|
||||
miscInfo.push({
|
||||
html: `<a is="emby-linkbutton" class="button-flat mediaInfoItem" href="${appRouter.getRouteUrl({
|
||||
@@ -121,11 +113,9 @@ import 'emby-button';
|
||||
const showFolderRuntime = item.Type === 'MusicAlbum' || item.MediaType === 'MusicArtist' || item.MediaType === 'Playlist' || item.MediaType === 'MusicGenre';
|
||||
|
||||
if (showFolderRuntime) {
|
||||
|
||||
count = item.SongCount || item.ChildCount;
|
||||
|
||||
if (count) {
|
||||
|
||||
miscInfo.push(globalize.translate('TrackCount', count));
|
||||
}
|
||||
|
||||
@@ -133,19 +123,15 @@ import 'emby-button';
|
||||
miscInfo.push(datetime.getDisplayRunningTime(item.RunTimeTicks));
|
||||
}
|
||||
} else if (item.Type === 'PhotoAlbum' || item.Type === 'BoxSet') {
|
||||
|
||||
count = item.ChildCount;
|
||||
|
||||
if (count) {
|
||||
|
||||
miscInfo.push(globalize.translate('ItemCount', count));
|
||||
}
|
||||
}
|
||||
|
||||
if ((item.Type === 'Episode' || item.MediaType === 'Photo') && options.originalAirDate !== false) {
|
||||
|
||||
if (item.PremiereDate) {
|
||||
|
||||
try {
|
||||
date = datetime.parseISO8601Date(item.PremiereDate);
|
||||
|
||||
@@ -159,7 +145,6 @@ import 'emby-button';
|
||||
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
if (item.RecordAnyTime) {
|
||||
|
||||
miscInfo.push(globalize.translate('Anytime'));
|
||||
} else {
|
||||
miscInfo.push(datetime.getDisplayTime(item.StartDate));
|
||||
@@ -173,7 +158,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
if (item.StartDate && item.Type !== 'Program' && item.Type !== 'SeriesTimer') {
|
||||
|
||||
try {
|
||||
date = datetime.parseISO8601Date(item.StartDate);
|
||||
|
||||
@@ -190,24 +174,18 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
if (options.year !== false && item.ProductionYear && item.Type === 'Series') {
|
||||
|
||||
if (item.Status === 'Continuing') {
|
||||
miscInfo.push(globalize.translate('SeriesYearToPresent', item.ProductionYear));
|
||||
|
||||
} else if (item.ProductionYear) {
|
||||
|
||||
text = item.ProductionYear;
|
||||
|
||||
if (item.EndDate) {
|
||||
|
||||
try {
|
||||
|
||||
const endYear = datetime.parseISO8601Date(item.EndDate).getFullYear();
|
||||
|
||||
if (endYear !== item.ProductionYear) {
|
||||
text += `-${datetime.parseISO8601Date(item.EndDate).getFullYear()}`;
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error('error parsing date:', item.EndDate);
|
||||
}
|
||||
@@ -218,7 +196,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
if (item.Type === 'Program') {
|
||||
|
||||
if (options.programIndicator !== false) {
|
||||
if (item.IsLive) {
|
||||
miscInfo.push({
|
||||
@@ -230,7 +207,7 @@ import 'emby-button';
|
||||
});
|
||||
} else if (item.IsSeries && !item.IsRepeat) {
|
||||
miscInfo.push({
|
||||
html: `<div class="mediaInfoProgramAttribute mediaInfoItem newTvProgram">${globalize.translate('AttributeNew')}</div>`
|
||||
html: `<div class="mediaInfoProgramAttribute mediaInfoItem newTvProgram">${globalize.translate('New')}</div>`
|
||||
});
|
||||
} else if (item.IsSeries && item.IsRepeat) {
|
||||
miscInfo.push({
|
||||
@@ -240,7 +217,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
if ((item.IsSeries || item.EpisodeTitle) && options.episodeTitle !== false) {
|
||||
|
||||
text = itemHelper.getDisplayName(item, {
|
||||
includeIndexNumber: options.episodeTitleIndexNumber
|
||||
});
|
||||
@@ -251,7 +227,6 @@ import 'emby-button';
|
||||
} else if (item.IsMovie && item.ProductionYear && options.originalAirDate !== false) {
|
||||
miscInfo.push(item.ProductionYear);
|
||||
} else if (item.PremiereDate && options.originalAirDate !== false) {
|
||||
|
||||
try {
|
||||
date = datetime.parseISO8601Date(item.PremiereDate);
|
||||
text = globalize.translate('OriginalAirDateValue', datetime.toLocaleDateString(date));
|
||||
@@ -266,12 +241,9 @@ import 'emby-button';
|
||||
|
||||
if (options.year !== false) {
|
||||
if (item.Type !== 'Series' && item.Type !== 'Episode' && item.Type !== 'Person' && item.MediaType !== 'Photo' && item.Type !== 'Program' && item.Type !== 'Season') {
|
||||
|
||||
if (item.ProductionYear) {
|
||||
|
||||
miscInfo.push(item.ProductionYear);
|
||||
} else if (item.PremiereDate) {
|
||||
|
||||
try {
|
||||
text = datetime.parseISO8601Date(item.PremiereDate).getFullYear();
|
||||
miscInfo.push(text);
|
||||
@@ -283,11 +255,8 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
if (item.RunTimeTicks && item.Type !== 'Series' && item.Type !== 'Program' && item.Type !== 'Book' && !showFolderRuntime && options.runtime !== false) {
|
||||
|
||||
if (item.Type === 'Audio') {
|
||||
|
||||
miscInfo.push(datetime.getDisplayRunningTime(item.RunTimeTicks));
|
||||
|
||||
} else {
|
||||
minutes = item.RunTimeTicks / 600000000;
|
||||
|
||||
@@ -327,7 +296,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
if (item.CriticRating && options.criticRating !== false) {
|
||||
|
||||
if (item.CriticRating >= 60) {
|
||||
html += `<div class="mediaInfoItem mediaInfoCriticRating mediaInfoCriticRatingFresh">${item.CriticRating}</div>`;
|
||||
} else {
|
||||
@@ -336,7 +304,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
if (options.endsAt !== false) {
|
||||
|
||||
const endsAt = getEndsAt(item);
|
||||
if (endsAt) {
|
||||
html += getMediaInfoItem(endsAt, 'endsAt');
|
||||
@@ -349,9 +316,7 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
export function getEndsAt(item) {
|
||||
|
||||
if (item.MediaType === 'Video' && item.RunTimeTicks) {
|
||||
|
||||
if (!item.StartDate) {
|
||||
let endDate = new Date().getTime() + (item.RunTimeTicks / 10000);
|
||||
endDate = new Date(endDate);
|
||||
@@ -365,7 +330,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
export function getEndsAtFromPosition(runtimeTicks, positionTicks, includeText) {
|
||||
|
||||
let endDate = new Date().getTime() + ((runtimeTicks - (positionTicks || 0)) / 10000);
|
||||
endDate = new Date(endDate);
|
||||
|
||||
@@ -378,12 +342,10 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
function getMediaInfoItem(m, cssClass) {
|
||||
|
||||
cssClass = cssClass ? (`${cssClass} mediaInfoItem`) : 'mediaInfoItem';
|
||||
let mediaInfoText = m;
|
||||
|
||||
if (typeof (m) !== 'string' && typeof (m) !== 'number') {
|
||||
|
||||
if (m.html) {
|
||||
return m.html;
|
||||
}
|
||||
@@ -408,17 +370,13 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
function dynamicEndTime(elem, item) {
|
||||
|
||||
const interval = setInterval(() => {
|
||||
|
||||
if (!document.body.contains(elem)) {
|
||||
|
||||
clearInterval(interval);
|
||||
return;
|
||||
}
|
||||
|
||||
elem.innerHTML = getEndsAt(item);
|
||||
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
@@ -437,7 +395,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
function afterFill(elem, item, options) {
|
||||
|
||||
if (options.endsAt !== false) {
|
||||
const endsAtElem = elem.querySelector('.endsAt');
|
||||
if (endsAtElem) {
|
||||
@@ -452,7 +409,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
function onChannelLinkClick(e) {
|
||||
|
||||
const channelId = this.getAttribute('data-id');
|
||||
const serverId = this.getAttribute('data-serverid');
|
||||
|
||||
@@ -463,7 +419,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
export function getPrimaryMediaInfoHtml(item, options) {
|
||||
|
||||
options = options || {};
|
||||
if (options.interactive == null) {
|
||||
options.interactive = false;
|
||||
@@ -473,7 +428,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
export function getSecondaryMediaInfoHtml(item, options) {
|
||||
|
||||
options = options || {};
|
||||
if (options.interactive == null) {
|
||||
options.interactive = false;
|
||||
@@ -486,12 +440,10 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
export function getResolutionText(i) {
|
||||
|
||||
const width = i.Width;
|
||||
const height = i.Height;
|
||||
|
||||
if (width && height) {
|
||||
|
||||
if (width >= 3800 || height >= 2000) {
|
||||
return '4K';
|
||||
}
|
||||
@@ -514,19 +466,16 @@ import 'emby-button';
|
||||
return '720p';
|
||||
}
|
||||
if (width >= 700 || height >= 400) {
|
||||
|
||||
if (i.IsInterlaced) {
|
||||
return '480i';
|
||||
}
|
||||
return '480p';
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getAudioStreamForDisplay(item) {
|
||||
|
||||
if (!item.MediaSources) {
|
||||
return null;
|
||||
}
|
||||
@@ -542,7 +491,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
export function getMediaInfoStats(item, options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
const list = [];
|
||||
@@ -568,10 +516,6 @@ import 'emby-button';
|
||||
});
|
||||
}
|
||||
|
||||
//if (mediaSource.Container) {
|
||||
// html += '<div class="mediaInfoIcon mediaInfoText">' + mediaSource.Container + '</div>';
|
||||
//}
|
||||
|
||||
const resolutionText = getResolutionText(videoStream);
|
||||
if (resolutionText) {
|
||||
list.push({
|
||||
@@ -591,19 +535,12 @@ import 'emby-button';
|
||||
let channelText;
|
||||
|
||||
if (channels === 8) {
|
||||
|
||||
channelText = '7.1';
|
||||
|
||||
} else if (channels === 7) {
|
||||
|
||||
channelText = '6.1';
|
||||
|
||||
} else if (channels === 6) {
|
||||
|
||||
channelText = '5.1';
|
||||
|
||||
} else if (channels === 2) {
|
||||
|
||||
channelText = '2.0';
|
||||
}
|
||||
|
||||
@@ -629,7 +566,6 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
if (item.DateCreated && itemHelper.enableDateAddedDisplay(item)) {
|
||||
|
||||
const dateCreated = datetime.parseISO8601Date(item.DateCreated);
|
||||
|
||||
list.push({
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import itemHelper from 'itemHelper';
|
||||
import dom from 'dom';
|
||||
import layoutManager from 'layoutManager';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import datetime from 'datetime';
|
||||
import loading from 'loading';
|
||||
import focusManager from 'focusManager';
|
||||
import connectionManager from 'connectionManager';
|
||||
import globalize from 'globalize';
|
||||
import require from 'require';
|
||||
import shell from 'shell';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-input';
|
||||
@@ -31,17 +28,14 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function closeDialog(isSubmitted) {
|
||||
|
||||
if (isDialog()) {
|
||||
dialogHelper.close(currentContext);
|
||||
}
|
||||
}
|
||||
|
||||
function submitUpdatedItem(form, item) {
|
||||
|
||||
function afterContentTypeUpdated() {
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('MessageItemSaved'));
|
||||
});
|
||||
|
||||
@@ -52,11 +46,9 @@ import 'flexStyles';
|
||||
const apiClient = getApiClient();
|
||||
|
||||
apiClient.updateItem(item).then(function () {
|
||||
|
||||
const newContentType = form.querySelector('#selectContentType').value || '';
|
||||
|
||||
if ((metadataEditorInfo.ContentType || '') !== newContentType) {
|
||||
|
||||
apiClient.ajax({
|
||||
|
||||
url: apiClient.getUrl('Items/' + item.Id + '/ContentType', {
|
||||
@@ -68,11 +60,9 @@ import 'flexStyles';
|
||||
}).then(function () {
|
||||
afterContentTypeUpdated();
|
||||
});
|
||||
|
||||
} else {
|
||||
afterContentTypeUpdated();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -84,13 +74,9 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function getAlbumArtists(form) {
|
||||
|
||||
return form.querySelector('#txtAlbumArtist').value.trim().split(';').filter(function (s) {
|
||||
|
||||
return s.length > 0;
|
||||
|
||||
}).map(function (a) {
|
||||
|
||||
return {
|
||||
Name: a
|
||||
};
|
||||
@@ -98,13 +84,9 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function getArtists(form) {
|
||||
|
||||
return form.querySelector('#txtArtist').value.trim().split(';').filter(function (s) {
|
||||
|
||||
return s.length > 0;
|
||||
|
||||
}).map(function (a) {
|
||||
|
||||
return {
|
||||
Name: a
|
||||
};
|
||||
@@ -112,7 +94,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function getDateValue(form, element, property) {
|
||||
|
||||
let val = form.querySelector(element).value;
|
||||
|
||||
if (!val) {
|
||||
@@ -120,14 +101,12 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
if (currentItem[property]) {
|
||||
|
||||
const date = datetime.parseISO8601Date(currentItem[property], true);
|
||||
|
||||
const parts = date.toISOString().split('T');
|
||||
|
||||
// If the date is the same, preserve the time
|
||||
if (parts[0].indexOf(val) === 0) {
|
||||
|
||||
const iso = parts[1];
|
||||
|
||||
val += 'T' + iso;
|
||||
@@ -138,7 +117,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
|
||||
loading.show();
|
||||
|
||||
const form = this;
|
||||
@@ -199,14 +177,12 @@ import 'flexStyles';
|
||||
item.PreferredMetadataCountryCode = form.querySelector('#selectCountry').value;
|
||||
|
||||
if (currentItem.Type === 'Person') {
|
||||
|
||||
const placeOfBirth = form.querySelector('#txtPlaceOfBirth').value;
|
||||
|
||||
item.ProductionLocations = placeOfBirth ? [placeOfBirth] : [];
|
||||
}
|
||||
|
||||
if (currentItem.Type === 'Series') {
|
||||
|
||||
// 600000000
|
||||
const seriesRuntime = form.querySelector('#txtSeriesRuntime').value;
|
||||
item.RunTimeTicks = seriesRuntime ? (seriesRuntime * 600000000) : null;
|
||||
@@ -249,11 +225,8 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function editPerson(context, person, index) {
|
||||
|
||||
require(['personEditor'], function (personEditor) {
|
||||
|
||||
import('personEditor').then(({default: personEditor}) => {
|
||||
personEditor.show(person).then(function (updatedPerson) {
|
||||
|
||||
const isNew = index === -1;
|
||||
|
||||
if (isNew) {
|
||||
@@ -271,14 +244,14 @@ import 'flexStyles';
|
||||
if (parentId) {
|
||||
reload(context, parentId, item.ServerId);
|
||||
} else {
|
||||
require(['appRouter'], function (appRouter) {
|
||||
import('appRouter').then(({default: appRouter}) => {
|
||||
appRouter.goHome();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showMoreMenu(context, button, user) {
|
||||
require(['itemContextMenu'], function (itemContextMenu) {
|
||||
import('itemContextMenu').then(({default: itemContextMenu}) => {
|
||||
var item = currentItem;
|
||||
|
||||
itemContextMenu.show({
|
||||
@@ -303,7 +276,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function onEditorClick(e) {
|
||||
|
||||
const btnRemoveFromEditorList = dom.parentWithClass(e.target, 'btnRemoveFromEditorList');
|
||||
if (btnRemoveFromEditorList) {
|
||||
removeElementFromList(btnRemoveFromEditorList);
|
||||
@@ -317,7 +289,7 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function getApiClient() {
|
||||
return connectionManager.getApiClient(currentItem.ServerId);
|
||||
return window.connectionManager.getApiClient(currentItem.ServerId);
|
||||
}
|
||||
|
||||
function bindAll(elems, eventName, fn) {
|
||||
@@ -376,12 +348,10 @@ import 'flexStyles';
|
||||
form.addEventListener('submit', onSubmit);
|
||||
|
||||
context.querySelector('#btnAddPerson').addEventListener('click', function (event, data) {
|
||||
|
||||
editPerson(context, {}, -1);
|
||||
});
|
||||
|
||||
context.querySelector('#peopleList').addEventListener('click', function (e) {
|
||||
|
||||
let index;
|
||||
const btnDeletePerson = dom.parentWithClass(e.target, 'btnDeletePerson');
|
||||
if (btnDeletePerson) {
|
||||
@@ -399,8 +369,7 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function getItem(itemId, serverId) {
|
||||
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
if (itemId) {
|
||||
return apiClient.getItem(apiClient.getCurrentUserId(), itemId);
|
||||
@@ -410,8 +379,7 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function getEditorConfig(itemId, serverId) {
|
||||
|
||||
const apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
if (itemId) {
|
||||
return apiClient.getJSON(apiClient.getUrl('Items/' + itemId + '/MetadataEditor'));
|
||||
@@ -421,13 +389,11 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function populateCountries(select, allCountries) {
|
||||
|
||||
let html = '';
|
||||
|
||||
html += "<option value=''></option>";
|
||||
|
||||
for (let i = 0, length = allCountries.length; i < length; i++) {
|
||||
|
||||
const culture = allCountries[i];
|
||||
|
||||
html += "<option value='" + culture.TwoLetterISORegionName + "'>" + culture.DisplayName + '</option>';
|
||||
@@ -437,13 +403,11 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function populateLanguages(select, languages) {
|
||||
|
||||
let html = '';
|
||||
|
||||
html += "<option value=''></option>";
|
||||
|
||||
for (let i = 0, length = languages.length; i < length; i++) {
|
||||
|
||||
const culture = languages[i];
|
||||
|
||||
html += "<option value='" + culture.TwoLetterISOLanguageName + "'>" + culture.DisplayName + '</option>';
|
||||
@@ -453,7 +417,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function renderContentTypeOptions(context, metadataInfo) {
|
||||
|
||||
if (!metadataInfo.ContentTypeOptions.length) {
|
||||
hideElement('#fldContentType', context);
|
||||
} else {
|
||||
@@ -461,9 +424,7 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
const html = metadataInfo.ContentTypeOptions.map(function (i) {
|
||||
|
||||
return '<option value="' + i.Value + '">' + i.Name + '</option>';
|
||||
|
||||
}).join('');
|
||||
|
||||
const selectEl = context.querySelector('#selectContentType');
|
||||
@@ -472,13 +433,11 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function loadExternalIds(context, item, externalIds) {
|
||||
|
||||
let html = '';
|
||||
|
||||
const providerIds = item.ProviderIds || {};
|
||||
|
||||
for (let i = 0, length = externalIds.length; i < length; i++) {
|
||||
|
||||
const idInfo = externalIds[i];
|
||||
|
||||
const id = 'txt1' + idInfo.Key;
|
||||
@@ -524,7 +483,6 @@ import 'flexStyles';
|
||||
function hideElement(selector, context, multiple) {
|
||||
context = context || document;
|
||||
if (typeof selector === 'string') {
|
||||
|
||||
const elements = multiple ? context.querySelectorAll(selector) : [context.querySelector(selector)];
|
||||
|
||||
Array.prototype.forEach.call(elements, function (el) {
|
||||
@@ -543,7 +501,6 @@ import 'flexStyles';
|
||||
function showElement(selector, context, multiple) {
|
||||
context = context || document;
|
||||
if (typeof selector === 'string') {
|
||||
|
||||
const elements = multiple ? context.querySelectorAll(selector) : [context.querySelector(selector)];
|
||||
|
||||
Array.prototype.forEach.call(elements, function (el) {
|
||||
@@ -745,7 +702,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function fillItemInfo(context, item, parentalRatingOptions) {
|
||||
|
||||
let select = context.querySelector('#selectOfficialRating');
|
||||
|
||||
populateRatings(parentalRatingOptions, select, item.OfficialRating);
|
||||
@@ -867,7 +823,6 @@ import 'flexStyles';
|
||||
context.querySelector('#selectCountry').value = item.PreferredMetadataCountryCode || '';
|
||||
|
||||
if (item.RunTimeTicks) {
|
||||
|
||||
const minutes = item.RunTimeTicks / 600000000;
|
||||
|
||||
context.querySelector('#txtSeriesRuntime').value = Math.round(minutes);
|
||||
@@ -877,7 +832,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function populateRatings(allParentalRatings, select, currentValue) {
|
||||
|
||||
let html = '';
|
||||
|
||||
html += "<option value=''></option>";
|
||||
@@ -888,7 +842,6 @@ import 'flexStyles';
|
||||
let currentValueFound = false;
|
||||
|
||||
for (let i = 0, length = allParentalRatings.length; i < length; i++) {
|
||||
|
||||
rating = allParentalRatings[i];
|
||||
|
||||
ratings.push({ Name: rating.Name, Value: rating.Name });
|
||||
@@ -903,7 +856,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
for (let i = 0, length = ratings.length; i < length; i++) {
|
||||
|
||||
rating = ratings[i];
|
||||
|
||||
html += "<option value='" + rating.Value + "'>" + rating.Name + '</option>';
|
||||
@@ -922,7 +874,6 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function populateListView(list, items, sortCallback) {
|
||||
|
||||
items = items || [];
|
||||
if (typeof (sortCallback) === 'undefined') {
|
||||
items.sort(function (a, b) {
|
||||
@@ -954,14 +905,12 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function populatePeople(context, people) {
|
||||
|
||||
let lastType = '';
|
||||
const lastType = '';
|
||||
let html = '';
|
||||
|
||||
const elem = context.querySelector('#peopleList');
|
||||
|
||||
for (let i = 0, length = people.length; i < length; i++) {
|
||||
|
||||
const person = people[i];
|
||||
|
||||
html += '<div class="listItem">';
|
||||
@@ -991,10 +940,8 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function getLockedFieldsHtml(fields, currentFields) {
|
||||
|
||||
let html = '';
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
|
||||
const field = fields[i];
|
||||
const name = field.name;
|
||||
const value = field.value || field.name;
|
||||
@@ -1041,11 +988,9 @@ import 'flexStyles';
|
||||
}
|
||||
|
||||
function reload(context, itemId, serverId) {
|
||||
|
||||
loading.show();
|
||||
|
||||
Promise.all([getItem(itemId, serverId), getEditorConfig(itemId, serverId)]).then(function (responses) {
|
||||
|
||||
const item = responses[0];
|
||||
metadataEditorInfo = responses[1];
|
||||
|
||||
@@ -1122,7 +1067,7 @@ import 'flexStyles';
|
||||
|
||||
currentContext = dlg;
|
||||
|
||||
init(dlg, connectionManager.getApiClient(serverId));
|
||||
init(dlg, window.connectionManager.getApiClient(serverId));
|
||||
|
||||
reload(dlg, itemId, serverId);
|
||||
});
|
||||
@@ -1137,7 +1082,6 @@ import 'flexStyles';
|
||||
|
||||
embed: function (elem, itemId, serverId) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
loading.show();
|
||||
|
||||
import('text!./metadataEditor.template.html').then(({default: template}) => {
|
||||
@@ -1150,7 +1094,7 @@ import 'flexStyles';
|
||||
|
||||
currentContext = elem;
|
||||
|
||||
init(elem, connectionManager.getApiClient(serverId));
|
||||
init(elem, window.connectionManager.getApiClient(serverId));
|
||||
reload(elem, itemId, serverId);
|
||||
|
||||
focusManager.autoFocus(elem);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import require from 'require';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-input';
|
||||
import 'emby-select';
|
||||
@@ -18,9 +17,7 @@ import 'css!./../formdialog';
|
||||
|
||||
function show(person) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
import('text!./personEditor.template.html').then(({default: template}) => {
|
||||
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
@@ -54,7 +51,6 @@ import 'css!./../formdialog';
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
|
||||
}
|
||||
@@ -67,7 +63,6 @@ import 'css!./../formdialog';
|
||||
});
|
||||
|
||||
dlg.querySelector('.selectPersonType').addEventListener('change', function (e) {
|
||||
|
||||
if (this.value === 'Actor') {
|
||||
dlg.querySelector('.fldRole').classList.remove('hide');
|
||||
} else {
|
||||
@@ -76,12 +71,10 @@ import 'css!./../formdialog';
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
dlg.querySelector('form').addEventListener('submit', function (e) {
|
||||
|
||||
submitted = true;
|
||||
|
||||
person.Name = dlg.querySelector('.txtPersonName', dlg).value;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import browser from 'browser';
|
||||
import appHost from 'apphost';
|
||||
import loading from 'loading';
|
||||
import connectionManager from 'connectionManager';
|
||||
import globalize from 'globalize';
|
||||
import dom from 'dom';
|
||||
import 'css!./multiSelect';
|
||||
@@ -13,10 +12,8 @@ import 'css!./multiSelect';
|
||||
let currentSelectionCommandsPanel;
|
||||
|
||||
function hideSelections() {
|
||||
|
||||
const selectionCommandsPanel = currentSelectionCommandsPanel;
|
||||
if (selectionCommandsPanel) {
|
||||
|
||||
selectionCommandsPanel.parentNode.removeChild(selectionCommandsPanel);
|
||||
currentSelectionCommandsPanel = null;
|
||||
|
||||
@@ -24,7 +21,6 @@ import 'css!./multiSelect';
|
||||
selectedElements = [];
|
||||
const elems = document.querySelectorAll('.itemSelectionPanel');
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
const parent = elems[i].parentNode;
|
||||
parent.removeChild(elems[i]);
|
||||
parent.classList.remove('withMultiSelect');
|
||||
@@ -33,13 +29,11 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
function onItemSelectionPanelClick(e, itemSelectionPanel) {
|
||||
|
||||
// toggle the checkbox, if it wasn't clicked on
|
||||
if (!dom.parentWithClass(e.target, 'chkItemSelect')) {
|
||||
const chkItemSelect = itemSelectionPanel.querySelector('.chkItemSelect');
|
||||
|
||||
if (chkItemSelect) {
|
||||
|
||||
if (chkItemSelect.classList.contains('checkedInitial')) {
|
||||
chkItemSelect.classList.remove('checkedInitial');
|
||||
} else {
|
||||
@@ -56,11 +50,9 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
function updateItemSelection(chkItemSelect, selected) {
|
||||
|
||||
const id = dom.parentWithAttribute(chkItemSelect, 'data-id').getAttribute('data-id');
|
||||
|
||||
if (selected) {
|
||||
|
||||
const current = selectedItems.filter(i => {
|
||||
return i === id;
|
||||
});
|
||||
@@ -69,7 +61,6 @@ import 'css!./multiSelect';
|
||||
selectedItems.push(id);
|
||||
selectedElements.push(chkItemSelect);
|
||||
}
|
||||
|
||||
} else {
|
||||
selectedItems = selectedItems.filter(i => {
|
||||
return i !== id;
|
||||
@@ -94,11 +85,9 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
function showSelection(item, isChecked) {
|
||||
|
||||
let itemSelectionPanel = item.querySelector('.itemSelectionPanel');
|
||||
|
||||
if (!itemSelectionPanel) {
|
||||
|
||||
itemSelectionPanel = document.createElement('div');
|
||||
itemSelectionPanel.classList.add('itemSelectionPanel');
|
||||
|
||||
@@ -120,11 +109,9 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
function showSelectionCommands() {
|
||||
|
||||
let selectionCommandsPanel = currentSelectionCommandsPanel;
|
||||
|
||||
if (!selectionCommandsPanel) {
|
||||
|
||||
selectionCommandsPanel = document.createElement('div');
|
||||
selectionCommandsPanel.classList.add('selectionCommandsPanel');
|
||||
|
||||
@@ -150,9 +137,7 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
function alertText(options) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert(options).then(resolve, resolve);
|
||||
});
|
||||
@@ -160,9 +145,7 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
function deleteItems(apiClient, itemIds) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let msg = globalize.translate('ConfirmDeleteItem');
|
||||
let title = globalize.translate('HeaderDeleteItem');
|
||||
|
||||
@@ -172,28 +155,23 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
import('confirm').then(({default: confirm}) => {
|
||||
|
||||
confirm(msg, title).then(() => {
|
||||
const promises = itemIds.map(itemId => {
|
||||
apiClient.deleteItem(itemId);
|
||||
});
|
||||
|
||||
Promise.all(promises).then(resolve, () => {
|
||||
|
||||
alertText(globalize.translate('ErrorDeletingItem')).then(reject, reject);
|
||||
});
|
||||
}, reject);
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function showMenuForSelectedItems(e) {
|
||||
|
||||
const apiClient = connectionManager.currentApiClient();
|
||||
const apiClient = window.connectionManager.currentApiClient();
|
||||
|
||||
apiClient.getCurrentUser().then(user => {
|
||||
|
||||
const menuItems = [];
|
||||
|
||||
menuItems.push({
|
||||
@@ -219,7 +197,7 @@ import 'css!./multiSelect';
|
||||
|
||||
if (user.Policy.EnableContentDownloading && appHost.supports('filedownload')) {
|
||||
menuItems.push({
|
||||
name: globalize.translate('ButtonDownload'),
|
||||
name: globalize.translate('Download'),
|
||||
id: 'download',
|
||||
icon: 'file_download'
|
||||
});
|
||||
@@ -317,17 +295,14 @@ import 'css!./multiSelect';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function dispatchNeedsRefresh() {
|
||||
|
||||
const elems = [];
|
||||
|
||||
[].forEach.call(selectedElements, i => {
|
||||
|
||||
const container = dom.parentWithAttribute(i, 'is', 'emby-itemscontainer');
|
||||
|
||||
if (container && !elems.includes(container)) {
|
||||
@@ -341,9 +316,7 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
function combineVersions(apiClient, selection) {
|
||||
|
||||
if (selection.length < 2) {
|
||||
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert({
|
||||
|
||||
@@ -361,7 +334,6 @@ import 'css!./multiSelect';
|
||||
url: apiClient.getUrl('Videos/MergeVersions', { Ids: selection.join(',') })
|
||||
|
||||
}).then(() => {
|
||||
|
||||
loading.hide();
|
||||
hideSelections();
|
||||
dispatchNeedsRefresh();
|
||||
@@ -369,7 +341,6 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
function showSelections(initialCard) {
|
||||
|
||||
import('emby-checkbox').then(() => {
|
||||
const cards = document.querySelectorAll('.card');
|
||||
for (let i = 0, length = cards.length; i < length; i++) {
|
||||
@@ -382,11 +353,9 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
function onContainerClick(e) {
|
||||
|
||||
const target = e.target;
|
||||
|
||||
if (selectedItems.length) {
|
||||
|
||||
const card = dom.parentWithClass(target, 'card');
|
||||
if (card) {
|
||||
const itemSelectionPanel = card.querySelector('.itemSelectionPanel');
|
||||
@@ -404,17 +373,14 @@ import 'css!./multiSelect';
|
||||
document.addEventListener('viewbeforehide', hideSelections);
|
||||
|
||||
export default function (options) {
|
||||
|
||||
const self = this;
|
||||
|
||||
const container = options.container;
|
||||
|
||||
function onTapHold(e) {
|
||||
|
||||
const card = dom.parentWithClass(e.target, 'card');
|
||||
|
||||
if (card) {
|
||||
|
||||
showSelections(card);
|
||||
}
|
||||
|
||||
@@ -427,7 +393,6 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
function getTouches(e) {
|
||||
|
||||
return e.changedTouches || e.targetTouches || e.touches;
|
||||
}
|
||||
|
||||
@@ -436,7 +401,6 @@ import 'css!./multiSelect';
|
||||
let touchStartX;
|
||||
let touchStartY;
|
||||
function onTouchStart(e) {
|
||||
|
||||
const touch = getTouches(e)[0];
|
||||
touchTarget = null;
|
||||
touchStartX = 0;
|
||||
@@ -451,7 +415,6 @@ import 'css!./multiSelect';
|
||||
const card = dom.parentWithClass(element, 'card');
|
||||
|
||||
if (card) {
|
||||
|
||||
if (touchStartTimeout) {
|
||||
clearTimeout(touchStartTimeout);
|
||||
touchStartTimeout = null;
|
||||
@@ -465,7 +428,6 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
function onTouchMove(e) {
|
||||
|
||||
if (touchTarget) {
|
||||
const touch = getTouches(e)[0];
|
||||
let deltaX;
|
||||
@@ -487,12 +449,10 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
function onTouchEnd(e) {
|
||||
|
||||
onMouseOut(e);
|
||||
}
|
||||
|
||||
function onMouseDown(e) {
|
||||
|
||||
if (touchStartTimeout) {
|
||||
clearTimeout(touchStartTimeout);
|
||||
touchStartTimeout = null;
|
||||
@@ -503,7 +463,6 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
function onMouseOut(e) {
|
||||
|
||||
if (touchStartTimeout) {
|
||||
clearTimeout(touchStartTimeout);
|
||||
touchStartTimeout = null;
|
||||
@@ -512,7 +471,6 @@ import 'css!./multiSelect';
|
||||
}
|
||||
|
||||
function onTouchStartTimerFired() {
|
||||
|
||||
if (!touchTarget) {
|
||||
return;
|
||||
}
|
||||
@@ -521,13 +479,11 @@ import 'css!./multiSelect';
|
||||
touchTarget = null;
|
||||
|
||||
if (card) {
|
||||
|
||||
showSelections(card);
|
||||
}
|
||||
}
|
||||
|
||||
function initTapHold(element) {
|
||||
|
||||
// mobile safari doesn't allow contextmenu override
|
||||
if (browser.touch && !browser.safari) {
|
||||
element.addEventListener('contextmenu', onTapHold);
|
||||
@@ -565,7 +521,6 @@ import 'css!./multiSelect';
|
||||
self.onContainerClick = onContainerClick;
|
||||
|
||||
self.destroy = () => {
|
||||
|
||||
container.removeEventListener('click', onContainerClick);
|
||||
container.removeEventListener('contextmenu', onTapHold);
|
||||
|
||||
@@ -580,10 +535,6 @@ import 'css!./multiSelect';
|
||||
dom.removeEventListener(element, 'touchend', onTouchEnd, {
|
||||
passive: true
|
||||
});
|
||||
// this fires in safari due to magnifying class
|
||||
//dom.removeEventListener(element, "touchcancel", onTouchEnd, {
|
||||
// passive: true
|
||||
//});
|
||||
dom.removeEventListener(element, 'mousedown', onMouseDown, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
@@ -1,192 +1,181 @@
|
||||
define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'require'], function (serverNotifications, playbackManager, events, globalize, require) {
|
||||
'use strict';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import playbackManager from 'playbackManager';
|
||||
import events from 'events';
|
||||
import globalize from 'globalize';
|
||||
|
||||
function onOneDocumentClick() {
|
||||
document.removeEventListener('click', onOneDocumentClick);
|
||||
document.removeEventListener('keydown', onOneDocumentClick);
|
||||
function onOneDocumentClick() {
|
||||
document.removeEventListener('click', onOneDocumentClick);
|
||||
document.removeEventListener('keydown', onOneDocumentClick);
|
||||
|
||||
// don't request notification permissions if they're already granted or denied
|
||||
if (window.Notification && window.Notification.permission === 'default') {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
Notification.requestPermission();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', onOneDocumentClick);
|
||||
document.addEventListener('keydown', onOneDocumentClick);
|
||||
|
||||
var serviceWorkerRegistration;
|
||||
|
||||
function closeAfter(notification, timeoutMs) {
|
||||
setTimeout(function () {
|
||||
if (notification.close) {
|
||||
notification.close();
|
||||
} else if (notification.cancel) {
|
||||
notification.cancel();
|
||||
}
|
||||
}, timeoutMs);
|
||||
}
|
||||
|
||||
function resetRegistration() {
|
||||
// don't request notification permissions if they're already granted or denied
|
||||
if (window.Notification && window.Notification.permission === 'default') {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
var serviceWorker = navigator.serviceWorker;
|
||||
if (serviceWorker) {
|
||||
serviceWorker.ready.then(function (registration) {
|
||||
serviceWorkerRegistration = registration;
|
||||
});
|
||||
Notification.requestPermission();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', onOneDocumentClick);
|
||||
document.addEventListener('keydown', onOneDocumentClick);
|
||||
|
||||
let serviceWorkerRegistration;
|
||||
|
||||
function closeAfter(notification, timeoutMs) {
|
||||
setTimeout(function () {
|
||||
if (notification.close) {
|
||||
notification.close();
|
||||
} else if (notification.cancel) {
|
||||
notification.cancel();
|
||||
}
|
||||
}, timeoutMs);
|
||||
}
|
||||
|
||||
function resetRegistration() {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
let serviceWorker = navigator.serviceWorker;
|
||||
if (serviceWorker) {
|
||||
serviceWorker.ready.then(function (registration) {
|
||||
serviceWorkerRegistration = registration;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
resetRegistration();
|
||||
|
||||
function showPersistentNotification(title, options, timeoutMs) {
|
||||
serviceWorkerRegistration.showNotification(title, options);
|
||||
}
|
||||
|
||||
function showNonPersistentNotification(title, options, timeoutMs) {
|
||||
try {
|
||||
let notif = new Notification(title, options); /* eslint-disable-line compat/compat */
|
||||
|
||||
if (notif.show) {
|
||||
notif.show();
|
||||
}
|
||||
|
||||
if (timeoutMs) {
|
||||
closeAfter(notif, timeoutMs);
|
||||
}
|
||||
} catch (err) {
|
||||
if (options.actions) {
|
||||
options.actions = [];
|
||||
showNonPersistentNotification(title, options, timeoutMs);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showNotification(options, timeoutMs, apiClient) {
|
||||
let title = options.title;
|
||||
|
||||
options.data = options.data || {};
|
||||
options.data.serverId = apiClient.serverInfo().Id;
|
||||
options.icon = options.icon || getIconUrl();
|
||||
options.badge = options.badge || getIconUrl('badge.png');
|
||||
|
||||
resetRegistration();
|
||||
|
||||
function showPersistentNotification(title, options, timeoutMs) {
|
||||
serviceWorkerRegistration.showNotification(title, options);
|
||||
if (serviceWorkerRegistration) {
|
||||
showPersistentNotification(title, options, timeoutMs);
|
||||
return;
|
||||
}
|
||||
|
||||
function showNonPersistentNotification(title, options, timeoutMs) {
|
||||
showNonPersistentNotification(title, options, timeoutMs);
|
||||
}
|
||||
|
||||
try {
|
||||
var notif = new Notification(title, options); /* eslint-disable-line compat/compat */
|
||||
|
||||
if (notif.show) {
|
||||
notif.show();
|
||||
}
|
||||
|
||||
if (timeoutMs) {
|
||||
closeAfter(notif, timeoutMs);
|
||||
}
|
||||
} catch (err) {
|
||||
if (options.actions) {
|
||||
options.actions = [];
|
||||
showNonPersistentNotification(title, options, timeoutMs);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
function showNewItemNotification(item, apiClient) {
|
||||
if (playbackManager.isPlayingLocally(['Video'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
function showNotification(options, timeoutMs, apiClient) {
|
||||
let body = item.Name;
|
||||
|
||||
var title = options.title;
|
||||
|
||||
options.data = options.data || {};
|
||||
options.data.serverId = apiClient.serverInfo().Id;
|
||||
options.icon = options.icon || getIconUrl();
|
||||
options.badge = options.badge || getIconUrl('badge.png');
|
||||
|
||||
resetRegistration();
|
||||
|
||||
if (serviceWorkerRegistration) {
|
||||
showPersistentNotification(title, options, timeoutMs);
|
||||
return;
|
||||
}
|
||||
|
||||
showNonPersistentNotification(title, options, timeoutMs);
|
||||
if (item.SeriesName) {
|
||||
body = item.SeriesName + ' - ' + body;
|
||||
}
|
||||
|
||||
function showNewItemNotification(item, apiClient) {
|
||||
let notification = {
|
||||
title: 'New ' + item.Type,
|
||||
body: body,
|
||||
vibrate: true,
|
||||
tag: 'newItem' + item.Id,
|
||||
data: {}
|
||||
};
|
||||
|
||||
if (playbackManager.isPlayingLocally(['Video'])) {
|
||||
return;
|
||||
}
|
||||
let imageTags = item.ImageTags || {};
|
||||
|
||||
var body = item.Name;
|
||||
|
||||
if (item.SeriesName) {
|
||||
body = item.SeriesName + ' - ' + body;
|
||||
}
|
||||
|
||||
var notification = {
|
||||
title: 'New ' + item.Type,
|
||||
body: body,
|
||||
vibrate: true,
|
||||
tag: 'newItem' + item.Id,
|
||||
data: {
|
||||
//options: {
|
||||
// url: LibraryBrowser.getHref(item)
|
||||
//}
|
||||
}
|
||||
};
|
||||
|
||||
var imageTags = item.ImageTags || {};
|
||||
|
||||
if (imageTags.Primary) {
|
||||
|
||||
notification.icon = apiClient.getScaledImageUrl(item.Id, {
|
||||
width: 80,
|
||||
tag: imageTags.Primary,
|
||||
type: 'Primary'
|
||||
});
|
||||
}
|
||||
|
||||
showNotification(notification, 15000, apiClient);
|
||||
}
|
||||
|
||||
function onLibraryChanged(data, apiClient) {
|
||||
|
||||
var newItems = data.ItemsAdded;
|
||||
|
||||
if (!newItems.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't put a massive number of Id's onto the query string
|
||||
if (newItems.length > 12) {
|
||||
newItems.length = 12;
|
||||
}
|
||||
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), {
|
||||
|
||||
Recursive: true,
|
||||
Limit: 3,
|
||||
Filters: 'IsNotFolder',
|
||||
SortBy: 'DateCreated',
|
||||
SortOrder: 'Descending',
|
||||
Ids: newItems.join(','),
|
||||
MediaTypes: 'Audio,Video',
|
||||
EnableTotalRecordCount: false
|
||||
|
||||
}).then(function (result) {
|
||||
|
||||
var items = result.Items;
|
||||
|
||||
for (var i = 0, length = items.length ; i < length; i++) {
|
||||
|
||||
showNewItemNotification(items[i], apiClient);
|
||||
}
|
||||
if (imageTags.Primary) {
|
||||
notification.icon = apiClient.getScaledImageUrl(item.Id, {
|
||||
width: 80,
|
||||
tag: imageTags.Primary,
|
||||
type: 'Primary'
|
||||
});
|
||||
}
|
||||
|
||||
function getIconUrl(name) {
|
||||
name = name || 'notificationicon.png';
|
||||
return require.toUrl('.').split('?')[0] + '/' + name;
|
||||
showNotification(notification, 15000, apiClient);
|
||||
}
|
||||
|
||||
function onLibraryChanged(data, apiClient) {
|
||||
let newItems = data.ItemsAdded;
|
||||
|
||||
if (!newItems.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
function showPackageInstallNotification(apiClient, installation, status) {
|
||||
// Don't put a massive number of Id's onto the query string
|
||||
if (newItems.length > 12) {
|
||||
newItems.length = 12;
|
||||
}
|
||||
|
||||
apiClient.getCurrentUser().then(function (user) {
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), {
|
||||
|
||||
if (!user.Policy.IsAdministrator) {
|
||||
return;
|
||||
}
|
||||
Recursive: true,
|
||||
Limit: 3,
|
||||
Filters: 'IsNotFolder',
|
||||
SortBy: 'DateCreated',
|
||||
SortOrder: 'Descending',
|
||||
Ids: newItems.join(','),
|
||||
MediaTypes: 'Audio,Video',
|
||||
EnableTotalRecordCount: false
|
||||
|
||||
var notification = {
|
||||
tag: 'install' + installation.Id,
|
||||
data: {}
|
||||
};
|
||||
}).then(function (result) {
|
||||
let items = result.Items;
|
||||
|
||||
if (status === 'completed') {
|
||||
notification.title = globalize.translate('PackageInstallCompleted', installation.Name, installation.Version);
|
||||
notification.vibrate = true;
|
||||
} else if (status === 'cancelled') {
|
||||
notification.title = globalize.translate('PackageInstallCancelled', installation.Name, installation.Version);
|
||||
} else if (status === 'failed') {
|
||||
notification.title = globalize.translate('PackageInstallFailed', installation.Name, installation.Version);
|
||||
notification.vibrate = true;
|
||||
} else if (status === 'progress') {
|
||||
notification.title = globalize.translate('InstallingPackage', installation.Name, installation.Version);
|
||||
for (const item of items) {
|
||||
showNewItemNotification(item, apiClient);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
notification.actions =
|
||||
function getIconUrl(name) {
|
||||
name = name || 'notificationicon.png';
|
||||
return './components/notifications/' + name;
|
||||
}
|
||||
|
||||
function showPackageInstallNotification(apiClient, installation, status) {
|
||||
apiClient.getCurrentUser().then(function (user) {
|
||||
if (!user.Policy.IsAdministrator) {
|
||||
return;
|
||||
}
|
||||
|
||||
let notification = {
|
||||
tag: 'install' + installation.Id,
|
||||
data: {}
|
||||
};
|
||||
|
||||
if (status === 'completed') {
|
||||
notification.title = globalize.translate('PackageInstallCompleted', installation.Name, installation.Version);
|
||||
notification.vibrate = true;
|
||||
} else if (status === 'cancelled') {
|
||||
notification.title = globalize.translate('PackageInstallCancelled', installation.Name, installation.Version);
|
||||
} else if (status === 'failed') {
|
||||
notification.title = globalize.translate('PackageInstallFailed', installation.Name, installation.Version);
|
||||
notification.vibrate = true;
|
||||
} else if (status === 'progress') {
|
||||
notification.title = globalize.translate('InstallingPackage', installation.Name, installation.Version);
|
||||
|
||||
notification.actions =
|
||||
[
|
||||
{
|
||||
action: 'cancel-install',
|
||||
@@ -195,77 +184,75 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
|
||||
}
|
||||
];
|
||||
|
||||
notification.data.id = installation.id;
|
||||
}
|
||||
notification.data.id = installation.id;
|
||||
}
|
||||
|
||||
if (status === 'progress') {
|
||||
if (status === 'progress') {
|
||||
let percentComplete = Math.round(installation.PercentComplete || 0);
|
||||
|
||||
var percentComplete = Math.round(installation.PercentComplete || 0);
|
||||
notification.body = percentComplete + '% complete.';
|
||||
}
|
||||
|
||||
notification.body = percentComplete + '% complete.';
|
||||
}
|
||||
let timeout = status === 'cancelled' ? 5000 : 0;
|
||||
|
||||
var timeout = status === 'cancelled' ? 5000 : 0;
|
||||
|
||||
showNotification(notification, timeout, apiClient);
|
||||
});
|
||||
}
|
||||
|
||||
events.on(serverNotifications, 'LibraryChanged', function (e, apiClient, data) {
|
||||
onLibraryChanged(data, apiClient);
|
||||
showNotification(notification, timeout, apiClient);
|
||||
});
|
||||
}
|
||||
|
||||
events.on(serverNotifications, 'PackageInstallationCompleted', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'completed');
|
||||
});
|
||||
events.on(serverNotifications, 'LibraryChanged', function (e, apiClient, data) {
|
||||
onLibraryChanged(data, apiClient);
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'PackageInstallationFailed', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'failed');
|
||||
});
|
||||
events.on(serverNotifications, 'PackageInstallationCompleted', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'completed');
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'PackageInstallationCancelled', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'cancelled');
|
||||
});
|
||||
events.on(serverNotifications, 'PackageInstallationFailed', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'failed');
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'PackageInstalling', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'progress');
|
||||
});
|
||||
events.on(serverNotifications, 'PackageInstallationCancelled', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'cancelled');
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'ServerShuttingDown', function (e, apiClient, data) {
|
||||
var serverId = apiClient.serverInfo().Id;
|
||||
var notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('ServerNameIsShuttingDown', apiClient.serverInfo().Name)
|
||||
};
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
events.on(serverNotifications, 'PackageInstalling', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'progress');
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'ServerRestarting', function (e, apiClient, data) {
|
||||
var serverId = apiClient.serverInfo().Id;
|
||||
var notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('ServerNameIsRestarting', apiClient.serverInfo().Name)
|
||||
};
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
events.on(serverNotifications, 'ServerShuttingDown', function (e, apiClient, data) {
|
||||
let serverId = apiClient.serverInfo().Id;
|
||||
let notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('ServerNameIsShuttingDown', apiClient.serverInfo().Name)
|
||||
};
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'RestartRequired', function (e, apiClient) {
|
||||
events.on(serverNotifications, 'ServerRestarting', function (e, apiClient, data) {
|
||||
let serverId = apiClient.serverInfo().Id;
|
||||
let notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('ServerNameIsRestarting', apiClient.serverInfo().Name)
|
||||
};
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
|
||||
var serverId = apiClient.serverInfo().Id;
|
||||
var notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('PleaseRestartServerName', apiClient.serverInfo().Name)
|
||||
};
|
||||
events.on(serverNotifications, 'RestartRequired', function (e, apiClient) {
|
||||
let serverId = apiClient.serverInfo().Id;
|
||||
let notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('PleaseRestartServerName', apiClient.serverInfo().Name)
|
||||
};
|
||||
|
||||
notification.actions =
|
||||
notification.actions =
|
||||
[
|
||||
{
|
||||
action: 'restart',
|
||||
title: globalize.translate('ButtonRestart'),
|
||||
title: globalize.translate('Restart'),
|
||||
icon: getIconUrl()
|
||||
}
|
||||
];
|
||||
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import require from 'require';
|
||||
import datetime from 'datetime';
|
||||
import itemHelper from 'itemHelper';
|
||||
import events from 'events';
|
||||
import browser from 'browser';
|
||||
import imageLoader from 'imageLoader';
|
||||
@@ -9,7 +7,6 @@ import playbackManager from 'playbackManager';
|
||||
import nowPlayingHelper from 'nowPlayingHelper';
|
||||
import appHost from 'apphost';
|
||||
import dom from 'dom';
|
||||
import connectionManager from 'connectionManager';
|
||||
import itemContextMenu from 'itemContextMenu';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-ratingbutton';
|
||||
@@ -39,7 +36,6 @@ import 'emby-ratingbutton';
|
||||
let isVisibilityAllowed = true;
|
||||
|
||||
function getNowPlayingBarHtml() {
|
||||
|
||||
let html = '';
|
||||
|
||||
html += '<div class="nowPlayingBar hide nowPlayingBar-hidden">';
|
||||
@@ -99,12 +95,10 @@ import 'emby-ratingbutton';
|
||||
}
|
||||
|
||||
function onSlideDownComplete() {
|
||||
|
||||
this.classList.add('hide');
|
||||
}
|
||||
|
||||
function slideDown(elem) {
|
||||
|
||||
// trigger reflow
|
||||
void elem.offsetWidth;
|
||||
|
||||
@@ -116,7 +110,6 @@ import 'emby-ratingbutton';
|
||||
}
|
||||
|
||||
function slideUp(elem) {
|
||||
|
||||
dom.removeEventListener(elem, dom.whichTransitionEvent(), onSlideDownComplete, {
|
||||
once: true
|
||||
});
|
||||
@@ -134,7 +127,6 @@ import 'emby-ratingbutton';
|
||||
}
|
||||
|
||||
function bindEvents(elem) {
|
||||
|
||||
currentTimeElement = elem.querySelector('.nowPlayingBarCurrentTime');
|
||||
nowPlayingImageElement = elem.querySelector('.nowPlayingImage');
|
||||
nowPlayingTextElement = elem.querySelector('.nowPlayingBarText');
|
||||
@@ -147,15 +139,12 @@ import 'emby-ratingbutton';
|
||||
volumeSliderContainer = elem.querySelector('.nowPlayingBarVolumeSliderContainer');
|
||||
|
||||
muteButton.addEventListener('click', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
playbackManager.toggleMute(currentPlayer);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
elem.querySelector('.stopButton').addEventListener('click', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
playbackManager.stop(currentPlayer);
|
||||
}
|
||||
@@ -166,7 +155,6 @@ import 'emby-ratingbutton';
|
||||
});
|
||||
|
||||
elem.querySelector('.nextTrackButton').addEventListener('click', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
playbackManager.nextTrack(currentPlayer);
|
||||
}
|
||||
@@ -226,18 +214,14 @@ import 'emby-ratingbutton';
|
||||
});
|
||||
|
||||
positionSlider.addEventListener('change', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
|
||||
const newPercent = parseFloat(this.value);
|
||||
|
||||
playbackManager.seekPercent(newPercent, currentPlayer);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
positionSlider.getBubbleText = function (value) {
|
||||
|
||||
const state = lastPlayerState;
|
||||
|
||||
if (!state || !state.NowPlayingItem || !currentRuntimeTicks) {
|
||||
@@ -252,7 +236,6 @@ import 'emby-ratingbutton';
|
||||
};
|
||||
|
||||
elem.addEventListener('click', function (e) {
|
||||
|
||||
if (!dom.parentWithTag(e.target, ['BUTTON', 'INPUT'])) {
|
||||
showRemoteControl();
|
||||
}
|
||||
@@ -260,7 +243,6 @@ import 'emby-ratingbutton';
|
||||
}
|
||||
|
||||
function showRemoteControl() {
|
||||
|
||||
import('appRouter').then(({default: appRouter}) => {
|
||||
appRouter.showNowPlaying();
|
||||
});
|
||||
@@ -268,7 +250,6 @@ import 'emby-ratingbutton';
|
||||
|
||||
let nowPlayingBarElement;
|
||||
function getNowPlayingBar() {
|
||||
|
||||
if (nowPlayingBarElement) {
|
||||
return Promise.resolve(nowPlayingBarElement);
|
||||
}
|
||||
@@ -329,7 +310,6 @@ import 'emby-ratingbutton';
|
||||
}
|
||||
|
||||
function updatePlayerStateInternal(event, state, player) {
|
||||
|
||||
showNowPlayingBar();
|
||||
|
||||
lastPlayerState = state;
|
||||
@@ -417,7 +397,6 @@ import 'emby-ratingbutton';
|
||||
}
|
||||
|
||||
function updatePlayerVolumeState(isMuted, volumeLevel) {
|
||||
|
||||
const supportedCommands = currentPlayerSupportedCommands;
|
||||
|
||||
let showMuteButton = true;
|
||||
@@ -448,7 +427,6 @@ import 'emby-ratingbutton';
|
||||
|
||||
// See bindEvents for why this is necessary
|
||||
if (volumeSlider) {
|
||||
|
||||
volumeSliderContainer.classList.toggle('hide', !showVolumeSlider);
|
||||
|
||||
if (!volumeSlider.dragging) {
|
||||
@@ -458,7 +436,6 @@ import 'emby-ratingbutton';
|
||||
}
|
||||
|
||||
function seriesImageUrl(item, options) {
|
||||
|
||||
if (!item) {
|
||||
throw new Error('item cannot be null!');
|
||||
}
|
||||
@@ -471,28 +448,23 @@ import 'emby-ratingbutton';
|
||||
options.type = options.type || 'Primary';
|
||||
|
||||
if (options.type === 'Primary') {
|
||||
|
||||
if (item.SeriesPrimaryImageTag) {
|
||||
|
||||
options.tag = item.SeriesPrimaryImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.type === 'Thumb') {
|
||||
|
||||
if (item.SeriesThumbImageTag) {
|
||||
|
||||
options.tag = item.SeriesThumbImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
}
|
||||
if (item.ParentThumbImageTag) {
|
||||
|
||||
options.tag = item.ParentThumbImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,7 +472,6 @@ import 'emby-ratingbutton';
|
||||
}
|
||||
|
||||
function imageUrl(item, options) {
|
||||
|
||||
if (!item) {
|
||||
throw new Error('item cannot be null!');
|
||||
}
|
||||
@@ -509,15 +480,13 @@ import 'emby-ratingbutton';
|
||||
options.type = options.type || 'Primary';
|
||||
|
||||
if (item.ImageTags && item.ImageTags[options.type]) {
|
||||
|
||||
options.tag = item.ImageTags[options.type];
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options);
|
||||
}
|
||||
|
||||
if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
|
||||
options.tag = item.AlbumPrimaryImageTag;
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -525,26 +494,25 @@ import 'emby-ratingbutton';
|
||||
|
||||
let currentImgUrl;
|
||||
function updateNowPlayingInfo(state) {
|
||||
|
||||
const nowPlayingItem = state.NowPlayingItem;
|
||||
|
||||
const textLines = nowPlayingItem ? nowPlayingHelper.getNowPlayingNames(nowPlayingItem) : [];
|
||||
nowPlayingTextElement.innerHTML = '';
|
||||
if (textLines) {
|
||||
let itemText = document.createElement('div');
|
||||
let secondaryText = document.createElement('div');
|
||||
const itemText = document.createElement('div');
|
||||
const secondaryText = document.createElement('div');
|
||||
secondaryText.classList.add('nowPlayingBarSecondaryText');
|
||||
if (textLines.length > 1) {
|
||||
textLines[1].secondary = true;
|
||||
if (textLines[1].text) {
|
||||
let text = document.createElement('a');
|
||||
const text = document.createElement('a');
|
||||
text.innerHTML = textLines[1].text;
|
||||
secondaryText.appendChild(text);
|
||||
}
|
||||
}
|
||||
|
||||
if (textLines[0].text) {
|
||||
let text = document.createElement('a');
|
||||
const text = document.createElement('a');
|
||||
text.innerHTML = textLines[0].text;
|
||||
itemText.appendChild(text);
|
||||
}
|
||||
@@ -579,18 +547,17 @@ import 'emby-ratingbutton';
|
||||
|
||||
if (nowPlayingItem.Id) {
|
||||
if (isRefreshing) {
|
||||
|
||||
const apiClient = connectionManager.getApiClient(nowPlayingItem.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(nowPlayingItem.ServerId);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), nowPlayingItem.Id).then(function (item) {
|
||||
const userData = item.UserData || {};
|
||||
const likes = userData.Likes == null ? '' : userData.Likes;
|
||||
if (!layoutManager.mobile) {
|
||||
let contextButton = nowPlayingBarElement.querySelector('.btnToggleContextMenu');
|
||||
// We remove the previous event listener by replacing the item in each update event
|
||||
let contextButtonClone = contextButton.cloneNode(true);
|
||||
const contextButtonClone = contextButton.cloneNode(true);
|
||||
contextButton.parentNode.replaceChild(contextButtonClone, contextButton);
|
||||
contextButton = nowPlayingBarElement.querySelector('.btnToggleContextMenu');
|
||||
let options = {
|
||||
const options = {
|
||||
play: false,
|
||||
queue: false,
|
||||
clearQueue: true,
|
||||
@@ -632,10 +599,10 @@ import 'emby-ratingbutton';
|
||||
return;
|
||||
}
|
||||
|
||||
let shuffleMode = playbackManager.getQueueShuffleMode();
|
||||
let context = nowPlayingBarElement;
|
||||
const shuffleMode = playbackManager.getQueueShuffleMode();
|
||||
const context = nowPlayingBarElement;
|
||||
const cssClass = 'buttonActive';
|
||||
let toggleShuffleButton = context.querySelector('.btnShuffleQueue');
|
||||
const toggleShuffleButton = context.querySelector('.btnShuffleQueue');
|
||||
switch (shuffleMode) {
|
||||
case 'Shuffle':
|
||||
toggleShuffleButton.classList.add(cssClass);
|
||||
@@ -657,7 +624,6 @@ import 'emby-ratingbutton';
|
||||
}
|
||||
|
||||
function hideNowPlayingBar() {
|
||||
|
||||
isEnabled = false;
|
||||
|
||||
// Use a timeout to prevent the bar from hiding and showing quickly
|
||||
@@ -666,13 +632,11 @@ import 'emby-ratingbutton';
|
||||
// Don't call getNowPlayingBar here because we don't want to end up creating it just to hide it
|
||||
const elem = document.getElementsByClassName('nowPlayingBar')[0];
|
||||
if (elem) {
|
||||
|
||||
slideDown(elem);
|
||||
}
|
||||
}
|
||||
|
||||
function onPlaybackStopped(e, state) {
|
||||
|
||||
console.debug('nowplaying event: ' + e.type);
|
||||
const player = this;
|
||||
|
||||
@@ -688,7 +652,6 @@ import 'emby-ratingbutton';
|
||||
}
|
||||
|
||||
function onPlayPauseStateChanged(e) {
|
||||
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
@@ -698,7 +661,6 @@ import 'emby-ratingbutton';
|
||||
}
|
||||
|
||||
function onStateChanged(event, state) {
|
||||
|
||||
console.debug('nowplaying event: ' + event.type);
|
||||
const player = this;
|
||||
|
||||
@@ -725,7 +687,6 @@ import 'emby-ratingbutton';
|
||||
}
|
||||
|
||||
function onTimeUpdate(e) {
|
||||
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
@@ -733,18 +694,16 @@ import 'emby-ratingbutton';
|
||||
// Try to avoid hammering the document with changes
|
||||
const now = new Date().getTime();
|
||||
if ((now - lastUpdateTime) < 700) {
|
||||
|
||||
return;
|
||||
}
|
||||
lastUpdateTime = now;
|
||||
|
||||
const player = this;
|
||||
currentRuntimeTicks = playbackManager.duration(player);
|
||||
updateTimeDisplay(playbackManager.currentTime(player), currentRuntimeTicks, playbackManager.getBufferedRanges(player));
|
||||
updateTimeDisplay(playbackManager.currentTime(player) * 10000, currentRuntimeTicks, playbackManager.getBufferedRanges(player));
|
||||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
|
||||
const player = currentPlayer;
|
||||
|
||||
if (player) {
|
||||
@@ -764,7 +723,6 @@ import 'emby-ratingbutton';
|
||||
}
|
||||
|
||||
function onVolumeChanged(e) {
|
||||
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
@@ -775,14 +733,12 @@ import 'emby-ratingbutton';
|
||||
}
|
||||
|
||||
function refreshFromPlayer(player) {
|
||||
|
||||
const state = playbackManager.getPlayerState(player);
|
||||
|
||||
onStateChanged.call(player, { type: 'init' }, state);
|
||||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
|
||||
if (player === currentPlayer) {
|
||||
return;
|
||||
}
|
||||
@@ -815,16 +771,12 @@ import 'emby-ratingbutton';
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
|
||||
document.addEventListener('viewbeforeshow', function (e) {
|
||||
|
||||
if (!e.detail.options.enableMediaControl) {
|
||||
|
||||
if (isVisibilityAllowed) {
|
||||
isVisibilityAllowed = false;
|
||||
hideNowPlayingBar();
|
||||
}
|
||||
|
||||
} else if (!isVisibilityAllowed) {
|
||||
|
||||
isVisibilityAllowed = true;
|
||||
if (currentPlayer) {
|
||||
refreshFromPlayer(currentPlayer);
|
||||
|
||||
+111
-123
@@ -1,152 +1,140 @@
|
||||
define(['appSettings', 'pluginManager'], function (appSettings, pluginManager) {
|
||||
'use strict';
|
||||
import appSettings from 'appSettings';
|
||||
import pluginManager from 'pluginManager';
|
||||
/* eslint-disable indent */
|
||||
|
||||
var settingsKey = 'installedpackages1';
|
||||
class PackageManager {
|
||||
#packagesList = [];
|
||||
#settingsKey = 'installedpackages1';
|
||||
|
||||
function addPackage(packageManager, pkg) {
|
||||
init() {
|
||||
console.groupCollapsed('loading packages');
|
||||
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
|
||||
|
||||
packageManager.packagesList = packageManager.packagesList.filter(function (p) {
|
||||
return Promise.all(manifestUrls.map((url) => {
|
||||
return this.loadPackage(url);
|
||||
}))
|
||||
.then(() => {
|
||||
console.debug('finished loading packages');
|
||||
return Promise.resolve();
|
||||
})
|
||||
.catch(() => {
|
||||
return Promise.resolve();
|
||||
}).finally(() => {
|
||||
console.groupEnd('loading packages');
|
||||
});
|
||||
}
|
||||
|
||||
return p.name !== pkg.name;
|
||||
});
|
||||
get packages() {
|
||||
return this.#packagesList.slice(0);
|
||||
}
|
||||
|
||||
packageManager.packagesList.push(pkg);
|
||||
}
|
||||
install(url) {
|
||||
return this.loadPackage(url, true).then((pkg) => {
|
||||
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
|
||||
|
||||
function removeUrl(url) {
|
||||
|
||||
var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]');
|
||||
|
||||
manifestUrls = manifestUrls.filter(function (i) {
|
||||
return i !== url;
|
||||
});
|
||||
|
||||
appSettings.set(settingsKey, JSON.stringify(manifestUrls));
|
||||
}
|
||||
|
||||
function loadPackage(packageManager, url, throwError) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
var originalUrl = url;
|
||||
url += url.indexOf('?') === -1 ? '?' : '&';
|
||||
url += 't=' + new Date().getTime();
|
||||
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
var onError = function () {
|
||||
|
||||
if (throwError === true) {
|
||||
reject();
|
||||
} else {
|
||||
removeUrl(originalUrl);
|
||||
resolve();
|
||||
if (!manifestUrls.includes(url)) {
|
||||
manifestUrls.push(url);
|
||||
appSettings.set(this.#settingsKey, JSON.stringify(manifestUrls));
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onload = function (e) {
|
||||
if (this.status < 400) {
|
||||
return pkg;
|
||||
});
|
||||
}
|
||||
|
||||
var pkg = JSON.parse(this.response);
|
||||
pkg.url = originalUrl;
|
||||
uninstall(name) {
|
||||
var pkg = this.#packagesList.filter((p) => {
|
||||
return p.name === name;
|
||||
})[0];
|
||||
|
||||
addPackage(packageManager, pkg);
|
||||
if (pkg) {
|
||||
this.#packagesList = this.#packagesList.filter((p) => {
|
||||
return p.name !== name;
|
||||
});
|
||||
|
||||
var plugins = pkg.plugins || [];
|
||||
if (pkg.plugin) {
|
||||
plugins.push(pkg.plugin);
|
||||
}
|
||||
var promises = plugins.map(function (pluginUrl) {
|
||||
return pluginManager.loadPlugin(packageManager.mapPath(pkg, pluginUrl));
|
||||
});
|
||||
Promise.all(promises).then(resolve, resolve);
|
||||
|
||||
} else {
|
||||
onError();
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = onError;
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
function PackageManager() {
|
||||
|
||||
this.packagesList = [];
|
||||
}
|
||||
|
||||
PackageManager.prototype.init = function () {
|
||||
var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]');
|
||||
|
||||
var instance = this;
|
||||
return Promise.all(manifestUrls.map(function (u) {
|
||||
|
||||
return loadPackage(instance, u);
|
||||
|
||||
})).then(function () {
|
||||
return Promise.resolve();
|
||||
}, function () {
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
PackageManager.prototype.packages = function () {
|
||||
return this.packagesList.slice(0);
|
||||
};
|
||||
|
||||
PackageManager.prototype.install = function (url) {
|
||||
|
||||
return loadPackage(this, url, true).then(function (pkg) {
|
||||
|
||||
var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]');
|
||||
|
||||
if (manifestUrls.indexOf(url) === -1) {
|
||||
manifestUrls.push(url);
|
||||
appSettings.set(settingsKey, JSON.stringify(manifestUrls));
|
||||
this.removeUrl(pkg.url);
|
||||
}
|
||||
|
||||
return pkg;
|
||||
});
|
||||
};
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
PackageManager.prototype.uninstall = function (name) {
|
||||
mapPath(pkg, pluginUrl) {
|
||||
var urlLower = pluginUrl.toLowerCase();
|
||||
if (urlLower.startsWith('http:') || urlLower.startsWith('https:') || urlLower.startsWith('file:')) {
|
||||
return pluginUrl;
|
||||
}
|
||||
|
||||
var pkg = this.packagesList.filter(function (p) {
|
||||
var packageUrl = pkg.url;
|
||||
packageUrl = packageUrl.substring(0, packageUrl.lastIndexOf('/'));
|
||||
|
||||
return p.name === name;
|
||||
})[0];
|
||||
packageUrl += '/';
|
||||
packageUrl += pluginUrl;
|
||||
|
||||
if (pkg) {
|
||||
return packageUrl;
|
||||
}
|
||||
|
||||
this.packagesList = this.packagesList.filter(function (p) {
|
||||
|
||||
return p.name !== name;
|
||||
addPackage(pkg) {
|
||||
this.#packagesList = this.#packagesList.filter((p) => {
|
||||
return p.name !== pkg.name;
|
||||
});
|
||||
|
||||
removeUrl(pkg.url);
|
||||
this.#packagesList.push(pkg);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
removeUrl(url) {
|
||||
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
|
||||
|
||||
PackageManager.prototype.mapPath = function (pkg, pluginUrl) {
|
||||
manifestUrls = manifestUrls.filter((i) => {
|
||||
return i !== url;
|
||||
});
|
||||
|
||||
var urlLower = pluginUrl.toLowerCase();
|
||||
if (urlLower.indexOf('http:') === 0 || urlLower.indexOf('https:') === 0 || urlLower.indexOf('file:') === 0) {
|
||||
return pluginUrl;
|
||||
appSettings.set(this.#settingsKey, JSON.stringify(manifestUrls));
|
||||
}
|
||||
|
||||
var packageUrl = pkg.url;
|
||||
packageUrl = packageUrl.substring(0, packageUrl.lastIndexOf('/'));
|
||||
loadPackage(url, throwError = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var xhr = new XMLHttpRequest();
|
||||
var originalUrl = url;
|
||||
url += url.indexOf('?') === -1 ? '?' : '&';
|
||||
url += 't=' + new Date().getTime();
|
||||
|
||||
packageUrl += '/';
|
||||
packageUrl += pluginUrl;
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
return packageUrl;
|
||||
};
|
||||
var onError = () => {
|
||||
if (throwError === true) {
|
||||
reject();
|
||||
} else {
|
||||
this.removeUrl(originalUrl);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
return new PackageManager();
|
||||
});
|
||||
xhr.onload = () => {
|
||||
if (this.status < 400) {
|
||||
var pkg = JSON.parse(this.response);
|
||||
pkg.url = originalUrl;
|
||||
|
||||
this.addPackage(pkg);
|
||||
|
||||
var plugins = pkg.plugins || [];
|
||||
if (pkg.plugin) {
|
||||
plugins.push(pkg.plugin);
|
||||
}
|
||||
var promises = plugins.map((pluginUrl) => {
|
||||
return pluginManager.loadPlugin(this.mapPath(pkg, pluginUrl));
|
||||
});
|
||||
Promise.all(promises).then(resolve, resolve);
|
||||
} else {
|
||||
onError();
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = onError;
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default new PackageManager();
|
||||
|
||||
@@ -23,10 +23,8 @@ function getOsdElementHtml() {
|
||||
}
|
||||
|
||||
function ensureOsdElement() {
|
||||
|
||||
var elem = osdElement;
|
||||
if (!elem) {
|
||||
|
||||
enableAnimation = browser.supportsCssAnimation();
|
||||
|
||||
elem = document.createElement('div');
|
||||
@@ -50,7 +48,6 @@ function onHideComplete() {
|
||||
|
||||
var hideTimeout;
|
||||
function showOsd() {
|
||||
|
||||
clearHideTimeout();
|
||||
|
||||
var elem = osdElement;
|
||||
@@ -79,12 +76,10 @@ function clearHideTimeout() {
|
||||
}
|
||||
|
||||
function hideOsd() {
|
||||
|
||||
clearHideTimeout();
|
||||
|
||||
var elem = osdElement;
|
||||
if (elem) {
|
||||
|
||||
if (enableAnimation) {
|
||||
// trigger reflow
|
||||
void elem.offsetWidth;
|
||||
@@ -108,7 +103,6 @@ function setIcon(iconElement, icon) {
|
||||
}
|
||||
|
||||
function updateElementsFromPlayer(brightness) {
|
||||
|
||||
if (iconElement) {
|
||||
if (brightness >= 80) {
|
||||
setIcon(iconElement, 'brightness_high');
|
||||
@@ -124,7 +118,6 @@ function updateElementsFromPlayer(brightness) {
|
||||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
|
||||
var player = currentPlayer;
|
||||
|
||||
if (player) {
|
||||
@@ -135,7 +128,6 @@ function releaseCurrentPlayer() {
|
||||
}
|
||||
|
||||
function onBrightnessChanged(e) {
|
||||
|
||||
var player = this;
|
||||
|
||||
ensureOsdElement();
|
||||
@@ -146,7 +138,6 @@ function onBrightnessChanged(e) {
|
||||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
|
||||
if (player === currentPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import playbackManager from 'playbackManager';
|
||||
import nowPlayingHelper from 'nowPlayingHelper';
|
||||
import events from 'events';
|
||||
import connectionManager from 'connectionManager';
|
||||
/* eslint-disable indent */
|
||||
|
||||
// Reports media playback to the device for lock screen control
|
||||
@@ -16,16 +15,16 @@ import connectionManager from 'connectionManager';
|
||||
} else if (options.type === 'Primary' && item.SeriesPrimaryImageTag) {
|
||||
options.tag = item.SeriesPrimaryImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
} else if (options.type === 'Thumb') {
|
||||
if (item.SeriesThumbImageTag) {
|
||||
options.tag = item.SeriesThumbImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
} else if (item.ParentThumbImageTag) {
|
||||
options.tag = item.ParentThumbImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,11 +37,11 @@ import connectionManager from 'connectionManager';
|
||||
if (item.ImageTags && item.ImageTags[options.type]) {
|
||||
options.tag = item.ImageTags[options.type];
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.Id, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.Id, options);
|
||||
} else if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
options.tag = item.AlbumPrimaryImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -127,7 +126,7 @@ import connectionManager from 'connectionManager';
|
||||
artwork: getImageUrls(item)
|
||||
});
|
||||
} else {
|
||||
let itemImageUrl = seriesImageUrl(item, { maxHeight: 3000 }) || imageUrl(item, { maxHeight: 3000 });
|
||||
const itemImageUrl = seriesImageUrl(item, { maxHeight: 3000 }) || imageUrl(item, { maxHeight: 3000 });
|
||||
|
||||
window.NativeShell.updateMediaSession({
|
||||
action: eventName,
|
||||
@@ -244,10 +243,10 @@ import connectionManager from 'connectionManager';
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
navigator.mediaSession.setActionHandler('seekto', function (object) {
|
||||
let item = playbackManager.getPlayerState(currentPlayer).NowPlayingItem;
|
||||
const item = playbackManager.getPlayerState(currentPlayer).NowPlayingItem;
|
||||
// Convert to ms
|
||||
let duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0);
|
||||
let wantedTime = object.seekTime * 1000;
|
||||
const duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0);
|
||||
const wantedTime = object.seekTime * 1000;
|
||||
playbackManager.seekPercent(wantedTime / duration * 100, currentPlayer);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
|
||||
|
||||
var topItem = nowPlayingItem;
|
||||
var bottomItem = null;
|
||||
var topText = nowPlayingItem.Name;
|
||||
@@ -25,7 +24,6 @@ export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
|
||||
var bottomText = '';
|
||||
|
||||
if (nowPlayingItem.ArtistItems && nowPlayingItem.ArtistItems.length) {
|
||||
|
||||
bottomItem = {
|
||||
Id: nowPlayingItem.ArtistItems[0].Id,
|
||||
Name: nowPlayingItem.ArtistItems[0].Name,
|
||||
@@ -36,9 +34,7 @@ export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
|
||||
bottomText = nowPlayingItem.ArtistItems.map(function (a) {
|
||||
return a.Name;
|
||||
}).join(', ');
|
||||
|
||||
} else if (nowPlayingItem.Artists && nowPlayingItem.Artists.length) {
|
||||
|
||||
bottomText = nowPlayingItem.Artists.join(', ');
|
||||
} else if (nowPlayingItem.SeriesName || nowPlayingItem.Album) {
|
||||
bottomText = topText;
|
||||
|
||||
+1108
-1442
File diff suppressed because it is too large
Load Diff
@@ -14,15 +14,13 @@ function onOrientationChangeError(err) {
|
||||
}
|
||||
|
||||
events.on(playbackManager, 'playbackstart', function (e, player, state) {
|
||||
|
||||
var isLocalVideo = player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player);
|
||||
|
||||
if (isLocalVideo && layoutManager.mobile) {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
var lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation || (screen.orientation && screen.orientation.lock);
|
||||
var lockOrientation = window.screen.lockOrientation || window.screen.mozLockOrientation || window.screen.msLockOrientation || (window.screen.orientation && window.screen.orientation.lock);
|
||||
|
||||
if (lockOrientation) {
|
||||
|
||||
try {
|
||||
var promise = lockOrientation('landscape');
|
||||
if (promise.then) {
|
||||
@@ -39,11 +37,9 @@ events.on(playbackManager, 'playbackstart', function (e, player, state) {
|
||||
});
|
||||
|
||||
events.on(playbackManager, 'playbackstop', function (e, playbackStopInfo) {
|
||||
|
||||
if (orientationLocked && !playbackStopInfo.nextMediaType) {
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
var unlockOrientation = screen.unlockOrientation || screen.mozUnlockOrientation || screen.msUnlockOrientation || (screen.orientation && screen.orientation.unlock);
|
||||
var unlockOrientation = window.screen.unlockOrientation || window.screen.mozUnlockOrientation || window.screen.msUnlockOrientation || (window.screen.orientation && window.screen.orientation.unlock);
|
||||
|
||||
if (unlockOrientation) {
|
||||
try {
|
||||
|
||||
@@ -8,7 +8,6 @@ import globalize from 'globalize';
|
||||
import appHost from 'apphost';
|
||||
|
||||
function mirrorItem(info, player) {
|
||||
|
||||
var item = info.item;
|
||||
|
||||
playbackManager.displayContent({
|
||||
@@ -21,9 +20,7 @@ function mirrorItem(info, player) {
|
||||
}
|
||||
|
||||
function mirrorIfEnabled(info) {
|
||||
|
||||
if (info && playbackManager.enableDisplayMirroring()) {
|
||||
|
||||
var getPlayerInfo = playbackManager.getPlayerInfo();
|
||||
|
||||
if (getPlayerInfo) {
|
||||
@@ -39,9 +36,7 @@ function emptyCallback() {
|
||||
}
|
||||
|
||||
function getTargetSecondaryText(target) {
|
||||
|
||||
if (target.user) {
|
||||
|
||||
return target.user.Name;
|
||||
}
|
||||
|
||||
@@ -49,7 +44,6 @@ function getTargetSecondaryText(target) {
|
||||
}
|
||||
|
||||
function getIcon(target) {
|
||||
|
||||
var deviceType = target.deviceType;
|
||||
|
||||
if (!deviceType && target.isLocalPlayer) {
|
||||
@@ -67,7 +61,6 @@ function getIcon(target) {
|
||||
}
|
||||
|
||||
switch (deviceType) {
|
||||
|
||||
case 'smartphone':
|
||||
return 'smartphone';
|
||||
case 'tablet':
|
||||
@@ -84,7 +77,6 @@ function getIcon(target) {
|
||||
}
|
||||
|
||||
export function show(button) {
|
||||
|
||||
var currentPlayerInfo = playbackManager.getPlayerInfo();
|
||||
|
||||
if (currentPlayerInfo) {
|
||||
@@ -99,9 +91,7 @@ export function show(button) {
|
||||
loading.show();
|
||||
|
||||
playbackManager.getTargets().then(function (targets) {
|
||||
|
||||
var menuItems = targets.map(function (t) {
|
||||
|
||||
var name = t.name;
|
||||
|
||||
if (t.appName && t.appName !== t.name) {
|
||||
@@ -115,11 +105,9 @@ export function show(button) {
|
||||
secondaryText: getTargetSecondaryText(t),
|
||||
icon: getIcon(t)
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
import('actionsheet').then(({default: actionsheet}) => {
|
||||
|
||||
loading.hide();
|
||||
|
||||
var menuOptions = {
|
||||
@@ -133,12 +121,11 @@ export function show(button) {
|
||||
|
||||
// Unfortunately we can't allow the url to change or chromecast will throw a security error
|
||||
// Might be able to solve this in the future by moving the dialogs to hashbangs
|
||||
if (!(!browser.chrome || appHost.supports('castmenuhashchange'))) {
|
||||
if (!(!browser.chrome && !browser.edgeChromium || appHost.supports('castmenuhashchange'))) {
|
||||
menuOptions.enableHistory = false;
|
||||
}
|
||||
|
||||
actionsheet.show(menuOptions).then(function (id) {
|
||||
|
||||
var target = targets.filter(function (t) {
|
||||
return t.id === id;
|
||||
})[0];
|
||||
@@ -146,7 +133,6 @@ export function show(button) {
|
||||
playbackManager.trySetActivePlayer(target.playerName, target);
|
||||
|
||||
mirrorIfEnabled();
|
||||
|
||||
}, emptyCallback);
|
||||
});
|
||||
});
|
||||
@@ -164,11 +150,8 @@ function showActivePlayerMenu(playerInfo) {
|
||||
}
|
||||
|
||||
function disconnectFromPlayer(currentDeviceName) {
|
||||
|
||||
if (playbackManager.getSupportedCommands().indexOf('EndSession') !== -1) {
|
||||
|
||||
import('dialog').then(({default: dialog}) => {
|
||||
|
||||
var menuItems = [];
|
||||
|
||||
menuItems.push({
|
||||
@@ -182,12 +165,10 @@ function disconnectFromPlayer(currentDeviceName) {
|
||||
|
||||
dialog({
|
||||
buttons: menuItems,
|
||||
//positionTo: positionTo,
|
||||
text: globalize.translate('ConfirmEndPlayerSession', currentDeviceName)
|
||||
|
||||
}).then(function (id) {
|
||||
switch (id) {
|
||||
|
||||
case 'yes':
|
||||
playbackManager.getCurrentPlayer().endSession();
|
||||
playbackManager.setDefaultPlayerActive();
|
||||
@@ -199,17 +180,13 @@ function disconnectFromPlayer(currentDeviceName) {
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
playbackManager.setDefaultPlayerActive();
|
||||
}
|
||||
}
|
||||
|
||||
function showActivePlayerMenuInternal(dialogHelper, playerInfo) {
|
||||
|
||||
var html = '';
|
||||
|
||||
var dialogOptions = {
|
||||
@@ -235,7 +212,6 @@ function showActivePlayerMenuInternal(dialogHelper, playerInfo) {
|
||||
html += '<div>';
|
||||
|
||||
if (playerInfo.supportedCommands.indexOf('DisplayContent') !== -1) {
|
||||
|
||||
html += '<label class="checkboxContainer">';
|
||||
var checkedHtml = playbackManager.enableDisplayMirroring() ? ' checked' : '';
|
||||
html += '<input type="checkbox" is="emby-checkbox" class="chkMirror"' + checkedHtml + '/>';
|
||||
@@ -294,7 +270,6 @@ function onMirrorChange() {
|
||||
}
|
||||
|
||||
document.addEventListener('viewshow', function (e) {
|
||||
|
||||
var state = e.detail.state || {};
|
||||
var item = state.item;
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import connectionManager from 'connectionManager';
|
||||
import actionsheet from 'actionsheet';
|
||||
import playbackManager from 'playbackManager';
|
||||
import globalize from 'globalize';
|
||||
import qualityoptions from 'qualityoptions';
|
||||
|
||||
function showQualityMenu(player, btn) {
|
||||
|
||||
var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) {
|
||||
return stream.Type === 'Video';
|
||||
})[0];
|
||||
@@ -88,8 +86,6 @@ function showRepeatModeMenu(player, btn) {
|
||||
|
||||
function getQualitySecondaryText(player) {
|
||||
var state = playbackManager.getPlayerState(player);
|
||||
var isAutoEnabled = playbackManager.enableAutomaticBitrateDetection(player);
|
||||
var currentMaxBitrate = playbackManager.getMaxStreamingBitrate(player);
|
||||
|
||||
var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) {
|
||||
return stream.Type === 'Video';
|
||||
@@ -106,20 +102,6 @@ function getQualitySecondaryText(player) {
|
||||
enableAuto: true
|
||||
});
|
||||
|
||||
var menuItems = options.map(function (o) {
|
||||
var opt = {
|
||||
name: o.name,
|
||||
id: o.bitrate,
|
||||
asideText: o.secondaryText
|
||||
};
|
||||
|
||||
if (o.selected) {
|
||||
opt.selected = true;
|
||||
}
|
||||
|
||||
return opt;
|
||||
});
|
||||
|
||||
var selectedOption = options.filter(function (o) {
|
||||
return o.selected;
|
||||
});
|
||||
@@ -166,9 +148,30 @@ function showAspectRatioMenu(player, btn) {
|
||||
});
|
||||
}
|
||||
|
||||
function showPlaybackRateMenu(player, btn) {
|
||||
// each has a name and id
|
||||
const currentId = playbackManager.getPlaybackRate(player);
|
||||
const menuItems = playbackManager.getSupportedPlaybackRates(player).map(i => ({
|
||||
id: i.id,
|
||||
name: i.name,
|
||||
selected: i.id === currentId
|
||||
}));
|
||||
|
||||
return actionsheet.show({
|
||||
items: menuItems,
|
||||
positionTo: btn
|
||||
}).then(function (id) {
|
||||
if (id) {
|
||||
playbackManager.setPlaybackRate(id, player);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
}
|
||||
|
||||
function showWithUser(options, player, user) {
|
||||
var supportedCommands = playbackManager.getSupportedCommands(player);
|
||||
var mediaType = options.mediaType;
|
||||
|
||||
var menuItems = [];
|
||||
if (supportedCommands.indexOf('SetAspectRatio') !== -1) {
|
||||
@@ -184,6 +187,17 @@ function showWithUser(options, player, user) {
|
||||
});
|
||||
}
|
||||
|
||||
if (supportedCommands.indexOf('PlaybackRate') !== -1) {
|
||||
const currentPlaybackRateId = playbackManager.getPlaybackRate(player);
|
||||
const currentPlaybackRate = playbackManager.getSupportedPlaybackRates(player).filter(i => i.id === currentPlaybackRateId)[0];
|
||||
|
||||
menuItems.push({
|
||||
name: globalize.translate('PlaybackRate'),
|
||||
id: 'playbackrate',
|
||||
asideText: currentPlaybackRate ? currentPlaybackRate.name : null
|
||||
});
|
||||
}
|
||||
|
||||
if (user && user.Policy.EnableVideoPlaybackTranscoding) {
|
||||
var secondaryQualityText = getQualitySecondaryText(player);
|
||||
|
||||
@@ -236,7 +250,7 @@ export function show(options) {
|
||||
return showWithUser(options, player, null);
|
||||
}
|
||||
|
||||
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
var apiClient = window.connectionManager.getApiClient(currentItem.ServerId);
|
||||
return apiClient.getCurrentUser().then(function (user) {
|
||||
return showWithUser(options, player, user);
|
||||
});
|
||||
@@ -248,6 +262,8 @@ function handleSelectedOption(id, options, player) {
|
||||
return showQualityMenu(player, options.positionTo);
|
||||
case 'aspectratio':
|
||||
return showAspectRatioMenu(player, options.positionTo);
|
||||
case 'playbackrate':
|
||||
return showPlaybackRateMenu(player, options.positionTo);
|
||||
case 'repeatmode':
|
||||
return showRepeatModeMenu(player, options.positionTo);
|
||||
case 'stats':
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export function getDisplayPlayMethod(session) {
|
||||
|
||||
if (!session.NowPlayingItem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,64 +1,56 @@
|
||||
define([], function () {
|
||||
'use strict';
|
||||
/*eslint prefer-const: "error"*/
|
||||
|
||||
var currentId = 0;
|
||||
function addUniquePlaylistItemId(item) {
|
||||
let currentId = 0;
|
||||
function addUniquePlaylistItemId(item) {
|
||||
if (!item.PlaylistItemId) {
|
||||
item.PlaylistItemId = 'playlistItem' + currentId;
|
||||
currentId++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!item.PlaylistItemId) {
|
||||
|
||||
item.PlaylistItemId = 'playlistItem' + currentId;
|
||||
currentId++;
|
||||
function findPlaylistIndex(playlistItemId, list) {
|
||||
for (let i = 0, length = list.length; i < length; i++) {
|
||||
if (list[i].PlaylistItemId === playlistItemId) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
function findPlaylistIndex(playlistItemId, list) {
|
||||
|
||||
for (var i = 0, length = list.length; i < length; i++) {
|
||||
if (list[i].PlaylistItemId === playlistItemId) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
function PlayQueueManager() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
class PlayQueueManager {
|
||||
constructor() {
|
||||
this._sortedPlaylist = [];
|
||||
this._playlist = [];
|
||||
this._repeatMode = 'RepeatNone';
|
||||
this._shuffleMode = 'Sorted';
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.getPlaylist = function () {
|
||||
getPlaylist() {
|
||||
return this._playlist.slice(0);
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.setPlaylist = function (items) {
|
||||
}
|
||||
|
||||
setPlaylist(items) {
|
||||
items = items.slice(0);
|
||||
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
for (let i = 0, length = items.length; i < length; i++) {
|
||||
addUniquePlaylistItemId(items[i]);
|
||||
}
|
||||
|
||||
this._currentPlaylistItemId = null;
|
||||
this._playlist = items;
|
||||
this._repeatMode = 'RepeatNone';
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.queue = function (items) {
|
||||
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
}
|
||||
|
||||
queue(items) {
|
||||
for (let i = 0, length = items.length; i < length; i++) {
|
||||
addUniquePlaylistItemId(items[i]);
|
||||
|
||||
this._playlist.push(items[i]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.shufflePlaylist = function () {
|
||||
shufflePlaylist() {
|
||||
this._sortedPlaylist = [];
|
||||
for (const item of this._playlist) {
|
||||
this._sortedPlaylist.push(item);
|
||||
@@ -73,43 +65,31 @@ define([], function () {
|
||||
}
|
||||
this._playlist.unshift(currentPlaylistItem);
|
||||
this._shuffleMode = 'Shuffle';
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.sortShuffledPlaylist = function () {
|
||||
sortShuffledPlaylist() {
|
||||
this._playlist = [];
|
||||
for (let item of this._sortedPlaylist) {
|
||||
for (const item of this._sortedPlaylist) {
|
||||
this._playlist.push(item);
|
||||
}
|
||||
this._sortedPlaylist = [];
|
||||
this._shuffleMode = 'Sorted';
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.clearPlaylist = function (clearCurrentItem = false) {
|
||||
clearPlaylist(clearCurrentItem = false) {
|
||||
const currentPlaylistItem = this._playlist.splice(this.getCurrentPlaylistIndex(), 1)[0];
|
||||
this._playlist = [];
|
||||
if (!clearCurrentItem) {
|
||||
this._playlist.push(currentPlaylistItem);
|
||||
}
|
||||
};
|
||||
|
||||
function arrayInsertAt(destArray, pos, arrayToInsert) {
|
||||
var args = [];
|
||||
args.push(pos); // where to insert
|
||||
args.push(0); // nothing to remove
|
||||
args = args.concat(arrayToInsert); // add on array to insert
|
||||
destArray.splice.apply(destArray, args); // splice it in
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.queueNext = function (items) {
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
queueNext(items) {
|
||||
for (let i = 0, length = items.length; i < length; i++) {
|
||||
addUniquePlaylistItemId(items[i]);
|
||||
}
|
||||
|
||||
var currentIndex = this.getCurrentPlaylistIndex();
|
||||
let currentIndex = this.getCurrentPlaylistIndex();
|
||||
|
||||
if (currentIndex === -1) {
|
||||
currentIndex = this._playlist.length;
|
||||
@@ -118,48 +98,43 @@ define([], function () {
|
||||
}
|
||||
|
||||
arrayInsertAt(this._playlist, currentIndex, items);
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.getCurrentPlaylistIndex = function () {
|
||||
}
|
||||
|
||||
getCurrentPlaylistIndex() {
|
||||
return findPlaylistIndex(this.getCurrentPlaylistItemId(), this._playlist);
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.getCurrentItem = function () {
|
||||
|
||||
var index = findPlaylistIndex(this.getCurrentPlaylistItemId(), this._playlist);
|
||||
getCurrentItem() {
|
||||
const index = findPlaylistIndex(this.getCurrentPlaylistItemId(), this._playlist);
|
||||
|
||||
return index === -1 ? null : this._playlist[index];
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.getCurrentPlaylistItemId = function () {
|
||||
getCurrentPlaylistItemId() {
|
||||
return this._currentPlaylistItemId;
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.setPlaylistState = function (playlistItemId, playlistIndex) {
|
||||
}
|
||||
|
||||
setPlaylistState(playlistItemId, playlistIndex) {
|
||||
this._currentPlaylistItemId = playlistItemId;
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.setPlaylistIndex = function (playlistIndex) {
|
||||
}
|
||||
|
||||
setPlaylistIndex(playlistIndex) {
|
||||
if (playlistIndex < 0) {
|
||||
this.setPlaylistState(null);
|
||||
} else {
|
||||
this.setPlaylistState(this._playlist[playlistIndex].PlaylistItemId);
|
||||
}
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.removeFromPlaylist = function (playlistItemIds) {
|
||||
}
|
||||
|
||||
removeFromPlaylist(playlistItemIds) {
|
||||
if (this._playlist.length <= playlistItemIds.length) {
|
||||
return {
|
||||
result: 'empty'
|
||||
};
|
||||
}
|
||||
|
||||
var currentPlaylistItemId = this.getCurrentPlaylistItemId();
|
||||
var isCurrentIndex = playlistItemIds.indexOf(currentPlaylistItemId) !== -1;
|
||||
const currentPlaylistItemId = this.getCurrentPlaylistItemId();
|
||||
const isCurrentIndex = playlistItemIds.indexOf(currentPlaylistItemId) !== -1;
|
||||
|
||||
this._sortedPlaylist = this._sortedPlaylist.filter(function (item) {
|
||||
return !playlistItemIds.includes(item.PlaylistItemId);
|
||||
@@ -173,18 +148,13 @@ define([], function () {
|
||||
result: 'removed',
|
||||
isCurrentIndex: isCurrentIndex
|
||||
};
|
||||
};
|
||||
|
||||
function moveInArray(array, from, to) {
|
||||
array.splice(to, 0, array.splice(from, 1)[0]);
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.movePlaylistItem = function (playlistItemId, newIndex) {
|
||||
movePlaylistItem(playlistItemId, newIndex) {
|
||||
const playlist = this.getPlaylist();
|
||||
|
||||
var playlist = this.getPlaylist();
|
||||
|
||||
var oldIndex;
|
||||
for (var i = 0, length = playlist.length; i < length; i++) {
|
||||
let oldIndex;
|
||||
for (let i = 0, length = playlist.length; i < length; i++) {
|
||||
if (playlist[i].PlaylistItemId === playlistItemId) {
|
||||
oldIndex = i;
|
||||
break;
|
||||
@@ -210,31 +180,30 @@ define([], function () {
|
||||
playlistItemId: playlistItemId,
|
||||
newIndex: newIndex
|
||||
};
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.reset = function () {
|
||||
}
|
||||
|
||||
reset() {
|
||||
this._sortedPlaylist = [];
|
||||
this._playlist = [];
|
||||
this._currentPlaylistItemId = null;
|
||||
this._repeatMode = 'RepeatNone';
|
||||
this._shuffleMode = 'Sorted';
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.setRepeatMode = function (value) {
|
||||
setRepeatMode(value) {
|
||||
const repeatModes = ['RepeatOne', 'RepeatAll', 'RepeatNone'];
|
||||
if (repeatModes.includes(value)) {
|
||||
this._repeatMode = value;
|
||||
} else {
|
||||
throw new TypeError('invalid value provided for setRepeatMode');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.getRepeatMode = function () {
|
||||
getRepeatMode() {
|
||||
return this._repeatMode;
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.setShuffleMode = function (value) {
|
||||
setShuffleMode(value) {
|
||||
switch (value) {
|
||||
case 'Shuffle':
|
||||
this.shufflePlaylist();
|
||||
@@ -245,9 +214,9 @@ define([], function () {
|
||||
default:
|
||||
throw new TypeError('invalid value provided to setShuffleMode');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.toggleShuffleMode = function () {
|
||||
toggleShuffleMode() {
|
||||
switch (this._shuffleMode) {
|
||||
case 'Shuffle':
|
||||
this.setShuffleMode('Sorted');
|
||||
@@ -258,20 +227,18 @@ define([], function () {
|
||||
default:
|
||||
throw new TypeError('current value for shufflequeue is invalid');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.getShuffleMode = function () {
|
||||
getShuffleMode() {
|
||||
return this._shuffleMode;
|
||||
};
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.getNextItemInfo = function () {
|
||||
|
||||
var newIndex;
|
||||
var playlist = this.getPlaylist();
|
||||
var playlistLength = playlist.length;
|
||||
getNextItemInfo() {
|
||||
let newIndex;
|
||||
const playlist = this.getPlaylist();
|
||||
const playlistLength = playlist.length;
|
||||
|
||||
switch (this.getRepeatMode()) {
|
||||
|
||||
case 'RepeatOne':
|
||||
newIndex = this.getCurrentPlaylistIndex();
|
||||
break;
|
||||
@@ -290,7 +257,7 @@ define([], function () {
|
||||
return null;
|
||||
}
|
||||
|
||||
var item = playlist[newIndex];
|
||||
const item = playlist[newIndex];
|
||||
|
||||
if (!item) {
|
||||
return null;
|
||||
@@ -300,7 +267,19 @@ define([], function () {
|
||||
item: item,
|
||||
index: newIndex
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return PlayQueueManager;
|
||||
});
|
||||
function arrayInsertAt(destArray, pos, arrayToInsert) {
|
||||
let args = [];
|
||||
args.push(pos); // where to insert
|
||||
args.push(0); // nothing to remove
|
||||
args = args.concat(arrayToInsert); // add on array to insert
|
||||
destArray.splice.apply(destArray, args); // splice it in
|
||||
}
|
||||
|
||||
function moveInArray(array, from, to) {
|
||||
array.splice(to, 0, array.splice(from, 1)[0]);
|
||||
}
|
||||
|
||||
export default PlayQueueManager;
|
||||
|
||||
@@ -23,10 +23,8 @@ function getOsdElementHtml() {
|
||||
}
|
||||
|
||||
function ensureOsdElement() {
|
||||
|
||||
var elem = osdElement;
|
||||
if (!elem) {
|
||||
|
||||
enableAnimation = browser.supportsCssAnimation();
|
||||
|
||||
elem = document.createElement('div');
|
||||
@@ -50,7 +48,6 @@ function onHideComplete() {
|
||||
|
||||
var hideTimeout;
|
||||
function showOsd() {
|
||||
|
||||
clearHideTimeout();
|
||||
|
||||
var elem = osdElement;
|
||||
@@ -79,12 +76,10 @@ function clearHideTimeout() {
|
||||
}
|
||||
|
||||
function hideOsd() {
|
||||
|
||||
clearHideTimeout();
|
||||
|
||||
var elem = osdElement;
|
||||
if (elem) {
|
||||
|
||||
if (enableAnimation) {
|
||||
// trigger reflow
|
||||
void elem.offsetWidth;
|
||||
@@ -103,7 +98,6 @@ function hideOsd() {
|
||||
}
|
||||
|
||||
function updatePlayerVolumeState(isMuted, volume) {
|
||||
|
||||
if (iconElement) {
|
||||
iconElement.classList.remove('volume_off', 'volume_up');
|
||||
iconElement.classList.add(isMuted ? 'volume_off' : 'volume_up');
|
||||
@@ -114,7 +108,6 @@ function updatePlayerVolumeState(isMuted, volume) {
|
||||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
|
||||
var player = currentPlayer;
|
||||
|
||||
if (player) {
|
||||
@@ -125,7 +118,6 @@ function releaseCurrentPlayer() {
|
||||
}
|
||||
|
||||
function onVolumeChanged(e) {
|
||||
|
||||
var player = this;
|
||||
|
||||
ensureOsdElement();
|
||||
@@ -136,7 +128,6 @@ function onVolumeChanged(e) {
|
||||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
|
||||
if (player === currentPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import focusManager from 'focusManager';
|
||||
import qualityoptions from 'qualityoptions';
|
||||
import globalize from 'globalize';
|
||||
import loading from 'loading';
|
||||
import connectionManager from 'connectionManager';
|
||||
import events from 'events';
|
||||
import 'emby-select';
|
||||
import 'emby-checkbox';
|
||||
@@ -13,7 +12,6 @@ import 'emby-checkbox';
|
||||
/* eslint-disable indent */
|
||||
|
||||
function fillSkipLengths(select) {
|
||||
|
||||
const options = [5, 10, 15, 20, 25, 30];
|
||||
|
||||
select.innerHTML = options.map(option => {
|
||||
@@ -27,13 +25,11 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function populateLanguages(select, languages) {
|
||||
|
||||
let html = '';
|
||||
|
||||
html += `<option value=''>${globalize.translate('AnyLanguage')}</option>`;
|
||||
|
||||
for (let i = 0, length = languages.length; i < length; i++) {
|
||||
|
||||
const culture = languages[i];
|
||||
|
||||
html += `<option value='${culture.ThreeLetterISOLanguageName}'>${culture.DisplayName}</option>`;
|
||||
@@ -43,7 +39,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function setMaxBitrateIntoField(select, isInNetwork, mediatype) {
|
||||
|
||||
const options = mediatype === 'Audio' ? qualityoptions.getAudioQualityOptions({
|
||||
|
||||
currentMaxBitrate: appSettings.maxStreamingBitrate(isInNetwork, mediatype),
|
||||
@@ -59,7 +54,6 @@ import 'emby-checkbox';
|
||||
});
|
||||
|
||||
select.innerHTML = options.map(i => {
|
||||
|
||||
// render empty string instead of 0 for the auto option
|
||||
return `<option value="${i.bitrate || ''}">${i.name}</option>`;
|
||||
}).join('');
|
||||
@@ -72,7 +66,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function fillChromecastQuality(select) {
|
||||
|
||||
const options = qualityoptions.getVideoQualityOptions({
|
||||
|
||||
currentMaxBitrate: appSettings.maxChromecastBitrate(),
|
||||
@@ -81,7 +74,6 @@ import 'emby-checkbox';
|
||||
});
|
||||
|
||||
select.innerHTML = options.map(i => {
|
||||
|
||||
// render empty string instead of 0 for the auto option
|
||||
return `<option value="${i.bitrate || ''}">${i.name}</option>`;
|
||||
}).join('');
|
||||
@@ -90,7 +82,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function setMaxBitrateFromField(select, isInNetwork, mediatype) {
|
||||
|
||||
if (select.value) {
|
||||
appSettings.maxStreamingBitrate(isInNetwork, mediatype, select.value);
|
||||
appSettings.enableAutomaticBitrateDetection(isInNetwork, mediatype, false);
|
||||
@@ -100,7 +91,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function showHideQualityFields(context, user, apiClient) {
|
||||
|
||||
if (user.Policy.EnableVideoPlaybackTranscoding) {
|
||||
context.querySelector('.videoQualitySection').classList.remove('hide');
|
||||
} else {
|
||||
@@ -108,7 +98,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
if (appHost.supports('multiserver')) {
|
||||
|
||||
context.querySelector('.fldVideoInNetworkQuality').classList.remove('hide');
|
||||
context.querySelector('.fldVideoInternetQuality').classList.remove('hide');
|
||||
|
||||
@@ -122,15 +111,12 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
apiClient.getEndpointInfo().then(endpointInfo => {
|
||||
|
||||
if (endpointInfo.IsInNetwork) {
|
||||
|
||||
context.querySelector('.fldVideoInNetworkQuality').classList.remove('hide');
|
||||
|
||||
context.querySelector('.fldVideoInternetQuality').classList.add('hide');
|
||||
context.querySelector('.musicQualitySection').classList.add('hide');
|
||||
} else {
|
||||
|
||||
context.querySelector('.fldVideoInNetworkQuality').classList.add('hide');
|
||||
|
||||
context.querySelector('.fldVideoInternetQuality').classList.remove('hide');
|
||||
@@ -145,7 +131,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function showOrHideEpisodesField(context) {
|
||||
|
||||
if (browser.tizen || browser.web0s) {
|
||||
context.querySelector('.fldEpisodeAutoPlay').classList.add('hide');
|
||||
return;
|
||||
@@ -155,14 +140,12 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function loadForm(context, user, userSettings, apiClient) {
|
||||
|
||||
const loggedInUserId = apiClient.getCurrentUserId();
|
||||
const userId = user.Id;
|
||||
|
||||
showHideQualityFields(context, user, apiClient);
|
||||
|
||||
apiClient.getCultures().then(allCultures => {
|
||||
|
||||
populateLanguages(context.querySelector('#selectAudioLanguage'), allCultures);
|
||||
|
||||
context.querySelector('#selectAudioLanguage', context).value = user.Configuration.AudioLanguagePreference || '';
|
||||
@@ -171,7 +154,6 @@ import 'emby-checkbox';
|
||||
|
||||
// hide cinema mode options if disabled at server level
|
||||
apiClient.getNamedConfiguration('cinemamode').then(cinemaConfig => {
|
||||
|
||||
if (cinemaConfig.EnableIntrosForMovies || cinemaConfig.EnableIntrosForEpisodes) {
|
||||
context.querySelector('.cinemaModeOptions').classList.remove('hide');
|
||||
} else {
|
||||
@@ -232,7 +214,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function saveUser(context, user, userSettingsInstance, apiClient) {
|
||||
|
||||
appSettings.enableSystemExternalPlayers(context.querySelector('.chkExternalVideoPlayer').checked);
|
||||
|
||||
appSettings.maxChromecastBitrate(context.querySelector('.selectChromecastVideoQuality').value);
|
||||
@@ -256,13 +237,10 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
|
||||
|
||||
loading.show();
|
||||
|
||||
apiClient.getUser(userId).then(user => {
|
||||
|
||||
saveUser(context, user, userSettings, apiClient).then(() => {
|
||||
|
||||
loading.hide();
|
||||
if (enableSaveConfirmation) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
@@ -271,7 +249,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
events.trigger(instance, 'saved');
|
||||
|
||||
}, () => {
|
||||
loading.hide();
|
||||
});
|
||||
@@ -279,14 +256,12 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
|
||||
const self = this;
|
||||
const apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userId = self.options.userId;
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(() => {
|
||||
|
||||
const enableSaveConfirmation = self.options.enableSaveConfirmation;
|
||||
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
|
||||
});
|
||||
@@ -299,9 +274,7 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
function embed(options, self) {
|
||||
|
||||
return import('text!./playbackSettings.template.html').then(({default: template}) => {
|
||||
|
||||
options.element.innerHTML = globalize.translateHtml(template, 'core');
|
||||
|
||||
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
|
||||
@@ -325,20 +298,17 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
loadData() {
|
||||
|
||||
const self = this;
|
||||
const context = self.options.element;
|
||||
|
||||
loading.show();
|
||||
|
||||
const userId = self.options.userId;
|
||||
const apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
apiClient.getUser(userId).then(user => {
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(() => {
|
||||
|
||||
self.dataLoaded = true;
|
||||
|
||||
loadForm(context, user, userSettings, apiClient);
|
||||
@@ -351,7 +321,6 @@ import 'emby-checkbox';
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
||||
this.options = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
<div class="selectContainer">
|
||||
<select is="emby-select" class="selectChromecastVersion" label="${LabelChromecastVersion}">
|
||||
<option value="stable">${LabelStable}</option>
|
||||
<option value="nightly">${LabelNightly}</option>
|
||||
<option value="unstable">${LabelUnstable}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -99,6 +99,6 @@
|
||||
</div>
|
||||
|
||||
<button is="emby-button" type="submit" class="raised button-submit block btnSave hide">
|
||||
<span>${ButtonSave}</span>
|
||||
<span>${Save}</span>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import events from 'events';
|
||||
import globalize from 'globalize';
|
||||
import playbackManager from 'playbackManager';
|
||||
import connectionManager from 'connectionManager';
|
||||
import syncPlayManager from 'syncPlayManager';
|
||||
import playMethodHelper from 'playMethodHelper';
|
||||
import layoutManager from 'layoutManager';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import 'paper-icon-button-light';
|
||||
import 'css!./playerstats';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function init(instance) {
|
||||
|
||||
const parent = document.createElement('div');
|
||||
|
||||
parent.classList.add('playerStats');
|
||||
@@ -51,9 +48,7 @@ import 'css!./playerstats';
|
||||
}
|
||||
|
||||
function renderStats(elem, categories) {
|
||||
|
||||
elem.querySelector('.playerStats-stats').innerHTML = categories.map(function (category) {
|
||||
|
||||
let categoryHtml = '';
|
||||
|
||||
const stats = category.stats;
|
||||
@@ -73,7 +68,6 @@ import 'css!./playerstats';
|
||||
}
|
||||
|
||||
for (let i = 0, length = stats.length; i < length; i++) {
|
||||
|
||||
categoryHtml += '<div class="playerStats-stat">';
|
||||
|
||||
const stat = stats[i];
|
||||
@@ -90,36 +84,31 @@ import 'css!./playerstats';
|
||||
}
|
||||
|
||||
return categoryHtml;
|
||||
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function getSession(instance, player) {
|
||||
|
||||
const now = new Date().getTime();
|
||||
|
||||
if ((now - (instance.lastSessionTime || 0)) < 10000) {
|
||||
return Promise.resolve(instance.lastSession);
|
||||
}
|
||||
|
||||
const apiClient = connectionManager.getApiClient(playbackManager.currentItem(player).ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(playbackManager.currentItem(player).ServerId);
|
||||
|
||||
return apiClient.getSessions({
|
||||
deviceId: apiClient.deviceId()
|
||||
}).then(function (sessions) {
|
||||
|
||||
instance.lastSession = sessions[0] || {};
|
||||
instance.lastSessionTime = new Date().getTime();
|
||||
|
||||
return Promise.resolve(instance.lastSession);
|
||||
|
||||
}, function () {
|
||||
return Promise.resolve({});
|
||||
});
|
||||
}
|
||||
|
||||
function translateReason(reason) {
|
||||
|
||||
return globalize.translate('' + reason);
|
||||
}
|
||||
|
||||
@@ -132,7 +121,6 @@ import 'css!./playerstats';
|
||||
let audioChannels;
|
||||
|
||||
if (session.TranscodingInfo) {
|
||||
|
||||
videoCodec = session.TranscodingInfo.VideoCodec;
|
||||
audioCodec = session.TranscodingInfo.AudioCodec;
|
||||
totalBitrate = session.TranscodingInfo.Bitrate;
|
||||
@@ -140,7 +128,6 @@ import 'css!./playerstats';
|
||||
}
|
||||
|
||||
if (videoCodec) {
|
||||
|
||||
sessionStats.push({
|
||||
label: globalize.translate('LabelVideoCodec'),
|
||||
value: session.TranscodingInfo.IsVideoDirect ? (videoCodec.toUpperCase() + ' (direct)') : videoCodec.toUpperCase()
|
||||
@@ -148,45 +135,39 @@ import 'css!./playerstats';
|
||||
}
|
||||
|
||||
if (audioCodec) {
|
||||
|
||||
sessionStats.push({
|
||||
label: globalize.translate('LabelAudioCodec'),
|
||||
value: session.TranscodingInfo.IsAudioDirect ? (audioCodec.toUpperCase() + ' (direct)') : audioCodec.toUpperCase()
|
||||
});
|
||||
}
|
||||
|
||||
//if (audioChannels) {
|
||||
|
||||
// sessionStats.push({
|
||||
// label: 'Audio channels:',
|
||||
// value: audioChannels
|
||||
// });
|
||||
//}
|
||||
if (audioChannels) {
|
||||
sessionStats.push({
|
||||
label: globalize.translate('LabelAudioChannels'),
|
||||
value: audioChannels
|
||||
});
|
||||
}
|
||||
|
||||
if (displayPlayMethod === 'Transcode') {
|
||||
if (totalBitrate) {
|
||||
|
||||
sessionStats.push({
|
||||
label: globalize.translate('LabelBitrate'),
|
||||
value: getDisplayBitrate(totalBitrate)
|
||||
});
|
||||
}
|
||||
if (session.TranscodingInfo.CompletionPercentage) {
|
||||
|
||||
sessionStats.push({
|
||||
label: globalize.translate('LabelTranscodingProgress'),
|
||||
value: session.TranscodingInfo.CompletionPercentage.toFixed(1) + '%'
|
||||
});
|
||||
}
|
||||
if (session.TranscodingInfo.Framerate) {
|
||||
|
||||
sessionStats.push({
|
||||
label: globalize.translate('LabelTranscodingFramerate'),
|
||||
value: session.TranscodingInfo.Framerate + ' fps'
|
||||
});
|
||||
}
|
||||
if (session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo.TranscodeReasons.length) {
|
||||
|
||||
sessionStats.push({
|
||||
label: globalize.translate('LabelReasonForTranscoding'),
|
||||
value: session.TranscodingInfo.TranscodeReasons.map(translateReason).join('<br/>')
|
||||
@@ -198,7 +179,6 @@ import 'css!./playerstats';
|
||||
}
|
||||
|
||||
function getDisplayBitrate(bitrate) {
|
||||
|
||||
if (bitrate > 1000000) {
|
||||
return (bitrate / 1000000).toFixed(1) + ' Mbps';
|
||||
} else {
|
||||
@@ -217,7 +197,6 @@ import 'css!./playerstats';
|
||||
}
|
||||
|
||||
function getMediaSourceStats(session, player, displayPlayMethod) {
|
||||
|
||||
const sessionStats = [];
|
||||
|
||||
const mediaSource = playbackManager.currentMediaSource(player) || {};
|
||||
@@ -239,7 +218,6 @@ import 'css!./playerstats';
|
||||
}
|
||||
|
||||
if (totalBitrate) {
|
||||
|
||||
sessionStats.push({
|
||||
label: globalize.translate('LabelBitrate'),
|
||||
value: getDisplayBitrate(totalBitrate)
|
||||
@@ -248,18 +226,14 @@ import 'css!./playerstats';
|
||||
|
||||
const mediaStreams = mediaSource.MediaStreams || [];
|
||||
const videoStream = mediaStreams.filter(function (s) {
|
||||
|
||||
return s.Type === 'Video';
|
||||
|
||||
})[0] || {};
|
||||
|
||||
const videoCodec = videoStream.Codec;
|
||||
|
||||
const audioStreamIndex = playbackManager.getAudioStreamIndex(player);
|
||||
const audioStream = playbackManager.audioTracks(player).filter(function (s) {
|
||||
|
||||
return s.Type === 'Audio' && s.Index === audioStreamIndex;
|
||||
|
||||
})[0] || {};
|
||||
|
||||
const audioCodec = audioStream.Codec;
|
||||
@@ -360,12 +334,10 @@ import 'css!./playerstats';
|
||||
}
|
||||
|
||||
function getStats(instance, player) {
|
||||
|
||||
const statsPromise = player.getStats ? player.getStats() : Promise.resolve({});
|
||||
const sessionPromise = getSession(instance, player);
|
||||
|
||||
return Promise.all([statsPromise, sessionPromise]).then(function (responses) {
|
||||
|
||||
const playerStatsResult = responses[0];
|
||||
const playerStats = playerStatsResult.categories || [];
|
||||
const session = responses[1];
|
||||
@@ -392,7 +364,6 @@ import 'css!./playerstats';
|
||||
categories.push(baseCategory);
|
||||
|
||||
for (let i = 0, length = playerStats.length; i < length; i++) {
|
||||
|
||||
const category = playerStats[i];
|
||||
if (category.type === 'audio') {
|
||||
category.name = 'Audio Info';
|
||||
@@ -403,7 +374,6 @@ import 'css!./playerstats';
|
||||
}
|
||||
|
||||
if (session.TranscodingInfo) {
|
||||
|
||||
categories.push({
|
||||
stats: getTranscodingStats(session, player, displayPlayMethod),
|
||||
name: displayPlayMethod === 'Transcode' ? 'Transcoding Info' : 'Direct Stream Info'
|
||||
@@ -415,7 +385,7 @@ import 'css!./playerstats';
|
||||
name: 'Original Media Info'
|
||||
});
|
||||
|
||||
var apiClient = connectionManager.getApiClient(playbackManager.currentItem(player).ServerId);
|
||||
var apiClient = window.connectionManager.getApiClient(playbackManager.currentItem(player).ServerId);
|
||||
if (syncPlayManager.isSyncPlayEnabled() && apiClient.isMinServerVersion('10.6.0')) {
|
||||
categories.push({
|
||||
stats: getSyncPlayStats(),
|
||||
@@ -428,7 +398,6 @@ import 'css!./playerstats';
|
||||
}
|
||||
|
||||
function renderPlayerStats(instance, player) {
|
||||
|
||||
const now = new Date().getTime();
|
||||
|
||||
if ((now - (instance.lastRender || 0)) < 700) {
|
||||
@@ -438,7 +407,6 @@ import 'css!./playerstats';
|
||||
instance.lastRender = now;
|
||||
|
||||
getStats(instance, player).then(function (stats) {
|
||||
|
||||
const elem = instance.element;
|
||||
if (!elem) {
|
||||
return;
|
||||
@@ -449,7 +417,6 @@ import 'css!./playerstats';
|
||||
}
|
||||
|
||||
function bindEvents(instance, player) {
|
||||
|
||||
const localOnTimeUpdate = function () {
|
||||
renderPlayerStats(instance, player);
|
||||
};
|
||||
@@ -459,7 +426,6 @@ import 'css!./playerstats';
|
||||
}
|
||||
|
||||
function unbindEvents(instance, player) {
|
||||
|
||||
const localOnTimeUpdate = instance.onTimeUpdate;
|
||||
|
||||
if (localOnTimeUpdate) {
|
||||
@@ -469,7 +435,6 @@ import 'css!./playerstats';
|
||||
|
||||
class PlayerStats {
|
||||
constructor(options) {
|
||||
|
||||
this.options = options;
|
||||
|
||||
init(this);
|
||||
@@ -478,7 +443,6 @@ class PlayerStats {
|
||||
}
|
||||
|
||||
enabled(enabled) {
|
||||
|
||||
if (enabled == null) {
|
||||
return this._enabled;
|
||||
}
|
||||
@@ -504,11 +468,9 @@ class PlayerStats {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
||||
const options = this.options;
|
||||
|
||||
if (options) {
|
||||
|
||||
this.options = null;
|
||||
unbindEvents(this, options.player);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import dialogHelper from 'dialogHelper';
|
||||
import loading from 'loading';
|
||||
import layoutManager from 'layoutManager';
|
||||
import playbackManager from 'playbackManager';
|
||||
import connectionManager from 'connectionManager';
|
||||
import * as userSettings from 'userSettings';
|
||||
import appRouter from 'appRouter';
|
||||
import globalize from 'globalize';
|
||||
@@ -22,7 +21,7 @@ import 'emby-button';
|
||||
const panel = dom.parentWithClass(this, 'dialog');
|
||||
|
||||
const playlistId = panel.querySelector('#selectPlaylistToAddTo').value;
|
||||
const apiClient = connectionManager.getApiClient(currentServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(currentServerId);
|
||||
|
||||
if (playlistId) {
|
||||
userSettings.set('playlisteditor-lastplaylistid', playlistId);
|
||||
@@ -113,7 +112,7 @@ import 'emby-button';
|
||||
EnableTotalRecordCount: false
|
||||
};
|
||||
|
||||
const apiClient = connectionManager.getApiClient(currentServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(currentServerId);
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), options).then(result => {
|
||||
let html = '';
|
||||
|
||||
@@ -210,7 +209,7 @@ import 'emby-button';
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
import('scrollHelper').then(scrollHelper => {
|
||||
import('scrollHelper').then((scrollHelper) => {
|
||||
const fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
|
||||
@@ -4,7 +4,6 @@ import playbackManager from 'playbackManager';
|
||||
import globalize from 'globalize';
|
||||
|
||||
export function show(options) {
|
||||
|
||||
var item = options.item;
|
||||
|
||||
var resumePositionTicks = item.UserData ? item.UserData.PlaybackPositionTicks : null;
|
||||
@@ -38,7 +37,6 @@ export function show(options) {
|
||||
|
||||
}).then(function (id) {
|
||||
switch (id) {
|
||||
|
||||
case 'play':
|
||||
playbackManager.play({
|
||||
ids: [playableItemId],
|
||||
|
||||
+104
-112
@@ -1,50 +1,47 @@
|
||||
define(['events', 'globalize'], function (events, globalize) {
|
||||
'use strict';
|
||||
import events from 'events';
|
||||
import globalize from 'globalize';
|
||||
/* eslint-disable indent */
|
||||
|
||||
// TODO: replace with each plugin version
|
||||
var cacheParam = new Date().getTime();
|
||||
|
||||
function loadStrings(plugin) {
|
||||
var strings = plugin.getTranslations ? plugin.getTranslations() : [];
|
||||
return globalize.loadStrings({
|
||||
name: plugin.id || plugin.packageName,
|
||||
strings: strings
|
||||
});
|
||||
}
|
||||
class PluginManager {
|
||||
pluginsList = [];
|
||||
|
||||
function definePluginRoute(pluginManager, route, plugin) {
|
||||
get plugins() {
|
||||
return this.pluginsList;
|
||||
}
|
||||
|
||||
route.contentPath = pluginManager.mapPath(plugin, route.path);
|
||||
route.path = pluginManager.mapRoute(plugin, route);
|
||||
#loadStrings(plugin) {
|
||||
var strings = plugin.getTranslations ? plugin.getTranslations() : [];
|
||||
return globalize.loadStrings({
|
||||
name: plugin.id || plugin.packageName,
|
||||
strings: strings
|
||||
});
|
||||
}
|
||||
|
||||
Emby.App.defineRoute(route, plugin.id);
|
||||
}
|
||||
#definePluginRoute(route, plugin) {
|
||||
route.contentPath = this.mapPath(plugin, route.path);
|
||||
route.path = this.#mapRoute(plugin, route);
|
||||
|
||||
function PluginManager() {
|
||||
Emby.App.defineRoute(route, plugin.id);
|
||||
}
|
||||
|
||||
this.pluginsList = [];
|
||||
}
|
||||
|
||||
PluginManager.prototype.loadPlugin = function(pluginSpec) {
|
||||
|
||||
var instance = this;
|
||||
|
||||
function registerPlugin(plugin) {
|
||||
instance.register(plugin);
|
||||
#registerPlugin(plugin) {
|
||||
this.#register(plugin);
|
||||
|
||||
if (plugin.getRoutes) {
|
||||
plugin.getRoutes().forEach(function (route) {
|
||||
definePluginRoute(instance, route, plugin);
|
||||
plugin.getRoutes().forEach((route) => {
|
||||
this.#definePluginRoute(route, plugin);
|
||||
});
|
||||
}
|
||||
|
||||
if (plugin.type === 'skin') {
|
||||
|
||||
// translations won't be loaded for skins until needed
|
||||
return Promise.resolve(plugin);
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
loadStrings(plugin)
|
||||
this.#loadStrings(plugin)
|
||||
.then(function () {
|
||||
resolve(plugin);
|
||||
})
|
||||
@@ -53,107 +50,102 @@ define(['events', 'globalize'], function (events, globalize) {
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof pluginSpec === 'string') {
|
||||
console.debug('Loading plugin (via deprecated requirejs method): ' + pluginSpec);
|
||||
loadPlugin(pluginSpec) {
|
||||
if (typeof pluginSpec === 'string') {
|
||||
console.debug('Loading plugin (via deprecated requirejs method): ' + pluginSpec);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
require([pluginSpec], (pluginFactory) => {
|
||||
var plugin = pluginFactory.default ? new pluginFactory.default() : new pluginFactory();
|
||||
return new Promise((resolve, reject) => {
|
||||
require([pluginSpec], (pluginFactory) => {
|
||||
var plugin = pluginFactory.default ? new pluginFactory.default() : new pluginFactory();
|
||||
|
||||
// See if it's already installed
|
||||
var existing = instance.pluginsList.filter(function (p) {
|
||||
return p.id === plugin.id;
|
||||
})[0];
|
||||
// See if it's already installed
|
||||
var existing = this.pluginsList.filter(function (p) {
|
||||
return p.id === plugin.id;
|
||||
})[0];
|
||||
|
||||
if (existing) {
|
||||
resolve(pluginSpec);
|
||||
}
|
||||
if (existing) {
|
||||
resolve(pluginSpec);
|
||||
}
|
||||
|
||||
plugin.installUrl = pluginSpec;
|
||||
plugin.installUrl = pluginSpec;
|
||||
|
||||
var separatorIndex = Math.max(pluginSpec.lastIndexOf('/'), pluginSpec.lastIndexOf('\\'));
|
||||
plugin.baseUrl = pluginSpec.substring(0, separatorIndex);
|
||||
var separatorIndex = Math.max(pluginSpec.lastIndexOf('/'), pluginSpec.lastIndexOf('\\'));
|
||||
plugin.baseUrl = pluginSpec.substring(0, separatorIndex);
|
||||
|
||||
var paths = {};
|
||||
paths[plugin.id] = plugin.baseUrl;
|
||||
var paths = {};
|
||||
paths[plugin.id] = plugin.baseUrl;
|
||||
|
||||
requirejs.config({
|
||||
waitSeconds: 0,
|
||||
paths: paths
|
||||
requirejs.config({
|
||||
waitSeconds: 0,
|
||||
paths: paths
|
||||
});
|
||||
|
||||
this.#registerPlugin(plugin).then(resolve).catch(reject);
|
||||
});
|
||||
|
||||
registerPlugin(plugin).then(resolve).catch(reject);
|
||||
});
|
||||
} else if (pluginSpec.then) {
|
||||
return pluginSpec.then(pluginBuilder => {
|
||||
return pluginBuilder();
|
||||
}).then((plugin) => {
|
||||
console.debug(`Plugin loaded: ${plugin.id}`);
|
||||
return this.#registerPlugin(plugin);
|
||||
});
|
||||
} else {
|
||||
const err = new TypeError('Plugins have to be a Promise that resolves to a plugin builder function or a RequireJS url (deprecated)');
|
||||
console.error(err);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}
|
||||
|
||||
// In lieu of automatic discovery, plugins will register dynamic objects
|
||||
// Each object will have the following properties:
|
||||
// name
|
||||
// type (skin, screensaver, etc)
|
||||
#register(obj) {
|
||||
this.pluginsList.push(obj);
|
||||
events.trigger(this, 'registered', [obj]);
|
||||
}
|
||||
|
||||
ofType(type) {
|
||||
return this.pluginsList.filter((o) => {
|
||||
return o.type === type;
|
||||
});
|
||||
} else if (pluginSpec.then) {
|
||||
return pluginSpec.then(pluginBuilder => {
|
||||
return pluginBuilder();
|
||||
}).then(plugin => {
|
||||
console.debug(`Plugin loaded: ${plugin.id}`);
|
||||
return registerPlugin(plugin);
|
||||
});
|
||||
} else {
|
||||
const err = new Error('Plugins have to be a Promise that resolves to a plugin builder function or a requirejs urls (deprecated)');
|
||||
console.error(err);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
};
|
||||
|
||||
// In lieu of automatic discovery, plugins will register dynamic objects
|
||||
// Each object will have the following properties:
|
||||
// name
|
||||
// type (skin, screensaver, etc)
|
||||
PluginManager.prototype.register = function (obj) {
|
||||
|
||||
this.pluginsList.push(obj);
|
||||
events.trigger(this, 'registered', [obj]);
|
||||
};
|
||||
|
||||
PluginManager.prototype.ofType = function (type) {
|
||||
|
||||
return this.pluginsList.filter(function (o) {
|
||||
return o.type === type;
|
||||
});
|
||||
};
|
||||
|
||||
PluginManager.prototype.plugins = function () {
|
||||
return this.pluginsList;
|
||||
};
|
||||
|
||||
PluginManager.prototype.mapRoute = function (plugin, route) {
|
||||
|
||||
if (typeof plugin === 'string') {
|
||||
plugin = this.pluginsList.filter(function (p) {
|
||||
return (p.id || p.packageName) === plugin;
|
||||
})[0];
|
||||
}
|
||||
|
||||
route = route.path || route;
|
||||
#mapRoute(plugin, route) {
|
||||
if (typeof plugin === 'string') {
|
||||
plugin = this.pluginsList.filter((p) => {
|
||||
return (p.id || p.packageName) === plugin;
|
||||
})[0];
|
||||
}
|
||||
|
||||
if (route.toLowerCase().indexOf('http') === 0) {
|
||||
return route;
|
||||
route = route.path || route;
|
||||
|
||||
if (route.toLowerCase().startsWith('http')) {
|
||||
return route;
|
||||
}
|
||||
|
||||
return '/plugins/' + plugin.id + '/' + route;
|
||||
}
|
||||
|
||||
return '/plugins/' + plugin.id + '/' + route;
|
||||
};
|
||||
mapPath(plugin, path, addCacheParam) {
|
||||
if (typeof plugin === 'string') {
|
||||
plugin = this.pluginsList.filter((p) => {
|
||||
return (p.id || p.packageName) === plugin;
|
||||
})[0];
|
||||
}
|
||||
|
||||
PluginManager.prototype.mapPath = function (plugin, path, addCacheParam) {
|
||||
var url = plugin.baseUrl + '/' + path;
|
||||
|
||||
if (typeof plugin === 'string') {
|
||||
plugin = this.pluginsList.filter(function (p) {
|
||||
return (p.id || p.packageName) === plugin;
|
||||
})[0];
|
||||
if (addCacheParam) {
|
||||
url += url.includes('?') ? '&' : '?';
|
||||
url += 'v=' + cacheParam;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
var url = plugin.baseUrl + '/' + path;
|
||||
/* eslint-enable indent */
|
||||
|
||||
if (addCacheParam) {
|
||||
url += url.indexOf('?') === -1 ? '?' : '&';
|
||||
url += 'v=' + cacheParam;
|
||||
}
|
||||
|
||||
return url;
|
||||
};
|
||||
|
||||
return new PluginManager();
|
||||
});
|
||||
export default new PluginManager();
|
||||
|
||||
@@ -12,7 +12,6 @@ import 'formDialogStyle';
|
||||
|
||||
/* eslint-disable indent */
|
||||
export default (() => {
|
||||
|
||||
function replaceAll(str, find, replace) {
|
||||
return str.split(find).join(replace);
|
||||
}
|
||||
@@ -68,7 +67,6 @@ export default (() => {
|
||||
let submitValue;
|
||||
|
||||
dlg.querySelector('form').addEventListener('submit', e => {
|
||||
|
||||
submitValue = dlg.querySelector('#txtInput').value;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
+149
-161
@@ -1,170 +1,158 @@
|
||||
define(['globalize'], function (globalize) {
|
||||
'use strict';
|
||||
import globalize from 'globalize';
|
||||
|
||||
function getVideoQualityOptions(options) {
|
||||
export function getVideoQualityOptions(options) {
|
||||
var maxStreamingBitrate = options.currentMaxBitrate;
|
||||
var videoWidth = options.videoWidth;
|
||||
var videoHeight = options.videoHeight;
|
||||
|
||||
var maxStreamingBitrate = options.currentMaxBitrate;
|
||||
var videoWidth = options.videoWidth;
|
||||
var videoHeight = options.videoHeight;
|
||||
|
||||
// If the aspect ratio is less than 16/9 (1.77), set the width as if it were pillarboxed.
|
||||
// 4:3 1440x1080 -> 1920x1080
|
||||
if (videoWidth / videoHeight < 16 / 9) {
|
||||
videoWidth = videoHeight * (16 / 9);
|
||||
}
|
||||
|
||||
var maxAllowedWidth = videoWidth || 4096;
|
||||
//var maxAllowedHeight = videoHeight || 2304;
|
||||
|
||||
var qualityOptions = [];
|
||||
|
||||
if (maxAllowedWidth >= 3800) {
|
||||
qualityOptions.push({ name: '4K - 120 Mbps', maxHeight: 2160, bitrate: 120000000 });
|
||||
qualityOptions.push({ name: '4K - 100 Mbps', maxHeight: 2160, bitrate: 100000000 });
|
||||
qualityOptions.push({ name: '4K - 80 Mbps', maxHeight: 2160, bitrate: 80000000 });
|
||||
}
|
||||
|
||||
// Some 1080- videos are reported as 1912?
|
||||
if (maxAllowedWidth >= 1900) {
|
||||
|
||||
qualityOptions.push({ name: '1080p - 60 Mbps', maxHeight: 1080, bitrate: 60000000 });
|
||||
qualityOptions.push({ name: '1080p - 50 Mbps', maxHeight: 1080, bitrate: 50000000 });
|
||||
qualityOptions.push({ name: '1080p - 40 Mbps', maxHeight: 1080, bitrate: 40000000 });
|
||||
qualityOptions.push({ name: '1080p - 30 Mbps', maxHeight: 1080, bitrate: 30000000 });
|
||||
qualityOptions.push({ name: '1080p - 25 Mbps', maxHeight: 1080, bitrate: 25000000 });
|
||||
qualityOptions.push({ name: '1080p - 20 Mbps', maxHeight: 1080, bitrate: 20000000 });
|
||||
qualityOptions.push({ name: '1080p - 15 Mbps', maxHeight: 1080, bitrate: 15000000 });
|
||||
qualityOptions.push({ name: '1080p - 10 Mbps', maxHeight: 1080, bitrate: 10000001 });
|
||||
qualityOptions.push({ name: '1080p - 8 Mbps', maxHeight: 1080, bitrate: 8000001 });
|
||||
qualityOptions.push({ name: '1080p - 6 Mbps', maxHeight: 1080, bitrate: 6000001 });
|
||||
qualityOptions.push({ name: '1080p - 5 Mbps', maxHeight: 1080, bitrate: 5000001 });
|
||||
qualityOptions.push({ name: '1080p - 4 Mbps', maxHeight: 1080, bitrate: 4000002 });
|
||||
|
||||
} else if (maxAllowedWidth >= 1260) {
|
||||
qualityOptions.push({ name: '720p - 10 Mbps', maxHeight: 720, bitrate: 10000000 });
|
||||
qualityOptions.push({ name: '720p - 8 Mbps', maxHeight: 720, bitrate: 8000000 });
|
||||
qualityOptions.push({ name: '720p - 6 Mbps', maxHeight: 720, bitrate: 6000000 });
|
||||
qualityOptions.push({ name: '720p - 5 Mbps', maxHeight: 720, bitrate: 5000000 });
|
||||
|
||||
} else if (maxAllowedWidth >= 620) {
|
||||
qualityOptions.push({ name: '480p - 4 Mbps', maxHeight: 480, bitrate: 4000001 });
|
||||
qualityOptions.push({ name: '480p - 3 Mbps', maxHeight: 480, bitrate: 3000001 });
|
||||
qualityOptions.push({ name: '480p - 2.5 Mbps', maxHeight: 480, bitrate: 2500000 });
|
||||
qualityOptions.push({ name: '480p - 2 Mbps', maxHeight: 480, bitrate: 2000001 });
|
||||
qualityOptions.push({ name: '480p - 1.5 Mbps', maxHeight: 480, bitrate: 1500001 });
|
||||
}
|
||||
|
||||
if (maxAllowedWidth >= 1260) {
|
||||
qualityOptions.push({ name: '720p - 4 Mbps', maxHeight: 720, bitrate: 4000000 });
|
||||
qualityOptions.push({ name: '720p - 3 Mbps', maxHeight: 720, bitrate: 3000000 });
|
||||
qualityOptions.push({ name: '720p - 2 Mbps', maxHeight: 720, bitrate: 2000000 });
|
||||
|
||||
// The extra 1 is because they're keyed off the bitrate value
|
||||
qualityOptions.push({ name: '720p - 1.5 Mbps', maxHeight: 720, bitrate: 1500000 });
|
||||
qualityOptions.push({ name: '720p - 1 Mbps', maxHeight: 720, bitrate: 1000001 });
|
||||
}
|
||||
|
||||
qualityOptions.push({ name: '480p - 1 Mbps', maxHeight: 480, bitrate: 1000000 });
|
||||
qualityOptions.push({ name: '480p - 720 kbps', maxHeight: 480, bitrate: 720000 });
|
||||
qualityOptions.push({ name: '480p - 420 kbps', maxHeight: 480, bitrate: 420000 });
|
||||
qualityOptions.push({ name: '360p', maxHeight: 360, bitrate: 400000 });
|
||||
qualityOptions.push({ name: '240p', maxHeight: 240, bitrate: 320000 });
|
||||
qualityOptions.push({ name: '144p', maxHeight: 144, bitrate: 192000 });
|
||||
|
||||
var autoQualityOption = {
|
||||
name: globalize.translate('Auto'),
|
||||
bitrate: 0,
|
||||
selected: options.isAutomaticBitrateEnabled
|
||||
};
|
||||
|
||||
if (options.enableAuto) {
|
||||
qualityOptions.push(autoQualityOption);
|
||||
}
|
||||
|
||||
if (maxStreamingBitrate) {
|
||||
var selectedIndex = -1;
|
||||
for (var i = 0, length = qualityOptions.length; i < length; i++) {
|
||||
|
||||
var option = qualityOptions[i];
|
||||
|
||||
if (selectedIndex === -1 && option.bitrate <= maxStreamingBitrate) {
|
||||
selectedIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedIndex === -1) {
|
||||
|
||||
selectedIndex = qualityOptions.length - 1;
|
||||
}
|
||||
|
||||
var currentQualityOption = qualityOptions[selectedIndex];
|
||||
|
||||
if (!options.isAutomaticBitrateEnabled) {
|
||||
currentQualityOption.selected = true;
|
||||
} else {
|
||||
autoQualityOption.autoText = currentQualityOption.name;
|
||||
}
|
||||
}
|
||||
|
||||
return qualityOptions;
|
||||
// If the aspect ratio is less than 16/9 (1.77), set the width as if it were pillarboxed.
|
||||
// 4:3 1440x1080 -> 1920x1080
|
||||
if (videoWidth / videoHeight < 16 / 9) {
|
||||
videoWidth = videoHeight * (16 / 9);
|
||||
}
|
||||
|
||||
function getAudioQualityOptions(options) {
|
||||
var maxAllowedWidth = videoWidth || 4096;
|
||||
|
||||
var maxStreamingBitrate = options.currentMaxBitrate;
|
||||
var qualityOptions = [];
|
||||
|
||||
var qualityOptions = [];
|
||||
|
||||
qualityOptions.push({ name: '2 Mbps', bitrate: 2000000 });
|
||||
qualityOptions.push({ name: '1.5 Mbps', bitrate: 1500000 });
|
||||
qualityOptions.push({ name: '1 Mbps', bitrate: 1000000 });
|
||||
qualityOptions.push({ name: '320 kbps', bitrate: 320000 });
|
||||
qualityOptions.push({ name: '256 kbps', bitrate: 256000 });
|
||||
qualityOptions.push({ name: '192 kbps', bitrate: 192000 });
|
||||
qualityOptions.push({ name: '128 kbps', bitrate: 128000 });
|
||||
qualityOptions.push({ name: '96 kbps', bitrate: 96000 });
|
||||
qualityOptions.push({ name: '64 kbps', bitrate: 64000 });
|
||||
|
||||
var autoQualityOption = {
|
||||
name: globalize.translate('Auto'),
|
||||
bitrate: 0,
|
||||
selected: options.isAutomaticBitrateEnabled
|
||||
};
|
||||
|
||||
if (options.enableAuto) {
|
||||
qualityOptions.push(autoQualityOption);
|
||||
}
|
||||
|
||||
if (maxStreamingBitrate) {
|
||||
var selectedIndex = -1;
|
||||
for (var i = 0, length = qualityOptions.length; i < length; i++) {
|
||||
|
||||
var option = qualityOptions[i];
|
||||
|
||||
if (selectedIndex === -1 && option.bitrate <= maxStreamingBitrate) {
|
||||
selectedIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedIndex === -1) {
|
||||
|
||||
selectedIndex = qualityOptions.length - 1;
|
||||
}
|
||||
|
||||
var currentQualityOption = qualityOptions[selectedIndex];
|
||||
|
||||
if (!options.isAutomaticBitrateEnabled) {
|
||||
currentQualityOption.selected = true;
|
||||
} else {
|
||||
autoQualityOption.autoText = currentQualityOption.name;
|
||||
}
|
||||
}
|
||||
|
||||
return qualityOptions;
|
||||
if (maxAllowedWidth >= 3800) {
|
||||
qualityOptions.push({ name: '4K - 120 Mbps', maxHeight: 2160, bitrate: 120000000 });
|
||||
qualityOptions.push({ name: '4K - 100 Mbps', maxHeight: 2160, bitrate: 100000000 });
|
||||
qualityOptions.push({ name: '4K - 80 Mbps', maxHeight: 2160, bitrate: 80000000 });
|
||||
}
|
||||
|
||||
return {
|
||||
getVideoQualityOptions: getVideoQualityOptions,
|
||||
getAudioQualityOptions: getAudioQualityOptions
|
||||
// Some 1080- videos are reported as 1912?
|
||||
if (maxAllowedWidth >= 1900) {
|
||||
qualityOptions.push({ name: '1080p - 60 Mbps', maxHeight: 1080, bitrate: 60000000 });
|
||||
qualityOptions.push({ name: '1080p - 50 Mbps', maxHeight: 1080, bitrate: 50000000 });
|
||||
qualityOptions.push({ name: '1080p - 40 Mbps', maxHeight: 1080, bitrate: 40000000 });
|
||||
qualityOptions.push({ name: '1080p - 30 Mbps', maxHeight: 1080, bitrate: 30000000 });
|
||||
qualityOptions.push({ name: '1080p - 25 Mbps', maxHeight: 1080, bitrate: 25000000 });
|
||||
qualityOptions.push({ name: '1080p - 20 Mbps', maxHeight: 1080, bitrate: 20000000 });
|
||||
qualityOptions.push({ name: '1080p - 15 Mbps', maxHeight: 1080, bitrate: 15000000 });
|
||||
qualityOptions.push({ name: '1080p - 10 Mbps', maxHeight: 1080, bitrate: 10000001 });
|
||||
qualityOptions.push({ name: '1080p - 8 Mbps', maxHeight: 1080, bitrate: 8000001 });
|
||||
qualityOptions.push({ name: '1080p - 6 Mbps', maxHeight: 1080, bitrate: 6000001 });
|
||||
qualityOptions.push({ name: '1080p - 5 Mbps', maxHeight: 1080, bitrate: 5000001 });
|
||||
qualityOptions.push({ name: '1080p - 4 Mbps', maxHeight: 1080, bitrate: 4000002 });
|
||||
} else if (maxAllowedWidth >= 1260) {
|
||||
qualityOptions.push({ name: '720p - 10 Mbps', maxHeight: 720, bitrate: 10000000 });
|
||||
qualityOptions.push({ name: '720p - 8 Mbps', maxHeight: 720, bitrate: 8000000 });
|
||||
qualityOptions.push({ name: '720p - 6 Mbps', maxHeight: 720, bitrate: 6000000 });
|
||||
qualityOptions.push({ name: '720p - 5 Mbps', maxHeight: 720, bitrate: 5000000 });
|
||||
} else if (maxAllowedWidth >= 620) {
|
||||
qualityOptions.push({ name: '480p - 4 Mbps', maxHeight: 480, bitrate: 4000001 });
|
||||
qualityOptions.push({ name: '480p - 3 Mbps', maxHeight: 480, bitrate: 3000001 });
|
||||
qualityOptions.push({ name: '480p - 2.5 Mbps', maxHeight: 480, bitrate: 2500000 });
|
||||
qualityOptions.push({ name: '480p - 2 Mbps', maxHeight: 480, bitrate: 2000001 });
|
||||
qualityOptions.push({ name: '480p - 1.5 Mbps', maxHeight: 480, bitrate: 1500001 });
|
||||
}
|
||||
|
||||
if (maxAllowedWidth >= 1260) {
|
||||
qualityOptions.push({ name: '720p - 4 Mbps', maxHeight: 720, bitrate: 4000000 });
|
||||
qualityOptions.push({ name: '720p - 3 Mbps', maxHeight: 720, bitrate: 3000000 });
|
||||
qualityOptions.push({ name: '720p - 2 Mbps', maxHeight: 720, bitrate: 2000000 });
|
||||
|
||||
// The extra 1 is because they're keyed off the bitrate value
|
||||
qualityOptions.push({ name: '720p - 1.5 Mbps', maxHeight: 720, bitrate: 1500000 });
|
||||
qualityOptions.push({ name: '720p - 1 Mbps', maxHeight: 720, bitrate: 1000001 });
|
||||
}
|
||||
|
||||
qualityOptions.push({ name: '480p - 1 Mbps', maxHeight: 480, bitrate: 1000000 });
|
||||
qualityOptions.push({ name: '480p - 720 kbps', maxHeight: 480, bitrate: 720000 });
|
||||
qualityOptions.push({ name: '480p - 420 kbps', maxHeight: 480, bitrate: 420000 });
|
||||
qualityOptions.push({ name: '360p', maxHeight: 360, bitrate: 400000 });
|
||||
qualityOptions.push({ name: '240p', maxHeight: 240, bitrate: 320000 });
|
||||
qualityOptions.push({ name: '144p', maxHeight: 144, bitrate: 192000 });
|
||||
|
||||
var autoQualityOption = {
|
||||
name: globalize.translate('Auto'),
|
||||
bitrate: 0,
|
||||
selected: options.isAutomaticBitrateEnabled
|
||||
};
|
||||
});
|
||||
|
||||
if (options.enableAuto) {
|
||||
qualityOptions.push(autoQualityOption);
|
||||
}
|
||||
|
||||
if (maxStreamingBitrate) {
|
||||
var selectedIndex = -1;
|
||||
for (var i = 0, length = qualityOptions.length; i < length; i++) {
|
||||
var option = qualityOptions[i];
|
||||
|
||||
if (selectedIndex === -1 && option.bitrate <= maxStreamingBitrate) {
|
||||
selectedIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedIndex === -1) {
|
||||
selectedIndex = qualityOptions.length - 1;
|
||||
}
|
||||
|
||||
var currentQualityOption = qualityOptions[selectedIndex];
|
||||
|
||||
if (!options.isAutomaticBitrateEnabled) {
|
||||
currentQualityOption.selected = true;
|
||||
} else {
|
||||
autoQualityOption.autoText = currentQualityOption.name;
|
||||
}
|
||||
}
|
||||
|
||||
return qualityOptions;
|
||||
}
|
||||
|
||||
export function getAudioQualityOptions(options) {
|
||||
var maxStreamingBitrate = options.currentMaxBitrate;
|
||||
|
||||
var qualityOptions = [];
|
||||
|
||||
qualityOptions.push({ name: '2 Mbps', bitrate: 2000000 });
|
||||
qualityOptions.push({ name: '1.5 Mbps', bitrate: 1500000 });
|
||||
qualityOptions.push({ name: '1 Mbps', bitrate: 1000000 });
|
||||
qualityOptions.push({ name: '320 kbps', bitrate: 320000 });
|
||||
qualityOptions.push({ name: '256 kbps', bitrate: 256000 });
|
||||
qualityOptions.push({ name: '192 kbps', bitrate: 192000 });
|
||||
qualityOptions.push({ name: '128 kbps', bitrate: 128000 });
|
||||
qualityOptions.push({ name: '96 kbps', bitrate: 96000 });
|
||||
qualityOptions.push({ name: '64 kbps', bitrate: 64000 });
|
||||
|
||||
var autoQualityOption = {
|
||||
name: globalize.translate('Auto'),
|
||||
bitrate: 0,
|
||||
selected: options.isAutomaticBitrateEnabled
|
||||
};
|
||||
|
||||
if (options.enableAuto) {
|
||||
qualityOptions.push(autoQualityOption);
|
||||
}
|
||||
|
||||
if (maxStreamingBitrate) {
|
||||
var selectedIndex = -1;
|
||||
for (var i = 0, length = qualityOptions.length; i < length; i++) {
|
||||
var option = qualityOptions[i];
|
||||
|
||||
if (selectedIndex === -1 && option.bitrate <= maxStreamingBitrate) {
|
||||
selectedIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedIndex === -1) {
|
||||
selectedIndex = qualityOptions.length - 1;
|
||||
}
|
||||
|
||||
var currentQualityOption = qualityOptions[selectedIndex];
|
||||
|
||||
if (!options.isAutomaticBitrateEnabled) {
|
||||
currentQualityOption.selected = true;
|
||||
} else {
|
||||
autoQualityOption.autoText = currentQualityOption.name;
|
||||
}
|
||||
}
|
||||
|
||||
return qualityOptions;
|
||||
}
|
||||
|
||||
export default {
|
||||
getVideoQualityOptions,
|
||||
getAudioQualityOptions
|
||||
};
|
||||
|
||||
@@ -1,37 +1,39 @@
|
||||
define(['globalize', 'connectionManager', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'paper-icon-button-light', 'emby-button', 'css!./recordingfields'], function (globalize, connectionManager, require, loading, appHost, dom, recordingHelper, events) {
|
||||
'use strict';
|
||||
import dom from 'dom';
|
||||
import recordingHelper from 'recordingHelper';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-button';
|
||||
import 'css!./recordingfields';
|
||||
|
||||
function onRecordingButtonClick(e) {
|
||||
function onRecordingButtonClick(e) {
|
||||
const item = this.item;
|
||||
|
||||
var item = this.item;
|
||||
if (item) {
|
||||
const serverId = item.ServerId;
|
||||
const programId = item.Id;
|
||||
const timerId = item.TimerId;
|
||||
const timerStatus = item.Status;
|
||||
const seriesTimerId = item.SeriesTimerId;
|
||||
|
||||
if (item) {
|
||||
const instance = this;
|
||||
|
||||
var serverId = item.ServerId;
|
||||
var programId = item.Id;
|
||||
var timerId = item.TimerId;
|
||||
var timerStatus = item.Status;
|
||||
var seriesTimerId = item.SeriesTimerId;
|
||||
|
||||
var instance = this;
|
||||
|
||||
recordingHelper.toggleRecording(serverId, programId, timerId, timerStatus, seriesTimerId).then(function () {
|
||||
instance.refresh(serverId, programId);
|
||||
});
|
||||
}
|
||||
recordingHelper.toggleRecording(serverId, programId, timerId, timerStatus, seriesTimerId).then(function () {
|
||||
instance.refresh(serverId, programId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function setButtonIcon(button, icon) {
|
||||
var inner = button.querySelector('.material-icons');
|
||||
inner.classList.remove('fiber_smart_record');
|
||||
inner.classList.remove('fiber_manual_record');
|
||||
inner.classList.add(icon);
|
||||
}
|
||||
function setButtonIcon(button, icon) {
|
||||
const inner = button.querySelector('.material-icons');
|
||||
inner.classList.remove('fiber_smart_record');
|
||||
inner.classList.remove('fiber_manual_record');
|
||||
inner.classList.add(icon);
|
||||
}
|
||||
|
||||
function RecordingButton(options) {
|
||||
class RecordingButton {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
|
||||
var button = options.button;
|
||||
const button = options.button;
|
||||
|
||||
setButtonIcon(button, 'fiber_manual_record');
|
||||
|
||||
@@ -41,7 +43,7 @@ define(['globalize', 'connectionManager', 'require', 'loading', 'apphost', 'dom'
|
||||
this.refresh(options.itemId, options.serverId);
|
||||
}
|
||||
|
||||
var clickFn = onRecordingButtonClick.bind(this);
|
||||
const clickFn = onRecordingButtonClick.bind(this);
|
||||
this.clickFn = clickFn;
|
||||
|
||||
dom.addEventListener(button, 'click', clickFn, {
|
||||
@@ -49,45 +51,17 @@ define(['globalize', 'connectionManager', 'require', 'loading', 'apphost', 'dom'
|
||||
});
|
||||
}
|
||||
|
||||
function getIndicatorIcon(item) {
|
||||
|
||||
var status;
|
||||
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
return 'fiber_smart_record';
|
||||
} else if (item.TimerId || item.SeriesTimerId) {
|
||||
|
||||
status = item.Status || 'Cancelled';
|
||||
} else if (item.Type === 'Timer') {
|
||||
|
||||
status = item.Status;
|
||||
} else {
|
||||
return 'fiber_manual_record';
|
||||
}
|
||||
|
||||
if (item.SeriesTimerId) {
|
||||
|
||||
if (status !== 'Cancelled') {
|
||||
return 'fiber_smart_record';
|
||||
}
|
||||
}
|
||||
|
||||
return 'fiber_manual_record';
|
||||
}
|
||||
|
||||
RecordingButton.prototype.refresh = function (serverId, itemId) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
var self = this;
|
||||
refresh(serverId, itemId) {
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
const self = this;
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
|
||||
self.refreshItem(item);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
RecordingButton.prototype.refreshItem = function (item) {
|
||||
|
||||
var options = this.options;
|
||||
var button = options.button;
|
||||
refreshItem(item) {
|
||||
const options = this.options;
|
||||
const button = options.button;
|
||||
this.item = item;
|
||||
setButtonIcon(button, getIndicatorIcon(item));
|
||||
|
||||
@@ -96,16 +70,15 @@ define(['globalize', 'connectionManager', 'require', 'loading', 'apphost', 'dom'
|
||||
} else {
|
||||
button.classList.remove('recordingIcon-active');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
RecordingButton.prototype.destroy = function () {
|
||||
|
||||
var options = this.options;
|
||||
destroy() {
|
||||
const options = this.options;
|
||||
|
||||
if (options) {
|
||||
var button = options.button;
|
||||
const button = options.button;
|
||||
|
||||
var clickFn = this.clickFn;
|
||||
const clickFn = this.clickFn;
|
||||
|
||||
if (clickFn) {
|
||||
dom.removeEventListener(button, 'click', clickFn, {
|
||||
@@ -116,7 +89,29 @@ define(['globalize', 'connectionManager', 'require', 'loading', 'apphost', 'dom'
|
||||
|
||||
this.options = null;
|
||||
this.item = null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return RecordingButton;
|
||||
});
|
||||
function getIndicatorIcon(item) {
|
||||
let status;
|
||||
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
return 'fiber_smart_record';
|
||||
} else if (item.TimerId || item.SeriesTimerId) {
|
||||
status = item.Status || 'Cancelled';
|
||||
} else if (item.Type === 'Timer') {
|
||||
status = item.Status;
|
||||
} else {
|
||||
return 'fiber_manual_record';
|
||||
}
|
||||
|
||||
if (item.SeriesTimerId) {
|
||||
if (status !== 'Cancelled') {
|
||||
return 'fiber_smart_record';
|
||||
}
|
||||
}
|
||||
|
||||
return 'fiber_manual_record';
|
||||
}
|
||||
|
||||
export default RecordingButton;
|
||||
|
||||
@@ -1,205 +1,203 @@
|
||||
define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'datetime', 'imageLoader', 'recordingFields', 'events', 'emby-checkbox', 'emby-button', 'emby-collapse', 'emby-input', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, datetime, imageLoader, recordingFields, events) {
|
||||
'use strict';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import globalize from 'globalize';
|
||||
import layoutManager from 'layoutManager';
|
||||
import mediaInfo from 'mediaInfo';
|
||||
import require from 'require';
|
||||
import loading from 'loading';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import datetime from 'datetime';
|
||||
import imageLoader from 'imageLoader';
|
||||
import recordingFields from 'recordingFields';
|
||||
import events from 'events';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-button';
|
||||
import 'emby-collapse';
|
||||
import 'emby-input';
|
||||
import 'paper-icon-button-light';
|
||||
import 'css!./../formdialog';
|
||||
import 'css!./recordingcreator';
|
||||
import 'material-icons';
|
||||
|
||||
var currentDialog;
|
||||
var closeAction;
|
||||
var currentRecordingFields;
|
||||
let currentDialog;
|
||||
let closeAction;
|
||||
let currentRecordingFields;
|
||||
|
||||
function closeDialog() {
|
||||
function closeDialog() {
|
||||
dialogHelper.close(currentDialog);
|
||||
}
|
||||
|
||||
dialogHelper.close(currentDialog);
|
||||
function init(context) {
|
||||
context.querySelector('.btnPlay').addEventListener('click', function () {
|
||||
closeAction = 'play';
|
||||
closeDialog();
|
||||
});
|
||||
|
||||
context.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
closeAction = null;
|
||||
closeDialog();
|
||||
});
|
||||
}
|
||||
|
||||
function getImageUrl(item, apiClient, imageHeight) {
|
||||
const imageTags = item.ImageTags || {};
|
||||
|
||||
if (item.PrimaryImageTag) {
|
||||
imageTags.Primary = item.PrimaryImageTag;
|
||||
}
|
||||
|
||||
function init(context) {
|
||||
|
||||
context.querySelector('.btnPlay').addEventListener('click', function () {
|
||||
|
||||
closeAction = 'play';
|
||||
closeDialog();
|
||||
if (imageTags.Primary) {
|
||||
return apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Primary',
|
||||
maxHeight: imageHeight,
|
||||
tag: item.ImageTags.Primary
|
||||
});
|
||||
|
||||
context.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
closeAction = null;
|
||||
closeDialog();
|
||||
} else if (imageTags.Thumb) {
|
||||
return apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Thumb',
|
||||
maxHeight: imageHeight,
|
||||
tag: item.ImageTags.Thumb
|
||||
});
|
||||
}
|
||||
|
||||
function getImageUrl(item, apiClient, imageHeight) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var imageTags = item.ImageTags || {};
|
||||
function renderRecording(context, defaultTimer, program, apiClient, refreshRecordingStateOnly) {
|
||||
if (!refreshRecordingStateOnly) {
|
||||
const imgUrl = getImageUrl(program, apiClient, 200);
|
||||
const imageContainer = context.querySelector('.recordingDialog-imageContainer');
|
||||
|
||||
if (item.PrimaryImageTag) {
|
||||
imageTags.Primary = item.PrimaryImageTag;
|
||||
if (imgUrl) {
|
||||
imageContainer.innerHTML = '<img src="' + require.toUrl('.').split('?')[0] + '/empty.png" data-src="' + imgUrl + '" class="recordingDialog-img lazy" />';
|
||||
imageContainer.classList.remove('hide');
|
||||
|
||||
imageLoader.lazyChildren(imageContainer);
|
||||
} else {
|
||||
imageContainer.innerHTML = '';
|
||||
imageContainer.classList.add('hide');
|
||||
}
|
||||
|
||||
if (imageTags.Primary) {
|
||||
context.querySelector('.recordingDialog-itemName').innerHTML = program.Name;
|
||||
context.querySelector('.formDialogHeaderTitle').innerHTML = program.Name;
|
||||
context.querySelector('.itemGenres').innerHTML = (program.Genres || []).join(' / ');
|
||||
context.querySelector('.itemOverview').innerHTML = program.Overview || '';
|
||||
|
||||
return apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Primary',
|
||||
maxHeight: imageHeight,
|
||||
tag: item.ImageTags.Primary
|
||||
const formDialogFooter = context.querySelector('.formDialogFooter');
|
||||
const now = new Date();
|
||||
if (now >= datetime.parseISO8601Date(program.StartDate, true) && now < datetime.parseISO8601Date(program.EndDate, true)) {
|
||||
formDialogFooter.classList.remove('hide');
|
||||
} else {
|
||||
formDialogFooter.classList.add('hide');
|
||||
}
|
||||
|
||||
context.querySelector('.itemMiscInfoPrimary').innerHTML = mediaInfo.getPrimaryMediaInfoHtml(program);
|
||||
}
|
||||
|
||||
context.querySelector('.itemMiscInfoSecondary').innerHTML = mediaInfo.getSecondaryMediaInfoHtml(program, {
|
||||
});
|
||||
|
||||
loading.hide();
|
||||
}
|
||||
|
||||
function reload(context, programId, serverId, refreshRecordingStateOnly) {
|
||||
loading.show();
|
||||
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
const promise1 = apiClient.getNewLiveTvTimerDefaults({ programId: programId });
|
||||
const promise2 = apiClient.getLiveTvProgram(programId, apiClient.getCurrentUserId());
|
||||
|
||||
Promise.all([promise1, promise2]).then(function (responses) {
|
||||
const defaults = responses[0];
|
||||
const program = responses[1];
|
||||
|
||||
renderRecording(context, defaults, program, apiClient, refreshRecordingStateOnly);
|
||||
});
|
||||
}
|
||||
|
||||
function executeCloseAction(action, programId, serverId) {
|
||||
if (action === 'play') {
|
||||
import('playbackManager').then(({ default: playbackManager }) => {
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
apiClient.getLiveTvProgram(programId, apiClient.getCurrentUserId()).then(function (item) {
|
||||
playbackManager.play({
|
||||
ids: [item.ChannelId],
|
||||
serverId: serverId
|
||||
});
|
||||
});
|
||||
} else if (imageTags.Thumb) {
|
||||
|
||||
return apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Thumb',
|
||||
maxHeight: imageHeight,
|
||||
tag: item.ImageTags.Thumb
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function renderRecording(context, defaultTimer, program, apiClient, refreshRecordingStateOnly) {
|
||||
|
||||
if (!refreshRecordingStateOnly) {
|
||||
var imgUrl = getImageUrl(program, apiClient, 200);
|
||||
var imageContainer = context.querySelector('.recordingDialog-imageContainer');
|
||||
|
||||
if (imgUrl) {
|
||||
imageContainer.innerHTML = '<img src="' + require.toUrl('.').split('?')[0] + '/empty.png" data-src="' + imgUrl + '" class="recordingDialog-img lazy" />';
|
||||
imageContainer.classList.remove('hide');
|
||||
|
||||
imageLoader.lazyChildren(imageContainer);
|
||||
} else {
|
||||
imageContainer.innerHTML = '';
|
||||
imageContainer.classList.add('hide');
|
||||
}
|
||||
|
||||
context.querySelector('.recordingDialog-itemName').innerHTML = program.Name;
|
||||
context.querySelector('.formDialogHeaderTitle').innerHTML = program.Name;
|
||||
context.querySelector('.itemGenres').innerHTML = (program.Genres || []).join(' / ');
|
||||
context.querySelector('.itemOverview').innerHTML = program.Overview || '';
|
||||
|
||||
var formDialogFooter = context.querySelector('.formDialogFooter');
|
||||
var now = new Date();
|
||||
if (now >= datetime.parseISO8601Date(program.StartDate, true) && now < datetime.parseISO8601Date(program.EndDate, true)) {
|
||||
formDialogFooter.classList.remove('hide');
|
||||
} else {
|
||||
formDialogFooter.classList.add('hide');
|
||||
}
|
||||
|
||||
context.querySelector('.itemMiscInfoPrimary').innerHTML = mediaInfo.getPrimaryMediaInfoHtml(program);
|
||||
}
|
||||
|
||||
context.querySelector('.itemMiscInfoSecondary').innerHTML = mediaInfo.getSecondaryMediaInfoHtml(program, {
|
||||
});
|
||||
|
||||
loading.hide();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function reload(context, programId, serverId, refreshRecordingStateOnly) {
|
||||
function showEditor(itemId, serverId) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
closeAction = null;
|
||||
|
||||
loading.show();
|
||||
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
import('text!./recordingcreator.template.html').then(({ default: template }) => {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
var promise1 = apiClient.getNewLiveTvTimerDefaults({ programId: programId });
|
||||
var promise2 = apiClient.getLiveTvProgram(programId, apiClient.getCurrentUserId());
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
Promise.all([promise1, promise2]).then(function (responses) {
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
var defaults = responses[0];
|
||||
var program = responses[1];
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.classList.add('recordingDialog');
|
||||
|
||||
renderRecording(context, defaults, program, apiClient, refreshRecordingStateOnly);
|
||||
});
|
||||
}
|
||||
let html = '';
|
||||
|
||||
function executeCloseAction(action, programId, serverId) {
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
|
||||
if (action === 'play') {
|
||||
dlg.innerHTML = html;
|
||||
|
||||
require(['playbackManager'], function (playbackManager) {
|
||||
currentDialog = dlg;
|
||||
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
function onRecordingChanged() {
|
||||
reload(dlg, itemId, serverId, true);
|
||||
}
|
||||
|
||||
apiClient.getLiveTvProgram(programId, apiClient.getCurrentUserId()).then(function (item) {
|
||||
dlg.addEventListener('close', function () {
|
||||
events.off(currentRecordingFields, 'recordingchanged', onRecordingChanged);
|
||||
executeCloseAction(closeAction, itemId, serverId);
|
||||
|
||||
playbackManager.play({
|
||||
ids: [item.ChannelId],
|
||||
serverId: serverId
|
||||
});
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function showEditor(itemId, serverId) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
closeAction = null;
|
||||
|
||||
loading.show();
|
||||
|
||||
require(['text!./recordingcreator.template.html'], function (template) {
|
||||
|
||||
var dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
if (currentRecordingFields && currentRecordingFields.hasChanged()) {
|
||||
resolve();
|
||||
} else {
|
||||
dialogOptions.size = 'small';
|
||||
reject();
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.classList.add('recordingDialog');
|
||||
|
||||
var html = '';
|
||||
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
currentDialog = dlg;
|
||||
|
||||
function onRecordingChanged() {
|
||||
reload(dlg, itemId, serverId, true);
|
||||
}
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
events.off(currentRecordingFields, 'recordingchanged', onRecordingChanged);
|
||||
executeCloseAction(closeAction, itemId, serverId);
|
||||
|
||||
if (currentRecordingFields && currentRecordingFields.hasChanged()) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
init(dlg);
|
||||
|
||||
reload(dlg, itemId, serverId);
|
||||
|
||||
currentRecordingFields = new recordingFields({
|
||||
parent: dlg.querySelector('.recordingFields'),
|
||||
programId: itemId,
|
||||
serverId: serverId
|
||||
});
|
||||
|
||||
events.on(currentRecordingFields, 'recordingchanged', onRecordingChanged);
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: showEditor
|
||||
};
|
||||
});
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
init(dlg);
|
||||
|
||||
reload(dlg, itemId, serverId);
|
||||
|
||||
currentRecordingFields = new recordingFields({
|
||||
parent: dlg.querySelector('.recordingFields'),
|
||||
programId: itemId,
|
||||
serverId: serverId
|
||||
});
|
||||
|
||||
events.on(currentRecordingFields, 'recordingchanged', onRecordingChanged);
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
show: showEditor
|
||||
};
|
||||
|
||||
@@ -1,162 +1,154 @@
|
||||
define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'imageLoader', 'scrollStyles', 'emby-button', 'emby-collapse', 'emby-input', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons', 'flexStyles'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, imageLoader) {
|
||||
'use strict';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import globalize from 'globalize';
|
||||
import layoutManager from 'layoutManager';
|
||||
import loading from 'loading';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import 'scrollStyles';
|
||||
import 'emby-button';
|
||||
import 'emby-collapse';
|
||||
import 'emby-input';
|
||||
import 'paper-icon-button-light';
|
||||
import 'css!./../formdialog';
|
||||
import 'css!./recordingcreator';
|
||||
import 'material-icons';
|
||||
import 'flexStyles';
|
||||
|
||||
var currentDialog;
|
||||
var recordingDeleted = false;
|
||||
var currentItemId;
|
||||
var currentServerId;
|
||||
var currentResolve;
|
||||
let currentDialog;
|
||||
let recordingDeleted = false;
|
||||
let currentItemId;
|
||||
let currentServerId;
|
||||
let currentResolve;
|
||||
|
||||
function deleteTimer(apiClient, timerId) {
|
||||
function deleteTimer(apiClient, timerId) {
|
||||
return import('recordingHelper').then(({ default: recordingHelper }) => {
|
||||
recordingHelper.cancelTimerWithConfirmation(timerId, apiClient.serverId());
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
function renderTimer(context, item, apiClient) {
|
||||
context.querySelector('#txtPrePaddingMinutes').value = item.PrePaddingSeconds / 60;
|
||||
context.querySelector('#txtPostPaddingMinutes').value = item.PostPaddingSeconds / 60;
|
||||
|
||||
require(['recordingHelper'], function (recordingHelper) {
|
||||
loading.hide();
|
||||
}
|
||||
|
||||
recordingHelper.cancelTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject);
|
||||
});
|
||||
function closeDialog(isDeleted) {
|
||||
recordingDeleted = isDeleted;
|
||||
dialogHelper.close(currentDialog);
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
const form = this;
|
||||
|
||||
const apiClient = window.connectionManager.getApiClient(currentServerId);
|
||||
|
||||
apiClient.getLiveTvTimer(currentItemId).then(function (item) {
|
||||
item.PrePaddingSeconds = form.querySelector('#txtPrePaddingMinutes').value * 60;
|
||||
item.PostPaddingSeconds = form.querySelector('#txtPostPaddingMinutes').value * 60;
|
||||
apiClient.updateLiveTvTimer(item).then(currentResolve);
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
// Disable default form submission
|
||||
return false;
|
||||
}
|
||||
|
||||
function init(context) {
|
||||
context.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
closeDialog(false);
|
||||
});
|
||||
|
||||
context.querySelector('.btnCancelRecording').addEventListener('click', function () {
|
||||
const apiClient = window.connectionManager.getApiClient(currentServerId);
|
||||
|
||||
deleteTimer(apiClient, currentItemId).then(function () {
|
||||
closeDialog(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function renderTimer(context, item, apiClient) {
|
||||
context.querySelector('form').addEventListener('submit', onSubmit);
|
||||
}
|
||||
|
||||
var program = item.ProgramInfo || {};
|
||||
|
||||
context.querySelector('#txtPrePaddingMinutes').value = item.PrePaddingSeconds / 60;
|
||||
context.querySelector('#txtPostPaddingMinutes').value = item.PostPaddingSeconds / 60;
|
||||
function reload(context, id) {
|
||||
loading.show();
|
||||
currentItemId = id;
|
||||
|
||||
const apiClient = window.connectionManager.getApiClient(currentServerId);
|
||||
apiClient.getLiveTvTimer(id).then(function (result) {
|
||||
renderTimer(context, result, apiClient);
|
||||
loading.hide();
|
||||
}
|
||||
|
||||
function closeDialog(isDeleted) {
|
||||
|
||||
recordingDeleted = isDeleted;
|
||||
|
||||
dialogHelper.close(currentDialog);
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
|
||||
var form = this;
|
||||
|
||||
var apiClient = connectionManager.getApiClient(currentServerId);
|
||||
|
||||
apiClient.getLiveTvTimer(currentItemId).then(function (item) {
|
||||
item.PrePaddingSeconds = form.querySelector('#txtPrePaddingMinutes').value * 60;
|
||||
item.PostPaddingSeconds = form.querySelector('#txtPostPaddingMinutes').value * 60;
|
||||
apiClient.updateLiveTvTimer(item).then(currentResolve);
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
// Disable default form submission
|
||||
return false;
|
||||
}
|
||||
|
||||
function init(context) {
|
||||
|
||||
context.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
closeDialog(false);
|
||||
});
|
||||
|
||||
context.querySelector('.btnCancelRecording').addEventListener('click', function () {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(currentServerId);
|
||||
deleteTimer(apiClient, currentItemId).then(function () {
|
||||
closeDialog(true);
|
||||
});
|
||||
});
|
||||
|
||||
context.querySelector('form').addEventListener('submit', onSubmit);
|
||||
}
|
||||
|
||||
function reload(context, id) {
|
||||
});
|
||||
}
|
||||
|
||||
function showEditor(itemId, serverId, options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
recordingDeleted = false;
|
||||
currentServerId = serverId;
|
||||
loading.show();
|
||||
currentItemId = id;
|
||||
options = options || {};
|
||||
currentResolve = resolve;
|
||||
|
||||
var apiClient = connectionManager.getApiClient(currentServerId);
|
||||
apiClient.getLiveTvTimer(id).then(function (result) {
|
||||
import('text!./recordingeditor.template.html').then(({default: template}) => {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
renderTimer(context, result, apiClient);
|
||||
loading.hide();
|
||||
});
|
||||
}
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
}
|
||||
|
||||
function showEditor(itemId, serverId, options) {
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.classList.add('recordingDialog');
|
||||
|
||||
recordingDeleted = false;
|
||||
currentServerId = serverId;
|
||||
loading.show();
|
||||
options = options || {};
|
||||
currentResolve = resolve;
|
||||
if (!layoutManager.tv) {
|
||||
dlg.style['min-width'] = '20%';
|
||||
dlg.classList.add('dialog-fullscreen-lowres');
|
||||
}
|
||||
|
||||
require(['text!./recordingeditor.template.html'], function (template) {
|
||||
var dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
let html = '';
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
if (options.enableCancel === false) {
|
||||
dlg.querySelector('.formDialogFooter').classList.add('hide');
|
||||
}
|
||||
|
||||
currentDialog = dlg;
|
||||
|
||||
dlg.addEventListener('closing', function () {
|
||||
if (!recordingDeleted) {
|
||||
dlg.querySelector('.btnSubmit').click();
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.classList.add('recordingDialog');
|
||||
|
||||
if (!layoutManager.tv) {
|
||||
dlg.style['min-width'] = '20%';
|
||||
dlg.classList.add('dialog-fullscreen-lowres');
|
||||
}
|
||||
|
||||
var html = '';
|
||||
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
if (options.enableCancel === false) {
|
||||
dlg.querySelector('.formDialogFooter').classList.add('hide');
|
||||
}
|
||||
|
||||
currentDialog = dlg;
|
||||
|
||||
dlg.addEventListener('closing', function () {
|
||||
|
||||
if (!recordingDeleted) {
|
||||
dlg.querySelector('.btnSubmit').click();
|
||||
}
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (recordingDeleted) {
|
||||
resolve({
|
||||
updated: true,
|
||||
deleted: true
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
init(dlg);
|
||||
|
||||
reload(dlg, itemId);
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: showEditor
|
||||
};
|
||||
});
|
||||
dlg.addEventListener('close', function () {
|
||||
if (recordingDeleted) {
|
||||
resolve({
|
||||
updated: true,
|
||||
deleted: true
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
init(dlg);
|
||||
|
||||
reload(dlg, itemId);
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
show: showEditor
|
||||
};
|
||||
|
||||
@@ -1,224 +1,125 @@
|
||||
define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'paper-icon-button-light', 'emby-button', 'css!./recordingfields', 'flexStyles'], function (globalize, connectionManager, serverNotifications, require, loading, appHost, dom, recordingHelper, events) {
|
||||
'use strict';
|
||||
import globalize from 'globalize';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import loading from 'loading';
|
||||
import dom from 'dom';
|
||||
import recordingHelper from 'recordingHelper';
|
||||
import events from 'events';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-button';
|
||||
import 'css!./recordingfields';
|
||||
import 'flexStyles';
|
||||
|
||||
function loadData(parent, program, apiClient) {
|
||||
if (program.IsSeries) {
|
||||
parent.querySelector('.recordSeriesContainer').classList.remove('hide');
|
||||
/*eslint prefer-const: "error"*/
|
||||
|
||||
function loadData(parent, program, apiClient) {
|
||||
if (program.IsSeries) {
|
||||
parent.querySelector('.recordSeriesContainer').classList.remove('hide');
|
||||
} else {
|
||||
parent.querySelector('.recordSeriesContainer').classList.add('hide');
|
||||
}
|
||||
|
||||
if (program.SeriesTimerId) {
|
||||
parent.querySelector('.btnManageSeriesRecording').classList.remove('hide');
|
||||
parent.querySelector('.seriesRecordingButton .recordingIcon').classList.add('recordingIcon-active');
|
||||
parent.querySelector('.seriesRecordingButton .buttonText').innerHTML = globalize.translate('CancelSeries');
|
||||
} else {
|
||||
parent.querySelector('.btnManageSeriesRecording').classList.add('hide');
|
||||
parent.querySelector('.seriesRecordingButton .recordingIcon').classList.remove('recordingIcon-active');
|
||||
parent.querySelector('.seriesRecordingButton .buttonText').innerHTML = globalize.translate('RecordSeries');
|
||||
}
|
||||
|
||||
if (program.TimerId && program.Status !== 'Cancelled') {
|
||||
parent.querySelector('.btnManageRecording').classList.remove('hide');
|
||||
parent.querySelector('.singleRecordingButton .recordingIcon').classList.add('recordingIcon-active');
|
||||
if (program.Status === 'InProgress') {
|
||||
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('StopRecording');
|
||||
} else {
|
||||
parent.querySelector('.recordSeriesContainer').classList.add('hide');
|
||||
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('DoNotRecord');
|
||||
}
|
||||
} else {
|
||||
parent.querySelector('.btnManageRecording').classList.add('hide');
|
||||
parent.querySelector('.singleRecordingButton .recordingIcon').classList.remove('recordingIcon-active');
|
||||
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('Record');
|
||||
}
|
||||
}
|
||||
|
||||
if (program.SeriesTimerId) {
|
||||
parent.querySelector('.btnManageSeriesRecording').classList.remove('hide');
|
||||
parent.querySelector('.seriesRecordingButton .recordingIcon').classList.add('recordingIcon-active');
|
||||
parent.querySelector('.seriesRecordingButton .buttonText').innerHTML = globalize.translate('CancelSeries');
|
||||
} else {
|
||||
parent.querySelector('.btnManageSeriesRecording').classList.add('hide');
|
||||
parent.querySelector('.seriesRecordingButton .recordingIcon').classList.remove('recordingIcon-active');
|
||||
parent.querySelector('.seriesRecordingButton .buttonText').innerHTML = globalize.translate('RecordSeries');
|
||||
function fetchData(instance) {
|
||||
const options = instance.options;
|
||||
const apiClient = window.connectionManager.getApiClient(options.serverId);
|
||||
|
||||
options.parent.querySelector('.recordingFields').classList.remove('hide');
|
||||
return apiClient.getLiveTvProgram(options.programId, apiClient.getCurrentUserId()).then(function (program) {
|
||||
instance.TimerId = program.TimerId;
|
||||
instance.Status = program.Status;
|
||||
instance.SeriesTimerId = program.SeriesTimerId;
|
||||
loadData(options.parent, program, apiClient);
|
||||
});
|
||||
}
|
||||
|
||||
function onTimerChangedExternally(e, apiClient, data) {
|
||||
const options = this.options;
|
||||
let refresh = false;
|
||||
|
||||
if (data.Id) {
|
||||
if (this.TimerId === data.Id) {
|
||||
refresh = true;
|
||||
}
|
||||
|
||||
if (program.TimerId && program.Status !== 'Cancelled') {
|
||||
parent.querySelector('.btnManageRecording').classList.remove('hide');
|
||||
parent.querySelector('.singleRecordingButton .recordingIcon').classList.add('recordingIcon-active');
|
||||
if (program.Status === 'InProgress') {
|
||||
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('StopRecording');
|
||||
} else {
|
||||
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('DoNotRecord');
|
||||
}
|
||||
} else {
|
||||
parent.querySelector('.btnManageRecording').classList.add('hide');
|
||||
parent.querySelector('.singleRecordingButton .recordingIcon').classList.remove('recordingIcon-active');
|
||||
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('Record');
|
||||
}
|
||||
if (data.ProgramId && options) {
|
||||
if (options.programId === data.ProgramId) {
|
||||
refresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
function fetchData(instance) {
|
||||
|
||||
var options = instance.options;
|
||||
var apiClient = connectionManager.getApiClient(options.serverId);
|
||||
|
||||
options.parent.querySelector('.recordingFields').classList.remove('hide');
|
||||
return apiClient.getLiveTvProgram(options.programId, apiClient.getCurrentUserId()).then(function (program) {
|
||||
instance.TimerId = program.TimerId;
|
||||
instance.Status = program.Status;
|
||||
instance.SeriesTimerId = program.SeriesTimerId;
|
||||
loadData(options.parent, program, apiClient);
|
||||
});
|
||||
if (refresh) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
function onTimerChangedExternally(e, apiClient, data) {
|
||||
var options = this.options;
|
||||
var refresh = false;
|
||||
function onSeriesTimerChangedExternally(e, apiClient, data) {
|
||||
const options = this.options;
|
||||
let refresh = false;
|
||||
|
||||
if (data.Id) {
|
||||
if (this.TimerId === data.Id) {
|
||||
refresh = true;
|
||||
}
|
||||
if (data.Id) {
|
||||
if (this.SeriesTimerId === data.Id) {
|
||||
refresh = true;
|
||||
}
|
||||
if (data.ProgramId && options) {
|
||||
if (options.programId === data.ProgramId) {
|
||||
refresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (refresh) {
|
||||
this.refresh();
|
||||
}
|
||||
if (data.ProgramId && options) {
|
||||
if (options.programId === data.ProgramId) {
|
||||
refresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
function onSeriesTimerChangedExternally(e, apiClient, data) {
|
||||
var options = this.options;
|
||||
var refresh = false;
|
||||
|
||||
if (data.Id) {
|
||||
if (this.SeriesTimerId === data.Id) {
|
||||
refresh = true;
|
||||
}
|
||||
}
|
||||
if (data.ProgramId && options) {
|
||||
if (options.programId === data.ProgramId) {
|
||||
refresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (refresh) {
|
||||
this.refresh();
|
||||
}
|
||||
if (refresh) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
function RecordingEditor(options) {
|
||||
class RecordingEditor {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
this.embed();
|
||||
|
||||
var timerChangedHandler = onTimerChangedExternally.bind(this);
|
||||
const timerChangedHandler = onTimerChangedExternally.bind(this);
|
||||
this.timerChangedHandler = timerChangedHandler;
|
||||
|
||||
events.on(serverNotifications, 'TimerCreated', timerChangedHandler);
|
||||
events.on(serverNotifications, 'TimerCancelled', timerChangedHandler);
|
||||
|
||||
var seriesTimerChangedHandler = onSeriesTimerChangedExternally.bind(this);
|
||||
const seriesTimerChangedHandler = onSeriesTimerChangedExternally.bind(this);
|
||||
this.seriesTimerChangedHandler = seriesTimerChangedHandler;
|
||||
|
||||
events.on(serverNotifications, 'SeriesTimerCreated', seriesTimerChangedHandler);
|
||||
events.on(serverNotifications, 'SeriesTimerCancelled', seriesTimerChangedHandler);
|
||||
}
|
||||
|
||||
function onManageRecordingClick(e) {
|
||||
var options = this.options;
|
||||
if (!this.TimerId || this.Status === 'Cancelled') {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
require(['recordingEditor'], function (recordingEditor) {
|
||||
recordingEditor.show(self.TimerId, options.serverId, {
|
||||
enableCancel: false
|
||||
}).then(function () {
|
||||
self.changed = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onManageSeriesRecordingClick(e) {
|
||||
|
||||
var options = this.options;
|
||||
|
||||
if (!this.SeriesTimerId) {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
require(['seriesRecordingEditor'], function (seriesRecordingEditor) {
|
||||
|
||||
seriesRecordingEditor.show(self.SeriesTimerId, options.serverId, {
|
||||
|
||||
enableCancel: false
|
||||
|
||||
}).then(function () {
|
||||
self.changed = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onRecordChange(e) {
|
||||
|
||||
this.changed = true;
|
||||
|
||||
var self = this;
|
||||
var options = this.options;
|
||||
var apiClient = connectionManager.getApiClient(options.serverId);
|
||||
|
||||
var button = dom.parentWithTag(e.target, 'BUTTON');
|
||||
var isChecked = !button.querySelector('.material-icons').classList.contains('recordingIcon-active');
|
||||
|
||||
var hasEnabledTimer = this.TimerId && this.Status !== 'Cancelled';
|
||||
|
||||
if (isChecked) {
|
||||
if (!hasEnabledTimer) {
|
||||
loading.show();
|
||||
recordingHelper.createRecording(apiClient, options.programId, false).then(function () {
|
||||
events.trigger(self, 'recordingchanged');
|
||||
fetchData(self);
|
||||
loading.hide();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (hasEnabledTimer) {
|
||||
loading.show();
|
||||
recordingHelper.cancelTimer(apiClient, this.TimerId, true).then(function () {
|
||||
events.trigger(self, 'recordingchanged');
|
||||
fetchData(self);
|
||||
loading.hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sendToast(msg) {
|
||||
require(['toast'], function (toast) {
|
||||
toast(msg);
|
||||
});
|
||||
}
|
||||
|
||||
function onRecordSeriesChange(e) {
|
||||
|
||||
this.changed = true;
|
||||
|
||||
var self = this;
|
||||
var options = this.options;
|
||||
var apiClient = connectionManager.getApiClient(options.serverId);
|
||||
|
||||
var button = dom.parentWithTag(e.target, 'BUTTON');
|
||||
var isChecked = !button.querySelector('.material-icons').classList.contains('recordingIcon-active');
|
||||
|
||||
if (isChecked) {
|
||||
options.parent.querySelector('.recordSeriesContainer').classList.remove('hide');
|
||||
if (!this.SeriesTimerId) {
|
||||
var promise = this.TimerId ?
|
||||
recordingHelper.changeRecordingToSeries(apiClient, this.TimerId, options.programId) :
|
||||
recordingHelper.createRecording(apiClient, options.programId, true);
|
||||
promise.then(function () {
|
||||
fetchData(self);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (this.SeriesTimerId) {
|
||||
apiClient.cancelLiveTvSeriesTimer(this.SeriesTimerId).then(function () {
|
||||
sendToast(globalize.translate('RecordingCancelled'));
|
||||
fetchData(self);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RecordingEditor.prototype.embed = function () {
|
||||
var self = this;
|
||||
embed() {
|
||||
const self = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(['text!./recordingfields.template.html'], function (template) {
|
||||
var options = self.options;
|
||||
var context = options.parent;
|
||||
import('text!./recordingfields.template.html').then(({default: template}) => {
|
||||
const options = self.options;
|
||||
const context = options.parent;
|
||||
context.innerHTML = globalize.translateHtml(template, 'core');
|
||||
|
||||
context.querySelector('.singleRecordingButton').addEventListener('click', onRecordChange.bind(self));
|
||||
@@ -229,29 +130,134 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa
|
||||
fetchData(self).then(resolve);
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
RecordingEditor.prototype.hasChanged = function () {
|
||||
hasChanged() {
|
||||
return this.changed;
|
||||
};
|
||||
}
|
||||
|
||||
RecordingEditor.prototype.refresh = function () {
|
||||
refresh() {
|
||||
fetchData(this);
|
||||
};
|
||||
}
|
||||
|
||||
RecordingEditor.prototype.destroy = function () {
|
||||
var timerChangedHandler = this.timerChangedHandler;
|
||||
destroy() {
|
||||
const timerChangedHandler = this.timerChangedHandler;
|
||||
this.timerChangedHandler = null;
|
||||
|
||||
events.off(serverNotifications, 'TimerCreated', timerChangedHandler);
|
||||
events.off(serverNotifications, 'TimerCancelled', timerChangedHandler);
|
||||
|
||||
var seriesTimerChangedHandler = this.seriesTimerChangedHandler;
|
||||
const seriesTimerChangedHandler = this.seriesTimerChangedHandler;
|
||||
this.seriesTimerChangedHandler = null;
|
||||
|
||||
events.off(serverNotifications, 'SeriesTimerCreated', seriesTimerChangedHandler);
|
||||
events.off(serverNotifications, 'SeriesTimerCancelled', seriesTimerChangedHandler);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return RecordingEditor;
|
||||
});
|
||||
function onManageRecordingClick(e) {
|
||||
const options = this.options;
|
||||
if (!this.TimerId || this.Status === 'Cancelled') {
|
||||
return;
|
||||
}
|
||||
|
||||
const self = this;
|
||||
import('recordingEditor').then(({default: recordingEditor}) => {
|
||||
recordingEditor.show(self.TimerId, options.serverId, {
|
||||
enableCancel: false
|
||||
}).then(function () {
|
||||
self.changed = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onManageSeriesRecordingClick(e) {
|
||||
const options = this.options;
|
||||
|
||||
if (!this.SeriesTimerId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const self = this;
|
||||
|
||||
import('seriesRecordingEditor').then(({default: seriesRecordingEditor}) => {
|
||||
seriesRecordingEditor.show(self.SeriesTimerId, options.serverId, {
|
||||
|
||||
enableCancel: false
|
||||
|
||||
}).then(function () {
|
||||
self.changed = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onRecordChange(e) {
|
||||
this.changed = true;
|
||||
|
||||
const self = this;
|
||||
const options = this.options;
|
||||
const apiClient = window.connectionManager.getApiClient(options.serverId);
|
||||
|
||||
const button = dom.parentWithTag(e.target, 'BUTTON');
|
||||
const isChecked = !button.querySelector('.material-icons').classList.contains('recordingIcon-active');
|
||||
|
||||
const hasEnabledTimer = this.TimerId && this.Status !== 'Cancelled';
|
||||
|
||||
if (isChecked) {
|
||||
if (!hasEnabledTimer) {
|
||||
loading.show();
|
||||
recordingHelper.createRecording(apiClient, options.programId, false).then(function () {
|
||||
events.trigger(self, 'recordingchanged');
|
||||
fetchData(self);
|
||||
loading.hide();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (hasEnabledTimer) {
|
||||
loading.show();
|
||||
recordingHelper.cancelTimer(apiClient, this.TimerId, true).then(function () {
|
||||
events.trigger(self, 'recordingchanged');
|
||||
fetchData(self);
|
||||
loading.hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sendToast(msg) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(msg);
|
||||
});
|
||||
}
|
||||
|
||||
function onRecordSeriesChange(e) {
|
||||
this.changed = true;
|
||||
|
||||
const self = this;
|
||||
const options = this.options;
|
||||
const apiClient = window.connectionManager.getApiClient(options.serverId);
|
||||
|
||||
const button = dom.parentWithTag(e.target, 'BUTTON');
|
||||
const isChecked = !button.querySelector('.material-icons').classList.contains('recordingIcon-active');
|
||||
|
||||
if (isChecked) {
|
||||
options.parent.querySelector('.recordSeriesContainer').classList.remove('hide');
|
||||
if (!this.SeriesTimerId) {
|
||||
const promise = this.TimerId ?
|
||||
recordingHelper.changeRecordingToSeries(apiClient, this.TimerId, options.programId) :
|
||||
recordingHelper.createRecording(apiClient, options.programId, true);
|
||||
promise.then(function () {
|
||||
fetchData(self);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (this.SeriesTimerId) {
|
||||
apiClient.cancelLiveTvSeriesTimer(this.SeriesTimerId).then(function () {
|
||||
sendToast(globalize.translate('RecordingCancelled'));
|
||||
fetchData(self);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default RecordingEditor;
|
||||
|
||||
@@ -1,217 +1,194 @@
|
||||
define(['globalize', 'loading', 'connectionManager'], function (globalize, loading, connectionManager) {
|
||||
'use strict';
|
||||
import globalize from 'globalize';
|
||||
import loading from 'loading';
|
||||
|
||||
function changeRecordingToSeries(apiClient, timerId, programId, confirmTimerCancellation) {
|
||||
/*eslint prefer-const: "error"*/
|
||||
|
||||
loading.show();
|
||||
function changeRecordingToSeries(apiClient, timerId, programId, confirmTimerCancellation) {
|
||||
loading.show();
|
||||
|
||||
return apiClient.getItem(apiClient.getCurrentUserId(), programId).then(function (item) {
|
||||
return apiClient.getItem(apiClient.getCurrentUserId(), programId).then(function (item) {
|
||||
if (item.IsSeries) {
|
||||
// create series
|
||||
return apiClient.getNewLiveTvTimerDefaults({ programId: programId }).then(function (timerDefaults) {
|
||||
return apiClient.createLiveTvSeriesTimer(timerDefaults).then(function () {
|
||||
loading.hide();
|
||||
sendToast(globalize.translate('SeriesRecordingScheduled'));
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// cancel
|
||||
if (confirmTimerCancellation) {
|
||||
return cancelTimerWithConfirmation(timerId, apiClient.serverId());
|
||||
}
|
||||
|
||||
if (item.IsSeries) {
|
||||
// create series
|
||||
return apiClient.getNewLiveTvTimerDefaults({ programId: programId }).then(function (timerDefaults) {
|
||||
return cancelTimer(apiClient.serverId(), timerId, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return apiClient.createLiveTvSeriesTimer(timerDefaults).then(function () {
|
||||
function cancelTimerWithConfirmation(timerId, serverId) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
import('confirm').then(({ default: confirm }) => {
|
||||
confirm.default({
|
||||
|
||||
loading.hide();
|
||||
sendToast(globalize.translate('SeriesRecordingScheduled'));
|
||||
text: globalize.translate('MessageConfirmRecordingCancellation'),
|
||||
primary: 'delete',
|
||||
confirmText: globalize.translate('HeaderCancelRecording'),
|
||||
cancelText: globalize.translate('HeaderKeepRecording')
|
||||
|
||||
}).then(function () {
|
||||
loading.show();
|
||||
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
cancelTimer(apiClient, timerId, true).then(resolve, reject);
|
||||
}, reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function cancelSeriesTimerWithConfirmation(timerId, serverId) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
import('confirm').then(({ default: confirm }) => {
|
||||
confirm.default({
|
||||
|
||||
text: globalize.translate('MessageConfirmRecordingCancellation'),
|
||||
primary: 'delete',
|
||||
confirmText: globalize.translate('HeaderCancelSeries'),
|
||||
cancelText: globalize.translate('HeaderKeepSeries')
|
||||
|
||||
}).then(function () {
|
||||
loading.show();
|
||||
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
apiClient.cancelLiveTvSeriesTimer(timerId).then(function () {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('SeriesCancelled'));
|
||||
});
|
||||
|
||||
loading.hide();
|
||||
resolve();
|
||||
}, reject);
|
||||
}, reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function cancelTimer(apiClient, timerId, hideLoading) {
|
||||
loading.show();
|
||||
return apiClient.cancelLiveTvTimer(timerId).then(function () {
|
||||
if (hideLoading !== false) {
|
||||
loading.hide();
|
||||
sendToast(globalize.translate('RecordingCancelled'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createRecording(apiClient, programId, isSeries) {
|
||||
loading.show();
|
||||
return apiClient.getNewLiveTvTimerDefaults({ programId: programId }).then(function (item) {
|
||||
const promise = isSeries ?
|
||||
apiClient.createLiveTvSeriesTimer(item) :
|
||||
apiClient.createLiveTvTimer(item);
|
||||
|
||||
return promise.then(function () {
|
||||
loading.hide();
|
||||
sendToast(globalize.translate('RecordingScheduled'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function sendToast(msg) {
|
||||
import('toast').then(({ default: toast }) => {
|
||||
toast(msg);
|
||||
});
|
||||
}
|
||||
|
||||
function showMultiCancellationPrompt(serverId, programId, timerId, timerStatus, seriesTimerId) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
import('dialog').then(({ default: dialog }) => {
|
||||
const items = [];
|
||||
|
||||
items.push({
|
||||
name: globalize.translate('HeaderKeepRecording'),
|
||||
id: 'cancel',
|
||||
type: 'submit'
|
||||
});
|
||||
|
||||
if (timerStatus === 'InProgress') {
|
||||
items.push({
|
||||
name: globalize.translate('HeaderStopRecording'),
|
||||
id: 'canceltimer',
|
||||
type: 'cancel'
|
||||
});
|
||||
} else {
|
||||
// cancel
|
||||
if (confirmTimerCancellation) {
|
||||
return cancelTimerWithConfirmation(timerId, apiClient.serverId());
|
||||
}
|
||||
|
||||
return cancelTimer(apiClient.serverId(), timerId, true);
|
||||
items.push({
|
||||
name: globalize.translate('HeaderCancelRecording'),
|
||||
id: 'canceltimer',
|
||||
type: 'cancel'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cancelTimerWithConfirmation(timerId, serverId) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['confirm'], function (confirm) {
|
||||
|
||||
confirm.default({
|
||||
|
||||
text: globalize.translate('MessageConfirmRecordingCancellation'),
|
||||
primary: 'delete',
|
||||
confirmText: globalize.translate('HeaderCancelRecording'),
|
||||
cancelText: globalize.translate('HeaderKeepRecording')
|
||||
|
||||
}).then(function () {
|
||||
|
||||
loading.show();
|
||||
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
cancelTimer(apiClient, timerId, true).then(resolve, reject);
|
||||
|
||||
}, reject);
|
||||
items.push({
|
||||
name: globalize.translate('HeaderCancelSeries'),
|
||||
id: 'cancelseriestimer',
|
||||
type: 'cancel'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function cancelSeriesTimerWithConfirmation(timerId, serverId) {
|
||||
dialog({
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
text: globalize.translate('MessageConfirmRecordingCancellation'),
|
||||
buttons: items
|
||||
|
||||
require(['confirm'], function (confirm) {
|
||||
|
||||
confirm.default({
|
||||
|
||||
text: globalize.translate('MessageConfirmRecordingCancellation'),
|
||||
primary: 'delete',
|
||||
confirmText: globalize.translate('HeaderCancelSeries'),
|
||||
cancelText: globalize.translate('HeaderKeepSeries')
|
||||
|
||||
}).then(function () {
|
||||
}).then(function (result) {
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
if (result === 'canceltimer') {
|
||||
loading.show();
|
||||
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
apiClient.cancelLiveTvSeriesTimer(timerId).then(function () {
|
||||
cancelTimer(apiClient, timerId, true).then(resolve, reject);
|
||||
} else if (result === 'cancelseriestimer') {
|
||||
loading.show();
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
apiClient.cancelLiveTvSeriesTimer(seriesTimerId).then(function () {
|
||||
import('toast').then(({ default: toast }) => {
|
||||
toast(globalize.translate('SeriesCancelled'));
|
||||
});
|
||||
|
||||
loading.hide();
|
||||
resolve();
|
||||
}, reject);
|
||||
|
||||
}, reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function cancelTimer(apiClient, timerId, hideLoading) {
|
||||
loading.show();
|
||||
return apiClient.cancelLiveTvTimer(timerId).then(function () {
|
||||
|
||||
if (hideLoading !== false) {
|
||||
loading.hide();
|
||||
sendToast(globalize.translate('RecordingCancelled'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createRecording(apiClient, programId, isSeries) {
|
||||
|
||||
loading.show();
|
||||
return apiClient.getNewLiveTvTimerDefaults({ programId: programId }).then(function (item) {
|
||||
|
||||
var promise = isSeries ?
|
||||
apiClient.createLiveTvSeriesTimer(item) :
|
||||
apiClient.createLiveTvTimer(item);
|
||||
|
||||
return promise.then(function () {
|
||||
|
||||
loading.hide();
|
||||
sendToast(globalize.translate('RecordingScheduled'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function sendToast(msg) {
|
||||
require(['toast'], function (toast) {
|
||||
toast(msg);
|
||||
});
|
||||
}
|
||||
|
||||
function showMultiCancellationPrompt(serverId, programId, timerId, timerStatus, seriesTimerId) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['dialog'], function (dialog) {
|
||||
|
||||
var items = [];
|
||||
|
||||
items.push({
|
||||
name: globalize.translate('HeaderKeepRecording'),
|
||||
id: 'cancel',
|
||||
type: 'submit'
|
||||
});
|
||||
|
||||
if (timerStatus === 'InProgress') {
|
||||
items.push({
|
||||
name: globalize.translate('HeaderStopRecording'),
|
||||
id: 'canceltimer',
|
||||
type: 'cancel'
|
||||
});
|
||||
} else {
|
||||
items.push({
|
||||
name: globalize.translate('HeaderCancelRecording'),
|
||||
id: 'canceltimer',
|
||||
type: 'cancel'
|
||||
});
|
||||
resolve();
|
||||
}
|
||||
|
||||
items.push({
|
||||
name: globalize.translate('HeaderCancelSeries'),
|
||||
id: 'cancelseriestimer',
|
||||
type: 'cancel'
|
||||
});
|
||||
|
||||
dialog({
|
||||
|
||||
text: globalize.translate('MessageConfirmRecordingCancellation'),
|
||||
buttons: items
|
||||
|
||||
}).then(function (result) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
|
||||
if (result === 'canceltimer') {
|
||||
loading.show();
|
||||
|
||||
cancelTimer(apiClient, timerId, true).then(resolve, reject);
|
||||
} else if (result === 'cancelseriestimer') {
|
||||
|
||||
loading.show();
|
||||
|
||||
apiClient.cancelLiveTvSeriesTimer(seriesTimerId).then(function () {
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
toast(globalize.translate('SeriesCancelled'));
|
||||
});
|
||||
|
||||
loading.hide();
|
||||
resolve();
|
||||
}, reject);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
|
||||
}, reject);
|
||||
});
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function toggleRecording(serverId, programId, timerId, timerStatus, seriesTimerId) {
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
var hasTimer = timerId && timerStatus !== 'Cancelled';
|
||||
if (seriesTimerId && hasTimer) {
|
||||
// cancel
|
||||
return showMultiCancellationPrompt(serverId, programId, timerId, timerStatus, seriesTimerId);
|
||||
} else if (hasTimer && programId) {
|
||||
// change to series recording, if possible
|
||||
// otherwise cancel individual recording
|
||||
return changeRecordingToSeries(apiClient, timerId, programId, true);
|
||||
} else if (programId) {
|
||||
// schedule recording
|
||||
return createRecording(apiClient, programId);
|
||||
} else {
|
||||
return Promise.reject();
|
||||
}
|
||||
function toggleRecording(serverId, programId, timerId, timerStatus, seriesTimerId) {
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
const hasTimer = timerId && timerStatus !== 'Cancelled';
|
||||
if (seriesTimerId && hasTimer) {
|
||||
// cancel
|
||||
return showMultiCancellationPrompt(serverId, programId, timerId, timerStatus, seriesTimerId);
|
||||
} else if (hasTimer && programId) {
|
||||
// change to series recording, if possible
|
||||
// otherwise cancel individual recording
|
||||
return changeRecordingToSeries(apiClient, timerId, programId, true);
|
||||
} else if (programId) {
|
||||
// schedule recording
|
||||
return createRecording(apiClient, programId);
|
||||
} else {
|
||||
return Promise.reject();
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
cancelTimer: cancelTimer,
|
||||
createRecording: createRecording,
|
||||
changeRecordingToSeries: changeRecordingToSeries,
|
||||
toggleRecording: toggleRecording,
|
||||
cancelTimerWithConfirmation: cancelTimerWithConfirmation,
|
||||
cancelSeriesTimerWithConfirmation: cancelSeriesTimerWithConfirmation
|
||||
};
|
||||
|
||||
return {
|
||||
cancelTimer: cancelTimer,
|
||||
createRecording: createRecording,
|
||||
changeRecordingToSeries: changeRecordingToSeries,
|
||||
toggleRecording: toggleRecording,
|
||||
cancelTimerWithConfirmation: cancelTimerWithConfirmation,
|
||||
cancelSeriesTimerWithConfirmation: cancelSeriesTimerWithConfirmation
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,160 +1,199 @@
|
||||
define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'imageLoader', 'datetime', 'scrollStyles', 'emby-button', 'emby-checkbox', 'emby-input', 'emby-select', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons', 'flexStyles'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, imageLoader, datetime) {
|
||||
'use strict';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import globalize from 'globalize';
|
||||
import layoutManager from 'layoutManager';
|
||||
import loading from 'loading';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import datetime from 'datetime';
|
||||
import 'scrollStyles';
|
||||
import 'emby-button';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-input';
|
||||
import 'emby-select';
|
||||
import 'paper-icon-button-light';
|
||||
import 'css!./../formdialog';
|
||||
import 'css!./recordingcreator';
|
||||
import 'material-icons';
|
||||
import 'flexStyles';
|
||||
|
||||
var currentDialog;
|
||||
var recordingUpdated = false;
|
||||
var recordingDeleted = false;
|
||||
var currentItemId;
|
||||
var currentServerId;
|
||||
/*eslint prefer-const: "error"*/
|
||||
|
||||
function deleteTimer(apiClient, timerId) {
|
||||
let currentDialog;
|
||||
let recordingUpdated = false;
|
||||
let recordingDeleted = false;
|
||||
let currentItemId;
|
||||
let currentServerId;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['recordingHelper'], function (recordingHelper) {
|
||||
|
||||
recordingHelper.cancelSeriesTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject);
|
||||
});
|
||||
function deleteTimer(apiClient, timerId) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
import('recordingHelper').then(({ default: recordingHelper }) => {
|
||||
recordingHelper.cancelSeriesTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderTimer(context, item) {
|
||||
context.querySelector('#txtPrePaddingMinutes').value = item.PrePaddingSeconds / 60;
|
||||
context.querySelector('#txtPostPaddingMinutes').value = item.PostPaddingSeconds / 60;
|
||||
|
||||
context.querySelector('.selectChannels').value = item.RecordAnyChannel ? 'all' : 'one';
|
||||
context.querySelector('.selectAirTime').value = item.RecordAnyTime ? 'any' : 'original';
|
||||
|
||||
context.querySelector('.selectShowType').value = item.RecordNewOnly ? 'new' : 'all';
|
||||
context.querySelector('.chkSkipEpisodesInLibrary').checked = item.SkipEpisodesInLibrary;
|
||||
context.querySelector('.selectKeepUpTo').value = item.KeepUpTo || 0;
|
||||
|
||||
if (item.ChannelName || item.ChannelNumber) {
|
||||
context.querySelector('.optionChannelOnly').innerHTML = globalize.translate('ChannelNameOnly', item.ChannelName || item.ChannelNumber);
|
||||
} else {
|
||||
context.querySelector('.optionChannelOnly').innerHTML = globalize.translate('OneChannel');
|
||||
}
|
||||
|
||||
function renderTimer(context, item, apiClient) {
|
||||
context.querySelector('.optionAroundTime').innerHTML = globalize.translate('AroundTime', datetime.getDisplayTime(datetime.parseISO8601Date(item.StartDate)));
|
||||
|
||||
var program = item.ProgramInfo || {};
|
||||
loading.hide();
|
||||
}
|
||||
|
||||
context.querySelector('#txtPrePaddingMinutes').value = item.PrePaddingSeconds / 60;
|
||||
context.querySelector('#txtPostPaddingMinutes').value = item.PostPaddingSeconds / 60;
|
||||
function closeDialog(isDeleted) {
|
||||
recordingUpdated = true;
|
||||
recordingDeleted = isDeleted;
|
||||
|
||||
context.querySelector('.selectChannels').value = item.RecordAnyChannel ? 'all' : 'one';
|
||||
context.querySelector('.selectAirTime').value = item.RecordAnyTime ? 'any' : 'original';
|
||||
dialogHelper.close(currentDialog);
|
||||
}
|
||||
|
||||
context.querySelector('.selectShowType').value = item.RecordNewOnly ? 'new' : 'all';
|
||||
context.querySelector('.chkSkipEpisodesInLibrary').checked = item.SkipEpisodesInLibrary;
|
||||
context.querySelector('.selectKeepUpTo').value = item.KeepUpTo || 0;
|
||||
function onSubmit(e) {
|
||||
const form = this;
|
||||
|
||||
if (item.ChannelName || item.ChannelNumber) {
|
||||
context.querySelector('.optionChannelOnly').innerHTML = globalize.translate('ChannelNameOnly', item.ChannelName || item.ChannelNumber);
|
||||
} else {
|
||||
context.querySelector('.optionChannelOnly').innerHTML = globalize.translate('OneChannel');
|
||||
}
|
||||
const apiClient = window.connectionManager.getApiClient(currentServerId);
|
||||
|
||||
context.querySelector('.optionAroundTime').innerHTML = globalize.translate('AroundTime', datetime.getDisplayTime(datetime.parseISO8601Date(item.StartDate)));
|
||||
apiClient.getLiveTvSeriesTimer(currentItemId).then(function (item) {
|
||||
item.PrePaddingSeconds = form.querySelector('#txtPrePaddingMinutes').value * 60;
|
||||
item.PostPaddingSeconds = form.querySelector('#txtPostPaddingMinutes').value * 60;
|
||||
item.RecordAnyChannel = form.querySelector('.selectChannels').value === 'all';
|
||||
item.RecordAnyTime = form.querySelector('.selectAirTime').value === 'any';
|
||||
item.RecordNewOnly = form.querySelector('.selectShowType').value === 'new';
|
||||
item.SkipEpisodesInLibrary = form.querySelector('.chkSkipEpisodesInLibrary').checked;
|
||||
item.KeepUpTo = form.querySelector('.selectKeepUpTo').value;
|
||||
|
||||
apiClient.updateLiveTvSeriesTimer(item);
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
// Disable default form submission
|
||||
return false;
|
||||
}
|
||||
|
||||
function init(context) {
|
||||
fillKeepUpTo(context);
|
||||
|
||||
context.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
closeDialog(false);
|
||||
});
|
||||
|
||||
context.querySelector('.btnCancelRecording').addEventListener('click', function () {
|
||||
const apiClient = window.connectionManager.getApiClient(currentServerId);
|
||||
deleteTimer(apiClient, currentItemId).then(function () {
|
||||
closeDialog(true);
|
||||
});
|
||||
});
|
||||
|
||||
context.querySelector('form').addEventListener('submit', onSubmit);
|
||||
}
|
||||
|
||||
function reload(context, id) {
|
||||
const apiClient = window.connectionManager.getApiClient(currentServerId);
|
||||
|
||||
loading.show();
|
||||
if (typeof id === 'string') {
|
||||
currentItemId = id;
|
||||
|
||||
apiClient.getLiveTvSeriesTimer(id).then(function (result) {
|
||||
renderTimer(context, result);
|
||||
loading.hide();
|
||||
});
|
||||
} else if (id) {
|
||||
currentItemId = id.Id;
|
||||
|
||||
renderTimer(context, id);
|
||||
loading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function closeDialog(isDeleted) {
|
||||
function fillKeepUpTo(context) {
|
||||
let html = '';
|
||||
|
||||
recordingUpdated = true;
|
||||
recordingDeleted = isDeleted;
|
||||
for (let i = 0; i <= 50; i++) {
|
||||
let text;
|
||||
|
||||
dialogHelper.close(currentDialog);
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
|
||||
var form = this;
|
||||
|
||||
var apiClient = connectionManager.getApiClient(currentServerId);
|
||||
|
||||
apiClient.getLiveTvSeriesTimer(currentItemId).then(function (item) {
|
||||
|
||||
item.PrePaddingSeconds = form.querySelector('#txtPrePaddingMinutes').value * 60;
|
||||
item.PostPaddingSeconds = form.querySelector('#txtPostPaddingMinutes').value * 60;
|
||||
item.RecordAnyChannel = form.querySelector('.selectChannels').value === 'all';
|
||||
item.RecordAnyTime = form.querySelector('.selectAirTime').value === 'any';
|
||||
item.RecordNewOnly = form.querySelector('.selectShowType').value === 'new';
|
||||
item.SkipEpisodesInLibrary = form.querySelector('.chkSkipEpisodesInLibrary').checked;
|
||||
item.KeepUpTo = form.querySelector('.selectKeepUpTo').value;
|
||||
|
||||
apiClient.updateLiveTvSeriesTimer(item);
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
// Disable default form submission
|
||||
return false;
|
||||
}
|
||||
|
||||
function init(context) {
|
||||
|
||||
fillKeepUpTo(context);
|
||||
|
||||
context.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
closeDialog(false);
|
||||
});
|
||||
|
||||
context.querySelector('.btnCancelRecording').addEventListener('click', function () {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(currentServerId);
|
||||
deleteTimer(apiClient, currentItemId).then(function () {
|
||||
closeDialog(true);
|
||||
});
|
||||
});
|
||||
|
||||
context.querySelector('form').addEventListener('submit', onSubmit);
|
||||
}
|
||||
|
||||
function reload(context, id) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(currentServerId);
|
||||
|
||||
loading.show();
|
||||
if (typeof id === 'string') {
|
||||
currentItemId = id;
|
||||
|
||||
apiClient.getLiveTvSeriesTimer(id).then(function (result) {
|
||||
|
||||
renderTimer(context, result, apiClient);
|
||||
loading.hide();
|
||||
});
|
||||
} else if (id) {
|
||||
|
||||
currentItemId = id.Id;
|
||||
|
||||
renderTimer(context, id, apiClient);
|
||||
loading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function fillKeepUpTo(context) {
|
||||
|
||||
var html = '';
|
||||
|
||||
for (var i = 0; i <= 50; i++) {
|
||||
|
||||
var text;
|
||||
|
||||
if (i === 0) {
|
||||
text = globalize.translate('AsManyAsPossible');
|
||||
} else if (i === 1) {
|
||||
text = globalize.translate('ValueOneEpisode');
|
||||
} else {
|
||||
text = globalize.translate('ValueEpisodeCount', i);
|
||||
}
|
||||
|
||||
html += '<option value="' + i + '">' + text + '</option>';
|
||||
if (i === 0) {
|
||||
text = globalize.translate('AsManyAsPossible');
|
||||
} else if (i === 1) {
|
||||
text = globalize.translate('ValueOneEpisode');
|
||||
} else {
|
||||
text = globalize.translate('ValueEpisodeCount', i);
|
||||
}
|
||||
|
||||
context.querySelector('.selectKeepUpTo').innerHTML = html;
|
||||
html += '<option value="' + i + '">' + text + '</option>';
|
||||
}
|
||||
|
||||
function onFieldChange(e) {
|
||||
this.querySelector('.btnSubmit').click();
|
||||
}
|
||||
context.querySelector('.selectKeepUpTo').innerHTML = html;
|
||||
}
|
||||
|
||||
function embed(itemId, serverId, options) {
|
||||
function onFieldChange() {
|
||||
this.querySelector('.btnSubmit').click();
|
||||
}
|
||||
|
||||
function embed(itemId, serverId, options) {
|
||||
recordingUpdated = false;
|
||||
recordingDeleted = false;
|
||||
currentServerId = serverId;
|
||||
loading.show();
|
||||
options = options || {};
|
||||
|
||||
import('text!./seriesrecordingeditor.template.html').then(({ default: template }) => {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
const dlg = options.context;
|
||||
|
||||
dlg.classList.add('hide');
|
||||
dlg.innerHTML = globalize.translateHtml(template, 'core');
|
||||
|
||||
dlg.querySelector('.formDialogHeader').classList.add('hide');
|
||||
dlg.querySelector('.formDialogFooter').classList.add('hide');
|
||||
dlg.querySelector('.formDialogContent').className = '';
|
||||
dlg.querySelector('.dialogContentInner').className = '';
|
||||
dlg.classList.remove('hide');
|
||||
|
||||
dlg.removeEventListener('change', onFieldChange);
|
||||
dlg.addEventListener('change', onFieldChange);
|
||||
|
||||
currentDialog = dlg;
|
||||
|
||||
init(dlg);
|
||||
|
||||
reload(dlg, itemId);
|
||||
});
|
||||
}
|
||||
|
||||
function showEditor(itemId, serverId, options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
recordingUpdated = false;
|
||||
recordingDeleted = false;
|
||||
currentServerId = serverId;
|
||||
loading.show();
|
||||
options = options || {};
|
||||
|
||||
require(['text!./seriesrecordingeditor.template.html'], function (template) {
|
||||
|
||||
var dialogOptions = {
|
||||
import('text!./seriesrecordingeditor.template.html').then(({ default: template }) => {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
@@ -165,106 +204,58 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = options.context;
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('hide');
|
||||
dlg.innerHTML = globalize.translateHtml(template, 'core');
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.classList.add('recordingDialog');
|
||||
|
||||
dlg.querySelector('.formDialogHeader').classList.add('hide');
|
||||
dlg.querySelector('.formDialogFooter').classList.add('hide');
|
||||
dlg.querySelector('.formDialogContent').className = '';
|
||||
dlg.querySelector('.dialogContentInner').className = '';
|
||||
dlg.classList.remove('hide');
|
||||
if (!layoutManager.tv) {
|
||||
dlg.style['min-width'] = '20%';
|
||||
}
|
||||
|
||||
dlg.removeEventListener('change', onFieldChange);
|
||||
dlg.addEventListener('change', onFieldChange);
|
||||
let html = '';
|
||||
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
if (options.enableCancel === false) {
|
||||
dlg.querySelector('.formDialogFooter').classList.add('hide');
|
||||
}
|
||||
|
||||
currentDialog = dlg;
|
||||
|
||||
dlg.addEventListener('closing', function () {
|
||||
if (!recordingDeleted) {
|
||||
this.querySelector('.btnSubmit').click();
|
||||
}
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
if (recordingUpdated) {
|
||||
resolve({
|
||||
updated: true,
|
||||
deleted: recordingDeleted
|
||||
});
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
init(dlg);
|
||||
|
||||
reload(dlg, itemId);
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showEditor(itemId, serverId, options) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
recordingUpdated = false;
|
||||
recordingDeleted = false;
|
||||
currentServerId = serverId;
|
||||
loading.show();
|
||||
options = options || {};
|
||||
|
||||
require(['text!./seriesrecordingeditor.template.html'], function (template) {
|
||||
|
||||
var dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.classList.add('recordingDialog');
|
||||
|
||||
if (!layoutManager.tv) {
|
||||
dlg.style['min-width'] = '20%';
|
||||
}
|
||||
|
||||
var html = '';
|
||||
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
if (options.enableCancel === false) {
|
||||
dlg.querySelector('.formDialogFooter').classList.add('hide');
|
||||
}
|
||||
|
||||
currentDialog = dlg;
|
||||
|
||||
dlg.addEventListener('closing', function () {
|
||||
|
||||
if (!recordingDeleted) {
|
||||
this.querySelector('.btnSubmit').click();
|
||||
}
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (recordingUpdated) {
|
||||
resolve({
|
||||
updated: true,
|
||||
deleted: recordingDeleted
|
||||
});
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
init(dlg);
|
||||
|
||||
reload(dlg, itemId);
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: showEditor,
|
||||
embed: embed
|
||||
};
|
||||
});
|
||||
export default {
|
||||
show: showEditor,
|
||||
embed: embed
|
||||
};
|
||||
|
||||
@@ -1,97 +1,107 @@
|
||||
define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'emby-input', 'emby-checkbox', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button'], function (dom, shell, dialogHelper, loading, layoutManager, connectionManager, appRouter, globalize) {
|
||||
'use strict';
|
||||
import dom from 'dom';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import loading from 'loading';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import 'emby-input';
|
||||
import 'emby-checkbox';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-select';
|
||||
import 'material-icons';
|
||||
import 'css!./../formdialog';
|
||||
import 'emby-button';
|
||||
|
||||
function getEditorHtml() {
|
||||
/*eslint prefer-const: "error"*/
|
||||
|
||||
var html = '';
|
||||
function getEditorHtml() {
|
||||
let html = '';
|
||||
|
||||
html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">';
|
||||
html += '<div class="dialogContentInner dialog-content-centered">';
|
||||
html += '<form style="margin:auto;">';
|
||||
html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">';
|
||||
html += '<div class="dialogContentInner dialog-content-centered">';
|
||||
html += '<form style="margin:auto;">';
|
||||
|
||||
html += '<div class="fldSelectPlaylist selectContainer">';
|
||||
html += '<select is="emby-select" id="selectMetadataRefreshMode" label="' + globalize.translate('LabelRefreshMode') + '">';
|
||||
html += '<option value="scan">' + globalize.translate('ScanForNewAndUpdatedFiles') + '</option>';
|
||||
html += '<option value="missing">' + globalize.translate('SearchForMissingMetadata') + '</option>';
|
||||
html += '<option value="all" selected>' + globalize.translate('ReplaceAllMetadata') + '</option>';
|
||||
html += '</select>';
|
||||
html += '</div>';
|
||||
html += '<div class="fldSelectPlaylist selectContainer">';
|
||||
html += '<select is="emby-select" id="selectMetadataRefreshMode" label="' + globalize.translate('LabelRefreshMode') + '">';
|
||||
html += '<option value="scan">' + globalize.translate('ScanForNewAndUpdatedFiles') + '</option>';
|
||||
html += '<option value="missing">' + globalize.translate('SearchForMissingMetadata') + '</option>';
|
||||
html += '<option value="all" selected>' + globalize.translate('ReplaceAllMetadata') + '</option>';
|
||||
html += '</select>';
|
||||
html += '</div>';
|
||||
|
||||
html += '<label class="checkboxContainer hide fldReplaceExistingImages">';
|
||||
html += '<input type="checkbox" is="emby-checkbox" class="chkReplaceImages" />';
|
||||
html += '<span>' + globalize.translate('ReplaceExistingImages') + '</span>';
|
||||
html += '</label>';
|
||||
html += '<label class="checkboxContainer hide fldReplaceExistingImages">';
|
||||
html += '<input type="checkbox" is="emby-checkbox" class="chkReplaceImages" />';
|
||||
html += '<span>' + globalize.translate('ReplaceExistingImages') + '</span>';
|
||||
html += '</label>';
|
||||
|
||||
html += '<div class="fieldDescription">';
|
||||
html += globalize.translate('RefreshDialogHelp');
|
||||
html += '</div>';
|
||||
html += '<div class="fieldDescription">';
|
||||
html += globalize.translate('RefreshDialogHelp');
|
||||
html += '</div>';
|
||||
|
||||
html += '<input type="hidden" class="fldSelectedItemIds" />';
|
||||
html += '<input type="hidden" class="fldSelectedItemIds" />';
|
||||
|
||||
html += '<br />';
|
||||
html += '<div class="formDialogFooter">';
|
||||
html += '<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">' + globalize.translate('Refresh') + '</button>';
|
||||
html += '</div>';
|
||||
html += '<br />';
|
||||
html += '<div class="formDialogFooter">';
|
||||
html += '<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">' + globalize.translate('Refresh') + '</button>';
|
||||
html += '</div>';
|
||||
|
||||
html += '</form>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
html += '</form>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
return html;
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
var fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
function centerFocus(elem, horiz, on) {
|
||||
import('scrollHelper').then(({default: scrollHelper}) => {
|
||||
const fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
loading.show();
|
||||
|
||||
const instance = this;
|
||||
const dlg = dom.parentWithClass(e.target, 'dialog');
|
||||
const options = instance.options;
|
||||
|
||||
const apiClient = window.connectionManager.getApiClient(options.serverId);
|
||||
|
||||
const replaceAllMetadata = dlg.querySelector('#selectMetadataRefreshMode').value === 'all';
|
||||
|
||||
const mode = dlg.querySelector('#selectMetadataRefreshMode').value === 'scan' ? 'Default' : 'FullRefresh';
|
||||
const replaceAllImages = mode === 'FullRefresh' && dlg.querySelector('.chkReplaceImages').checked;
|
||||
|
||||
options.itemIds.forEach(function (itemId) {
|
||||
apiClient.refreshItem(itemId, {
|
||||
|
||||
Recursive: true,
|
||||
ImageRefreshMode: mode,
|
||||
MetadataRefreshMode: mode,
|
||||
ReplaceAllImages: replaceAllImages,
|
||||
ReplaceAllMetadata: replaceAllMetadata
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function onSubmit(e) {
|
||||
dialogHelper.close(dlg);
|
||||
|
||||
loading.show();
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('RefreshQueued'));
|
||||
});
|
||||
|
||||
var instance = this;
|
||||
var dlg = dom.parentWithClass(e.target, 'dialog');
|
||||
var options = instance.options;
|
||||
loading.hide();
|
||||
|
||||
var apiClient = connectionManager.getApiClient(options.serverId);
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
var replaceAllMetadata = dlg.querySelector('#selectMetadataRefreshMode').value === 'all';
|
||||
|
||||
var mode = dlg.querySelector('#selectMetadataRefreshMode').value === 'scan' ? 'Default' : 'FullRefresh';
|
||||
var replaceAllImages = mode === 'FullRefresh' && dlg.querySelector('.chkReplaceImages').checked;
|
||||
|
||||
options.itemIds.forEach(function (itemId) {
|
||||
apiClient.refreshItem(itemId, {
|
||||
|
||||
Recursive: true,
|
||||
ImageRefreshMode: mode,
|
||||
MetadataRefreshMode: mode,
|
||||
ReplaceAllImages: replaceAllImages,
|
||||
ReplaceAllMetadata: replaceAllMetadata
|
||||
});
|
||||
});
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
toast(globalize.translate('RefreshQueued'));
|
||||
});
|
||||
|
||||
loading.hide();
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
function RefreshDialog(options) {
|
||||
class RefreshDialog {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
RefreshDialog.prototype.show = function () {
|
||||
|
||||
var dialogOptions = {
|
||||
show() {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
@@ -102,12 +112,12 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'connectionM
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var html = '';
|
||||
var title = globalize.translate('RefreshMetadata');
|
||||
let html = '';
|
||||
const title = globalize.translate('RefreshMetadata');
|
||||
|
||||
html += '<div class="formDialogHeader">';
|
||||
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
|
||||
@@ -124,7 +134,6 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'connectionM
|
||||
dlg.querySelector('form').addEventListener('submit', onSubmit.bind(this));
|
||||
|
||||
dlg.querySelector('#selectMetadataRefreshMode').addEventListener('change', function () {
|
||||
|
||||
if (this.value === 'scan') {
|
||||
dlg.querySelector('.fldReplaceExistingImages').classList.add('hide');
|
||||
} else {
|
||||
@@ -139,7 +148,6 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'connectionM
|
||||
dlg.querySelector('#selectMetadataRefreshMode').dispatchEvent(new CustomEvent('change'));
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
@@ -148,7 +156,6 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'connectionM
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
|
||||
}
|
||||
@@ -156,7 +163,7 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'connectionM
|
||||
dlg.addEventListener('close', resolve);
|
||||
dialogHelper.open(dlg);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return RefreshDialog;
|
||||
});
|
||||
export default RefreshDialog;
|
||||
|
||||
@@ -222,18 +222,10 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.layout-mobile .nowPlayingSecondaryButtons .btnShuffleQueue {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layout-mobile .nowPlayingSecondaryButtons .volumecontrol {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layout-mobile .nowPlayingSecondaryButtons .btnRepeat {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layout-desktop .nowPlayingInfoButtons .btnRepeat,
|
||||
.layout-tv .nowPlayingInfoButtons .btnRepeat {
|
||||
display: none;
|
||||
@@ -362,7 +354,8 @@
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.nowPlayingInfoButtons .btnRepeat {
|
||||
.nowPlayingInfoButtons .btnRepeat,
|
||||
.nowPlayingInfoButtons .btnRewind {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
margin-left: 0;
|
||||
@@ -370,7 +363,8 @@
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.nowPlayingInfoButtons .btnShuffleQueue {
|
||||
.nowPlayingInfoButtons .btnShuffleQueue,
|
||||
.nowPlayingInfoButtons .btnFastForward {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin-right: 0;
|
||||
@@ -468,7 +462,6 @@
|
||||
}
|
||||
|
||||
@media all and (max-width: 63em) {
|
||||
.nowPlayingSecondaryButtons .repeatToggleButton,
|
||||
.nowPlayingInfoButtons .playlist .listItemMediaInfo,
|
||||
.nowPlayingInfoButtons .btnStop {
|
||||
display: none !important;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user