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

915 lines
41 KiB
JavaScript
Raw Normal View History

define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageLoader', 'playbackManager', 'nowPlayingHelper', 'events', 'connectionManager', 'apphost', 'globalize', 'layoutManager', 'userSettings', 'cardBuilder', 'itemContextMenu', 'cardStyle', 'emby-itemscontainer', 'css!./remotecontrol.css', 'emby-ratingbutton'], function (browser, datetime, backdrop, libraryBrowser, listView, imageLoader, playbackManager, nowPlayingHelper, events, connectionManager, appHost, globalize, layoutManager, userSettings, cardBuilder, itemContextMenu) {
2020-05-04 12:44:12 +02:00
'use strict';
var showMuteButton = true;
var showVolumeSlider = true;
2019-02-02 11:14:40 -05:00
function showAudioMenu(context, player, button, item) {
var currentIndex = playbackManager.getAudioStreamIndex(player);
var streams = playbackManager.audioTracks(player);
var menuItems = streams.map(function (s) {
2019-02-02 11:14:40 -05:00
var menuItem = {
name: s.DisplayTitle,
id: s.Index
2019-02-02 11:14:40 -05:00
};
if (s.Index == currentIndex) {
2019-02-02 11:14:40 -05:00
menuItem.selected = true;
}
return menuItem;
});
2018-10-23 01:05:09 +03:00
2020-05-04 12:44:12 +02:00
require(['actionsheet'], function (actionsheet) {
2019-02-02 11:14:40 -05:00
actionsheet.show({
items: menuItems,
positionTo: button,
callback: function (id) {
playbackManager.setAudioStreamIndex(parseInt(id), player);
}
});
});
}
2018-10-23 01:05:09 +03:00
2019-02-02 11:14:40 -05:00
function showSubtitleMenu(context, player, button, item) {
var currentIndex = playbackManager.getSubtitleStreamIndex(player);
var streams = playbackManager.subtitleTracks(player);
var menuItems = streams.map(function (s) {
2019-02-02 11:14:40 -05:00
var menuItem = {
name: s.DisplayTitle,
id: s.Index
2019-02-02 11:14:40 -05:00
};
2018-10-23 01:05:09 +03:00
if (s.Index == currentIndex) {
2019-02-02 11:14:40 -05:00
menuItem.selected = true;
}
2018-10-23 01:05:09 +03:00
2019-02-02 11:14:40 -05:00
return menuItem;
});
menuItems.unshift({
id: -1,
2020-05-04 12:44:12 +02:00
name: globalize.translate('ButtonOff'),
2019-02-02 11:14:40 -05:00
selected: null == currentIndex
});
2018-10-23 01:05:09 +03:00
2020-05-04 12:44:12 +02:00
require(['actionsheet'], function (actionsheet) {
2019-02-02 11:14:40 -05:00
actionsheet.show({
items: menuItems,
positionTo: button,
callback: function (id) {
playbackManager.setSubtitleStreamIndex(parseInt(id), player);
}
});
});
}
2018-10-23 01:05:09 +03:00
2019-02-02 11:14:40 -05:00
function getNowPlayingNameHtml(nowPlayingItem, includeNonNameInfo) {
return nowPlayingHelper.getNowPlayingNames(nowPlayingItem, includeNonNameInfo).map(function (i) {
return i.text;
2020-05-04 12:44:12 +02:00
}).join('<br/>');
}
2018-10-23 01:05:09 +03:00
2019-02-02 11:14:40 -05:00
function seriesImageUrl(item, options) {
2020-05-04 12:44:12 +02:00
if ('Episode' !== item.Type) {
2019-02-02 11:14:40 -05:00
return null;
}
2018-10-23 01:05:09 +03:00
2019-02-12 10:01:11 -05:00
options = options || {};
2020-05-04 12:44:12 +02:00
options.type = options.type || 'Primary';
if ('Primary' === options.type && item.SeriesPrimaryImageTag) {
2019-02-02 11:14:40 -05:00
options.tag = item.SeriesPrimaryImageTag;
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
}
2018-10-23 01:05:09 +03:00
2020-05-04 12:44:12 +02:00
if ('Thumb' === options.type) {
2019-02-02 11:14:40 -05:00
if (item.SeriesThumbImageTag) {
options.tag = item.SeriesThumbImageTag;
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
}
2018-10-23 01:05:09 +03:00
2019-02-02 11:14:40 -05:00
if (item.ParentThumbImageTag) {
options.tag = item.ParentThumbImageTag;
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
}
}
2018-10-23 01:05:09 +03:00
2019-02-02 11:14:40 -05:00
return null;
}
2018-10-23 01:05:09 +03:00
2019-02-02 11:14:40 -05:00
function imageUrl(item, options) {
options = options || {};
2020-05-04 12:44:12 +02:00
options.type = options.type || 'Primary';
2018-10-23 01:05:09 +03:00
2019-02-02 11:14:40 -05:00
if (item.ImageTags && item.ImageTags[options.type]) {
options.tag = item.ImageTags[options.type];
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options);
2018-10-23 01:05:09 +03:00
}
2019-02-02 11:14:40 -05:00
if (item.AlbumId && item.AlbumPrimaryImageTag) {
options.tag = item.AlbumPrimaryImageTag;
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
}
2018-10-23 01:05:09 +03:00
2019-02-02 11:14:40 -05:00
return null;
}
2018-10-23 01:05:09 +03:00
2020-04-09 19:15:49 -04:00
function updateNowPlayingInfo(context, state, serverId) {
2019-02-02 11:14:40 -05:00
var item = state.NowPlayingItem;
2020-05-04 12:44:12 +02:00
var displayName = item ? getNowPlayingNameHtml(item).replace('<br/>', ' - ') : '';
if (typeof item !== 'undefined') {
var nowPlayingServerId = (item.ServerId || serverId);
2020-05-04 12:44:12 +02:00
if (item.Type == 'Audio' || item.MediaStreams[0].Type == 'Audio') {
var songName = item.Name;
if (item.Album != null && item.Artists != null) {
var artistsSeries = '';
var albumName = item.Album;
if (item.ArtistItems != null) {
2020-06-23 19:09:22 +02:00
for (const artist of item.ArtistItems) {
let artistName = artist.Name;
let artistId = artist.Id;
artistsSeries += `<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=${artistId}&amp;serverId=${nowPlayingServerId}">${artistName}</a>`;
if (artist !== item.ArtistItems.slice(-1)[0]) {
artistsSeries += ', ';
}
}
} else if (item.Artists) {
// For some reason, Chromecast Player doesn't return a item.ArtistItems object, so we need to fallback
// to normal item.Artists item.
// TODO: Normalise fields returned by all the players
2020-06-23 19:09:22 +02:00
for (const artist of item.Artists) {
artistsSeries += `<a>${artist}</a>`;
if (artist !== item.Artists.slice(-1)[0]) {
artistsSeries += ', ';
}
}
}
context.querySelector('.nowPlayingArtist').innerHTML = artistsSeries;
context.querySelector('.nowPlayingAlbum').innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=' + item.AlbumId + `&amp;serverId=${nowPlayingServerId}">${albumName}</a>`;
2020-04-09 19:15:49 -04:00
}
2020-05-04 12:44:12 +02:00
context.querySelector('.nowPlayingSongName').innerHTML = songName;
} else if (item.Type == 'Episode') {
if (item.SeasonName != null) {
var seasonName = item.SeasonName;
2020-05-04 12:44:12 +02:00
context.querySelector('.nowPlayingSeason').innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=' + item.SeasonId + `&amp;serverId=${nowPlayingServerId}">${seasonName}</a>`;
2020-04-10 13:06:26 -04:00
}
if (item.SeriesName != null) {
var seriesName = item.SeriesName;
2020-05-17 18:17:47 +02:00
if (item.SeriesId != null) {
2020-05-04 12:44:12 +02:00
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 {
2020-05-04 12:44:12 +02:00
context.querySelector('.nowPlayingSerie').innerHTML = seriesName;
}
}
2020-05-04 12:44:12 +02:00
context.querySelector('.nowPlayingEpisode').innerHTML = item.Name;
} else {
2020-05-04 12:44:12 +02:00
context.querySelector('.nowPlayingPageTitle').innerHTML = displayName;
2020-04-10 13:06:26 -04:00
}
2018-10-23 01:05:09 +03:00
2020-05-04 12:44:12 +02:00
if (displayName.length > 0 && item.Type != 'Audio' && item.Type != 'Episode') {
context.querySelector('.nowPlayingPageTitle').classList.remove('hide');
} else {
2020-05-04 12:44:12 +02:00
context.querySelector('.nowPlayingPageTitle').classList.add('hide');
}
2018-10-23 01:05:09 +03:00
var url = item ? seriesImageUrl(item, {
maxHeight: 300 * 2
}) || imageUrl(item, {
maxHeight: 300 * 2
}) : null;
2020-06-18 09:22:17 +02:00
let contextButton = context.querySelector('.btnToggleContextMenu');
// We remove the previous event listener by replacing the item in each update event
let contextButtonClone = contextButton.cloneNode(true);
contextButton.parentNode.replaceChild(contextButtonClone, contextButton);
contextButton = context.querySelector('.btnToggleContextMenu');
var options = {
play: false,
queue: false,
openAlbum: false,
positionTo: contextButton
};
var apiClient = connectionManager.getApiClient(item.ServerId);
apiClient.getCurrentUser().then(function (user) {
contextButton.addEventListener('click', function () {
itemContextMenu.show(Object.assign({
item: item,
user: user
}, options));
});
});
setImageUrl(context, state, url);
if (item) {
backdrop.setBackdrops([item]);
apiClient.getItem(apiClient.getCurrentUserId(), item.Id).then(function (fullItem) {
var userData = fullItem.UserData || {};
2020-05-04 12:44:12 +02:00
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 + '"><span class="material-icons favorite"></span></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 + '"><span class="material-icons favorite"></span></button>';
});
} else {
backdrop.clear();
2020-05-04 12:44:12 +02:00
context.querySelector('.nowPlayingPageUserDataButtons').innerHTML = '';
}
}
2019-02-02 11:14:40 -05:00
}
2020-04-09 19:15:49 -04:00
function setImageUrl(context, state, url) {
2019-02-02 11:14:40 -05:00
currentImgUrl = url;
2020-04-09 19:15:49 -04:00
var item = state.NowPlayingItem;
2020-05-04 12:44:12 +02:00
var imgContainer = context.querySelector('.nowPlayingPageImageContainer');
2019-02-02 11:14:40 -05:00
if (url) {
imgContainer.innerHTML = '<img class="nowPlayingPageImage" src="' + url + '" />';
2020-05-04 12:44:12 +02:00
if (item.Type == 'Audio') {
context.querySelector('.nowPlayingPageImage').classList.add('nowPlayingPageImageAudio');
context.querySelector('.nowPlayingPageImageContainer').classList.remove('nowPlayingPageImageAudio');
2020-04-09 19:15:49 -04:00
} else {
2020-05-04 12:44:12 +02:00
context.querySelector('.nowPlayingPageImageContainer').classList.add('nowPlayingPageImagePoster');
context.querySelector('.nowPlayingPageImage').classList.remove('nowPlayingPageImageAudio');
2020-04-09 19:15:49 -04:00
}
2019-02-02 11:14:40 -05:00
} else {
imgContainer.innerHTML = '<div class="nowPlayingPageImageContainerNoAlbum"><button data-action="link" class="cardImageContainer coveredImage ' + cardBuilder.getDefaultBackgroundClass(item.Name) + ' cardContent cardContent-shadow itemAction"><span class="cardImageIcon material-icons album"></span></button></div>';
}
}
2018-10-23 01:05:09 +03:00
2019-02-02 11:14:40 -05:00
function buttonVisible(btn, enabled) {
if (enabled) {
2020-05-04 12:44:12 +02:00
btn.classList.remove('hide');
} else {
2020-05-04 12:44:12 +02:00
btn.classList.add('hide');
2018-10-23 01:05:09 +03:00
}
}
2019-02-02 11:14:40 -05:00
function updateSupportedCommands(context, commands) {
2020-05-04 12:44:12 +02:00
var all = context.querySelectorAll('.btnCommand');
2019-02-02 11:14:40 -05:00
for (var i = 0, length = all.length; i < length; i++) {
2020-05-04 12:44:12 +02:00
var enableButton = -1 !== commands.indexOf(all[i].getAttribute('data-command'));
all[i].disabled = !enableButton;
2019-02-02 11:14:40 -05:00
}
}
2019-02-02 11:14:40 -05:00
var currentImgUrl;
return function () {
2020-06-23 23:41:52 +02:00
function toggleRepeat() {
switch (playbackManager.getRepeatMode()) {
case 'RepeatAll':
playbackManager.setRepeatMode('RepeatOne');
break;
case 'RepeatOne':
playbackManager.setRepeatMode('RepeatNone');
break;
case 'RepeatNone':
playbackManager.setRepeatMode('RepeatAll');
2019-02-02 11:14:40 -05:00
}
}
2019-02-02 11:14:40 -05:00
function updatePlayerState(player, context, state) {
lastPlayerState = state;
var item = state.NowPlayingItem;
var playerInfo = playbackManager.getPlayerInfo();
var supportedCommands = playerInfo.supportedCommands;
currentPlayerSupportedCommands = supportedCommands;
var playState = state.PlayState || {};
2020-05-04 12:44:12 +02:00
var isSupportedCommands = supportedCommands.includes('DisplayMessage') || supportedCommands.includes('SendString') || supportedCommands.includes('Select');
buttonVisible(context.querySelector('.btnToggleFullscreen'), item && 'Video' == item.MediaType && supportedCommands.includes('ToggleFullscreen'));
2019-02-02 11:14:40 -05:00
updateAudioTracksDisplay(player, context);
updateSubtitleTracksDisplay(player, context);
2020-05-04 12:44:12 +02:00
if (supportedCommands.includes('DisplayMessage') && !currentPlayer.isLocalPlayer) {
context.querySelector('.sendMessageSection').classList.remove('hide');
2019-02-02 11:14:40 -05:00
} else {
2020-05-04 12:44:12 +02:00
context.querySelector('.sendMessageSection').classList.add('hide');
2019-02-02 11:14:40 -05:00
}
2020-05-04 12:44:12 +02:00
if (supportedCommands.includes('SendString') && !currentPlayer.isLocalPlayer) {
context.querySelector('.sendTextSection').classList.remove('hide');
2019-02-02 11:14:40 -05:00
} else {
2020-05-04 12:44:12 +02:00
context.querySelector('.sendTextSection').classList.add('hide');
2019-02-02 11:14:40 -05:00
}
2020-05-04 12:44:12 +02:00
if (supportedCommands.includes('Select') && !currentPlayer.isLocalPlayer) {
context.querySelector('.navigationSection').classList.remove('hide');
2019-11-22 16:01:25 +01:00
} else {
2020-05-04 12:44:12 +02:00
context.querySelector('.navigationSection').classList.add('hide');
2019-11-22 16:01:25 +01:00
}
if (isSupportedCommands && !currentPlayer.isLocalPlayer) {
2020-05-04 12:44:12 +02:00
context.querySelector('.remoteControlSection').classList.remove('hide');
2020-04-12 20:15:58 -04:00
} else {
2020-05-04 12:44:12 +02:00
context.querySelector('.remoteControlSection').classList.add('hide');
2020-04-12 20:15:58 -04:00
}
2020-05-04 12:44:12 +02:00
buttonVisible(context.querySelector('.btnStop'), null != item);
buttonVisible(context.querySelector('.btnNextTrack'), null != item);
buttonVisible(context.querySelector('.btnPreviousTrack'), null != item);
2020-06-17 22:30:59 +02:00
if (layoutManager.mobile) {
buttonVisible(context.querySelector('.btnRewind'), false);
buttonVisible(context.querySelector('.btnFastForward'), false);
} else {
buttonVisible(context.querySelector('.btnRewind'), null != item);
buttonVisible(context.querySelector('.btnFastForward'), null != item);
}
2020-05-04 12:44:12 +02:00
var positionSlider = context.querySelector('.nowPlayingPositionSlider');
2019-02-02 11:14:40 -05:00
if (positionSlider && item && item.RunTimeTicks) {
positionSlider.setKeyboardSteps(userSettings.skipBackLength() * 1000000 / item.RunTimeTicks,
userSettings.skipForwardLength() * 1000000 / item.RunTimeTicks);
}
2019-02-02 11:14:40 -05:00
if (positionSlider && !positionSlider.dragging) {
positionSlider.disabled = !playState.CanSeek;
var isProgressClear = state.MediaSource && null == state.MediaSource.RunTimeTicks;
positionSlider.setIsClear(isProgressClear);
}
updatePlayPauseState(playState.IsPaused, null != item);
updateTimeDisplay(playState.PositionTicks, item ? item.RunTimeTicks : null);
updatePlayerVolumeState(context, playState.IsMuted, playState.VolumeLevel);
2020-05-04 12:44:12 +02:00
if (item && 'Video' == item.MediaType) {
context.classList.remove('hideVideoButtons');
2019-02-02 11:14:40 -05:00
} else {
2020-05-04 12:44:12 +02:00
context.classList.add('hideVideoButtons');
2019-02-02 11:14:40 -05:00
}
2020-06-23 23:41:52 +02:00
updateRepeatModeDisplay(playbackManager.getRepeatMode());
2020-06-22 11:25:16 +02:00
onShuffleQueueModeChange();
2019-02-02 11:14:40 -05:00
updateNowPlayingInfo(context, state);
}
2019-02-02 11:14:40 -05:00
function updateAudioTracksDisplay(player, context) {
var supportedCommands = currentPlayerSupportedCommands;
2020-05-04 12:44:12 +02:00
buttonVisible(context.querySelector('.btnAudioTracks'), playbackManager.audioTracks(player).length > 1 && -1 != supportedCommands.indexOf('SetAudioStreamIndex'));
}
2019-02-02 11:14:40 -05:00
function updateSubtitleTracksDisplay(player, context) {
var supportedCommands = currentPlayerSupportedCommands;
2020-05-04 12:44:12 +02:00
buttonVisible(context.querySelector('.btnSubtitles'), playbackManager.subtitleTracks(player).length && -1 != supportedCommands.indexOf('SetSubtitleStreamIndex'));
2019-02-02 11:14:40 -05:00
}
2018-10-23 01:05:09 +03:00
2019-02-02 11:14:40 -05:00
function updateRepeatModeDisplay(repeatMode) {
var context = dlg;
let toggleRepeatButtons = context.querySelectorAll('.repeatToggleButton');
2020-06-23 19:09:22 +02:00
const cssClass = 'repeatButton-active';
let innHtml = '<span class="material-icons repeat"></span>';
let repeatOn = true;
2020-06-23 19:09:22 +02:00
switch (repeatMode) {
case 'RepeatAll':
break;
case 'RepeatOne':
innHtml = '<span class="material-icons repeat_one"></span>';
break;
case 'RepeatNone':
2020-06-24 19:50:54 +02:00
default:
repeatOn = false;
break;
2020-06-23 19:09:22 +02:00
}
for (const toggleRepeatButton of toggleRepeatButtons) {
2020-06-23 23:41:52 +02:00
toggleRepeatButton.classList.toggle(cssClass, repeatOn);
2020-06-23 19:09:22 +02:00
toggleRepeatButton.innerHTML = innHtml;
2019-02-02 11:14:40 -05:00
}
}
2019-02-02 11:14:40 -05:00
function updatePlayerVolumeState(context, isMuted, volumeLevel) {
var view = context;
var supportedCommands = currentPlayerSupportedCommands;
2020-05-04 12:44:12 +02:00
if (-1 === supportedCommands.indexOf('Mute')) {
2019-02-02 11:14:40 -05:00
showMuteButton = false;
}
2020-05-04 12:44:12 +02:00
if (-1 === supportedCommands.indexOf('SetVolume')) {
2019-02-02 11:14:40 -05:00
showVolumeSlider = false;
}
2020-05-04 12:44:12 +02:00
if (currentPlayer.isLocalPlayer && appHost.supports('physicalvolumecontrol')) {
2019-02-02 11:14:40 -05:00
showMuteButton = false;
showVolumeSlider = false;
}
2020-05-04 12:44:12 +02:00
const buttonMute = view.querySelector('.buttonMute');
const buttonMuteIcon = buttonMute.querySelector('.material-icons');
2020-05-02 14:02:44 +03:00
2020-05-04 12:44:12 +02:00
buttonMuteIcon.classList.remove('volume_off', 'volume_up');
2020-05-02 14:02:44 +03:00
2019-02-02 11:14:40 -05:00
if (isMuted) {
2020-05-04 12:44:12 +02:00
buttonMute.setAttribute('title', globalize.translate('Unmute'));
buttonMuteIcon.classList.add('volume_off');
2019-02-02 11:14:40 -05:00
} else {
2020-05-04 12:44:12 +02:00
buttonMute.setAttribute('title', globalize.translate('Mute'));
buttonMuteIcon.classList.add('volume_up');
2019-02-02 11:14:40 -05:00
}
if (!showMuteButton && !showVolumeSlider) {
context.querySelector('.volumecontrol').classList.add('hide');
2019-02-02 11:14:40 -05:00
} else {
2020-06-24 19:50:54 +02:00
buttonMute.classList.toggle('hide', showMuteButton);
2019-02-02 11:14:40 -05:00
var nowPlayingVolumeSlider = context.querySelector('.nowPlayingVolumeSlider');
var nowPlayingVolumeSliderContainer = context.querySelector('.nowPlayingVolumeSliderContainer');
if (nowPlayingVolumeSlider) {
2020-06-24 19:50:54 +02:00
nowPlayingVolumeSliderContainer.classList.toggle('hide', !showVolumeSlider);
if (!nowPlayingVolumeSlider.dragging) {
nowPlayingVolumeSlider.value = volumeLevel || 0;
}
2019-02-02 11:14:40 -05:00
}
}
}
2019-02-02 11:14:40 -05:00
function updatePlayPauseState(isPaused, isActive) {
var context = dlg;
2020-05-04 12:44:12 +02:00
var btnPlayPause = context.querySelector('.btnPlayPause');
const btnPlayPauseIcon = btnPlayPause.querySelector('.material-icons');
2020-05-02 14:02:44 +03:00
2020-05-04 12:44:12 +02:00
btnPlayPauseIcon.classList.remove('play_circle_filled', 'pause_circle_filled');
btnPlayPauseIcon.classList.add(isPaused ? 'play_circle_filled' : 'pause_circle_filled');
2020-05-02 14:02:44 +03:00
2019-02-02 11:14:40 -05:00
buttonVisible(btnPlayPause, isActive);
}
2019-02-02 11:14:40 -05:00
function updateTimeDisplay(positionTicks, runtimeTicks) {
var context = dlg;
2020-05-04 12:44:12 +02:00
var positionSlider = context.querySelector('.nowPlayingPositionSlider');
2019-02-02 11:14:40 -05:00
if (positionSlider && !positionSlider.dragging) {
if (runtimeTicks) {
var pct = positionTicks / runtimeTicks;
pct *= 100;
positionSlider.value = pct;
} else {
positionSlider.value = 0;
}
}
2020-05-04 12:44:12 +02:00
context.querySelector('.positionTime').innerHTML = null == positionTicks ? '--:--' : datetime.getDisplayRunningTime(positionTicks);
context.querySelector('.runtime').innerHTML = null != runtimeTicks ? datetime.getDisplayRunningTime(runtimeTicks) : '--:--';
2019-02-02 11:14:40 -05:00
}
2019-02-02 11:14:40 -05:00
function getPlaylistItems(player) {
return playbackManager.getPlaylist(player);
}
2019-02-02 11:14:40 -05:00
function loadPlaylist(context, player) {
getPlaylistItems(player).then(function (items) {
2020-05-04 12:44:12 +02:00
var html = '';
let favoritesEnabled = true;
if (layoutManager.mobile) {
if (items.length > 0) {
context.querySelector('.btnTogglePlaylist').classList.remove('hide');
} else {
context.querySelector('.btnTogglePlaylist').classList.add('hide');
}
favoritesEnabled = false;
}
2019-02-02 11:14:40 -05:00
html += listView.getListViewHtml({
items: items,
smallIcon: true,
2020-05-04 12:44:12 +02:00
action: 'setplaylistindex',
enableUserDataButtons: favoritesEnabled,
2019-02-02 11:14:40 -05:00
rightButtons: [{
2020-05-04 12:44:12 +02:00
icon: 'remove_circle_outline',
title: globalize.translate('ButtonRemove'),
id: 'remove'
2019-02-02 11:14:40 -05:00
}],
dragHandle: true
});
2020-05-04 12:44:12 +02:00
var itemsContainer = context.querySelector('.playlist');
2019-02-02 11:14:40 -05:00
itemsContainer.innerHTML = html;
var playlistItemId = playbackManager.getCurrentPlaylistItemId(player);
if (playlistItemId) {
var img = itemsContainer.querySelector('.listItem[data-playlistItemId="' + playlistItemId + '"] .listItemImage');
if (img) {
2020-05-04 12:44:12 +02:00
img.classList.remove('lazy');
img.classList.add('playlistIndexIndicatorImage');
2019-02-02 11:14:40 -05:00
}
}
imageLoader.lazyChildren(itemsContainer);
});
2018-10-23 01:05:09 +03:00
}
function onPlaybackStart(e, state) {
2020-05-04 12:44:12 +02:00
console.debug('remotecontrol event: ' + e.type);
2019-02-02 11:14:40 -05:00
var player = this;
onStateChanged.call(player, e, state);
2019-02-02 11:14:40 -05:00
}
2020-06-23 23:41:52 +02:00
function onRepeatModeChange() {
updateRepeatModeDisplay(playbackManager.getRepeatMode());
2019-02-02 11:14:40 -05:00
}
2020-06-22 11:25:16 +02:00
function onShuffleQueueModeChange() {
let shuffleMode = playbackManager.getQueueShuffleMode(this);
let context = dlg;
2020-06-23 23:41:52 +02:00
const cssClass = 'shuffleQueue-active';
let shuffleButtons = context.querySelectorAll('.btnShuffleQueue');
for (let shuffleButton of shuffleButtons) {
2020-06-23 19:09:22 +02:00
switch (shuffleMode) {
case 'Shuffle':
2020-06-23 23:41:52 +02:00
shuffleButton.classList.toggle(cssClass, true);
break;
case 'Sorted':
default:
shuffleButton.classList.toggle(cssClass, false);
break;
}
}
onPlaylistUpdate();
}
function onPlaylistUpdate(e) {
2019-02-02 11:14:40 -05:00
loadPlaylist(dlg, this);
}
function onPlaylistItemRemoved(e, info) {
2019-02-02 11:14:40 -05:00
var context = dlg;
var playlistItemIds = info.playlistItemIds;
for (var i = 0, length = playlistItemIds.length; i < length; i++) {
var listItem = context.querySelector('.listItem[data-playlistItemId="' + playlistItemIds[i] + '"]');
2019-02-02 11:14:40 -05:00
if (listItem) {
listItem.parentNode.removeChild(listItem);
}
}
}
function onPlaybackStopped(e, state) {
2020-05-04 12:44:12 +02:00
console.debug('remotecontrol event: ' + e.type);
2019-02-02 11:14:40 -05:00
var player = this;
2019-02-02 11:14:40 -05:00
if (!state.NextMediaType) {
updatePlayerState(player, dlg, {});
loadPlaylist(dlg);
2019-02-24 10:53:41 +01:00
Emby.Page.back();
2019-02-02 11:14:40 -05:00
}
}
function onPlayPauseStateChanged(e) {
2019-02-02 11:14:40 -05:00
updatePlayPauseState(this.paused(), true);
}
2018-10-23 01:05:09 +03:00
2019-02-02 11:14:40 -05:00
function onStateChanged(event, state) {
var player = this;
updatePlayerState(player, dlg, state);
loadPlaylist(dlg, player);
2018-10-23 01:05:09 +03:00
}
function onTimeUpdate(e) {
2019-02-02 11:14:40 -05:00
var now = new Date().getTime();
2019-02-02 11:14:40 -05:00
if (!(now - lastUpdateTime < 700)) {
lastUpdateTime = now;
var player = this;
currentRuntimeTicks = playbackManager.duration(player);
updateTimeDisplay(playbackManager.currentTime(player), currentRuntimeTicks);
}
}
function onVolumeChanged(e) {
2019-02-02 11:14:40 -05:00
var player = this;
updatePlayerVolumeState(dlg, player.isMuted(), player.getVolume());
}
2019-02-02 11:14:40 -05:00
function releaseCurrentPlayer() {
var player = currentPlayer;
if (player) {
2020-05-04 12:44:12 +02:00
events.off(player, 'playbackstart', onPlaybackStart);
events.off(player, 'statechange', onStateChanged);
events.off(player, 'repeatmodechange', onRepeatModeChange);
2020-06-22 11:25:16 +02:00
events.off(player, 'shufflequeuemodechange', onShuffleQueueModeChange);
events.off(player, 'playlistitemremove', onPlaylistItemRemoved);
2020-05-04 12:44:12 +02:00
events.off(player, 'playlistitemmove', onPlaylistUpdate);
events.off(player, 'playbackstop', onPlaybackStopped);
events.off(player, 'volumechange', onVolumeChanged);
events.off(player, 'pause', onPlayPauseStateChanged);
events.off(player, 'unpause', onPlayPauseStateChanged);
events.off(player, 'timeupdate', onTimeUpdate);
2019-02-02 11:14:40 -05:00
currentPlayer = null;
}
}
2018-10-23 01:05:09 +03:00
2019-02-02 11:14:40 -05:00
function bindToPlayer(context, player) {
if (releaseCurrentPlayer(), currentPlayer = player, player) {
var state = playbackManager.getPlayerState(player);
onStateChanged.call(player, {
2020-05-04 12:44:12 +02:00
type: 'init'
2019-02-02 11:14:40 -05:00
}, state);
2020-05-04 12:44:12 +02:00
events.on(player, 'playbackstart', onPlaybackStart);
events.on(player, 'statechange', onStateChanged);
events.on(player, 'repeatmodechange', onRepeatModeChange);
2020-06-22 11:25:16 +02:00
events.on(player, 'shufflequeuemodechange', onShuffleQueueModeChange);
2020-05-04 12:44:12 +02:00
events.on(player, 'playlistitemremove', onPlaylistItemRemoved);
events.on(player, 'playlistitemmove', onPlaylistUpdate);
events.on(player, 'playbackstop', onPlaybackStopped);
events.on(player, 'volumechange', onVolumeChanged);
events.on(player, 'pause', onPlayPauseStateChanged);
events.on(player, 'unpause', onPlayPauseStateChanged);
events.on(player, 'timeupdate', onTimeUpdate);
2019-02-02 11:14:40 -05:00
var playerInfo = playbackManager.getPlayerInfo();
var supportedCommands = playerInfo.supportedCommands;
currentPlayerSupportedCommands = supportedCommands;
updateSupportedCommands(context, supportedCommands);
}
}
2019-02-02 11:14:40 -05:00
function onBtnCommandClick() {
if (currentPlayer) {
2020-05-04 12:44:12 +02:00
if (this.classList.contains('repeatToggleButton')) {
2020-06-23 23:41:52 +02:00
toggleRepeat();
2019-02-02 11:14:40 -05:00
} else {
playbackManager.sendCommand({
2020-05-04 12:44:12 +02:00
Name: this.getAttribute('data-command')
2019-02-02 11:14:40 -05:00
}, currentPlayer);
}
}
2018-10-23 01:05:09 +03:00
}
2019-02-02 11:14:40 -05:00
function getSaveablePlaylistItems() {
return getPlaylistItems(currentPlayer).then(function (items) {
return items.filter(function (i) {
return i.Id && i.ServerId;
});
2019-02-02 11:14:40 -05:00
});
}
2019-02-02 11:14:40 -05:00
function savePlaylist() {
2020-05-04 12:44:12 +02:00
require(['playlistEditor'], function (playlistEditor) {
2019-02-02 11:14:40 -05:00
getSaveablePlaylistItems().then(function (items) {
var serverId = items.length ? items[0].ServerId : ApiClient.serverId();
new playlistEditor().show({
items: items.map(function (i) {
return i.Id;
2019-02-02 11:14:40 -05:00
}),
serverId: serverId,
enableAddToPlayQueue: false,
2020-05-04 12:44:12 +02:00
defaultValue: 'new'
2019-02-02 11:14:40 -05:00
});
});
});
2018-10-23 01:05:09 +03:00
}
2019-02-02 11:14:40 -05:00
function bindEvents(context) {
2020-05-04 12:44:12 +02:00
var btnCommand = context.querySelectorAll('.btnCommand');
var positionSlider = context.querySelector('.nowPlayingPositionSlider');
2019-02-02 11:14:40 -05:00
for (var i = 0, length = btnCommand.length; i < length; i++) {
2020-05-04 12:44:12 +02:00
btnCommand[i].addEventListener('click', onBtnCommandClick);
2019-02-02 11:14:40 -05:00
}
2020-05-04 12:44:12 +02:00
context.querySelector('.btnToggleFullscreen').addEventListener('click', function (e) {
2019-02-02 11:14:40 -05:00
if (currentPlayer) {
playbackManager.sendCommand({
2020-05-04 12:44:12 +02:00
Name: e.target.getAttribute('data-command')
2019-02-02 11:14:40 -05:00
}, currentPlayer);
}
});
2020-05-04 12:44:12 +02:00
context.querySelector('.btnAudioTracks').addEventListener('click', function (e) {
2019-02-02 11:14:40 -05:00
if (currentPlayer && lastPlayerState && lastPlayerState.NowPlayingItem) {
showAudioMenu(context, currentPlayer, e.target, lastPlayerState.NowPlayingItem);
2019-02-02 11:14:40 -05:00
}
});
2020-05-04 12:44:12 +02:00
context.querySelector('.btnSubtitles').addEventListener('click', function (e) {
2019-02-02 11:14:40 -05:00
if (currentPlayer && lastPlayerState && lastPlayerState.NowPlayingItem) {
showSubtitleMenu(context, currentPlayer, e.target, lastPlayerState.NowPlayingItem);
2019-02-02 11:14:40 -05:00
}
});
2020-05-04 12:44:12 +02:00
context.querySelector('.btnStop').addEventListener('click', function () {
2019-02-02 11:14:40 -05:00
if (currentPlayer) {
playbackManager.stop(currentPlayer);
}
});
2020-05-04 12:44:12 +02:00
context.querySelector('.btnPlayPause').addEventListener('click', function () {
2019-02-02 11:14:40 -05:00
if (currentPlayer) {
playbackManager.playPause(currentPlayer);
}
});
2020-05-04 12:44:12 +02:00
context.querySelector('.btnNextTrack').addEventListener('click', function () {
2019-02-02 11:14:40 -05:00
if (currentPlayer) {
playbackManager.nextTrack(currentPlayer);
}
});
2020-05-04 12:44:12 +02:00
context.querySelector('.btnRewind').addEventListener('click', function () {
2019-02-02 11:14:40 -05:00
if (currentPlayer) {
playbackManager.rewind(currentPlayer);
}
});
2020-05-04 12:44:12 +02:00
context.querySelector('.btnFastForward').addEventListener('click', function () {
2019-02-02 11:14:40 -05:00
if (currentPlayer) {
playbackManager.fastForward(currentPlayer);
}
});
2020-06-23 19:09:22 +02:00
for (const shuffleButton of context.querySelectorAll('.btnShuffleQueue')) {
shuffleButton.addEventListener('click', function () {
if (currentPlayer) {
2020-06-23 19:09:22 +02:00
playbackManager.toggleQueueShuffleMode(currentPlayer);
}
});
}
2020-06-18 09:30:31 +02:00
context.querySelector('.btnPreviousTrack').addEventListener('click', function (e) {
2019-02-02 11:14:40 -05:00
if (currentPlayer) {
if (currentPlayer.id === 'htmlaudioplayer' && (currentPlayer._currentTime >= 5 || !playbackManager.previousTrack(currentPlayer))) {
2020-06-18 09:30:31 +02:00
// Cancel this event if doubleclick is fired
if (e.detail > 1 && playbackManager.previousTrack(currentPlayer)) {
2020-06-18 09:30:31 +02:00
return;
}
playbackManager.seekPercent(0, currentPlayer);
2020-06-23 19:09:22 +02:00
// This is done automatically by playbackManager. However, setting this here gives instant visual feedback.
// TODO: Check why seekPercentage doesn't reflect the changes inmmediately, so we can remove this workaround.
positionSlider.value = 0;
} else {
playbackManager.previousTrack(currentPlayer);
}
2019-02-02 11:14:40 -05:00
}
});
2020-06-18 09:30:31 +02:00
context.querySelector('.btnPreviousTrack').addEventListener('dblclick', function () {
if (currentPlayer) {
playbackManager.previousTrack(currentPlayer);
}
});
positionSlider.addEventListener('change', function () {
2019-02-02 11:14:40 -05:00
var value = this.value;
if (currentPlayer) {
var newPercent = parseFloat(value);
playbackManager.seekPercent(newPercent, currentPlayer);
}
});
positionSlider.getBubbleText = function (value) {
2019-02-02 11:14:40 -05:00
var state = lastPlayerState;
if (!state || !state.NowPlayingItem || !currentRuntimeTicks) {
2020-05-04 12:44:12 +02:00
return '--:--';
2019-02-02 11:14:40 -05:00
}
var ticks = currentRuntimeTicks;
ticks /= 100;
ticks *= value;
return datetime.getDisplayRunningTime(ticks);
};
2020-02-15 16:51:37 +03:00
function setVolume() {
playbackManager.setVolume(this.value, currentPlayer);
2020-02-15 16:51:37 +03:00
}
2020-05-04 12:44:12 +02:00
context.querySelector('.nowPlayingVolumeSlider').addEventListener('change', setVolume);
context.querySelector('.nowPlayingVolumeSlider').addEventListener('mousemove', setVolume);
context.querySelector('.nowPlayingVolumeSlider').addEventListener('touchmove', setVolume);
context.querySelector('.buttonMute').addEventListener('click', function () {
2019-02-02 11:14:40 -05:00
playbackManager.toggleMute(currentPlayer);
});
2020-05-04 12:44:12 +02:00
var playlistContainer = context.querySelector('.playlist');
playlistContainer.addEventListener('action-remove', function (e) {
playbackManager.removeFromPlaylist([e.detail.playlistItemId], currentPlayer);
2019-02-02 11:14:40 -05:00
});
2020-05-04 12:44:12 +02:00
playlistContainer.addEventListener('itemdrop', function (e) {
var newIndex = e.detail.newIndex;
var playlistItemId = e.detail.playlistItemId;
2019-02-02 11:14:40 -05:00
playbackManager.movePlaylistItem(playlistItemId, newIndex, currentPlayer);
});
2020-05-04 12:44:12 +02:00
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('.volumecontrol').classList.add('hide');
if (layoutManager.mobile) {
context.querySelector('.playlistSectionButton').classList.remove('playlistSectionButtonTransparent');
}
2020-04-09 19:15:49 -04:00
} else {
2020-05-04 12:44:12 +02:00
context.querySelector('.playlist').classList.add('hide');
context.querySelector('.btnSavePlaylist').classList.add('hide');
2020-06-23 19:09:22 +02:00
if (showMuteButton || showVolumeSlider) {
context.querySelector('.volumecontrol').classList.remove('hide');
}
if (layoutManager.mobile) {
context.querySelector('.playlistSectionButton').classList.add('playlistSectionButtonTransparent');
}
2020-04-09 19:15:49 -04:00
}
});
2019-02-02 11:14:40 -05:00
}
2019-02-02 11:14:40 -05:00
function onPlayerChange() {
bindToPlayer(dlg, playbackManager.getCurrentPlayer());
}
function onMessageSubmit(e) {
var form = e.target;
2019-02-02 11:14:40 -05:00
playbackManager.sendCommand({
2020-05-04 12:44:12 +02:00
Name: 'DisplayMessage',
2019-02-02 11:14:40 -05:00
Arguments: {
2020-05-04 12:44:12 +02:00
Header: form.querySelector('#txtMessageTitle').value,
Text: form.querySelector('#txtMessageText', form).value
2019-02-02 11:14:40 -05:00
}
}, currentPlayer);
2020-05-04 12:44:12 +02:00
form.querySelector('input').value = '';
2019-02-02 11:14:40 -05:00
2020-05-04 12:44:12 +02:00
require(['toast'], function (toast) {
toast('Message sent.');
2019-02-02 11:14:40 -05:00
});
e.preventDefault();
e.stopPropagation();
2019-02-02 11:14:40 -05:00
return false;
}
function onSendStringSubmit(e) {
var form = e.target;
2019-02-02 11:14:40 -05:00
playbackManager.sendCommand({
2020-05-04 12:44:12 +02:00
Name: 'SendString',
2019-02-02 11:14:40 -05:00
Arguments: {
2020-05-04 12:44:12 +02:00
String: form.querySelector('#txtTypeText', form).value
2019-02-02 11:14:40 -05:00
}
}, currentPlayer);
2020-05-04 12:44:12 +02:00
form.querySelector('input').value = '';
2019-02-02 11:14:40 -05:00
2020-05-04 12:44:12 +02:00
require(['toast'], function (toast) {
toast('Text sent.');
2019-02-02 11:14:40 -05:00
});
e.preventDefault();
e.stopPropagation();
2019-02-02 11:14:40 -05:00
return false;
}
2019-02-02 11:14:40 -05:00
function init(ownerView, context) {
2020-04-28 16:09:40 +03:00
let 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')}><span class="xlargePaperIconButton material-icons volume_up"></span></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>';
let optionsSection = context.querySelector('.playlistSectionButton');
if (!layoutManager.mobile) {
context.querySelector('.nowPlayingSecondaryButtons').insertAdjacentHTML('beforeend', volumecontrolHtml);
optionsSection.classList.remove('align-items-center', 'justify-content-center');
optionsSection.classList.add('align-items-right', 'justify-content-flex-end');
context.querySelector('.playlist').classList.remove('hide');
context.querySelector('.btnSavePlaylist').classList.remove('hide');
context.classList.add('padded-bottom');
} else {
optionsSection.querySelector('.btnTogglePlaylist').insertAdjacentHTML('afterend', volumecontrolHtml);
optionsSection.classList.add('playlistSectionButtonTransparent');
context.querySelector('.btnTogglePlaylist').classList.remove('hide');
context.querySelector('.playlistSectionButton').classList.remove('justify-content-center');
context.querySelector('.playlistSectionButton').classList.add('justify-content-space-between');
}
2019-02-02 11:14:40 -05:00
bindEvents(context);
2020-05-04 12:44:12 +02:00
context.querySelector('.sendMessageForm').addEventListener('submit', onMessageSubmit);
context.querySelector('.typeTextForm').addEventListener('submit', onSendStringSubmit);
events.on(playbackManager, 'playerchange', onPlayerChange);
if (layoutManager.tv) {
2020-05-04 12:44:12 +02:00
var positionSlider = context.querySelector('.nowPlayingPositionSlider');
positionSlider.classList.add('focusable');
positionSlider.enableKeyboardDragging();
}
2019-02-02 11:14:40 -05:00
}
function onDialogClosed(e) {
2019-02-02 11:14:40 -05:00
releaseCurrentPlayer();
2020-05-04 12:44:12 +02:00
events.off(playbackManager, 'playerchange', onPlayerChange);
2019-02-02 11:14:40 -05:00
lastPlayerState = null;
}
2019-02-02 11:14:40 -05:00
function onShow(context, tab) {
currentImgUrl = null;
bindToPlayer(context, playbackManager.getCurrentPlayer());
}
2019-02-02 11:14:40 -05:00
var dlg;
var currentPlayer;
var lastPlayerState;
var currentPlayerSupportedCommands = [];
var lastUpdateTime = 0;
var currentRuntimeTicks = 0;
var self = this;
self.init = function (ownerView, context) {
dlg = context;
init(ownerView, dlg);
};
self.onShow = function () {
onShow(dlg, window.location.hash);
};
self.destroy = function () {
onDialogClosed();
};
};
});