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

First separation commit.

Added LICENSE, README.md, CONTRIBUTORS.md
This commit is contained in:
Erwin de Haan 2019-01-09 12:36:54 +01:00
parent 09513af31b
commit 4678528d00
657 changed files with 422 additions and 0 deletions

View file

@ -0,0 +1,28 @@
define([], function() {
"use strict";
function supportsHtmlMediaAutoplay() {
return new Promise(function(resolve, reject) {
var timeout, elem = document.createElement("video"),
elemStyle = elem.style;
if (!("autoplay" in elem)) return void reject();
elemStyle.position = "absolute", elemStyle.height = 0, elemStyle.width = 0, elem.setAttribute("autoplay", "autoplay"), elem.style.display = "none", document.body.appendChild(elem);
var testAutoplay = function(arg) {
clearTimeout(timeout), elem.removeEventListener("playing", testAutoplay), elem.removeEventListener("play", testAutoplay);
var supported = arg && "playing" === arg.type || arg && "play" === arg.type || 0 !== elem.currentTime;
elem.parentNode.removeChild(elem), supported ? resolve() : reject()
};
elem.addEventListener("play", testAutoplay), elem.addEventListener("playing", testAutoplay);
try {
elem.src = "data:video/mp4;base64,AAAAHGZ0eXBtcDQyAAAAAG1wNDJpc29tYXZjMQAAAz5tb292AAAAbG12aGQAAAAAzaNacc2jWnEAAV+QAAFfkAABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAGGlvZHMAAAAAEICAgAcAT////3//AAACQ3RyYWsAAABcdGtoZAAAAAHNo1pxzaNacQAAAAEAAAAAAAFfkAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAEAAAABAAAAAAAd9tZGlhAAAAIG1kaGQAAAAAzaNacc2jWnEAAV+QAAFfkFXEAAAAAAAhaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAAAAAAGWbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAABVnN0YmwAAACpc3RzZAAAAAAAAAABAAAAmWF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAEAAQAEgAAABIAAAAAAAAAAEOSlZUL0FWQyBDb2RpbmcAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAxYXZjQwH0AAr/4QAZZ/QACq609NQYBBkAAAMAAQAAAwAKjxImoAEABWjOAa8gAAAAEmNvbHJuY2xjAAYAAQAGAAAAGHN0dHMAAAAAAAAAAQAAAAUAAEZQAAAAKHN0c3oAAAAAAAAAAAAAAAUAAAIqAAAACAAAAAgAAAAIAAAACAAAAChzdHNjAAAAAAAAAAIAAAABAAAABAAAAAEAAAACAAAAAQAAAAEAAAAYc3RjbwAAAAAAAAACAAADYgAABaQAAAAUc3RzcwAAAAAAAAABAAAAAQAAABFzZHRwAAAAAAREREREAAAAb3VkdGEAAABnbWV0YQAAAAAAAAAhaGRscgAAAAAAAAAAbWRpcgAAAAAAAAAAAAAAAAAAAAA6aWxzdAAAADKpdG9vAAAAKmRhdGEAAAABAAAAAEhhbmRCcmFrZSAwLjkuOCAyMDEyMDcxODAwAAACUm1kYXQAAAHkBgX/4NxF6b3m2Ui3lizYINkj7u94MjY0IC0gY29yZSAxMjAgLSBILjI2NC9NUEVHLTQgQVZDIGNvZGVjIC0gQ29weWxlZnQgMjAwMy0yMDExIC0gaHR0cDovL3d3dy52aWRlb2xhbi5vcmcveDI2NC5odG1sIC0gb3B0aW9uczogY2FiYWM9MCByZWY9MSBkZWJsb2NrPTE6MDowIGFuYWx5c2U9MHgxOjAgbWU9ZXNhIHN1Ym1lPTkgcHN5PTAgbWl4ZWRfcmVmPTAgbWVfcmFuZ2U9NCBjaHJvbWFfbWU9MSB0cmVsbGlzPTAgOHg4ZGN0PTAgY3FtPTAgZGVhZHpvbmU9MjEsMTEgZmFzdF9wc2tpcD0wIGNocm9tYV9xcF9vZmZzZXQ9MCB0aHJlYWRzPTYgc2xpY2VkX3RocmVhZHM9MCBucj0wIGRlY2ltYXRlPTEgaW50ZXJsYWNlZD0wIGJsdXJheV9jb21wYXQ9MCBjb25zdHJhaW5lZF9pbnRyYT0wIGJmcmFtZXM9MCB3ZWlnaHRwPTAga2V5aW50PTUwIGtleWludF9taW49NSBzY2VuZWN1dD00MCBpbnRyYV9yZWZyZXNoPTAgcmM9Y3FwIG1idHJlZT0wIHFwPTAAgAAAAD5liISscR8A+E4ACAACFoAAITAAAgsAAPgYCoKgoC+L4vi+KAvi+L4YfAEAACMzgABF9AAEUGUgABDJiXnf4AAAAARBmiKUAAAABEGaQpQAAAAEQZpilAAAAARBmoKU";
var promise = elem.play();
promise && promise.catch && promise.catch(reject), timeout = setTimeout(testAutoplay, 500)
} catch (e) {
return void reject()
}
})
}
return {
supportsHtmlMediaAutoplay: supportsHtmlMediaAutoplay
}
});

View file

@ -0,0 +1,63 @@
define(["events", "playbackManager", "dom", "browser", "css!./iconosd", "material-icons"], function(events, playbackManager, dom, browser) {
"use strict";
function getOsdElementHtml() {
var html = "";
return html += '<i class="md-icon iconOsdIcon">&#xE1AC;</i>', html += '<div class="iconOsdProgressOuter"><div class="iconOsdProgressInner brightnessOsdProgressInner"></div></div>'
}
function ensureOsdElement() {
var elem = osdElement;
elem || (enableAnimation = browser.supportsCssAnimation(), elem = document.createElement("div"), elem.classList.add("hide"), elem.classList.add("iconOsd"), elem.classList.add("iconOsd-hidden"), elem.classList.add("brightnessOsd"), elem.innerHTML = getOsdElementHtml(), iconElement = elem.querySelector("i"), progressElement = elem.querySelector(".iconOsdProgressInner"), document.body.appendChild(elem), osdElement = elem)
}
function onHideComplete() {
this.classList.add("hide")
}
function showOsd() {
clearHideTimeout();
var elem = osdElement;
dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
once: !0
}), elem.classList.remove("hide"), elem.offsetWidth, requestAnimationFrame(function() {
elem.classList.remove("iconOsd-hidden"), hideTimeout = setTimeout(hideOsd, 3e3)
})
}
function clearHideTimeout() {
hideTimeout && (clearTimeout(hideTimeout), hideTimeout = null)
}
function hideOsd() {
clearHideTimeout();
var elem = osdElement;
elem && (enableAnimation ? (elem.offsetWidth, requestAnimationFrame(function() {
elem.classList.add("iconOsd-hidden"), dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
once: !0
})
})) : onHideComplete.call(elem))
}
function updateElementsFromPlayer(brightness) {
iconElement && (iconElement.innerHTML = brightness >= 80 ? "&#xE1AC;" : brightness >= 20 ? "&#xE1AE;" : "&#xE1AD;"), progressElement && (progressElement.style.width = (brightness || 0) + "%")
}
function releaseCurrentPlayer() {
var player = currentPlayer;
player && (events.off(player, "brightnesschange", onBrightnessChanged), events.off(player, "playbackstop", hideOsd), currentPlayer = null)
}
function onBrightnessChanged(e) {
var player = this;
ensureOsdElement(), updateElementsFromPlayer(playbackManager.getBrightness(player)), showOsd()
}
function bindToPlayer(player) {
player !== currentPlayer && (releaseCurrentPlayer(), currentPlayer = player, player && (hideOsd(), events.on(player, "brightnesschange", onBrightnessChanged), events.on(player, "playbackstop", hideOsd)))
}
var currentPlayer, osdElement, iconElement, progressElement, enableAnimation, hideTimeout;
events.on(playbackManager, "playerchange", function() {
bindToPlayer(playbackManager.getCurrentPlayer())
}), bindToPlayer(playbackManager.getCurrentPlayer())
});

View file

@ -0,0 +1,41 @@
define(["connectionManager", "globalize", "userSettings", "apphost"], function(connectionManager, globalize, userSettings, appHost) {
"use strict";
function getWeek(date) {
var d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())),
dayNum = d.getUTCDay() || 7;
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
var yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
return Math.ceil(((d - yearStart) / 864e5 + 1) / 7)
}
function showMessage(text, userSettingsKey, appHostFeature) {
if (appHost.supports(appHostFeature)) return Promise.resolve();
var now = new Date;
return userSettingsKey += now.getFullYear() + "-w" + getWeek(now), "1" === userSettings.get(userSettingsKey, !1) ? Promise.resolve() : new Promise(function(resolve, reject) {
userSettings.set(userSettingsKey, "1", !1), require(["alert"], function(alert) {
return alert(text).then(resolve, resolve)
})
})
}
function showBlurayMessage() {
return showMessage("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.", "blurayexpirementalinfo", "nativeblurayplayback")
}
function showDvdMessage() {
return showMessage("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.", "dvdexpirementalinfo", "nativedvdplayback")
}
function showIsoMessage() {
return showMessage("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.", "isoexpirementalinfo", "nativeisoplayback")
}
function ExpirementalPlaybackWarnings() {
this.name = "Experimental playback warnings", this.type = "preplayintercept", this.id = "expirementalplaybackwarnings"
}
return ExpirementalPlaybackWarnings.prototype.intercept = function(options) {
var item = options.item;
return item ? "Iso" === item.VideoType ? showIsoMessage() : "BluRay" === item.VideoType ? showBlurayMessage() : "Dvd" === item.VideoType ? showDvdMessage() : Promise.resolve() : Promise.resolve()
}, ExpirementalPlaybackWarnings
});

View file

@ -0,0 +1,45 @@
.iconOsd {
position: fixed;
top: 7%;
right: 3%;
z-index: 100000;
background: #222;
background: rgba(0, 0, 0, .8);
padding: 1em;
color: #fff;
backdrop-filter: blur(5px);
-webkit-border-radius: .25em;
border-radius: .25em;
-webkit-transition: opacity .2s ease-out;
-o-transition: opacity .2s ease-out;
transition: opacity .2s ease-out
}
.iconOsd-hidden {
opacity: 0
}
.iconOsdIcon {
font-size: 320%;
display: block;
margin: .25em .7em
}
.iconOsdProgressOuter {
margin: 1.5em .25em 1em;
height: .35em;
background: #222;
-webkit-border-radius: .25em;
border-radius: .25em
}
.iconOsdProgressInner {
background: #00a4dc;
height: 100%;
-webkit-border-radius: .25em;
border-radius: .25em
}
.brightnessOsdProgressInner {
background: #FF9800
}

View file

@ -0,0 +1,117 @@
define(["playbackManager", "nowPlayingHelper", "events", "connectionManager"], function(playbackManager, nowPlayingHelper, events, connectionManager) {
"use strict";
function seriesImageUrl(item, options) {
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) {
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.Id, options)) : item.AlbumId && item.AlbumPrimaryImageTag ? (options.tag = item.AlbumPrimaryImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options)) : null
}
function pushImageUrl(item, height, list) {
var imageOptions = {
height: height
},
url = seriesImageUrl(item, imageOptions) || imageUrl(item, imageOptions);
url && list.push({
src: url,
sizes: height + "x" + height
})
}
function getImageUrls(item) {
var list = [];
return pushImageUrl(item, 96, list), pushImageUrl(item, 128, list), pushImageUrl(item, 192, list), pushImageUrl(item, 256, list), pushImageUrl(item, 384, list), pushImageUrl(item, 512, list), list
}
function updatePlayerState(player, state, eventName) {
var item = state.NowPlayingItem;
if (!item) return void hideMediaControls();
var playState = state.PlayState || {},
parts = nowPlayingHelper.getNowPlayingNames(item),
artist = 1 === parts.length ? "" : parts[0].text,
title = parts[parts.length - 1].text;
if ("Video" === item.MediaType && parts.length > 1) {
var temp = artist;
artist = title, title = temp
}
var albumArtist;
item.AlbumArtists && item.AlbumArtists[0] && (albumArtist = item.AlbumArtists[0].Name);
var album = item.Album || "",
itemId = item.Id,
duration = parseInt(item.RunTimeTicks ? item.RunTimeTicks / 1e4 : 0),
currentTime = parseInt(playState.PositionTicks ? playState.PositionTicks / 1e4 : 0),
isPaused = playState.IsPaused || !1;
navigator.mediaSession.metadata = new MediaMetadata({
title: title,
artist: artist,
album: album,
artwork: getImageUrls(item),
albumArtist: albumArtist,
currentTime: currentTime,
duration: duration,
paused: isPaused,
itemId: itemId,
mediaType: item.MediaType
})
}
function onGeneralEvent(e) {
var player = this;
updatePlayerState(player, playbackManager.getPlayerState(player), e.type)
}
function onStateChanged(e, state) {
updatePlayerState(this, state, "statechange")
}
function onPlaybackStart(e, state) {
updatePlayerState(this, state, e.type)
}
function onPlaybackStopped(e, state) {
hideMediaControls()
}
function releaseCurrentPlayer() {
currentPlayer && (events.off(currentPlayer, "playbackstart", onPlaybackStart), events.off(currentPlayer, "playbackstop", onPlaybackStopped), events.off(currentPlayer, "unpause", onGeneralEvent), events.off(currentPlayer, "pause", onGeneralEvent), events.off(currentPlayer, "statechange", onStateChanged), events.off(currentPlayer, "timeupdate", onGeneralEvent), currentPlayer = null, hideMediaControls())
}
function hideMediaControls() {
navigator.mediaSession.metadata = null
}
function bindToPlayer(player) {
if (releaseCurrentPlayer(), player) {
currentPlayer = player;
updatePlayerState(player, playbackManager.getPlayerState(player), "init"), events.on(currentPlayer, "playbackstart", onPlaybackStart), events.on(currentPlayer, "playbackstop", onPlaybackStopped), events.on(currentPlayer, "unpause", onGeneralEvent), events.on(currentPlayer, "pause", onGeneralEvent), events.on(currentPlayer, "statechange", onStateChanged), events.on(currentPlayer, "timeupdate", onGeneralEvent)
}
}
function execute(name) {
playbackManager[name](currentPlayer)
}
var currentPlayer;
navigator.mediaSession.setActionHandler("previoustrack", function() {
execute("previousTrack")
}), navigator.mediaSession.setActionHandler("nexttrack", function() {
execute("nextTrack")
}), navigator.mediaSession.setActionHandler("play", function() {
execute("unpause")
}), navigator.mediaSession.setActionHandler("pause", function() {
execute("pause")
}), navigator.mediaSession.setActionHandler("seekbackward", function() {
execute("rewind")
}), navigator.mediaSession.setActionHandler("seekforward", function() {
execute("fastForward")
}), events.on(playbackManager, "playerchange", function() {
bindToPlayer(playbackManager.getCurrentPlayer())
}), bindToPlayer(playbackManager.getCurrentPlayer())
});

View file

@ -0,0 +1,40 @@
define([], function() {
"use strict";
function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
var topItem = nowPlayingItem,
bottomItem = null,
topText = nowPlayingItem.Name;
nowPlayingItem.AlbumId && "Audio" === nowPlayingItem.MediaType && (topItem = {
Id: nowPlayingItem.AlbumId,
Name: nowPlayingItem.Album,
Type: "MusicAlbum",
IsFolder: !0
}), "Video" === nowPlayingItem.MediaType && (null != nowPlayingItem.IndexNumber && (topText = nowPlayingItem.IndexNumber + " - " + topText), null != nowPlayingItem.ParentIndexNumber && (topText = nowPlayingItem.ParentIndexNumber + "." + topText));
var bottomText = "";
nowPlayingItem.ArtistItems && nowPlayingItem.ArtistItems.length ? (bottomItem = {
Id: nowPlayingItem.ArtistItems[0].Id,
Name: nowPlayingItem.ArtistItems[0].Name,
Type: "MusicArtist",
IsFolder: !0
}, bottomText = nowPlayingItem.ArtistItems.map(function(a) {
return a.Name
}).join(", ")) : nowPlayingItem.Artists && nowPlayingItem.Artists.length ? bottomText = nowPlayingItem.Artists.join(", ") : nowPlayingItem.SeriesName || nowPlayingItem.Album ? (bottomText = topText, topText = nowPlayingItem.SeriesName || nowPlayingItem.Album, bottomItem = topItem, topItem = nowPlayingItem.SeriesId ? {
Id: nowPlayingItem.SeriesId,
Name: nowPlayingItem.SeriesName,
Type: "Series",
IsFolder: !0
} : null) : nowPlayingItem.ProductionYear && !1 !== includeNonNameInfo && (bottomText = nowPlayingItem.ProductionYear);
var list = [];
return list.push({
text: topText,
item: topItem
}), bottomText && list.push({
text: bottomText,
item: bottomItem
}), list
}
return {
getNowPlayingNames: getNowPlayingNames
}
});

View file

@ -0,0 +1,29 @@
define(["connectionManager", "globalize"], function(connectionManager, globalize) {
"use strict";
function getRequirePromise(deps) {
return new Promise(function(resolve, reject) {
require(deps, resolve)
})
}
function showErrorMessage() {
return getRequirePromise(["alert"]).then(function(alert) {
return alert(globalize.translate("sharedcomponents#MessagePlayAccessRestricted")).then(function() {
return Promise.reject()
})
})
}
function PlayAccessValidation() {
this.name = "Playback validation", this.type = "preplayintercept", this.id = "playaccessvalidation", this.order = -2
}
return PlayAccessValidation.prototype.intercept = function(options) {
var item = options.item;
if (!item) return Promise.resolve();
var serverId = item.ServerId;
return serverId ? connectionManager.getApiClient(serverId).getCurrentUser().then(function(user) {
return user.Policy.EnableMediaPlayback ? Promise.resolve() : options.fullscreen ? showErrorMessage() : Promise.reject()
}) : Promise.resolve()
}, PlayAccessValidation
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,35 @@
define(["playbackManager", "layoutManager", "events"], function(playbackManager, layoutManager, events) {
"use strict";
function onOrientationChangeSuccess() {
orientationLocked = !0
}
function onOrientationChangeError(err) {
orientationLocked = !1, console.log("error locking orientation: " + err)
}
var orientationLocked;
events.on(playbackManager, "playbackstart", function(e, player, state) {
if (player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player) && layoutManager.mobile) {
var lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation || screen.orientation && screen.orientation.lock;
if (lockOrientation) try {
var promise = lockOrientation("landscape");
promise.then ? promise.then(onOrientationChangeSuccess, onOrientationChangeError) : orientationLocked = promise
} catch (err) {
onOrientationChangeError(err)
}
}
}), events.on(playbackManager, "playbackstop", function(e, playbackStopInfo) {
if (orientationLocked && !playbackStopInfo.nextMediaType) {
var unlockOrientation = screen.unlockOrientation || screen.mozUnlockOrientation || screen.msUnlockOrientation || screen.orientation && screen.orientation.unlock;
if (unlockOrientation) {
try {
unlockOrientation()
} catch (err) {
console.log("error unlocking orientation: " + err)
}
orientationLocked = !1
}
}
})
});

View file

@ -0,0 +1,43 @@
define(["playbackManager", "itemHelper"], function(playbackManager, itemHelper) {
"use strict";
function getRequirePromise(deps) {
return new Promise(function(resolve, reject) {
require(deps, resolve)
})
}
function validatePlayback(options) {
var feature = "playback";
if (!options.item || "TvChannel" !== options.item.Type && "Recording" !== options.item.Type || (feature = "livetv"), "playback" === feature) {
var player = playbackManager.getCurrentPlayer();
if (player && !player.isLocalPlayer) return Promise.resolve()
}
return getRequirePromise(["registrationServices"]).then(function(registrationServices) {
return registrationServices.validateFeature(feature, options).then(function(result) {
result && result.enableTimeLimit && startAutoStopTimer()
})
})
}
function startAutoStopTimer() {
stopAutoStopTimer(), autoStopTimeout = setTimeout(onAutoStopTimeout, 63e3)
}
function onAutoStopTimeout() {
stopAutoStopTimer(), playbackManager.stop()
}
function stopAutoStopTimer() {
var timeout = autoStopTimeout;
timeout && (clearTimeout(timeout), autoStopTimeout = null)
}
function PlaybackValidation() {
this.name = "Playback validation", this.type = "preplayintercept", this.id = "playbackvalidation", this.order = -1
}
var autoStopTimeout;
return PlaybackValidation.prototype.intercept = function(options) {
return options.fullscreen ? options.item && itemHelper.isLocalItem(options.item) ? Promise.resolve() : validatePlayback(options) : Promise.resolve()
}, PlaybackValidation
});

View file

@ -0,0 +1,158 @@
define(["appSettings", "events", "browser", "loading", "playbackManager", "appRouter", "globalize", "apphost"], function(appSettings, events, browser, loading, playbackManager, appRouter, globalize, appHost) {
"use strict";
function mirrorItem(info, player) {
var item = info.item;
playbackManager.displayContent({
ItemName: item.Name,
ItemId: item.Id,
ItemType: item.Type,
Context: info.context
}, player)
}
function mirrorIfEnabled(info) {
if (info && playbackManager.enableDisplayMirroring()) {
var getPlayerInfo = playbackManager.getPlayerInfo();
getPlayerInfo && (getPlayerInfo.isLocalPlayer || -1 === getPlayerInfo.supportedCommands.indexOf("DisplayContent") || mirrorItem(info, playbackManager.getCurrentPlayer()))
}
}
function emptyCallback() {}
function getTargetSecondaryText(target) {
return target.user ? target.user.Name : null
}
function getIcon(target) {
var deviceType = target.deviceType;
switch (!deviceType && target.isLocalPlayer && (deviceType = browser.tv ? "tv" : browser.mobile ? "smartphone" : "desktop"), deviceType || (deviceType = "tv"), deviceType) {
case "smartphone":
return "&#xE32C;";
case "tablet":
return "&#xE32F;";
case "tv":
return "&#xE333;";
case "cast":
return "&#xE307;";
case "desktop":
return "&#xE30A;";
default:
return "&#xE333;"
}
}
function showPlayerSelection(button) {
var currentPlayerInfo = playbackManager.getPlayerInfo();
if (currentPlayerInfo && !currentPlayerInfo.isLocalPlayer) return void showActivePlayerMenu(currentPlayerInfo);
var currentPlayerId = currentPlayerInfo ? currentPlayerInfo.id : null;
loading.show(), playbackManager.getTargets().then(function(targets) {
var menuItems = targets.map(function(t) {
var name = t.name;
return t.appName && t.appName !== t.name && (name += " - " + t.appName), {
name: name,
id: t.id,
selected: currentPlayerId === t.id,
secondaryText: getTargetSecondaryText(t),
icon: getIcon(t)
}
});
require(["actionsheet"], function(actionsheet) {
loading.hide();
var menuOptions = {
title: globalize.translate("sharedcomponents#HeaderPlayOn"),
items: menuItems,
positionTo: button,
resolveOnClick: !0,
border: !0
};
browser.chrome && !appHost.supports("castmenuhashchange") && (menuOptions.enableHistory = !1), actionsheet.show(menuOptions).then(function(id) {
var target = targets.filter(function(t) {
return t.id === id
})[0];
playbackManager.trySetActivePlayer(target.playerName, target), mirrorIfEnabled()
}, emptyCallback)
})
})
}
function showActivePlayerMenu(playerInfo) {
require(["dialogHelper", "dialog", "emby-checkbox", "emby-button"], function(dialogHelper) {
showActivePlayerMenuInternal(dialogHelper, playerInfo)
})
}
function disconnectFromPlayer(currentDeviceName) {
-1 !== playbackManager.getSupportedCommands().indexOf("EndSession") ? require(["dialog"], function(dialog) {
var menuItems = [];
menuItems.push({
name: globalize.translate("sharedcomponents#Yes"),
id: "yes"
}), menuItems.push({
name: globalize.translate("sharedcomponents#No"),
id: "no"
}), dialog({
buttons: menuItems,
text: globalize.translate("sharedcomponents#ConfirmEndPlayerSession", currentDeviceName)
}).then(function(id) {
switch (id) {
case "yes":
playbackManager.getCurrentPlayer().endSession(), playbackManager.setDefaultPlayerActive();
break;
case "no":
playbackManager.setDefaultPlayerActive()
}
})
}) : playbackManager.setDefaultPlayerActive()
}
function showActivePlayerMenuInternal(dialogHelper, playerInfo) {
var html = "",
dialogOptions = {
removeOnClose: !0
};
dialogOptions.modal = !1, dialogOptions.entryAnimationDuration = 160, dialogOptions.exitAnimationDuration = 160, dialogOptions.autoFocus = !1;
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add("promptDialog");
var currentDeviceName = playerInfo.deviceName || playerInfo.name;
if (html += '<div class="promptDialogContent" style="padding:1.5em;">', html += '<h2 style="margin-top:.5em;">', html += currentDeviceName, html += "</h2>", html += "<div>", -1 !== playerInfo.supportedCommands.indexOf("DisplayContent")) {
html += '<label class="checkboxContainer">';
html += '<input type="checkbox" is="emby-checkbox" class="chkMirror"' + (playbackManager.enableDisplayMirroring() ? " checked" : "") + "/>", html += "<span>" + globalize.translate("sharedcomponents#EnableDisplayMirroring") + "</span>", html += "</label>"
}
html += "</div>", html += '<div style="margin-top:1em;display:flex;justify-content: flex-end;">', html += '<button is="emby-button" type="button" class="button-flat btnRemoteControl promptDialogButton">' + globalize.translate("sharedcomponents#HeaderRemoteControl") + "</button>", html += '<button is="emby-button" type="button" class="button-flat btnDisconnect promptDialogButton ">' + globalize.translate("sharedcomponents#Disconnect") + "</button>", html += '<button is="emby-button" type="button" class="button-flat btnCancel promptDialogButton">' + globalize.translate("sharedcomponents#ButtonCancel") + "</button>", html += "</div>", html += "</div>", dlg.innerHTML = html;
var chkMirror = dlg.querySelector(".chkMirror");
chkMirror && chkMirror.addEventListener("change", onMirrorChange);
var destination = "",
btnRemoteControl = dlg.querySelector(".btnRemoteControl");
btnRemoteControl && btnRemoteControl.addEventListener("click", function() {
destination = "nowplaying", dialogHelper.close(dlg)
}), dlg.querySelector(".btnDisconnect").addEventListener("click", function() {
destination = "disconnectFromPlayer", dialogHelper.close(dlg)
}), dlg.querySelector(".btnCancel").addEventListener("click", function() {
dialogHelper.close(dlg)
}), dialogHelper.open(dlg).then(function() {
"nowplaying" === destination ? appRouter.showNowPlaying() : "disconnectFromPlayer" === destination && disconnectFromPlayer(currentDeviceName)
}, emptyCallback)
}
function onMirrorChange() {
playbackManager.enableDisplayMirroring(this.checked)
}
return document.addEventListener("viewshow", function(e) {
var state = e.detail.state || {},
item = state.item;
if (item && item.ServerId) return void mirrorIfEnabled({
item: item
})
}), events.on(appSettings, "change", function(e, name) {
"displaymirror" === name && mirrorIfEnabled()
}), events.on(playbackManager, "pairing", function(e) {
loading.show()
}), events.on(playbackManager, "paired", function(e) {
loading.hide()
}), events.on(playbackManager, "pairerror", function(e) {
loading.hide()
}), {
show: showPlayerSelection
}
});

View file

@ -0,0 +1,195 @@
define(["connectionManager", "actionsheet", "datetime", "playbackManager", "globalize", "appSettings", "qualityoptions"], function(connectionManager, actionsheet, datetime, playbackManager, globalize, appSettings, qualityoptions) {
"use strict";
function showQualityMenu(player, btn) {
var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function(stream) {
return "Video" === stream.Type
})[0],
videoWidth = videoStream ? videoStream.Width : null,
options = qualityoptions.getVideoQualityOptions({
currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player),
isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player),
videoWidth: videoWidth,
enableAuto: !0
}),
menuItems = options.map(function(o) {
var opt = {
name: o.name,
id: o.bitrate,
asideText: o.secondaryText
};
return o.selected && (opt.selected = !0), opt
}),
selectedId = options.filter(function(o) {
return o.selected
});
return selectedId = selectedId.length ? selectedId[0].bitrate : null, actionsheet.show({
items: menuItems,
positionTo: btn
}).then(function(id) {
var bitrate = parseInt(id);
bitrate !== selectedId && playbackManager.setMaxStreamingBitrate({
enableAutomaticBitrateDetection: !bitrate,
maxBitrate: bitrate
}, player)
})
}
function showRepeatModeMenu(player, btn) {
var menuItems = [],
currentValue = playbackManager.getRepeatMode(player);
return menuItems.push({
name: globalize.translate("sharedcomponents#RepeatAll"),
id: "RepeatAll",
selected: "RepeatAll" === currentValue
}), menuItems.push({
name: globalize.translate("sharedcomponents#RepeatOne"),
id: "RepeatOne",
selected: "RepeatOne" === currentValue
}), menuItems.push({
name: globalize.translate("sharedcomponents#None"),
id: "RepeatNone",
selected: "RepeatNone" === currentValue
}), actionsheet.show({
items: menuItems,
positionTo: btn
}).then(function(mode) {
mode && playbackManager.setRepeatMode(mode, player)
})
}
function getQualitySecondaryText(player) {
var state = playbackManager.getPlayerState(player),
videoStream = (playbackManager.enableAutomaticBitrateDetection(player), playbackManager.getMaxStreamingBitrate(player), playbackManager.currentMediaSource(player).MediaStreams.filter(function(stream) {
return "Video" === stream.Type
})[0]),
videoWidth = videoStream ? videoStream.Width : null,
options = qualityoptions.getVideoQualityOptions({
currentMaxBitrate: playbackManager.getMaxStreamingBitrate(player),
isAutomaticBitrateEnabled: playbackManager.enableAutomaticBitrateDetection(player),
videoWidth: videoWidth,
enableAuto: !0
}),
selectedOption = (options.map(function(o) {
var opt = {
name: o.name,
id: o.bitrate,
asideText: o.secondaryText
};
return o.selected && (opt.selected = !0), opt
}), options.filter(function(o) {
return o.selected
}));
if (!selectedOption.length) return null;
selectedOption = selectedOption[0];
var text = selectedOption.name;
return selectedOption.autoText && (state.PlayState && "Transcode" !== state.PlayState.PlayMethod ? text += " - Direct" : text += " " + selectedOption.autoText), text
}
function showAspectRatioMenu(player, btn) {
var currentId = playbackManager.getAspectRatio(player),
menuItems = playbackManager.getSupportedAspectRatios(player).map(function(i) {
return {
id: i.id,
name: i.name,
selected: i.id === currentId
}
});
return actionsheet.show({
items: menuItems,
positionTo: btn
}).then(function(id) {
return id ? (playbackManager.setAspectRatio(id, player), Promise.resolve()) : Promise.reject()
})
}
function showWithUser(options, player, user) {
var supportedCommands = playbackManager.getSupportedCommands(player),
menuItems = (options.mediaType, []);
if (-1 !== supportedCommands.indexOf("SetAspectRatio")) {
var currentAspectRatioId = playbackManager.getAspectRatio(player),
currentAspectRatio = playbackManager.getSupportedAspectRatios(player).filter(function(i) {
return i.id === currentAspectRatioId
})[0];
menuItems.push({
name: globalize.translate("sharedcomponents#AspectRatio"),
id: "aspectratio",
asideText: currentAspectRatio ? currentAspectRatio.name : null
})
}
if (menuItems.push({
name: globalize.translate("sharedcomponents#PlaybackSettings"),
id: "playbacksettings"
}), user && user.Policy.EnableVideoPlaybackTranscoding) {
var secondaryQualityText = getQualitySecondaryText(player);
menuItems.push({
name: globalize.translate("sharedcomponents#Quality"),
id: "quality",
asideText: secondaryQualityText
})
}
var repeatMode = playbackManager.getRepeatMode(player);
return -1 !== supportedCommands.indexOf("SetRepeatMode") && playbackManager.currentMediaSource(player).RunTimeTicks && menuItems.push({
name: globalize.translate("sharedcomponents#RepeatMode"),
id: "repeatmode",
asideText: "RepeatNone" === repeatMode ? globalize.translate("sharedcomponents#None") : globalize.translate("sharedcomponents#" + repeatMode)
}), options.stats && menuItems.push({
name: globalize.translate("sharedcomponents#StatsForNerds"),
id: "stats",
asideText: null
}), menuItems.push({
name: globalize.translate("sharedcomponents#SubtitleSettings"),
id: "subtitlesettings"
}), actionsheet.show({
items: menuItems,
positionTo: options.positionTo
}).then(function(id) {
return handleSelectedOption(id, options, player)
})
}
function show(options) {
var player = options.player,
currentItem = playbackManager.currentItem(player);
return currentItem && currentItem.ServerId ? connectionManager.getApiClient(currentItem.ServerId).getCurrentUser().then(function(user) {
return showWithUser(options, player, user)
}) : showWithUser(options, player, null)
}
function alertText(text) {
return new Promise(function(resolve, reject) {
require(["alert"], function(alert) {
alert(text).then(resolve)
})
})
}
function showSubtitleSettings(player, btn) {
return alertText(globalize.translate("sharedcomponents#SubtitleSettingsIntro"))
}
function showPlaybackSettings(player, btn) {
return alertText(globalize.translate("sharedcomponents#PlaybackSettingsIntro"))
}
function handleSelectedOption(id, options, player) {
switch (id) {
case "quality":
return showQualityMenu(player, options.positionTo);
case "aspectratio":
return showAspectRatioMenu(player, options.positionTo);
case "repeatmode":
return showRepeatModeMenu(player, options.positionTo);
case "subtitlesettings":
return showSubtitleSettings(player, options.positionTo);
case "playbacksettings":
return showPlaybackSettings(player, options.positionTo);
case "stats":
return options.onOption && options.onOption("stats"), Promise.resolve()
}
return Promise.reject()
}
return {
show: show
}
});

View file

@ -0,0 +1,10 @@
define([], function() {
"use strict";
function getDisplayPlayMethod(session) {
return session.NowPlayingItem ? session.TranscodingInfo && session.TranscodingInfo.IsVideoDirect ? "DirectStream" : "Transcode" === session.PlayState.PlayMethod ? "Transcode" : "DirectStream" === session.PlayState.PlayMethod ? "DirectPlay" : "DirectPlay" === session.PlayState.PlayMethod ? "DirectPlay" : void 0 : null
}
return {
getDisplayPlayMethod: getDisplayPlayMethod
}
});

View file

@ -0,0 +1,103 @@
define([], function() {
"use strict";
function addUniquePlaylistItemId(item) {
item.PlaylistItemId || (item.PlaylistItemId = "playlistItem" + currentId, currentId++)
}
function findPlaylistIndex(playlistItemId, list) {
for (var i = 0, length = list.length; i < length; i++)
if (list[i].PlaylistItemId === playlistItemId) return i;
return -1
}
function PlayQueueManager() {
this._playlist = [], this._repeatMode = "RepeatNone"
}
function arrayInsertAt(destArray, pos, arrayToInsert) {
var args = [];
args.push(pos), args.push(0), args = args.concat(arrayToInsert), destArray.splice.apply(destArray, args)
}
function moveInArray(array, from, to) {
array.splice(to, 0, array.splice(from, 1)[0])
}
var currentId = 0;
return PlayQueueManager.prototype.getPlaylist = function() {
return this._playlist.slice(0)
}, PlayQueueManager.prototype.setPlaylist = function(items) {
items = items.slice(0);
for (var i = 0, length = items.length; i < length; i++) addUniquePlaylistItemId(items[i]);
this._currentPlaylistItemId = null, this._playlist = items, this._repeatMode = "RepeatNone"
}, PlayQueueManager.prototype.queue = function(items) {
for (var i = 0, length = items.length; i < length; i++) addUniquePlaylistItemId(items[i]), this._playlist.push(items[i])
}, PlayQueueManager.prototype.queueNext = function(items) {
var i, length;
for (i = 0, length = items.length; i < length; i++) addUniquePlaylistItemId(items[i]);
var currentIndex = this.getCurrentPlaylistIndex(); - 1 === currentIndex ? currentIndex = this._playlist.length : currentIndex++, arrayInsertAt(this._playlist, currentIndex, items)
}, PlayQueueManager.prototype.getCurrentPlaylistIndex = function() {
return findPlaylistIndex(this.getCurrentPlaylistItemId(), this._playlist)
}, PlayQueueManager.prototype.getCurrentItem = function() {
var index = findPlaylistIndex(this.getCurrentPlaylistItemId(), this._playlist);
return -1 === index ? null : this._playlist[index]
}, PlayQueueManager.prototype.getCurrentPlaylistItemId = function() {
return this._currentPlaylistItemId
}, PlayQueueManager.prototype.setPlaylistState = function(playlistItemId, playlistIndex) {
this._currentPlaylistItemId = playlistItemId
}, PlayQueueManager.prototype.setPlaylistIndex = function(playlistIndex) {
playlistIndex < 0 ? this.setPlaylistState(null) : this.setPlaylistState(this._playlist[playlistIndex].PlaylistItemId)
}, PlayQueueManager.prototype.removeFromPlaylist = function(playlistItemIds) {
var playlist = this.getPlaylist();
if (playlist.length <= playlistItemIds.length) return {
result: "empty"
};
var currentPlaylistItemId = this.getCurrentPlaylistItemId(),
isCurrentIndex = -1 !== playlistItemIds.indexOf(currentPlaylistItemId);
return this._playlist = playlist.filter(function(item) {
return -1 === playlistItemIds.indexOf(item.PlaylistItemId)
}), {
result: "removed",
isCurrentIndex: isCurrentIndex
}
}, PlayQueueManager.prototype.movePlaylistItem = function(playlistItemId, newIndex) {
for (var oldIndex, playlist = this.getPlaylist(), i = 0, length = playlist.length; i < length; i++)
if (playlist[i].PlaylistItemId === playlistItemId) {
oldIndex = i;
break
} if (-1 === oldIndex || oldIndex === newIndex) return {
result: "noop"
};
if (newIndex >= playlist.length) throw new Error("newIndex out of bounds");
return moveInArray(playlist, oldIndex, newIndex), this._playlist = playlist, {
result: "moved",
playlistItemId: playlistItemId,
newIndex: newIndex
}
}, PlayQueueManager.prototype.reset = function() {
this._playlist = [], this._currentPlaylistItemId = null, this._repeatMode = "RepeatNone"
}, PlayQueueManager.prototype.setRepeatMode = function(value) {
this._repeatMode = value
}, PlayQueueManager.prototype.getRepeatMode = function() {
return this._repeatMode
}, PlayQueueManager.prototype.getNextItemInfo = function() {
var newIndex, playlist = this.getPlaylist(),
playlistLength = playlist.length;
switch (this.getRepeatMode()) {
case "RepeatOne":
newIndex = this.getCurrentPlaylistIndex();
break;
case "RepeatAll":
newIndex = this.getCurrentPlaylistIndex() + 1, newIndex >= playlistLength && (newIndex = 0);
break;
default:
newIndex = this.getCurrentPlaylistIndex() + 1
}
if (newIndex < 0 || newIndex >= playlistLength) return null;
var item = playlist[newIndex];
return item ? {
item: item,
index: newIndex
} : null
}, PlayQueueManager
});

View file

@ -0,0 +1,22 @@
define(["events", "playbackManager"], function(events, playbackManager) {
"use strict";
function transferPlayback(oldPlayer, newPlayer) {
var state = playbackManager.getPlayerState(oldPlayer),
item = state.NowPlayingItem;
if (item) {
var playState = state.PlayState || {},
resumePositionTicks = playState.PositionTicks || 0;
playbackManager.stop(oldPlayer).then(function() {
playbackManager.play({
ids: [item.Id],
serverId: item.ServerId,
startPositionTicks: resumePositionTicks
}, newPlayer)
})
}
}
events.on(playbackManager, "playerchange", function(e, newPlayer, newTarget, oldPlayer) {
if (oldPlayer && newPlayer) return oldPlayer.isLocalPlayer ? newPlayer.isLocalPlayer ? void console.log("Skipping remote control autoplay because newPlayer is a local player") : void transferPlayback(oldPlayer, newPlayer) : void console.log("Skipping remote control autoplay because oldPlayer is not a local player")
})
});

View file

@ -0,0 +1,63 @@
define(["events", "playbackManager", "dom", "browser", "css!./iconosd", "material-icons"], function(events, playbackManager, dom, browser) {
"use strict";
function getOsdElementHtml() {
var html = "";
return html += '<i class="md-icon iconOsdIcon">&#xE050;</i>', html += '<div class="iconOsdProgressOuter"><div class="iconOsdProgressInner"></div></div>'
}
function ensureOsdElement() {
var elem = osdElement;
elem || (enableAnimation = browser.supportsCssAnimation(), elem = document.createElement("div"), elem.classList.add("hide"), elem.classList.add("iconOsd"), elem.classList.add("iconOsd-hidden"), elem.classList.add("volumeOsd"), elem.innerHTML = getOsdElementHtml(), iconElement = elem.querySelector("i"), progressElement = elem.querySelector(".iconOsdProgressInner"), document.body.appendChild(elem), osdElement = elem)
}
function onHideComplete() {
this.classList.add("hide")
}
function showOsd() {
clearHideTimeout();
var elem = osdElement;
dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
once: !0
}), elem.classList.remove("hide"), elem.offsetWidth, requestAnimationFrame(function() {
elem.classList.remove("iconOsd-hidden"), hideTimeout = setTimeout(hideOsd, 3e3)
})
}
function clearHideTimeout() {
hideTimeout && (clearTimeout(hideTimeout), hideTimeout = null)
}
function hideOsd() {
clearHideTimeout();
var elem = osdElement;
elem && (enableAnimation ? (elem.offsetWidth, requestAnimationFrame(function() {
elem.classList.add("iconOsd-hidden"), dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
once: !0
})
})) : onHideComplete.call(elem))
}
function updatePlayerVolumeState(isMuted, volume) {
iconElement && (iconElement.innerHTML = isMuted ? "&#xE04F;" : "&#xE050;"), progressElement && (progressElement.style.width = (volume || 0) + "%")
}
function releaseCurrentPlayer() {
var player = currentPlayer;
player && (events.off(player, "volumechange", onVolumeChanged), events.off(player, "playbackstop", hideOsd), currentPlayer = null)
}
function onVolumeChanged(e) {
var player = this;
ensureOsdElement(), updatePlayerVolumeState(player.isMuted(), player.getVolume()), showOsd()
}
function bindToPlayer(player) {
player !== currentPlayer && (releaseCurrentPlayer(), currentPlayer = player, player && (hideOsd(), events.on(player, "volumechange", onVolumeChanged), events.on(player, "playbackstop", hideOsd)))
}
var currentPlayer, osdElement, iconElement, progressElement, enableAnimation, hideTimeout;
events.on(playbackManager, "playerchange", function() {
bindToPlayer(playbackManager.getCurrentPlayer())
}), bindToPlayer(playbackManager.getCurrentPlayer())
});