1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00
jellyfin-web/src/bower_components/emby-webcomponents/chromecast/chromecastplayer.js
Erwin de Haan 4678528d00 First separation commit.
Added LICENSE, README.md, CONTRIBUTORS.md
2019-01-09 12:36:54 +01:00

425 lines
No EOL
23 KiB
JavaScript

define(["appSettings", "userSettings", "playbackManager", "connectionManager", "globalize", "events", "require", "castSenderApiLoader"], function(appSettings, userSettings, playbackManager, connectionManager, globalize, events, require, castSenderApiLoader) {
"use strict";
function sendConnectionResult(isOk) {
var resolve = currentResolve,
reject = currentReject;
currentResolve = null, currentReject = null, isOk ? resolve && resolve() : reject ? reject() : playbackManager.removeActivePlayer(PlayerName)
}
function alertText(text, title) {
require(["alert"], function(alert) {
alert({
text: text,
title: title
})
})
}
function normalizeImages(state) {
if (state && state.NowPlayingItem) {
var item = state.NowPlayingItem;
item.ImageTags && item.ImageTags.Primary || item.PrimaryImageTag && (item.ImageTags = item.ImageTags || {}, item.ImageTags.Primary = item.PrimaryImageTag), item.BackdropImageTag && item.BackdropItemId === item.Id && (item.BackdropImageTags = [item.BackdropImageTag]), item.BackdropImageTag && item.BackdropItemId !== item.Id && (item.ParentBackdropImageTags = [item.BackdropImageTag], item.ParentBackdropItemId = item.BackdropItemId)
}
}
function getItemsForPlayback(apiClient, query) {
var userId = apiClient.getCurrentUserId();
return query.Ids && 1 === query.Ids.split(",").length ? apiClient.getItem(userId, query.Ids.split(",")).then(function(item) {
return {
Items: [item],
TotalRecordCount: 1
}
}) : (query.Limit = query.Limit || 100, query.ExcludeLocationTypes = "Virtual", query.EnableTotalRecordCount = !1, apiClient.getItems(userId, query))
}
function bindEventForRelay(instance, eventName) {
events.on(instance._castPlayer, eventName, function(e, data) {
var state = instance.getPlayerStateInternal(data);
events.trigger(instance, eventName, [state])
})
}
function initializeChromecast() {
var instance = this;
instance._castPlayer = new CastPlayer, document.dispatchEvent(new CustomEvent("chromecastloaded", {
detail: {
player: instance
}
})), events.on(instance._castPlayer, "connect", function(e) {
currentResolve ? sendConnectionResult(!0) : playbackManager.setActivePlayer(PlayerName, instance.getCurrentTargetInfo()), console.log("cc: connect"), instance.lastPlayerData = null
}), events.on(instance._castPlayer, "playbackstart", function(e, data) {
console.log("cc: playbackstart"), instance._castPlayer.initializeCastPlayer();
var state = instance.getPlayerStateInternal(data);
events.trigger(instance, "playbackstart", [state])
}), events.on(instance._castPlayer, "playbackstop", function(e, data) {
console.log("cc: playbackstop");
var state = instance.getPlayerStateInternal(data);
events.trigger(instance, "playbackstop", [state]), instance.lastPlayerData = {}
}), events.on(instance._castPlayer, "playbackprogress", function(e, data) {
var state = instance.getPlayerStateInternal(data);
events.trigger(instance, "timeupdate", [state])
}), bindEventForRelay(instance, "timeupdate"), bindEventForRelay(instance, "pause"), bindEventForRelay(instance, "unpause"), bindEventForRelay(instance, "volumechange"), bindEventForRelay(instance, "repeatmodechange"), events.on(instance._castPlayer, "playstatechange", function(e, data) {
var state = instance.getPlayerStateInternal(data);
events.trigger(instance, "pause", [state])
})
}
function ChromecastPlayer() {
this.name = PlayerName, this.type = "mediaplayer", this.id = "chromecast", this.isLocalPlayer = !1, this.lastPlayerData = {}, castSenderApiLoader.load().then(initializeChromecast.bind(this))
}
var currentResolve, currentReject, PlayerName = "Chromecast",
DEVICE_STATE = {
IDLE: 0,
ACTIVE: 1,
WARNING: 2,
ERROR: 3
},
PLAYER_STATE = {
IDLE: "IDLE",
LOADING: "LOADING",
LOADED: "LOADED",
PLAYING: "PLAYING",
PAUSED: "PAUSED",
STOPPED: "STOPPED",
SEEKING: "SEEKING",
ERROR: "ERROR"
},
CastPlayer = function() {
this.deviceState = DEVICE_STATE.IDLE, this.currentMediaSession = null, this.session = null, this.castPlayerState = PLAYER_STATE.IDLE, this.hasReceivers = !1, this.errorHandler = this.onError.bind(this), this.mediaStatusUpdateHandler = this.onMediaStatusUpdate.bind(this), this.initializeCastPlayer()
};
return CastPlayer.prototype.initializeCastPlayer = function() {
var chrome = window.chrome;
if (chrome) {
if (!chrome.cast || !chrome.cast.isAvailable) return void setTimeout(this.initializeCastPlayer.bind(this), 1e3);
var sessionRequest = new chrome.cast.SessionRequest("2D4B1DA3"),
apiConfig = new chrome.cast.ApiConfig(sessionRequest, this.sessionListener.bind(this), this.receiverListener.bind(this), "origin_scoped");
console.log("chromecast.initialize"), chrome.cast.initialize(apiConfig, this.onInitSuccess.bind(this), this.errorHandler)
}
}, CastPlayer.prototype.onInitSuccess = function() {
this.isInitialized = !0, console.log("chromecast init success")
}, CastPlayer.prototype.onError = function() {
console.log("chromecast error")
}, CastPlayer.prototype.sessionListener = function(e) {
this.session = e, this.session && (this.session.media[0] && this.onMediaDiscovered("activeSession", this.session.media[0]), this.onSessionConnected(e))
}, CastPlayer.prototype.messageListener = function(namespace, message) {
if ("string" == typeof message && (message = JSON.parse(message)), "playbackerror" === message.type) {
var errorCode = message.data;
setTimeout(function() {
alertText(globalize.translate("MessagePlaybackError" + errorCode), globalize.translate("HeaderPlaybackError"))
}, 300)
} else "connectionerror" === message.type ? setTimeout(function() {
alertText(globalize.translate("MessageChromecastConnectionError"), globalize.translate("HeaderError"))
}, 300) : message.type && events.trigger(this, message.type, [message.data])
}, CastPlayer.prototype.receiverListener = function(e) {
this.hasReceivers = "available" === e
}, CastPlayer.prototype.sessionUpdateListener = function(isAlive) {
isAlive || (this.session = null, this.deviceState = DEVICE_STATE.IDLE, this.castPlayerState = PLAYER_STATE.IDLE, this.currentMediaSession = null, sendConnectionResult(!1))
}, CastPlayer.prototype.launchApp = function() {
chrome.cast.requestSession(this.onRequestSessionSuccess.bind(this), this.onLaunchError.bind(this))
}, CastPlayer.prototype.onRequestSessionSuccess = function(e) {
this.onSessionConnected(e)
}, CastPlayer.prototype.onSessionConnected = function(session) {
this.session = session, this.deviceState = DEVICE_STATE.ACTIVE, this.session.addMessageListener("urn:x-cast:com.connectsdk", this.messageListener.bind(this)), this.session.addMediaListener(this.sessionMediaListener.bind(this)), this.session.addUpdateListener(this.sessionUpdateListener.bind(this)), events.trigger(this, "connect"), this.sendMessage({
options: {},
command: "Identify"
})
}, CastPlayer.prototype.sessionMediaListener = function(e) {
this.currentMediaSession = e, this.currentMediaSession.addUpdateListener(this.mediaStatusUpdateHandler)
}, CastPlayer.prototype.onLaunchError = function() {
this.deviceState = DEVICE_STATE.ERROR, sendConnectionResult(!1)
}, CastPlayer.prototype.stopApp = function() {
this.session && this.session.stop(this.onStopAppSuccess.bind(this, "Session stopped"), this.errorHandler)
}, CastPlayer.prototype.onStopAppSuccess = function(message) {
this.deviceState = DEVICE_STATE.IDLE, this.castPlayerState = PLAYER_STATE.IDLE, this.currentMediaSession = null
}, CastPlayer.prototype.loadMedia = function(options, command) {
return this.session ? (options.items = options.items.map(function(i) {
return {
Id: i.Id,
ServerId: i.ServerId,
Name: i.Name,
Type: i.Type,
MediaType: i.MediaType,
IsFolder: i.IsFolder
}
}), this.sendMessage({
options: options,
command: command
})) : Promise.reject()
}, CastPlayer.prototype.sendMessage = function(message) {
var player = this,
receiverName = null,
session = player.session;
session && session.receiver && session.receiver.friendlyName && (receiverName = session.receiver.friendlyName);
var apiClient;
apiClient = message.options && message.options.ServerId ? connectionManager.getApiClient(message.options.ServerId) : message.options && message.options.items && message.options.items.length ? connectionManager.getApiClient(message.options.items[0].ServerId) : connectionManager.currentApiClient(), message = Object.assign(message, {
userId: apiClient.getCurrentUserId(),
deviceId: apiClient.deviceId(),
accessToken: apiClient.accessToken(),
serverAddress: apiClient.serverAddress(),
serverId: apiClient.serverId(),
serverVersion: apiClient.serverVersion(),
receiverName: receiverName
});
var bitrateSetting = appSettings.maxChromecastBitrate();
return bitrateSetting && (message.maxBitrate = bitrateSetting), message.options && message.options.items && (message.subtitleAppearance = userSettings.getSubtitleAppearanceSettings(), message.subtitleBurnIn = appSettings.get("subtitleburnin") || ""), new Promise(function(resolve, reject) {
require(["chromecastHelper"], function(chromecastHelper) {
chromecastHelper.getServerAddress(apiClient).then(function(serverAddress) {
message.serverAddress = serverAddress, player.sendMessageInternal(message).then(resolve, reject)
}, reject)
})
})
}, CastPlayer.prototype.sendMessageInternal = function(message) {
return message = JSON.stringify(message), this.session.sendMessage("urn:x-cast:com.connectsdk", message, this.onPlayCommandSuccess.bind(this), this.errorHandler), Promise.resolve()
}, CastPlayer.prototype.onPlayCommandSuccess = function() {}, CastPlayer.prototype.onMediaDiscovered = function(how, mediaSession) {
this.currentMediaSession = mediaSession, "loadMedia" === how && (this.castPlayerState = PLAYER_STATE.PLAYING), "activeSession" === how && (this.castPlayerState = mediaSession.playerState), this.currentMediaSession.addUpdateListener(this.mediaStatusUpdateHandler)
}, CastPlayer.prototype.onMediaStatusUpdate = function(e) {
!1 === e && (this.castPlayerState = PLAYER_STATE.IDLE)
}, CastPlayer.prototype.setReceiverVolume = function(mute, vol) {
this.currentMediaSession && (mute ? this.session.setReceiverMuted(!0, this.mediaCommandSuccessCallback.bind(this), this.errorHandler) : this.session.setReceiverVolumeLevel(vol || 1, this.mediaCommandSuccessCallback.bind(this), this.errorHandler))
}, CastPlayer.prototype.mute = function() {
this.setReceiverVolume(!0)
}, CastPlayer.prototype.mediaCommandSuccessCallback = function(info, e) {}, ChromecastPlayer.prototype.tryPair = function(target) {
var castPlayer = this._castPlayer;
return castPlayer.deviceState !== DEVICE_STATE.ACTIVE && castPlayer.isInitialized ? new Promise(function(resolve, reject) {
currentResolve = resolve, currentReject = reject, castPlayer.launchApp()
}) : (currentResolve = null, currentReject = null, Promise.reject())
}, ChromecastPlayer.prototype.getTargets = function() {
var targets = [];
return this._castPlayer && this._castPlayer.hasReceivers && targets.push(this.getCurrentTargetInfo()), Promise.resolve(targets)
}, ChromecastPlayer.prototype.getCurrentTargetInfo = function() {
var appName = null,
castPlayer = this._castPlayer;
return castPlayer.session && castPlayer.session.receiver && castPlayer.session.receiver.friendlyName && (appName = castPlayer.session.receiver.friendlyName), {
name: PlayerName,
id: PlayerName,
playerName: PlayerName,
playableMediaTypes: ["Audio", "Video"],
isLocalPlayer: !1,
appName: PlayerName,
deviceName: appName,
supportedCommands: ["VolumeUp", "VolumeDown", "Mute", "Unmute", "ToggleMute", "SetVolume", "SetAudioStreamIndex", "SetSubtitleStreamIndex", "DisplayContent", "SetRepeatMode", "EndSession", "PlayMediaSource", "PlayTrailers"]
}
}, ChromecastPlayer.prototype.getPlayerStateInternal = function(data) {
var triggerStateChange = !1;
return data && !this.lastPlayerData && (triggerStateChange = !0), data = data || this.lastPlayerData, this.lastPlayerData = data, normalizeImages(data), triggerStateChange && events.trigger(this, "statechange", [data]), data
}, ChromecastPlayer.prototype.playWithCommand = function(options, command) {
if (!options.items) {
var apiClient = connectionManager.getApiClient(options.serverId),
instance = this;
return apiClient.getItem(apiClient.getCurrentUserId(), options.ids[0]).then(function(item) {
return options.items = [item], instance.playWithCommand(options, command)
})
}
return this._castPlayer.loadMedia(options, command)
}, ChromecastPlayer.prototype.seek = function(position) {
position = parseInt(position), position /= 1e7, this._castPlayer.sendMessage({
options: {
position: position
},
command: "Seek"
})
}, ChromecastPlayer.prototype.setAudioStreamIndex = function(index) {
this._castPlayer.sendMessage({
options: {
index: index
},
command: "SetAudioStreamIndex"
})
}, ChromecastPlayer.prototype.setSubtitleStreamIndex = function(index) {
this._castPlayer.sendMessage({
options: {
index: index
},
command: "SetSubtitleStreamIndex"
})
}, ChromecastPlayer.prototype.setMaxStreamingBitrate = function(options) {
this._castPlayer.sendMessage({
options: options,
command: "SetMaxStreamingBitrate"
})
}, ChromecastPlayer.prototype.isFullscreen = function() {
var state = this.lastPlayerData || {};
return state = state.PlayState || {}, state.IsFullscreen
}, ChromecastPlayer.prototype.nextTrack = function() {
this._castPlayer.sendMessage({
options: {},
command: "NextTrack"
})
}, ChromecastPlayer.prototype.previousTrack = function() {
this._castPlayer.sendMessage({
options: {},
command: "PreviousTrack"
})
}, ChromecastPlayer.prototype.volumeDown = function() {
this._castPlayer.sendMessage({
options: {},
command: "VolumeDown"
})
}, ChromecastPlayer.prototype.endSession = function() {
var instance = this;
this.stop().then(function() {
setTimeout(function() {
instance._castPlayer.stopApp()
}, 1e3)
})
}, ChromecastPlayer.prototype.volumeUp = function() {
this._castPlayer.sendMessage({
options: {},
command: "VolumeUp"
})
}, ChromecastPlayer.prototype.setVolume = function(vol) {
vol = Math.min(vol, 100), vol = Math.max(vol, 0), this._castPlayer.sendMessage({
options: {
volume: vol
},
command: "SetVolume"
})
}, ChromecastPlayer.prototype.unpause = function() {
this._castPlayer.sendMessage({
options: {},
command: "Unpause"
})
}, ChromecastPlayer.prototype.playPause = function() {
this._castPlayer.sendMessage({
options: {},
command: "PlayPause"
})
}, ChromecastPlayer.prototype.pause = function() {
this._castPlayer.sendMessage({
options: {},
command: "Pause"
})
}, ChromecastPlayer.prototype.stop = function() {
return this._castPlayer.sendMessage({
options: {},
command: "Stop"
})
}, ChromecastPlayer.prototype.displayContent = function(options) {
this._castPlayer.sendMessage({
options: options,
command: "DisplayContent"
})
}, ChromecastPlayer.prototype.setMute = function(isMuted) {
var castPlayer = this._castPlayer;
isMuted ? castPlayer.sendMessage({
options: {},
command: "Mute"
}) : castPlayer.sendMessage({
options: {},
command: "Unmute"
})
}, ChromecastPlayer.prototype.getRepeatMode = function() {
var state = this.lastPlayerData || {};
return state = state.PlayState || {}, state.RepeatMode
}, ChromecastPlayer.prototype.playTrailers = function(item) {
this._castPlayer.sendMessage({
options: {
ItemId: item.Id,
ServerId: item.ServerId
},
command: "PlayTrailers"
})
}, ChromecastPlayer.prototype.setRepeatMode = function(mode) {
this._castPlayer.sendMessage({
options: {
RepeatMode: mode
},
command: "SetRepeatMode"
})
}, ChromecastPlayer.prototype.toggleMute = function() {
this._castPlayer.sendMessage({
options: {},
command: "ToggleMute"
})
}, ChromecastPlayer.prototype.audioTracks = function() {
var state = this.lastPlayerData || {};
return state = state.NowPlayingItem || {}, (state.MediaStreams || []).filter(function(s) {
return "Audio" === s.Type
})
}, ChromecastPlayer.prototype.getAudioStreamIndex = function() {
var state = this.lastPlayerData || {};
return state = state.PlayState || {}, state.AudioStreamIndex
}, ChromecastPlayer.prototype.subtitleTracks = function() {
var state = this.lastPlayerData || {};
return state = state.NowPlayingItem || {}, (state.MediaStreams || []).filter(function(s) {
return "Subtitle" === s.Type
})
}, ChromecastPlayer.prototype.getSubtitleStreamIndex = function() {
var state = this.lastPlayerData || {};
return state = state.PlayState || {}, state.SubtitleStreamIndex
}, ChromecastPlayer.prototype.getMaxStreamingBitrate = function() {
var state = this.lastPlayerData || {};
return state = state.PlayState || {}, state.MaxStreamingBitrate
}, ChromecastPlayer.prototype.getVolume = function() {
var state = this.lastPlayerData || {};
return state = state.PlayState || {}, null == state.VolumeLevel ? 100 : state.VolumeLevel
}, ChromecastPlayer.prototype.isPlaying = function() {
return null != (this.lastPlayerData || {}).NowPlayingItem
}, ChromecastPlayer.prototype.isPlayingVideo = function() {
var state = this.lastPlayerData || {};
return state = state.NowPlayingItem || {}, "Video" === state.MediaType
}, ChromecastPlayer.prototype.isPlayingAudio = function() {
var state = this.lastPlayerData || {};
return state = state.NowPlayingItem || {}, "Audio" === state.MediaType
}, ChromecastPlayer.prototype.currentTime = function(val) {
if (null != val) return this.seek(val);
var state = this.lastPlayerData || {};
return state = state.PlayState || {}, state.PositionTicks
}, ChromecastPlayer.prototype.duration = function() {
var state = this.lastPlayerData || {};
return state = state.NowPlayingItem || {}, state.RunTimeTicks
}, ChromecastPlayer.prototype.getBufferedRanges = function() {
var state = this.lastPlayerData || {};
return state = state.PlayState || {}, state.BufferedRanges || []
}, ChromecastPlayer.prototype.paused = function() {
var state = this.lastPlayerData || {};
return state = state.PlayState || {}, state.IsPaused
}, ChromecastPlayer.prototype.isMuted = function() {
var state = this.lastPlayerData || {};
return state = state.PlayState || {}, state.IsMuted
}, ChromecastPlayer.prototype.shuffle = function(item) {
var apiClient = connectionManager.getApiClient(item.ServerId),
userId = apiClient.getCurrentUserId(),
instance = this;
apiClient.getItem(userId, item.Id).then(function(item) {
instance.playWithCommand({
items: [item]
}, "Shuffle")
})
}, ChromecastPlayer.prototype.instantMix = function(item) {
var apiClient = connectionManager.getApiClient(item.ServerId),
userId = apiClient.getCurrentUserId(),
instance = this;
apiClient.getItem(userId, item.Id).then(function(item) {
instance.playWithCommand({
items: [item]
}, "InstantMix")
})
}, ChromecastPlayer.prototype.canPlayMediaType = function(mediaType) {
return "audio" === (mediaType = (mediaType || "").toLowerCase()) || "video" === mediaType
}, ChromecastPlayer.prototype.canQueueMediaType = function(mediaType) {
return this.canPlayMediaType(mediaType)
}, ChromecastPlayer.prototype.queue = function(options) {
this.playWithCommand(options, "PlayLast")
}, ChromecastPlayer.prototype.queueNext = function(options) {
this.playWithCommand(options, "PlayNext")
}, ChromecastPlayer.prototype.play = function(options) {
if (options.items) return this.playWithCommand(options, "PlayNow");
if (!options.serverId) throw new Error("serverId required!");
var instance = this;
return getItemsForPlayback(connectionManager.getApiClient(options.serverId), {
Ids: options.ids.join(",")
}).then(function(result) {
return options.items = result.Items, instance.playWithCommand(options, "PlayNow")
})
}, ChromecastPlayer.prototype.toggleFullscreen = function() {}, ChromecastPlayer.prototype.beginPlayerUpdates = function() {}, ChromecastPlayer.prototype.endPlayerUpdates = function() {}, ChromecastPlayer.prototype.getPlaylist = function() {
return Promise.resolve([])
}, ChromecastPlayer.prototype.getCurrentPlaylistItemId = function() {}, ChromecastPlayer.prototype.setCurrentPlaylistItem = function(playlistItemId) {
return Promise.resolve()
}, ChromecastPlayer.prototype.removeFromPlaylist = function(playlistItemIds) {
return Promise.resolve()
}, ChromecastPlayer.prototype.getPlayerState = function() {
return this.getPlayerStateInternal() || {}
}, ChromecastPlayer
});