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

Merge branch 'master' into improve-builds

This commit is contained in:
Joshua M. Boniface 2020-04-25 22:20:49 -04:00 committed by GitHub
commit 5330fd1228
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
126 changed files with 3286 additions and 1971 deletions

View file

@ -200,7 +200,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
var apiClient = this;
if (data.status === 401) {
if (data.status === 403) {
if (data.errorCode === "ParentalControl") {
var isCurrentAllowed = currentRouteInfo ? (currentRouteInfo.route.anonymous || currentRouteInfo.route.startup) : true;
@ -268,6 +268,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
}
function getMaxBandwidth() {
/* eslint-disable compat/compat */
if (navigator.connection) {
var max = navigator.connection.downlinkMax;
if (max && max > 0 && max < Number.POSITIVE_INFINITY) {
@ -279,6 +280,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
return max;
}
}
/* eslint-enable compat/compat */
return null;
}
@ -577,7 +579,8 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
function showDirect(path) {
return new Promise(function(resolve, reject) {
resolveOnNextShow = resolve, page.show(baseUrl()+path);
resolveOnNextShow = resolve;
page.show(baseUrl() + path);
});
}

View file

@ -237,10 +237,6 @@ define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings"], f
features.push("voiceinput");
}
if (!browser.tv && !browser.xboxOne) {
browser.ps4;
}
if (supportsHtmlMediaAutoplay()) {
features.push("htmlaudioautoplay");
features.push("htmlvideoautoplay");
@ -351,8 +347,6 @@ define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings"], f
var deviceName;
var appName = "Jellyfin Web";
var appVersion = "10.6.0";
var visibilityChange;
var visibilityState;
var appHost = {
getWindowState: function () {
@ -426,40 +420,26 @@ define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings"], f
}
};
var doc = self.document;
var isHidden = false;
var hidden;
var visibilityChange;
if (doc) {
if (void 0 !== doc.visibilityState) {
visibilityChange = "visibilitychange";
visibilityState = "hidden";
if (typeof document.hidden !== "undefined") { /* eslint-disable-line compat/compat */
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
document.addEventListener(visibilityChange, function () {
/* eslint-disable-next-line compat/compat */
if (document[hidden]) {
onAppHidden();
} else {
if (void 0 !== doc.mozHidden) {
visibilityChange = "mozvisibilitychange";
visibilityState = "mozVisibilityState";
} else {
if (void 0 !== doc.msHidden) {
visibilityChange = "msvisibilitychange";
visibilityState = "msVisibilityState";
} else {
if (void 0 !== doc.webkitHidden) {
visibilityChange = "webkitvisibilitychange";
visibilityState = "webkitVisibilityState";
}
}
}
onAppVisible();
}
}
if (doc) {
doc.addEventListener(visibilityChange, function () {
if (document[visibilityState]) {
onAppHidden();
} else {
onAppVisible();
}
});
}
}, false);
if (self.addEventListener) {
self.addEventListener("focus", onAppVisible);

View file

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

View file

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

View file

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

View file

@ -1,77 +0,0 @@
define(['emby-progressring', 'dom', 'serverNotifications', 'events', 'registerElement'], function (EmbyProgressRing, dom, serverNotifications, events) {
'use strict';
function addNotificationEvent(instance, name, handler) {
var localHandler = handler.bind(instance);
events.on(serverNotifications, name, localHandler);
instance[name] = localHandler;
}
function removeNotificationEvent(instance, name) {
var handler = instance[name];
if (handler) {
events.off(serverNotifications, name, handler);
instance[name] = null;
}
}
function onRefreshProgress(e, apiClient, info) {
var indicator = this;
if (!indicator.itemId) {
indicator.itemId = dom.parentWithAttribute(indicator, 'data-id').getAttribute('data-id');
}
if (info.ItemId === indicator.itemId) {
var progress = parseFloat(info.Progress);
if (progress && progress < 100) {
this.classList.remove('hide');
} else {
this.classList.add('hide');
}
this.setProgress(progress);
}
}
var EmbyItemRefreshIndicatorPrototype = Object.create(EmbyProgressRing);
EmbyItemRefreshIndicatorPrototype.createdCallback = function () {
// base method
if (EmbyProgressRing.createdCallback) {
EmbyProgressRing.createdCallback.call(this);
}
addNotificationEvent(this, 'RefreshProgress', onRefreshProgress);
};
EmbyItemRefreshIndicatorPrototype.attachedCallback = function () {
// base method
if (EmbyProgressRing.attachedCallback) {
EmbyProgressRing.attachedCallback.call(this);
}
};
EmbyItemRefreshIndicatorPrototype.detachedCallback = function () {
// base method
if (EmbyProgressRing.detachedCallback) {
EmbyProgressRing.detachedCallback.call(this);
}
removeNotificationEvent(this, 'RefreshProgress');
this.itemId = null;
};
document.registerElement('emby-itemrefreshindicator', {
prototype: EmbyItemRefreshIndicatorPrototype,
extends: 'div'
});
});

View file

@ -1,482 +0,0 @@
define(['itemShortcuts', 'inputManager', 'connectionManager', 'playbackManager', 'imageLoader', 'layoutManager', 'browser', 'dom', 'loading', 'focusManager', 'serverNotifications', 'events', 'registerElement'], function (itemShortcuts, inputManager, connectionManager, playbackManager, imageLoader, layoutManager, browser, dom, loading, focusManager, serverNotifications, events) {
'use strict';
var ItemsContainerPrototype = Object.create(HTMLDivElement.prototype);
function onClick(e) {
var itemsContainer = this;
var target = e.target;
var multiSelect = itemsContainer.multiSelect;
if (multiSelect) {
if (multiSelect.onContainerClick.call(itemsContainer, e) === false) {
return;
}
}
itemShortcuts.onClick.call(itemsContainer, e);
}
function disableEvent(e) {
e.preventDefault();
e.stopPropagation();
return false;
}
function onContextMenu(e) {
var itemsContainer = this;
var target = e.target;
var card = dom.parentWithAttribute(target, 'data-id');
// check for serverId, it won't be present on selectserver
if (card && card.getAttribute('data-serverid')) {
inputManager.trigger('menu', {
sourceElement: card
});
e.preventDefault();
e.stopPropagation();
return false;
}
}
function getShortcutOptions() {
return {
click: false
};
}
ItemsContainerPrototype.enableMultiSelect = function (enabled) {
var current = this.multiSelect;
if (!enabled) {
if (current) {
current.destroy();
this.multiSelect = null;
}
return;
}
if (current) {
return;
}
var self = this;
require(['multiSelect'], function (MultiSelect) {
self.multiSelect = new MultiSelect({
container: self,
bindOnClick: false
});
});
};
function onDrop(evt, itemsContainer) {
var el = evt.item;
var newIndex = evt.newIndex;
var itemId = el.getAttribute('data-playlistitemid');
var playlistId = el.getAttribute('data-playlistid');
if (!playlistId) {
var oldIndex = evt.oldIndex;
el.dispatchEvent(new CustomEvent('itemdrop', {
detail: {
oldIndex: oldIndex,
newIndex: newIndex,
playlistItemId: itemId
},
bubbles: true,
cancelable: false
}));
return;
}
var serverId = el.getAttribute('data-serverid');
var apiClient = connectionManager.getApiClient(serverId);
loading.show();
apiClient.ajax({
url: apiClient.getUrl('Playlists/' + playlistId + '/Items/' + itemId + '/Move/' + newIndex),
type: 'POST'
}).then(function () {
loading.hide();
}, function () {
loading.hide();
itemsContainer.refreshItems();
});
}
ItemsContainerPrototype.enableDragReordering = function (enabled) {
var current = this.sortable;
if (!enabled) {
if (current) {
current.destroy();
this.sortable = null;
}
return;
}
if (current) {
return;
}
var self = this;
require(['sortable'], function (Sortable) {
self.sortable = new Sortable(self, {
draggable: ".listItem",
handle: '.listViewDragHandle',
// dragging ended
onEnd: function (evt) {
return onDrop(evt, self);
}
});
});
};
function onUserDataChanged(e, apiClient, userData) {
var itemsContainer = this;
require(['cardBuilder'], function (cardBuilder) {
cardBuilder.onUserDataChanged(userData, itemsContainer);
});
var eventsToMonitor = getEventsToMonitor(itemsContainer);
// TODO: Check user data change reason?
if (eventsToMonitor.indexOf('markfavorite') !== -1) {
itemsContainer.notifyRefreshNeeded();
} else if (eventsToMonitor.indexOf('markplayed') !== -1) {
itemsContainer.notifyRefreshNeeded();
}
}
function getEventsToMonitor(itemsContainer) {
var monitor = itemsContainer.getAttribute('data-monitor');
if (monitor) {
return monitor.split(',');
}
return [];
}
function onTimerCreated(e, apiClient, data) {
var itemsContainer = this;
if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
itemsContainer.notifyRefreshNeeded();
return;
}
var programId = data.ProgramId;
// This could be null, not supported by all tv providers
var newTimerId = data.Id;
require(['cardBuilder'], function (cardBuilder) {
cardBuilder.onTimerCreated(programId, newTimerId, itemsContainer);
});
}
function onSeriesTimerCreated(e, apiClient, data) {
var itemsContainer = this;
if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) {
itemsContainer.notifyRefreshNeeded();
return;
}
}
function onTimerCancelled(e, apiClient, data) {
var itemsContainer = this;
if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
itemsContainer.notifyRefreshNeeded();
return;
}
require(['cardBuilder'], function (cardBuilder) {
cardBuilder.onTimerCancelled(data.Id, itemsContainer);
});
}
function onSeriesTimerCancelled(e, apiClient, data) {
var itemsContainer = this;
if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) {
itemsContainer.notifyRefreshNeeded();
return;
}
require(['cardBuilder'], function (cardBuilder) {
cardBuilder.onSeriesTimerCancelled(data.Id, itemsContainer);
});
}
function onLibraryChanged(e, apiClient, data) {
var itemsContainer = this;
var eventsToMonitor = getEventsToMonitor(itemsContainer);
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 parentId = itemsContainer.getAttribute('data-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;
}
}
itemsContainer.notifyRefreshNeeded();
}
function onPlaybackStopped(e, stopInfo) {
var itemsContainer = this;
var state = stopInfo.state;
var eventsToMonitor = getEventsToMonitor(itemsContainer);
if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') {
if (eventsToMonitor.indexOf('videoplayback') !== -1) {
itemsContainer.notifyRefreshNeeded(true);
return;
}
} else if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Audio') {
if (eventsToMonitor.indexOf('audioplayback') !== -1) {
itemsContainer.notifyRefreshNeeded(true);
return;
}
}
}
function addNotificationEvent(instance, name, handler, owner) {
var localHandler = handler.bind(instance);
owner = owner || serverNotifications;
events.on(owner, name, localHandler);
instance['event_' + name] = localHandler;
}
function removeNotificationEvent(instance, name, owner) {
var handler = instance['event_' + name];
if (handler) {
owner = owner || serverNotifications;
events.off(owner, name, handler);
instance['event_' + name] = null;
}
}
ItemsContainerPrototype.createdCallback = function () {
this.classList.add('itemsContainer');
};
ItemsContainerPrototype.attachedCallback = function () {
this.addEventListener('click', onClick);
if (browser.touch) {
this.addEventListener('contextmenu', disableEvent);
} else {
if (this.getAttribute('data-contextmenu') !== 'false') {
this.addEventListener('contextmenu', onContextMenu);
}
}
if (layoutManager.desktop || layoutManager.mobile) {
if (this.getAttribute('data-multiselect') !== 'false') {
this.enableMultiSelect(true);
}
}
if (layoutManager.tv) {
this.classList.add('itemsContainer-tv');
}
itemShortcuts.on(this, getShortcutOptions());
addNotificationEvent(this, 'UserDataChanged', onUserDataChanged);
addNotificationEvent(this, 'TimerCreated', onTimerCreated);
addNotificationEvent(this, 'SeriesTimerCreated', onSeriesTimerCreated);
addNotificationEvent(this, 'TimerCancelled', onTimerCancelled);
addNotificationEvent(this, 'SeriesTimerCancelled', onSeriesTimerCancelled);
addNotificationEvent(this, 'LibraryChanged', onLibraryChanged);
addNotificationEvent(this, 'playbackstop', onPlaybackStopped, playbackManager);
if (this.getAttribute('data-dragreorder') === 'true') {
this.enableDragReordering(true);
}
};
ItemsContainerPrototype.detachedCallback = function () {
clearRefreshInterval(this);
this.enableMultiSelect(false);
this.enableDragReordering(false);
this.removeEventListener('click', onClick);
this.removeEventListener('contextmenu', onContextMenu);
this.removeEventListener('contextmenu', disableEvent);
itemShortcuts.off(this, getShortcutOptions());
removeNotificationEvent(this, 'UserDataChanged');
removeNotificationEvent(this, 'TimerCreated');
removeNotificationEvent(this, 'SeriesTimerCreated');
removeNotificationEvent(this, 'TimerCancelled');
removeNotificationEvent(this, 'SeriesTimerCancelled');
removeNotificationEvent(this, 'LibraryChanged');
removeNotificationEvent(this, 'playbackstop', playbackManager);
this.fetchData = null;
this.getItemsHtml = null;
this.parentContainer = null;
};
ItemsContainerPrototype.pause = function () {
clearRefreshInterval(this, true);
this.paused = true;
};
ItemsContainerPrototype.resume = function (options) {
this.paused = false;
var refreshIntervalEndTime = this.refreshIntervalEndTime;
if (refreshIntervalEndTime) {
var remainingMs = refreshIntervalEndTime - new Date().getTime();
if (remainingMs > 0 && !this.needsRefresh) {
resetRefreshInterval(this, remainingMs);
} else {
this.needsRefresh = true;
this.refreshIntervalEndTime = null;
}
}
if (this.needsRefresh || (options && options.refresh)) {
return this.refreshItems();
}
return Promise.resolve();
};
ItemsContainerPrototype.refreshItems = function () {
if (!this.fetchData) {
return Promise.resolve();
}
if (this.paused) {
this.needsRefresh = true;
return Promise.resolve();
}
this.needsRefresh = false;
return this.fetchData().then(onDataFetched.bind(this));
};
ItemsContainerPrototype.notifyRefreshNeeded = function (isInForeground) {
if (this.paused) {
this.needsRefresh = true;
return;
}
var timeout = this.refreshTimeout;
if (timeout) {
clearTimeout(timeout);
}
if (isInForeground === true) {
this.refreshItems();
} else {
this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 10000);
}
};
function clearRefreshInterval(itemsContainer, isPausing) {
if (itemsContainer.refreshInterval) {
clearInterval(itemsContainer.refreshInterval);
itemsContainer.refreshInterval = null;
if (!isPausing) {
itemsContainer.refreshIntervalEndTime = null;
}
}
}
function resetRefreshInterval(itemsContainer, intervalMs) {
clearRefreshInterval(itemsContainer);
if (!intervalMs) {
intervalMs = parseInt(itemsContainer.getAttribute('data-refreshinterval') || '0');
}
if (intervalMs) {
itemsContainer.refreshInterval = setInterval(itemsContainer.notifyRefreshNeeded.bind(itemsContainer), intervalMs);
itemsContainer.refreshIntervalEndTime = new Date().getTime() + intervalMs;
}
}
function onDataFetched(result) {
var items = result.Items || result;
var parentContainer = this.parentContainer;
if (parentContainer) {
if (items.length) {
parentContainer.classList.remove('hide');
} else {
parentContainer.classList.add('hide');
}
}
var activeElement = document.activeElement;
var focusId;
var hasActiveElement;
if (this.contains(activeElement)) {
hasActiveElement = true;
focusId = activeElement.getAttribute('data-id');
}
this.innerHTML = this.getItemsHtml(items);
imageLoader.lazyChildren(this);
if (hasActiveElement) {
setFocus(this, focusId);
}
resetRefreshInterval(this);
if (this.afterRefresh) {
this.afterRefresh(result);
}
}
function setFocus(itemsContainer, focusId) {
if (focusId) {
var newElement = itemsContainer.querySelector('[data-id="' + focusId + '"]');
if (newElement) {
try {
focusManager.focus(newElement);
return;
} catch (err) {
console.error(err);
}
}
}
focusManager.autoFocus(itemsContainer);
}
document.registerElement('emby-itemscontainer', {
prototype: ItemsContainerPrototype,
extends: 'div'
});
});

View file

@ -1,19 +0,0 @@
.emby-scrollbuttons {
position: absolute;
top: 0;
right: 0;
align-items: center;
justify-content: center;
min-width: 104px;
min-height: 24px;
padding-top: 1.25em;
z-index: 1;
color: #fff;
display: flex;
}
.emby-scrollbuttons-button > i {
min-width: 24px;
min-height: 24px;
display: block;
}

View file

@ -1,178 +0,0 @@
define(['layoutManager', 'dom', 'css!./emby-scrollbuttons', 'registerElement', 'paper-icon-button-light'], function (layoutManager, dom) {
'use strict';
var EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype);
EmbyScrollButtonsPrototype.createdCallback = function () {};
function getScrollButtonHtml(direction) {
var html = '';
var icon = direction === 'left' ? '&#xE5CB;' : '&#xE5CC;';
html += '<button type="button" is="paper-icon-button-light" data-ripple="false" data-direction="' + direction + '" class="emby-scrollbuttons-button">';
html += '<i class="material-icons">' + icon + '</i>';
html += '</button>';
return html;
}
function getScrollPosition(parent) {
if (parent.getScrollPosition) {
return parent.getScrollPosition();
}
return 0;
}
function getScrollWidth(parent) {
if (parent.getScrollSize) {
return parent.getScrollSize();
}
return 0;
}
function updateScrollButtons(scrollButtons, scrollSize, scrollPos, scrollWidth) {
// hack alert add twenty for rounding errors
if (scrollWidth <= scrollSize + 20) {
scrollButtons.scrollButtonsLeft.classList.add('hide');
scrollButtons.scrollButtonsRight.classList.add('hide');
}
if (scrollPos > 0) {
scrollButtons.scrollButtonsLeft.disabled = false;
} else {
scrollButtons.scrollButtonsLeft.disabled = true;
}
var scrollPosEnd = scrollPos + scrollSize;
if (scrollWidth > 0 && scrollPosEnd >= scrollWidth) {
scrollButtons.scrollButtonsRight.disabled = true;
} else {
scrollButtons.scrollButtonsRight.disabled = false;
}
}
function onScroll(e) {
var scrollButtons = this;
var scroller = this.scroller;
var scrollSize = getScrollSize(scroller);
var scrollPos = getScrollPosition(scroller);
var scrollWidth = getScrollWidth(scroller);
updateScrollButtons(scrollButtons, scrollSize, scrollPos, scrollWidth);
}
function getStyleValue(style, name) {
var value = style.getPropertyValue(name);
if (!value) {
return 0;
}
value = value.replace('px', '');
if (!value) {
return 0;
}
value = parseInt(value);
if (isNaN(value)) {
return 0;
}
return value;
}
function getScrollSize(elem) {
var scrollSize = elem.offsetWidth;
var style = window.getComputedStyle(elem, null);
var paddingLeft = getStyleValue(style, 'padding-left');
if (paddingLeft) {
scrollSize -= paddingLeft;
}
var paddingRight = getStyleValue(style, 'padding-right');
if (paddingRight) {
scrollSize -= paddingRight;
}
var slider = elem.getScrollSlider();
style = window.getComputedStyle(slider, null);
paddingLeft = getStyleValue(style, 'padding-left');
if (paddingLeft) {
scrollSize -= paddingLeft;
}
paddingRight = getStyleValue(style, 'padding-right');
if (paddingRight) {
scrollSize -= paddingRight;
}
return scrollSize;
}
function onScrollButtonClick(e) {
var scroller = this.parentNode.nextSibling;
var direction = this.getAttribute('data-direction');
var scrollSize = getScrollSize(scroller);
var scrollPos = getScrollPosition(scroller);
var scrollWidth = getScrollWidth(scroller);
var newPos;
if (direction === 'left') {
newPos = Math.max(0, scrollPos - scrollSize);
} else {
newPos = scrollPos + scrollSize;
}
scroller.scrollToPosition(newPos, false);
}
EmbyScrollButtonsPrototype.attachedCallback = function () {
var scroller = this.nextSibling;
this.scroller = scroller;
var parent = this.parentNode;
parent.classList.add('emby-scroller-container');
this.innerHTML = getScrollButtonHtml('left') + getScrollButtonHtml('right');
var buttons = this.querySelectorAll('.emby-scrollbuttons-button');
buttons[0].addEventListener('click', onScrollButtonClick);
buttons[1].addEventListener('click', onScrollButtonClick);
this.scrollButtonsLeft = buttons[0];
this.scrollButtonsRight = buttons[1];
var scrollHandler = onScroll.bind(this);
this.scrollHandler = scrollHandler;
scroller.addScrollEventListener(scrollHandler, {
capture: false,
passive: true
});
};
EmbyScrollButtonsPrototype.detachedCallback = function () {
var parent = this.scroller;
this.scroller = null;
var scrollHandler = this.scrollHandler;
if (parent && scrollHandler) {
parent.removeScrollEventListener(scrollHandler, {
capture: false,
passive: true
});
}
this.scrollHandler = null;
this.scrollButtonsLeft = null;
this.scrollButtonsRight = null;
};
document.registerElement('emby-scrollbuttons', {
prototype: EmbyScrollButtonsPrototype,
extends: 'div'
});
});

View file

@ -1,27 +0,0 @@
.emby-scroller-container {
position: relative;
}
.emby-scroller {
margin-left: 3.3%;
margin-right: 3.3%;
}
/* align first card in scroller to heading */
.itemsContainer > .card > .cardBox {
margin-left: 0;
margin-right: 1.2em;
}
.servers > .card > .cardBox {
margin-left: 0.6em;
margin-right: 0.6em;
}
.layout-tv .emby-scroller,
.layout-mobile .emby-scroller {
padding-left: 3.3%;
padding-right: 3.3%;
margin-left: 0;
margin-right: 0;
}

View file

@ -1,209 +0,0 @@
define(['scroller', 'dom', 'layoutManager', 'inputManager', 'focusManager', 'browser', 'registerElement', 'css!./emby-scroller'], function (scroller, dom, layoutManager, inputManager, focusManager, browser) {
'use strict';
var ScrollerPrototype = Object.create(HTMLDivElement.prototype);
ScrollerPrototype.createdCallback = function () {
this.classList.add('emby-scroller');
};
function initCenterFocus(elem, scrollerInstance) {
dom.addEventListener(elem, 'focus', function (e) {
var focused = focusManager.focusableParent(e.target);
if (focused) {
scrollerInstance.toCenter(focused);
}
}, {
capture: true,
passive: true
});
}
ScrollerPrototype.scrollToBeginning = function () {
if (this.scroller) {
this.scroller.slideTo(0, true);
}
};
ScrollerPrototype.toStart = function (elem, immediate) {
if (this.scroller) {
this.scroller.toStart(elem, immediate);
}
};
ScrollerPrototype.toCenter = function (elem, immediate) {
if (this.scroller) {
this.scroller.toCenter(elem, immediate);
}
};
ScrollerPrototype.scrollToPosition = function (pos, immediate) {
if (this.scroller) {
this.scroller.slideTo(pos, immediate);
}
};
ScrollerPrototype.getScrollPosition = function () {
if (this.scroller) {
return this.scroller.getScrollPosition();
}
};
ScrollerPrototype.getScrollSize = function () {
if (this.scroller) {
return this.scroller.getScrollSize();
}
};
ScrollerPrototype.getScrollEventName = function () {
if (this.scroller) {
return this.scroller.getScrollEventName();
}
};
ScrollerPrototype.getScrollSlider = function () {
if (this.scroller) {
return this.scroller.getScrollSlider();
}
};
ScrollerPrototype.addScrollEventListener = function (fn, options) {
if (this.scroller) {
dom.addEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options);
}
};
ScrollerPrototype.removeScrollEventListener = function (fn, options) {
if (this.scroller) {
dom.removeEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options);
}
};
function onInputCommand(e) {
var cmd = e.detail.command;
if (cmd === 'end') {
focusManager.focusLast(this, '.' + this.getAttribute('data-navcommands'));
e.preventDefault();
e.stopPropagation();
} else if (cmd === 'pageup') {
focusManager.moveFocus(e.target, this, '.' + this.getAttribute('data-navcommands'), -12);
e.preventDefault();
e.stopPropagation();
} else if (cmd === 'pagedown') {
focusManager.moveFocus(e.target, this, '.' + this.getAttribute('data-navcommands'), 12);
e.preventDefault();
e.stopPropagation();
}
}
function initHeadroom(elem) {
require(['headroom'], function (Headroom) {
var headroom = new Headroom([], {
scroller: elem
});
headroom.add(document.querySelector('.skinHeader'));
elem.headroom = headroom;
});
}
ScrollerPrototype.attachedCallback = function () {
if (this.getAttribute('data-navcommands')) {
inputManager.on(this, onInputCommand);
}
var horizontal = this.getAttribute('data-horizontal') !== 'false';
var slider = this.querySelector('.scrollSlider');
if (horizontal) {
slider.style['white-space'] = 'nowrap';
}
var bindHeader = this.getAttribute('data-bindheader') === 'true';
var scrollFrame = this;
var enableScrollButtons = layoutManager.desktop && horizontal && this.getAttribute('data-scrollbuttons') !== 'false';
var options = {
horizontal: horizontal,
mouseDragging: 1,
mouseWheel: this.getAttribute('data-mousewheel') !== 'false',
touchDragging: 1,
slidee: slider,
scrollBy: 200,
speed: horizontal ? 270 : 240,
elasticBounds: 1,
dragHandle: 1,
autoImmediate: true,
skipSlideToWhenVisible: this.getAttribute('data-skipfocuswhenvisible') === 'true',
dispatchScrollEvent: enableScrollButtons || bindHeader || this.getAttribute('data-scrollevent') === 'true',
hideScrollbar: enableScrollButtons || this.getAttribute('data-hidescrollbar') === 'true',
allowNativeSmoothScroll: this.getAttribute('data-allownativesmoothscroll') === 'true' && !enableScrollButtons,
allowNativeScroll: !enableScrollButtons,
forceHideScrollbars: enableScrollButtons,
// In edge, with the native scroll, the content jumps around when hovering over the buttons
requireAnimation: enableScrollButtons && browser.edge
};
// If just inserted it might not have any height yet - yes this is a hack
this.scroller = new scroller(scrollFrame, options);
this.scroller.init();
this.scroller.reload();
if (layoutManager.tv && this.getAttribute('data-centerfocus')) {
initCenterFocus(this, this.scroller);
}
if (bindHeader && layoutManager.mobile) {
initHeadroom(this);
}
if (enableScrollButtons) {
loadScrollButtons(this);
}
};
function loadScrollButtons(scroller) {
require(['emby-scrollbuttons'], function () {
scroller.insertAdjacentHTML('beforebegin', '<div is="emby-scrollbuttons" class="emby-scrollbuttons padded-right"></div>');
});
}
ScrollerPrototype.pause = function () {
var headroom = this.headroom;
if (headroom) {
headroom.pause();
}
};
ScrollerPrototype.resume = function () {
var headroom = this.headroom;
if (headroom) {
headroom.resume();
}
};
ScrollerPrototype.detachedCallback = function () {
if (this.getAttribute('data-navcommands')) {
inputManager.off(this, onInputCommand);
}
var headroom = this.headroom;
if (headroom) {
headroom.destroy();
this.headroom = null;
}
var scrollerInstance = this.scroller;
if (scrollerInstance) {
scrollerInstance.destroy();
this.scroller = null;
}
};
document.registerElement('emby-scroller', {
prototype: ScrollerPrototype,
extends: 'div'
});
});

View file

@ -1,43 +0,0 @@
.emby-tab-button {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: transparent;
box-shadow: none;
cursor: pointer;
outline: none;
width: auto;
font-family: inherit;
font-size: inherit;
display: inline-block;
vertical-align: middle;
flex-shrink: 0;
margin: 0;
padding: 1.5em 1.5em;
position: relative;
height: auto;
min-width: initial;
line-height: 1.25;
border-radius: 0;
overflow: hidden;
font-weight: 600;
}
.emby-tab-button.show-focus:focus {
/* these buttons are small so scale larger than usual */
transform: scale(1.3) !important;
background: 0 !important;
}
.emby-tabs-slider {
position: relative;
overflow: hidden;
}
.layout-mobile .emby-tabs-slider {
overflow: auto;
}
.tabContent:not(.is-active) {
display: none;
}

View file

@ -1,341 +0,0 @@
define(['dom', 'scroller', 'browser', 'layoutManager', 'focusManager', 'registerElement', 'css!./emby-tabs', 'scrollStyles'], function (dom, scroller, browser, layoutManager, focusManager) {
'use strict';
var EmbyTabs = Object.create(HTMLDivElement.prototype);
var buttonClass = 'emby-tab-button';
var activeButtonClass = buttonClass + '-active';
function setActiveTabButton(tabs, newButton, oldButton, animate) {
newButton.classList.add(activeButtonClass);
}
function getTabPanel(tabs, index) {
return null;
}
function removeActivePanelClass(tabs, index) {
var tabPanel = getTabPanel(tabs, index);
if (tabPanel) {
tabPanel.classList.remove('is-active');
}
}
function addActivePanelClass(tabs, index) {
var tabPanel = getTabPanel(tabs, index);
if (tabPanel) {
tabPanel.classList.add('is-active');
}
}
function fadeInRight(elem) {
var pct = browser.mobile ? '4%' : '0.5%';
var keyframes = [
{ opacity: '0', transform: 'translate3d(' + pct + ', 0, 0)', offset: 0 },
{ opacity: '1', transform: 'none', offset: 1 }];
elem.animate(keyframes, {
duration: 160,
iterations: 1,
easing: 'ease-out'
});
}
function triggerBeforeTabChange(tabs, index, previousIndex) {
tabs.dispatchEvent(new CustomEvent("beforetabchange", {
detail: {
selectedTabIndex: index,
previousIndex: previousIndex
}
}));
if (previousIndex != null && previousIndex !== index) {
removeActivePanelClass(tabs, previousIndex);
}
var newPanel = getTabPanel(tabs, index);
if (newPanel) {
// animate new panel ?
if (newPanel.animate) {
fadeInRight(newPanel);
}
newPanel.classList.add('is-active');
}
}
function onClick(e) {
var tabs = this;
var current = tabs.querySelector('.' + activeButtonClass);
var tabButton = dom.parentWithClass(e.target, buttonClass);
if (tabButton && tabButton !== current) {
if (current) {
current.classList.remove(activeButtonClass);
}
var previousIndex = current ? parseInt(current.getAttribute('data-index')) : null;
setActiveTabButton(tabs, tabButton, current, true);
var index = parseInt(tabButton.getAttribute('data-index'));
triggerBeforeTabChange(tabs, index, previousIndex);
// If toCenter is called syncronously within the click event, it sometimes ends up canceling it
setTimeout(function () {
tabs.selectedTabIndex = index;
tabs.dispatchEvent(new CustomEvent("tabchange", {
detail: {
selectedTabIndex: index,
previousIndex: previousIndex
}
}));
}, 120);
if (tabs.scroller) {
tabs.scroller.toCenter(tabButton, false);
}
}
}
function initScroller(tabs) {
if (tabs.scroller) {
return;
}
var contentScrollSlider = tabs.querySelector('.emby-tabs-slider');
if (contentScrollSlider) {
tabs.scroller = new scroller(tabs, {
horizontal: 1,
itemNav: 0,
mouseDragging: 1,
touchDragging: 1,
slidee: contentScrollSlider,
smart: true,
releaseSwing: true,
scrollBy: 200,
speed: 120,
elasticBounds: 1,
dragHandle: 1,
dynamicHandle: 1,
clickBar: 1,
hiddenScroll: true,
// In safari the transform is causing the headers to occasionally disappear or flicker
requireAnimation: !browser.safari,
allowNativeSmoothScroll: true
});
tabs.scroller.init();
} else {
tabs.classList.add('scrollX');
tabs.classList.add('hiddenScrollX');
tabs.classList.add('smoothScrollX');
}
}
EmbyTabs.createdCallback = function () {
if (this.classList.contains('emby-tabs')) {
return;
}
this.classList.add('emby-tabs');
this.classList.add('focusable');
dom.addEventListener(this, 'click', onClick, {
passive: true
});
};
EmbyTabs.focus = function () {
var selected = this.querySelector('.' + activeButtonClass);
if (selected) {
focusManager.focus(selected);
} else {
focusManager.autoFocus(this);
}
};
EmbyTabs.refresh = function () {
if (this.scroller) {
this.scroller.reload();
}
};
EmbyTabs.attachedCallback = function () {
initScroller(this);
var current = this.querySelector('.' + activeButtonClass);
var currentIndex = current ? parseInt(current.getAttribute('data-index')) : parseInt(this.getAttribute('data-index') || '0');
if (currentIndex !== -1) {
this.selectedTabIndex = currentIndex;
var tabButtons = this.querySelectorAll('.' + buttonClass);
var newTabButton = tabButtons[currentIndex];
if (newTabButton) {
setActiveTabButton(this, newTabButton, current, false);
}
}
if (!this.readyFired) {
this.readyFired = true;
this.dispatchEvent(new CustomEvent("ready", {}));
}
};
EmbyTabs.detachedCallback = function () {
if (this.scroller) {
this.scroller.destroy();
this.scroller = null;
}
dom.removeEventListener(this, 'click', onClick, {
passive: true
});
};
function getSelectedTabButton(elem) {
return elem.querySelector('.' + activeButtonClass);
}
EmbyTabs.selectedIndex = function (selected, triggerEvent) {
var tabs = this;
if (selected == null) {
return tabs.selectedTabIndex || 0;
}
var current = tabs.selectedIndex();
tabs.selectedTabIndex = selected;
var tabButtons = tabs.querySelectorAll('.' + buttonClass);
if (current === selected || triggerEvent === false) {
triggerBeforeTabChange(tabs, selected, current);
tabs.dispatchEvent(new CustomEvent("tabchange", {
detail: {
selectedTabIndex: selected
}
}));
var currentTabButton = tabButtons[current];
setActiveTabButton(tabs, tabButtons[selected], currentTabButton, false);
if (current !== selected && currentTabButton) {
currentTabButton.classList.remove(activeButtonClass);
}
} else {
onClick.call(tabs, {
target: tabButtons[selected]
});
//tabButtons[selected].click();
}
};
function getSibling(elem, method) {
var sibling = elem[method];
while (sibling) {
if (sibling.classList.contains(buttonClass)) {
if (!sibling.classList.contains('hide')) {
return sibling;
}
}
sibling = sibling[method];
}
return null;
}
EmbyTabs.selectNext = function () {
var current = getSelectedTabButton(this);
var sibling = getSibling(current, 'nextSibling');
if (sibling) {
onClick.call(this, {
target: sibling
});
}
};
EmbyTabs.selectPrevious = function () {
var current = getSelectedTabButton(this);
var sibling = getSibling(current, 'previousSibling');
if (sibling) {
onClick.call(this, {
target: sibling
});
}
};
EmbyTabs.triggerBeforeTabChange = function (selected) {
var tabs = this;
triggerBeforeTabChange(tabs, tabs.selectedIndex());
};
EmbyTabs.triggerTabChange = function (selected) {
var tabs = this;
tabs.dispatchEvent(new CustomEvent("tabchange", {
detail: {
selectedTabIndex: tabs.selectedIndex()
}
}));
};
EmbyTabs.setTabEnabled = function (index, enabled) {
var tabs = this;
var btn = this.querySelector('.emby-tab-button[data-index="' + index + '"]');
if (enabled) {
btn.classList.remove('hide');
} else {
btn.classList.remove('add');
}
};
document.registerElement('emby-tabs', {
prototype: EmbyTabs,
extends: 'div'
});
});

View file

@ -4,7 +4,7 @@ export function download(items) {
if (window.NativeShell) {
items.map(function (item) {
window.NativeShell.downloadFile(item.url);
window.NativeShell.downloadFile(item);
});
} else {
multiDownload(items.map(function (item) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -131,7 +131,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} else if (section === 'librarytiles' || section === 'smalllibrarytiles' || section === 'smalllibrarytiles-automobile' || section === 'librarytiles-automobile') {
loadLibraryTiles(elem, apiClient, user, userSettings, 'smallBackdrop', userViews, allSections);
} else if (section === 'librarybuttons') {
loadlibraryButtons(elem, apiClient, user, userSettings, userViews, allSections);
loadlibraryButtons(elem, apiClient, user, userSettings, userViews);
} else if (section === 'resume') {
loadResumeVideo(elem, apiClient, userId);
} else if (section === 'resumeaudio') {

View file

@ -31,7 +31,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
}
function enableHlsShakaPlayer(item, mediaSource, mediaType) {
/* eslint-disable-next-line compat/compat */
if (!!window.MediaSource && !!MediaSource.isTypeSupported) {
if (canPlayNativeHls()) {
@ -162,7 +162,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
}
}
function seekOnPlaybackStart(instance, element, ticks) {
function seekOnPlaybackStart(instance, element, ticks, onMediaReady) {
var seconds = (ticks || 0) / 10000000;
@ -175,6 +175,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
if (element.duration >= seconds) {
// media is ready, seek immediately
setCurrentTimeIfNeeded(element, seconds);
if (onMediaReady) onMediaReady();
} else {
// update video player position when media is ready to be sought
var events = ["durationchange", "loadeddata", "play", "loadedmetadata"];
@ -189,6 +190,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
events.map(function(name) {
element.removeEventListener(name, onMediaChange);
});
if (onMediaReady) onMediaReady();
}
};
events.map(function (name) {

View file

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

View file

@ -1,4 +1,4 @@
define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackManager', 'appRouter', 'appSettings', 'connectionManager', 'htmlMediaHelper', 'itemHelper', 'fullscreenManager', 'globalize'], function (browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager, htmlMediaHelper, itemHelper, fullscreenManager, globalize) {
define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackManager', 'appRouter', 'appSettings', 'connectionManager', 'htmlMediaHelper', 'itemHelper', 'screenfull', 'globalize'], function (browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager, htmlMediaHelper, itemHelper, screenfull, globalize) {
"use strict";
/* globals cast */
@ -600,8 +600,9 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
var offsetValue = parseFloat(offset);
// if .ass currently rendering
if (currentAssRenderer) {
if (currentSubtitlesOctopus) {
updateCurrentTrackOffset(offsetValue);
currentSubtitlesOctopus.timeOffset = offsetValue;
} else {
var trackElement = getTextTrack();
// if .vtt currently rendering
@ -794,7 +795,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
dlg.parentNode.removeChild(dlg);
}
fullscreenManager.exitFullscreen();
screenfull.exit();
};
function onEnded() {
@ -856,7 +857,9 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
loading.hide();
htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks);
htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks, function () {
if (currentSubtitlesOctopus) currentSubtitlesOctopus.resize();
});
if (self._currentPlayOptions.fullscreen) {
@ -1220,11 +1223,6 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
function updateSubtitleText(timeMs) {
// handle offset for ass tracks
if (currentTrackOffset) {
timeMs += (currentTrackOffset * 1000);
}
var clock = currentClock;
if (clock) {
try {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -6,6 +6,7 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
document.removeEventListener('keydown', onOneDocumentClick);
if (window.Notification) {
/* eslint-disable-next-line compat/compat */
Notification.requestPermission();
}
}
@ -26,6 +27,7 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
}
function resetRegistration() {
/* eslint-disable-next-line compat/compat */
var serviceWorker = navigator.serviceWorker;
if (serviceWorker) {
serviceWorker.ready.then(function (registration) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -258,6 +258,11 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
direction: 'horizontal',
// Loop is disabled due to the virtual slides option not supporting it.
loop: false,
zoom: {
minRatio: 1,
toggle: true,
containerClass: 'slider-zoom-container'
},
autoplay: !options.interactive,
keyboard: {
enabled: true
@ -307,8 +312,7 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
*/
function getSwiperSlideHtmlFromItem(item) {
return getSwiperSlideHtmlFromSlide({
imageUrl: getImgUrl(item),
originalImage: getImgUrl(item, true),
originalImage: getImgUrl(item),
//title: item.Name,
//description: item.Overview
Id: item.Id,

View file

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

View file

@ -1,159 +0,0 @@
define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby-button'], function (connectionManager, serverNotifications, events, globalize, EmbyButtonPrototype) {
'use strict';
function addNotificationEvent(instance, name, handler) {
var localHandler = handler.bind(instance);
events.on(serverNotifications, name, localHandler);
instance[name] = localHandler;
}
function removeNotificationEvent(instance, name) {
var handler = instance[name];
if (handler) {
events.off(serverNotifications, name, handler);
instance[name] = null;
}
}
function onClick(e) {
var button = this;
var id = button.getAttribute('data-id');
var serverId = button.getAttribute('data-serverid');
var apiClient = connectionManager.getApiClient(serverId);
if (!button.classList.contains('playstatebutton-played')) {
apiClient.markPlayed(apiClient.getCurrentUserId(), id, new Date());
setState(button, true);
} else {
apiClient.markUnplayed(apiClient.getCurrentUserId(), id, new Date());
setState(button, false);
}
}
function onUserDataChanged(e, apiClient, userData) {
var button = this;
if (userData.ItemId === button.getAttribute('data-id')) {
setState(button, userData.Played);
}
}
function setState(button, played, updateAttribute) {
var icon = button.iconElement;
if (!icon) {
button.iconElement = button.querySelector('i');
icon = button.iconElement;
}
if (played) {
button.classList.add('playstatebutton-played');
if (icon) {
icon.classList.add('playstatebutton-icon-played');
icon.classList.remove('playstatebutton-icon-unplayed');
}
} else {
button.classList.remove('playstatebutton-played');
if (icon) {
icon.classList.remove('playstatebutton-icon-played');
icon.classList.add('playstatebutton-icon-unplayed');
}
}
if (updateAttribute !== false) {
button.setAttribute('data-played', played);
}
}
function setTitle(button, itemType) {
if (itemType !== 'AudioBook' && itemType !== 'AudioPodcast') {
button.title = globalize.translate('Watched');
} else {
button.title = globalize.translate('Played');
}
var text = button.querySelector('.button-text');
if (text) {
text.innerHTML = button.title;
}
}
function clearEvents(button) {
button.removeEventListener('click', onClick);
removeNotificationEvent(button, 'UserDataChanged');
}
function bindEvents(button) {
clearEvents(button);
button.addEventListener('click', onClick);
addNotificationEvent(button, 'UserDataChanged', onUserDataChanged);
}
var EmbyPlaystateButtonPrototype = Object.create(EmbyButtonPrototype);
EmbyPlaystateButtonPrototype.createdCallback = function () {
// base method
if (EmbyButtonPrototype.createdCallback) {
EmbyButtonPrototype.createdCallback.call(this);
}
};
EmbyPlaystateButtonPrototype.attachedCallback = function () {
// base method
if (EmbyButtonPrototype.attachedCallback) {
EmbyButtonPrototype.attachedCallback.call(this);
}
var itemId = this.getAttribute('data-id');
var serverId = this.getAttribute('data-serverid');
if (itemId && serverId) {
setState(this, this.getAttribute('data-played') === 'true', false);
bindEvents(this);
setTitle(this, this.getAttribute('data-type'));
}
};
EmbyPlaystateButtonPrototype.detachedCallback = function () {
// base method
if (EmbyButtonPrototype.detachedCallback) {
EmbyButtonPrototype.detachedCallback.call(this);
}
clearEvents(this);
this.iconElement = null;
};
EmbyPlaystateButtonPrototype.setItem = function (item) {
if (item) {
this.setAttribute('data-id', item.Id);
this.setAttribute('data-serverid', item.ServerId);
var played = item.UserData && item.UserData.Played;
setState(this, played);
bindEvents(this);
setTitle(this, item.Type);
} else {
this.removeAttribute('data-id');
this.removeAttribute('data-serverid');
this.removeAttribute('data-played');
clearEvents(this);
}
};
document.registerElement('emby-playstatebutton', {
prototype: EmbyPlaystateButtonPrototype,
extends: 'button'
});
});

View file

@ -1,202 +0,0 @@
define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby-button'], function (connectionManager, serverNotifications, events, globalize, EmbyButtonPrototype) {
'use strict';
function addNotificationEvent(instance, name, handler) {
var localHandler = handler.bind(instance);
events.on(serverNotifications, name, localHandler);
instance[name] = localHandler;
}
function removeNotificationEvent(instance, name) {
var handler = instance[name];
if (handler) {
events.off(serverNotifications, name, handler);
instance[name] = null;
}
}
function showPicker(button, apiClient, itemId, likes, isFavorite) {
return apiClient.updateFavoriteStatus(apiClient.getCurrentUserId(), itemId, !isFavorite);
}
function onClick(e) {
var button = this;
var id = button.getAttribute('data-id');
var serverId = button.getAttribute('data-serverid');
var apiClient = connectionManager.getApiClient(serverId);
var likes = this.getAttribute('data-likes');
var isFavorite = this.getAttribute('data-isfavorite') === 'true';
if (likes === 'true') {
likes = true;
} else if (likes === 'false') {
likes = false;
} else {
likes = null;
}
showPicker(button, apiClient, id, likes, isFavorite).then(function (userData) {
setState(button, userData.Likes, userData.IsFavorite);
});
}
function onUserDataChanged(e, apiClient, userData) {
var button = this;
if (userData.ItemId === button.getAttribute('data-id')) {
setState(button, userData.Likes, userData.IsFavorite);
}
}
function setState(button, likes, isFavorite, updateAttribute) {
var icon = button.querySelector('i');
if (isFavorite) {
if (icon) {
icon.innerHTML = 'favorite';
icon.classList.add('ratingbutton-icon-withrating');
}
button.classList.add('ratingbutton-withrating');
} else if (likes) {
if (icon) {
icon.innerHTML = 'favorite';
icon.classList.remove('ratingbutton-icon-withrating');
//icon.innerHTML = 'thumb_up';
}
button.classList.remove('ratingbutton-withrating');
} else if (likes === false) {
if (icon) {
icon.innerHTML = 'favorite';
icon.classList.remove('ratingbutton-icon-withrating');
//icon.innerHTML = 'thumb_down';
}
button.classList.remove('ratingbutton-withrating');
} else {
if (icon) {
icon.innerHTML = 'favorite';
icon.classList.remove('ratingbutton-icon-withrating');
//icon.innerHTML = 'thumbs_up_down';
}
button.classList.remove('ratingbutton-withrating');
}
if (updateAttribute !== false) {
button.setAttribute('data-isfavorite', isFavorite);
button.setAttribute('data-likes', (likes === null ? '' : likes));
}
}
function setTitle(button) {
button.title = globalize.translate('Favorite');
var text = button.querySelector('.button-text');
if (text) {
text.innerHTML = button.title;
}
}
function clearEvents(button) {
button.removeEventListener('click', onClick);
removeNotificationEvent(button, 'UserDataChanged');
}
function bindEvents(button) {
clearEvents(button);
button.addEventListener('click', onClick);
addNotificationEvent(button, 'UserDataChanged', onUserDataChanged);
}
var EmbyRatingButtonPrototype = Object.create(EmbyButtonPrototype);
EmbyRatingButtonPrototype.createdCallback = function () {
// base method
if (EmbyButtonPrototype.createdCallback) {
EmbyButtonPrototype.createdCallback.call(this);
}
};
EmbyRatingButtonPrototype.attachedCallback = function () {
// base method
if (EmbyButtonPrototype.attachedCallback) {
EmbyButtonPrototype.attachedCallback.call(this);
}
var itemId = this.getAttribute('data-id');
var serverId = this.getAttribute('data-serverid');
if (itemId && serverId) {
var likes = this.getAttribute('data-likes');
var isFavorite = this.getAttribute('data-isfavorite') === 'true';
if (likes === 'true') {
likes = true;
} else if (likes === 'false') {
likes = false;
} else {
likes = null;
}
setState(this, likes, isFavorite, false);
bindEvents(this);
}
setTitle(this);
};
EmbyRatingButtonPrototype.detachedCallback = function () {
// base method
if (EmbyButtonPrototype.detachedCallback) {
EmbyButtonPrototype.detachedCallback.call(this);
}
clearEvents(this);
};
EmbyRatingButtonPrototype.setItem = function (item) {
if (item) {
this.setAttribute('data-id', item.Id);
this.setAttribute('data-serverid', item.ServerId);
var userData = item.UserData || {};
setState(this, userData.Likes, userData.IsFavorite);
bindEvents(this);
} else {
this.removeAttribute('data-id');
this.removeAttribute('data-serverid');
this.removeAttribute('data-likes');
this.removeAttribute('data-isfavorite');
clearEvents(this);
}
};
document.registerElement('emby-ratingbutton', {
prototype: EmbyRatingButtonPrototype,
extends: 'button'
});
});