2018-10-23 01:05:09 +03:00
|
|
|
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) {
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
function getNowPlayingBarHtml() {
|
|
|
|
var html = "";
|
|
|
|
return html += '<div class="nowPlayingBar hide nowPlayingBar-hidden">', html += '<div class="nowPlayingBarTop">', html += '<div class="nowPlayingBarPositionContainer sliderContainer">', html += '<input type="range" is="emby-slider" pin step=".01" min="0" max="100" value="0" class="slider-medium-thumb nowPlayingBarPositionSlider"/>', html += "</div>", html += '<div class="nowPlayingBarInfoContainer">', html += '<div class="nowPlayingImage"></div>', html += '<div class="nowPlayingBarText"></div>', html += "</div>", html += '<div class="nowPlayingBarCenter">', html += '<button is="paper-icon-button-light" class="previousTrackButton mediaButton"><i class="md-icon"></i></button>', html += '<button is="paper-icon-button-light" class="playPauseButton mediaButton"><i class="md-icon"></i></button>', html += '<button is="paper-icon-button-light" class="stopButton mediaButton"><i class="md-icon">stop</i></button>', html += '<button is="paper-icon-button-light" class="nextTrackButton mediaButton"><i class="md-icon"></i></button>', html += '<div class="nowPlayingBarCurrentTime"></div>', html += "</div>", html += '<div class="nowPlayingBarRight">', html += '<button is="paper-icon-button-light" class="muteButton mediaButton"><i class="md-icon"></i></button>', html += '<div class="sliderContainer nowPlayingBarVolumeSliderContainer hide" style="width:100px;vertical-align:middle;display:inline-flex;">', html += '<input type="range" is="emby-slider" pin step="1" min="0" max="100" value="0" class="slider-medium-thumb nowPlayingBarVolumeSlider"/>', html += "</div>", html += '<button is="paper-icon-button-light" class="toggleRepeatButton mediaButton"><i class="md-icon"></i></button>', html += '<div class="nowPlayingBarUserDataButtons">', html += "</div>", html += '<button is="paper-icon-button-light" class="playPauseButton mediaButton"><i class="md-icon"></i></button>', html += '<button is="paper-icon-button-light" class="remoteControlButton mediaButton"><i class="md-icon"></i></button>', html += "</div>", html += "</div>", html += "</div>"
|
|
|
|
}
|
|
|
|
|
|
|
|
function onSlideDownComplete() {
|
|
|
|
this.classList.add("hide")
|
|
|
|
}
|
|
|
|
|
|
|
|
function slideDown(elem) {
|
|
|
|
elem.offsetWidth, elem.classList.add("nowPlayingBar-hidden"), dom.addEventListener(elem, dom.whichTransitionEvent(), onSlideDownComplete, {
|
|
|
|
once: !0
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function slideUp(elem) {
|
|
|
|
dom.removeEventListener(elem, dom.whichTransitionEvent(), onSlideDownComplete, {
|
|
|
|
once: !0
|
|
|
|
}), elem.classList.remove("hide"), elem.offsetWidth, elem.classList.remove("nowPlayingBar-hidden")
|
|
|
|
}
|
|
|
|
|
|
|
|
function onPlayPauseClick() {
|
|
|
|
playbackManager.playPause(currentPlayer)
|
|
|
|
}
|
|
|
|
|
|
|
|
function bindEvents(elem) {
|
|
|
|
currentTimeElement = elem.querySelector(".nowPlayingBarCurrentTime"), nowPlayingImageElement = elem.querySelector(".nowPlayingImage"), nowPlayingTextElement = elem.querySelector(".nowPlayingBarText"), nowPlayingUserData = elem.querySelector(".nowPlayingBarUserDataButtons"), muteButton = elem.querySelector(".muteButton"), muteButton.addEventListener("click", function() {
|
|
|
|
currentPlayer && playbackManager.toggleMute(currentPlayer)
|
|
|
|
}), elem.querySelector(".stopButton").addEventListener("click", function() {
|
|
|
|
currentPlayer && playbackManager.stop(currentPlayer)
|
|
|
|
});
|
|
|
|
var i, length;
|
|
|
|
for (playPauseButtons = elem.querySelectorAll(".playPauseButton"), i = 0, length = playPauseButtons.length; i < length; i++) playPauseButtons[i].addEventListener("click", onPlayPauseClick);
|
|
|
|
elem.querySelector(".nextTrackButton").addEventListener("click", function() {
|
|
|
|
currentPlayer && playbackManager.nextTrack(currentPlayer)
|
|
|
|
}), elem.querySelector(".previousTrackButton").addEventListener("click", function() {
|
|
|
|
currentPlayer && playbackManager.previousTrack(currentPlayer)
|
|
|
|
}), elem.querySelector(".remoteControlButton").addEventListener("click", showRemoteControl), toggleRepeatButton = elem.querySelector(".toggleRepeatButton"), toggleRepeatButton.addEventListener("click", function() {
|
|
|
|
if (currentPlayer) switch (playbackManager.getRepeatMode(currentPlayer)) {
|
|
|
|
case "RepeatAll":
|
|
|
|
playbackManager.setRepeatMode("RepeatOne", currentPlayer);
|
|
|
|
break;
|
|
|
|
case "RepeatOne":
|
|
|
|
playbackManager.setRepeatMode("RepeatNone", currentPlayer);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
playbackManager.setRepeatMode("RepeatAll", currentPlayer)
|
|
|
|
}
|
|
|
|
}), toggleRepeatButtonIcon = toggleRepeatButton.querySelector("i"), volumeSlider = elem.querySelector(".nowPlayingBarVolumeSlider"), volumeSliderContainer = elem.querySelector(".nowPlayingBarVolumeSliderContainer"), appHost.supports("physicalvolumecontrol") ? volumeSliderContainer.classList.add("hide") : volumeSliderContainer.classList.remove("hide"), volumeSlider.addEventListener("change", function() {
|
|
|
|
currentPlayer && currentPlayer.setVolume(this.value)
|
|
|
|
}), positionSlider = elem.querySelector(".nowPlayingBarPositionSlider"), positionSlider.addEventListener("change", function() {
|
|
|
|
if (currentPlayer) {
|
|
|
|
var newPercent = parseFloat(this.value);
|
|
|
|
playbackManager.seekPercent(newPercent, currentPlayer)
|
|
|
|
}
|
|
|
|
}), positionSlider.getBubbleText = function(value) {
|
|
|
|
var state = lastPlayerState;
|
|
|
|
if (!state || !state.NowPlayingItem || !currentRuntimeTicks) return "--:--";
|
|
|
|
var ticks = currentRuntimeTicks;
|
|
|
|
return ticks /= 100, ticks *= value, datetime.getDisplayRunningTime(ticks)
|
|
|
|
}, elem.addEventListener("click", function(e) {
|
|
|
|
dom.parentWithTag(e.target, ["BUTTON", "INPUT", "A"]) || showRemoteControl()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function showRemoteControl() {
|
|
|
|
require(["appRouter"], function(appRouter) {
|
|
|
|
appRouter.showNowPlaying()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function getNowPlayingBar() {
|
|
|
|
return nowPlayingBarElement ? Promise.resolve(nowPlayingBarElement) : new Promise(function(resolve, reject) {
|
|
|
|
require(["appFooter-shared", "itemShortcuts", "css!./nowplayingbar.css", "emby-slider"], function(appfooter, itemShortcuts) {
|
|
|
|
var parentContainer = appfooter.element;
|
|
|
|
if (nowPlayingBarElement = parentContainer.querySelector(".nowPlayingBar")) return void resolve(nowPlayingBarElement);
|
|
|
|
parentContainer.insertAdjacentHTML("afterbegin", getNowPlayingBarHtml()), nowPlayingBarElement = parentContainer.querySelector(".nowPlayingBar"), browser.safari && browser.slow && nowPlayingBarElement.classList.add("noMediaProgress"), itemShortcuts.on(nowPlayingBarElement), bindEvents(nowPlayingBarElement), resolve(nowPlayingBarElement)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function showButton(button) {
|
|
|
|
button.classList.remove("hide")
|
|
|
|
}
|
|
|
|
|
|
|
|
function hideButton(button) {
|
|
|
|
button.classList.add("hide")
|
|
|
|
}
|
|
|
|
|
|
|
|
function updatePlayPauseState(isPaused) {
|
|
|
|
var i, length;
|
|
|
|
if (playPauseButtons)
|
|
|
|
if (isPaused)
|
|
|
|
for (i = 0, length = playPauseButtons.length; i < length; i++) playPauseButtons[i].querySelector("i").innerHTML = "play_arrow";
|
|
|
|
else
|
|
|
|
for (i = 0, length = playPauseButtons.length; i < length; i++) playPauseButtons[i].querySelector("i").innerHTML = "pause"
|
|
|
|
}
|
|
|
|
|
|
|
|
function updatePlayerStateInternal(event, state, player) {
|
|
|
|
showNowPlayingBar(), lastPlayerState = state;
|
|
|
|
var playerInfo = playbackManager.getPlayerInfo(),
|
|
|
|
playState = state.PlayState || {};
|
|
|
|
updatePlayPauseState(playState.IsPaused);
|
|
|
|
var supportedCommands = playerInfo.supportedCommands;
|
|
|
|
if (currentPlayerSupportedCommands = supportedCommands, -1 === supportedCommands.indexOf("SetRepeatMode") ? toggleRepeatButton.classList.add("hide") : toggleRepeatButton.classList.remove("hide"), updateRepeatModeDisplay(playState.RepeatMode), updatePlayerVolumeState(playState.IsMuted, playState.VolumeLevel), positionSlider && !positionSlider.dragging) {
|
|
|
|
positionSlider.disabled = !playState.CanSeek;
|
|
|
|
var isProgressClear = state.MediaSource && null == state.MediaSource.RunTimeTicks;
|
|
|
|
positionSlider.setIsClear(isProgressClear)
|
|
|
|
}
|
|
|
|
updateTimeDisplay(playState.PositionTicks, (state.NowPlayingItem || {}).RunTimeTicks, playbackManager.getBufferedRanges(player)), updateNowPlayingInfo(state)
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateRepeatModeDisplay(repeatMode) {
|
|
|
|
"RepeatAll" === repeatMode ? (toggleRepeatButtonIcon.innerHTML = "repeat", toggleRepeatButton.classList.add("repeatButton-active")) : "RepeatOne" === repeatMode ? (toggleRepeatButtonIcon.innerHTML = "repeat_one", toggleRepeatButton.classList.add("repeatButton-active")) : (toggleRepeatButtonIcon.innerHTML = "repeat", toggleRepeatButton.classList.remove("repeatButton-active"))
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateTimeDisplay(positionTicks, runtimeTicks, bufferedRanges) {
|
|
|
|
if (positionSlider && !positionSlider.dragging)
|
|
|
|
if (runtimeTicks) {
|
|
|
|
var pct = positionTicks / runtimeTicks;
|
|
|
|
pct *= 100, positionSlider.value = pct
|
|
|
|
} else positionSlider.value = 0;
|
|
|
|
if (positionSlider && positionSlider.setBufferedRanges(bufferedRanges, runtimeTicks, positionTicks), currentTimeElement) {
|
|
|
|
var timeText = null == positionTicks ? "--:--" : datetime.getDisplayRunningTime(positionTicks);
|
|
|
|
runtimeTicks && (timeText += " / " + datetime.getDisplayRunningTime(runtimeTicks)), currentTimeElement.innerHTML = timeText
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function updatePlayerVolumeState(isMuted, volumeLevel) {
|
|
|
|
var supportedCommands = currentPlayerSupportedCommands,
|
|
|
|
showMuteButton = !0,
|
|
|
|
showVolumeSlider = !0; - 1 === supportedCommands.indexOf("ToggleMute") && (showMuteButton = !1), muteButton.querySelector("i").innerHTML = isMuted ? "" : "", -1 === supportedCommands.indexOf("SetVolume") && (showVolumeSlider = !1), currentPlayer.isLocalPlayer && appHost.supports("physicalvolumecontrol") && (showMuteButton = !1, showVolumeSlider = !1), showMuteButton ? showButton(muteButton) : hideButton(muteButton), volumeSlider && (showVolumeSlider ? volumeSliderContainer.classList.remove("hide") : volumeSliderContainer.classList.add("hide"), volumeSlider.dragging || (volumeSlider.value = volumeLevel || 0))
|
|
|
|
}
|
|
|
|
|
|
|
|
function getTextActionButton(item, text, serverId) {
|
|
|
|
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">';
|
|
|
|
return html += text, html += "</button>"
|
|
|
|
}
|
|
|
|
|
|
|
|
function seriesImageUrl(item, options) {
|
|
|
|
if (!item) throw new Error("item cannot be null!");
|
|
|
|
if ("Episode" !== item.Type) return null;
|
|
|
|
if (options = options || {}, options.type = options.type || "Primary", "Primary" === options.type && item.SeriesPrimaryImageTag) return options.tag = item.SeriesPrimaryImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
|
|
|
if ("Thumb" === options.type) {
|
|
|
|
if (item.SeriesThumbImageTag) return options.tag = item.SeriesThumbImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
|
|
|
if (item.ParentThumbImageTag) return options.tag = item.ParentThumbImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options)
|
|
|
|
}
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
|
|
|
function imageUrl(item, options) {
|
|
|
|
if (!item) throw new Error("item cannot be null!");
|
|
|
|
return options = options || {}, options.type = options.type || "Primary", item.ImageTags && item.ImageTags[options.type] ? (options.tag = item.ImageTags[options.type], connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options)) : item.AlbumId && item.AlbumPrimaryImageTag ? (options.tag = item.AlbumPrimaryImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options)) : null
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateNowPlayingInfo(state) {
|
|
|
|
var nowPlayingItem = state.NowPlayingItem,
|
|
|
|
textLines = nowPlayingItem ? nowPlayingHelper.getNowPlayingNames(nowPlayingItem) : [];
|
|
|
|
textLines.length > 1 && (textLines[1].secondary = !0);
|
|
|
|
var serverId = nowPlayingItem ? nowPlayingItem.ServerId : null;
|
|
|
|
nowPlayingTextElement.innerHTML = textLines.map(function(nowPlayingName) {
|
|
|
|
var cssClass = nowPlayingName.secondary ? ' class="nowPlayingBarSecondaryText"' : "";
|
|
|
|
return nowPlayingName.item ? "<div" + cssClass + ">" + getTextActionButton(nowPlayingName.item, nowPlayingName.text, serverId) + "</div>" : "<div" + cssClass + ">" + nowPlayingName.text + "</div>"
|
|
|
|
}).join("");
|
|
|
|
var url = nowPlayingItem ? seriesImageUrl(nowPlayingItem, {
|
|
|
|
height: 70
|
|
|
|
}) || imageUrl(nowPlayingItem, {
|
|
|
|
height: 70
|
|
|
|
}) : null,
|
|
|
|
isRefreshing = !1;
|
|
|
|
if (url !== currentImgUrl && (currentImgUrl = url, isRefreshing = !0, url ? imageLoader.lazyImage(nowPlayingImageElement, url) : nowPlayingImageElement.style.backgroundImage = ""), nowPlayingItem.Id) {
|
|
|
|
if (isRefreshing) {
|
|
|
|
var apiClient = connectionManager.getApiClient(nowPlayingItem.ServerId);
|
|
|
|
apiClient.getItem(apiClient.getCurrentUserId(), nowPlayingItem.Id).then(function(item) {
|
|
|
|
var userData = item.UserData || {},
|
|
|
|
likes = null == userData.Likes ? "" : userData.Likes;
|
|
|
|
nowPlayingUserData.innerHTML = '<button is="emby-ratingbutton" type="button" class="listItemButton 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="md-icon"></i></button>'
|
|
|
|
})
|
|
|
|
}
|
|
|
|
} else nowPlayingUserData.innerHTML = ""
|
|
|
|
}
|
|
|
|
|
|
|
|
function onPlaybackStart(e, state) {
|
|
|
|
var player = this;
|
|
|
|
onStateChanged.call(player, e, state)
|
|
|
|
}
|
|
|
|
|
|
|
|
function onRepeatModeChange(e) {
|
|
|
|
if (isEnabled) {
|
|
|
|
var player = this;
|
|
|
|
updateRepeatModeDisplay(playbackManager.getRepeatMode(player))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function showNowPlayingBar() {
|
|
|
|
if (!isVisibilityAllowed) return void hideNowPlayingBar();
|
|
|
|
getNowPlayingBar().then(slideUp)
|
|
|
|
}
|
|
|
|
|
|
|
|
function hideNowPlayingBar() {
|
|
|
|
isEnabled = !1;
|
|
|
|
var elem = document.getElementsByClassName("nowPlayingBar")[0];
|
|
|
|
elem && slideDown(elem)
|
|
|
|
}
|
|
|
|
|
|
|
|
function onPlaybackStopped(e, state) {
|
|
|
|
this.isLocalPlayer ? "Audio" !== state.NextMediaType && hideNowPlayingBar() : state.NextMediaType || hideNowPlayingBar()
|
|
|
|
}
|
|
|
|
|
|
|
|
function onPlayPauseStateChanged(e) {
|
|
|
|
if (isEnabled) {
|
|
|
|
updatePlayPauseState(this.paused())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function onStateChanged(event, state) {
|
|
|
|
var player = this;
|
|
|
|
return !state.NowPlayingItem || layoutManager.tv ? void hideNowPlayingBar() : player.isLocalPlayer && state.NowPlayingItem && "Video" === state.NowPlayingItem.MediaType ? void hideNowPlayingBar() : (isEnabled = !0, nowPlayingBarElement ? void updatePlayerStateInternal(event, state, player) : void getNowPlayingBar().then(function() {
|
|
|
|
updatePlayerStateInternal(event, state, player)
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
function onTimeUpdate(e) {
|
|
|
|
if (isEnabled) {
|
|
|
|
var now = (new Date).getTime();
|
|
|
|
if (!(now - lastUpdateTime < 700)) {
|
|
|
|
lastUpdateTime = now;
|
|
|
|
var player = this;
|
|
|
|
currentRuntimeTicks = playbackManager.duration(player), updateTimeDisplay(playbackManager.currentTime(player), currentRuntimeTicks, playbackManager.getBufferedRanges(player))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function releaseCurrentPlayer() {
|
|
|
|
var player = currentPlayer;
|
|
|
|
player && (events.off(player, "playbackstart", onPlaybackStart), events.off(player, "statechange", onPlaybackStart), events.off(player, "repeatmodechange", onRepeatModeChange), 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), currentPlayer = null, hideNowPlayingBar())
|
|
|
|
}
|
|
|
|
|
|
|
|
function onVolumeChanged(e) {
|
|
|
|
if (isEnabled) {
|
|
|
|
var player = this;
|
|
|
|
updatePlayerVolumeState(player.isMuted(), player.getVolume())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function refreshFromPlayer(player) {
|
|
|
|
var state = playbackManager.getPlayerState(player);
|
|
|
|
onStateChanged.call(player, {
|
|
|
|
type: "init"
|
|
|
|
}, state)
|
|
|
|
}
|
|
|
|
|
|
|
|
function bindToPlayer(player) {
|
|
|
|
player !== currentPlayer && (releaseCurrentPlayer(), currentPlayer = player, player && (refreshFromPlayer(player), events.on(player, "playbackstart", onPlaybackStart), events.on(player, "statechange", onPlaybackStart), events.on(player, "repeatmodechange", onRepeatModeChange), 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)))
|
|
|
|
}
|
|
|
|
var currentPlayer, currentTimeElement, nowPlayingImageElement, nowPlayingTextElement, nowPlayingUserData, muteButton, volumeSlider, volumeSliderContainer, playPauseButtons, positionSlider, toggleRepeatButton, toggleRepeatButtonIcon, isEnabled, nowPlayingBarElement, currentImgUrl, currentPlayerSupportedCommands = [],
|
|
|
|
lastUpdateTime = 0,
|
|
|
|
lastPlayerState = {},
|
|
|
|
currentRuntimeTicks = 0,
|
|
|
|
isVisibilityAllowed = !0;
|
|
|
|
events.on(playbackManager, "playerchange", function() {
|
|
|
|
bindToPlayer(playbackManager.getCurrentPlayer())
|
|
|
|
}), bindToPlayer(playbackManager.getCurrentPlayer()), document.addEventListener("viewbeforeshow", function(e) {
|
|
|
|
e.detail.options.enableMediaControl ? isVisibilityAllowed || (isVisibilityAllowed = !0, currentPlayer ? refreshFromPlayer(currentPlayer) : hideNowPlayingBar()) : isVisibilityAllowed && (isVisibilityAllowed = !1, hideNowPlayingBar())
|
|
|
|
})
|
|
|
|
});
|