+
diff --git a/dashboard-ui/scripts/backdrops.js b/dashboard-ui/scripts/backdrops.js
index 3e7904159a..cd9ae91e98 100644
--- a/dashboard-ui/scripts/backdrops.js
+++ b/dashboard-ui/scripts/backdrops.js
@@ -107,6 +107,41 @@
return val == '1' || (val != '0' && !$.browser.mobile);
}
+ function setBackdrops(page, items) {
+
+ var images = items.filter(function (i) {
+
+ return i.BackdropImageTags.length > 0;
+
+ }).map(function (i) {
+ return {
+ id: i.Id,
+ tag: i.BackdropImageTags[0]
+ };
+ });
+
+ if (images.length) {
+ $(page).addClass('backdropPage');
+
+ var index = getRandom(0, images.length - 1);
+ var item = images[index];
+
+ var screenWidth = $(window).width();
+
+ var imgUrl = ApiClient.getScaledImageUrl(item.id, {
+ type: "Backdrop",
+ tag: item.tag,
+ maxWidth: screenWidth,
+ quality: 80
+ });
+
+ getElement().css('backgroundImage', 'url(\'' + imgUrl + '\')');
+
+ } else {
+ $(page).removeClass('backdropPage');
+ }
+ }
+
$(document).on('pagebeforeshow', ".page", function () {
var page = this;
@@ -128,4 +163,9 @@
});
+ window.Backdrops = {
+
+ setBackdrops: setBackdrops
+ };
+
})(jQuery, document);
\ No newline at end of file
diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js
index 630731fe37..9a2da9bf59 100644
--- a/dashboard-ui/scripts/chromecast.js
+++ b/dashboard-ui/scripts/chromecast.js
@@ -1,693 +1,724 @@
-(function (window, chrome, console) {
-
- // Based on https://github.com/googlecast/CastVideos-chrome/blob/master/CastVideos.js
-
- /**
- * Constants of states for Chromecast device
- **/
+(function (window, chrome, console) {
+
+ // Based on https://github.com/googlecast/CastVideos-chrome/blob/master/CastVideos.js
+
+ /**
+ * Constants of states for Chromecast device
+ **/
var DEVICE_STATE = {
- 'IDLE': 0,
- 'ACTIVE': 1,
- 'WARNING': 2,
+ 'IDLE': 0,
+ 'ACTIVE': 1,
+ 'WARNING': 2,
'ERROR': 3,
- };
-
- /**
- * Constants of states for CastPlayer
- **/
+ };
+
+ /**
+ * Constants of states for CastPlayer
+ **/
var PLAYER_STATE = {
- 'IDLE': 'IDLE',
- 'LOADING': 'LOADING',
- 'LOADED': 'LOADED',
- 'PLAYING': 'PLAYING',
- 'PAUSED': 'PAUSED',
- 'STOPPED': 'STOPPED',
- 'SEEKING': 'SEEKING',
+ 'IDLE': 'IDLE',
+ 'LOADING': 'LOADING',
+ 'LOADED': 'LOADED',
+ 'PLAYING': 'PLAYING',
+ 'PAUSED': 'PAUSED',
+ 'STOPPED': 'STOPPED',
+ 'SEEKING': 'SEEKING',
'ERROR': 'ERROR'
- };
-
- var PlayerName = 'Chromecast';
+ };
+
+ var PlayerName = 'Chromecast';
+
+ var messageNamespace = 'urn:x-cast:com.google.cast.sample.playlist';
+
var cPlayer = {
deviceState: DEVICE_STATE.IDLE
- };
- var CastPlayer = function () {
-
- /* device variables */
- // @type {DEVICE_STATE} A state for device
- this.deviceState = DEVICE_STATE.IDLE;
-
- /* Cast player variables */
- // @type {Object} a chrome.cast.media.Media object
- this.currentMediaSession = null;
- // @type {Number} volume
- this.currentVolume = 1;
-
- // @type {string} a chrome.cast.Session object
- this.session = null;
- // @type {PLAYER_STATE} A state for Cast media player
- this.castPlayerState = PLAYER_STATE.IDLE;
-
- // @type {Boolean} Fullscreen mode on/off
- this.fullscreen = false;
-
- /* Current media variables */
- // @type {Boolean} Audio on and off
- this.audio = true;
- // @type {Number} A number for current media index
- this.currentMediaIndex = 0;
- // @type {Number} A number for current media time
- this.currentMediaTime = 0;
- // @type {Number} A number for current media duration
- this.currentMediaDuration = -1;
- // @type {Timer} A timer for tracking progress of media
- this.timer = null;
- // @type {Boolean} A boolean to stop timer update of progress when triggered by media status event
- this.progressFlag = true;
- // @type {Number} A number in milliseconds for minimal progress update
- this.timerStep = 1000;
-
- this.hasReceivers = false;
-
- this.currentMediaOffset = 0;
-
- // Progress bar element id
- this.progressBar = "positionSlider";
-
- // Timec display element id
- this.duration = "currentTime";
-
- // Playback display element id
- this.playback = "playTime";
-
- // bind once - commit 2ebffc2271da0bc5e8b13821586aee2a2e3c7753
- this.errorHandler = this.onError.bind(this);
- this.incrementMediaTimeHandler = this.incrementMediaTime.bind(this);
- this.mediaStatusUpdateHandler = this.onMediaStatusUpdate.bind(this);
-
+ };
+
+ var CastPlayer = function () {
+
+ /* device variables */
+ // @type {DEVICE_STATE} A state for device
+ this.deviceState = DEVICE_STATE.IDLE;
+
+ /* Cast player variables */
+ // @type {Object} a chrome.cast.media.Media object
+ this.currentMediaSession = null;
+ // @type {Number} volume
+ this.currentVolume = 1;
+
+ // @type {string} a chrome.cast.Session object
+ this.session = null;
+ // @type {PLAYER_STATE} A state for Cast media player
+ this.castPlayerState = PLAYER_STATE.IDLE;
+
+ // @type {Boolean} Fullscreen mode on/off
+ this.fullscreen = false;
+
+ /* Current media variables */
+ // @type {Boolean} Audio on and off
+ this.audio = true;
+ // @type {Number} A number for current media index
+ this.currentMediaIndex = 0;
+ // @type {Number} A number for current media time
+ this.currentMediaTime = 0;
+ // @type {Number} A number for current media duration
+ this.currentMediaDuration = -1;
+ // @type {Timer} A timer for tracking progress of media
+ this.timer = null;
+ // @type {Boolean} A boolean to stop timer update of progress when triggered by media status event
+ this.progressFlag = true;
+ // @type {Number} A number in milliseconds for minimal progress update
+ this.timerStep = 1000;
+
+ this.hasReceivers = false;
+
+ this.currentMediaOffset = 0;
+
+ // Progress bar element id
+ this.progressBar = "positionSlider";
+
+ // Timec display element id
+ this.duration = "currentTime";
+
+ // Playback display element id
+ this.playback = "playTime";
+
+ // bind once - commit 2ebffc2271da0bc5e8b13821586aee2a2e3c7753
+ this.errorHandler = this.onError.bind(this);
+ this.incrementMediaTimeHandler = this.incrementMediaTime.bind(this);
+ this.mediaStatusUpdateHandler = this.onMediaStatusUpdate.bind(this);
+
this.initializeCastPlayer();
- };
-
- /**
- * Initialize Cast media player
- * Initializes the API. Note that either successCallback and errorCallback will be
- * invoked once the API has finished initialization. The sessionListener and
- * receiverListener may be invoked at any time afterwards, and possibly more than once.
- */
+ };
+
+ /**
+ * Initialize Cast media player
+ * Initializes the API. Note that either successCallback and errorCallback will be
+ * invoked once the API has finished initialization. The sessionListener and
+ * receiverListener may be invoked at any time afterwards, and possibly more than once.
+ */
CastPlayer.prototype.initializeCastPlayer = function () {
-
+
if (!chrome) {
return;
- }
-
+ }
+
if (!chrome.cast || !chrome.cast.isAvailable) {
-
- setTimeout(this.initializeCastPlayer.bind(this), 1000);
+
+ setTimeout(this.initializeCastPlayer.bind(this), 1000);
return;
- }
-
- // v1 Id AE4DA10A
- // v2 Id 472F0435
- // default receiver chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID
-
- var applicationID = chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID;
-
- // request session
- var sessionRequest = new chrome.cast.SessionRequest(applicationID);
- var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
- this.sessionListener.bind(this),
- this.receiverListener.bind(this));
-
- console.log('chromecast.initialize');
-
+ }
+
+ // v1 Id AE4DA10A
+ // v2 Id 472F0435
+ // default receiver chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID
+
+ var applicationID = "472F0435";
+
+ // request session
+ var sessionRequest = new chrome.cast.SessionRequest(applicationID);
+ var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
+ this.sessionListener.bind(this),
+ this.receiverListener.bind(this));
+
+ console.log('chromecast.initialize');
+
chrome.cast.initialize(apiConfig, this.onInitSuccess.bind(this), this.errorHandler);
-
- };
-
- /**
- * Callback function for init success
- */
+
+ };
+
+ /**
+ * Callback function for init success
+ */
CastPlayer.prototype.onInitSuccess = function () {
- this.isInitialized = true;
+ this.isInitialized = true;
console.log("chromecast init success");
- };
-
- /**
- * Generic error callback function
- */
+ };
+
+ /**
+ * Generic error callback function
+ */
CastPlayer.prototype.onError = function () {
console.log("chromecast error");
- };
-
- /**
- * @param {!Object} e A new session
- * This handles auto-join when a page is reloaded
- * When active session is detected, playback will automatically
- * join existing session and occur in Cast mode and media
- * status gets synced up with current media of the session
- */
+ };
+
+ /**
+ * @param {!Object} e A new session
+ * This handles auto-join when a page is reloaded
+ * When active session is detected, playback will automatically
+ * join existing session and occur in Cast mode and media
+ * status gets synced up with current media of the session
+ */
CastPlayer.prototype.sessionListener = function (e) {
- this.session = e;
+
+ this.session = e;
if (this.session) {
- this.deviceState = DEVICE_STATE.ACTIVE;
- MediaController.setActivePlayer(PlayerName);
+
+ console.log('sessionListener');
+
+ this.deviceState = DEVICE_STATE.ACTIVE;
+
+ MediaController.setActivePlayer(PlayerName);
+
if (this.session.media[0]) {
this.onMediaDiscovered('activeSession', this.session.media[0]);
- }
-
+ }
+
+ this.session.addMessageListener(messageNamespace, this.messageListener.bind(this));
this.session.addUpdateListener(this.sessionUpdateListener.bind(this));
}
- };
-
- /**
- * @param {string} e Receiver availability
- * This indicates availability of receivers but
- * does not provide a list of device IDs
- */
+ };
+
+ CastPlayer.prototype.messageListener = function (namespace, message) {
+
+ console.log('Message from receiver, namespace: ' + namespace + ', message: ' + message);
+ };
+
+ /**
+ * @param {string} e Receiver availability
+ * This indicates availability of receivers but
+ * does not provide a list of device IDs
+ */
CastPlayer.prototype.receiverListener = function (e) {
-
+
if (e === 'available') {
- console.log("chromecast receiver found");
+ console.log("chromecast receiver found");
this.hasReceivers = true;
- }
+ }
else {
- console.log("chromecast receiver list empty");
+ console.log("chromecast receiver list empty");
this.hasReceivers = false;
}
- };
-
- /**
- * session update listener
- */
+ };
+
+ /**
+ * session update listener
+ */
CastPlayer.prototype.sessionUpdateListener = function (isAlive) {
- if (!isAlive) {
- this.session = null;
- this.deviceState = DEVICE_STATE.IDLE;
- this.castPlayerState = PLAYER_STATE.IDLE;
- this.currentMediaSession = null;
- clearInterval(this.timer);
-
+
+ console.log('sessionUpdateListener alive: ' + isAlive);
+
+ if (isAlive) {
+ }
+ else {
+ this.session = null;
+ this.deviceState = DEVICE_STATE.IDLE;
+ this.castPlayerState = PLAYER_STATE.IDLE;
+ this.currentMediaSession = null;
+ clearInterval(this.timer);
+
MediaController.removeActivePlayer(PlayerName);
}
- };
-
- /**
- * Requests that a receiver application session be created or joined. By default, the SessionRequest
- * passed to the API at initialization time is used; this may be overridden by passing a different
- * session request in opt_sessionRequest.
- */
+ };
+
+ /**
+ * Requests that a receiver application session be created or joined. By default, the SessionRequest
+ * passed to the API at initialization time is used; this may be overridden by passing a different
+ * session request in opt_sessionRequest.
+ */
CastPlayer.prototype.launchApp = function () {
- console.log("chromecast launching app...");
- chrome.cast.requestSession(this.onRequestSessionSuccess.bind(this), this.onLaunchError.bind(this));
+ console.log("chromecast launching app...");
+ chrome.cast.requestSession(this.onRequestSessionSuccess.bind(this), this.onLaunchError.bind(this));
if (this.timer) {
clearInterval(this.timer);
}
- };
-
- /**
- * Callback function for request session success
- * @param {Object} e A chrome.cast.Session object
- */
+ };
+
+ /**
+ * Callback function for request session success
+ * @param {Object} e A chrome.cast.Session object
+ */
CastPlayer.prototype.onRequestSessionSuccess = function (e) {
- console.log("chromecast session success: " + e.sessionId);
- this.session = e;
- this.deviceState = DEVICE_STATE.ACTIVE;
+ console.log("chromecast session success: " + e.sessionId);
+ this.session = e;
+ this.deviceState = DEVICE_STATE.ACTIVE;
this.session.addUpdateListener(this.sessionUpdateListener.bind(this));
- };
-
- /**
- * Callback function for launch error
- */
+ };
+
+ /**
+ * Callback function for launch error
+ */
CastPlayer.prototype.onLaunchError = function () {
- console.log("chromecast launch error");
- this.deviceState = DEVICE_STATE.ERROR;
-
+ console.log("chromecast launch error");
+ this.deviceState = DEVICE_STATE.ERROR;
+
Dashboard.alert({
-
- title: Globalize.translate("Error"),
+
+ title: Globalize.translate("Error"),
message: Globalize.translate("ErrorLaunchingChromecast")
-
- });
-
+
+ });
+
MediaController.removeActivePlayer(PlayerName);
- };
-
- /**
- * Stops the running receiver application associated with the session.
- */
+ };
+
+ /**
+ * Stops the running receiver application associated with the session.
+ */
CastPlayer.prototype.stopApp = function () {
- this.session.stop(this.onStopAppSuccess.bind(this, 'Session stopped'),
+ this.session.stop(this.onStopAppSuccess.bind(this, 'Session stopped'),
this.errorHandler);
-
- };
-
- /**
- * Callback function for stop app success
- */
+
+ };
+
+ /**
+ * Callback function for stop app success
+ */
CastPlayer.prototype.onStopAppSuccess = function (message) {
- console.log(message);
- this.deviceState = DEVICE_STATE.IDLE;
- this.castPlayerState = PLAYER_STATE.IDLE;
- this.currentMediaSession = null;
+ console.log(message);
+ this.deviceState = DEVICE_STATE.IDLE;
+ this.castPlayerState = PLAYER_STATE.IDLE;
+ this.currentMediaSession = null;
clearInterval(this.timer);
- };
-
- /**
- * Loads media into a running receiver application
- * @param {Number} mediaIndex An index number to indicate current media content
- */
- CastPlayer.prototype.loadMedia = function (userId, options, command) {
-
+ };
+
+ /**
+ * Loads media into a running receiver application
+ * @param {Number} mediaIndex An index number to indicate current media content
+ */
+ CastPlayer.prototype.loadMedia = function (options, command) {
+
if (!this.session) {
- console.log("no session");
+ console.log("no session");
return;
}
- options.userId = userId;
-
var message = {
- playOptions: options,
- command: command
- };
-
- this.session.sendMessage('urn:x-cast:com.google.cast.sample.playlist', JSON.stringify(message));
- };
-
- /**
- * Callback function for loadMedia success
- * @param {Object} mediaSession A new media object.
- */
+ options: options,
+ command: command,
+
+ userId: Dashboard.getCurrentUserId(),
+ deviceId: ApiClient.deviceId(),
+ accessToken: ApiClient.accessToken(),
+ serverAddress: ApiClient.serverAddress()
+ };
+
+ message = JSON.stringify(message);
+ //console.log(message);
+
+ this.session.sendMessage(messageNamespace, message, this.onPlayCommandSuccess.bind(this), this.errorHandler);
+ };
+
+ CastPlayer.prototype.onPlayCommandSuccess = function() {
+ console.log('Play command was sent ok.');
+ };
+
+ /**
+ * Callback function for loadMedia success
+ * @param {Object} mediaSession A new media object.
+ */
CastPlayer.prototype.onMediaDiscovered = function (how, mediaSession) {
-
- console.log("chromecast new media session ID:" + mediaSession.mediaSessionId + ' (' + how + ')');
- this.currentMediaSession = mediaSession;
- this.currentMediaTime = mediaSession.currentTime;
-
+
+ console.log("chromecast new media session ID:" + mediaSession.mediaSessionId + ' (' + how + ')');
+ this.currentMediaSession = mediaSession;
+ this.currentMediaTime = mediaSession.currentTime;
+
if (how == 'loadMedia') {
- this.castPlayerState = PLAYER_STATE.PLAYING;
- clearInterval(this.timer);
+ this.castPlayerState = PLAYER_STATE.PLAYING;
+ clearInterval(this.timer);
this.startProgressTimer();
- }
-
+ }
+
if (how == 'activeSession') {
this.castPlayerState = mediaSession.playerState;
- }
-
- if (this.castPlayerState == PLAYER_STATE.PLAYING) {
- // start progress timer
+ }
+
+ if (this.castPlayerState == PLAYER_STATE.PLAYING) {
+ // start progress timer
this.startProgressTimer();
- }
-
- this.currentMediaSession.addUpdateListener(this.mediaStatusUpdateHandler);
+ }
+
+ this.currentMediaSession.addUpdateListener(this.mediaStatusUpdateHandler);
this.currentMediaDuration = mediaSession.media.duration * 10000000;
- };
-
- /**
- * Callback function when media load returns error
- */
+ };
+
+ /**
+ * Callback function when media load returns error
+ */
CastPlayer.prototype.onLoadMediaError = function (e) {
- console.log("chromecast media error");
+ console.log("chromecast media error");
this.castPlayerState = PLAYER_STATE.IDLE;
- };
-
- /**
- * Callback function for media status update from receiver
- * @param {!Boolean} e true/false
- */
+ };
+
+ /**
+ * Callback function for media status update from receiver
+ * @param {!Boolean} e true/false
+ */
CastPlayer.prototype.onMediaStatusUpdate = function (e) {
if (e == false) {
- this.currentMediaTime = 0;
+ this.currentMediaTime = 0;
this.castPlayerState = PLAYER_STATE.IDLE;
- }
- console.log("chromecast updating media");
+ }
+ console.log("chromecast updating media");
this.updateProgressBarByTimer();
- };
-
- /**
- * Helper function
- * Increment media current position by 1 second
- */
+ };
+
+ /**
+ * Helper function
+ * Increment media current position by 1 second
+ */
CastPlayer.prototype.incrementMediaTime = function () {
if (this.castPlayerState == PLAYER_STATE.PLAYING) {
if (this.currentMediaTime < this.currentMediaDuration) {
- this.currentMediaTime += 1;
+ this.currentMediaTime += 1;
this.updateProgressBarByTimer();
- }
+ }
else {
- this.currentMediaTime = 0;
+ this.currentMediaTime = 0;
clearInterval(this.timer);
}
}
- };
-
- /**
- * Play media in Cast mode
- */
+ };
+
+ /**
+ * Play media in Cast mode
+ */
CastPlayer.prototype.playMedia = function () {
-
+
if (!this.currentMediaSession) {
return;
- }
-
+ }
+
switch (this.castPlayerState) {
- case PLAYER_STATE.LOADED:
- case PLAYER_STATE.PAUSED:
- this.currentMediaSession.play(null,
- this.mediaCommandSuccessCallback.bind(this, "playing started for " + this.currentMediaSession.sessionId),
- this.errorHandler);
- this.currentMediaSession.addUpdateListener(this.mediaStatusUpdateHandler);
- this.castPlayerState = PLAYER_STATE.PLAYING;
- // start progress timer
- clearInterval(this.timer);
- this.startProgressTimer();
- break;
- case PLAYER_STATE.IDLE:
- case PLAYER_STATE.LOADING:
- case PLAYER_STATE.STOPPED:
- this.loadMedia();
- this.currentMediaSession.addUpdateListener(this.mediaStatusUpdateHandler);
- this.castPlayerState = PLAYER_STATE.PLAYING;
- break;
- default:
+ case PLAYER_STATE.LOADED:
+ case PLAYER_STATE.PAUSED:
+ this.currentMediaSession.play(null,
+ this.mediaCommandSuccessCallback.bind(this, "playing started for " + this.currentMediaSession.sessionId),
+ this.errorHandler);
+ this.currentMediaSession.addUpdateListener(this.mediaStatusUpdateHandler);
+ this.castPlayerState = PLAYER_STATE.PLAYING;
+ // start progress timer
+ clearInterval(this.timer);
+ this.startProgressTimer();
+ break;
+ case PLAYER_STATE.IDLE:
+ case PLAYER_STATE.LOADING:
+ case PLAYER_STATE.STOPPED:
+ this.loadMedia();
+ this.currentMediaSession.addUpdateListener(this.mediaStatusUpdateHandler);
+ this.castPlayerState = PLAYER_STATE.PLAYING;
+ break;
+ default:
break;
}
- };
-
- /**
- * Pause media playback in Cast mode
- */
+ };
+
+ /**
+ * Pause media playback in Cast mode
+ */
CastPlayer.prototype.pauseMedia = function () {
-
+
if (!this.currentMediaSession) {
return;
- }
-
+ }
+
if (this.castPlayerState == PLAYER_STATE.PLAYING) {
- this.castPlayerState = PLAYER_STATE.PAUSED;
- this.currentMediaSession.pause(null,
- this.mediaCommandSuccessCallback.bind(this, "paused " + this.currentMediaSession.sessionId),
- this.errorHandler);
+ this.castPlayerState = PLAYER_STATE.PAUSED;
+ this.currentMediaSession.pause(null,
+ this.mediaCommandSuccessCallback.bind(this, "paused " + this.currentMediaSession.sessionId),
+ this.errorHandler);
clearInterval(this.timer);
}
- };
-
- /**
- * Stop CC playback
- */
+ };
+
+ /**
+ * Stop CC playback
+ */
CastPlayer.prototype.stopMedia = function () {
-
+
if (!this.currentMediaSession) {
return;
- }
-
- this.currentMediaSession.stop(null,
- this.mediaCommandSuccessCallback.bind(this, "stopped " + this.currentMediaSession.sessionId),
- this.errorHandler);
- this.castPlayerState = PLAYER_STATE.STOPPED;
+ }
+
+ this.currentMediaSession.stop(null,
+ this.mediaCommandSuccessCallback.bind(this, "stopped " + this.currentMediaSession.sessionId),
+ this.errorHandler);
+ this.castPlayerState = PLAYER_STATE.STOPPED;
clearInterval(this.timer);
- };
-
- /**
- * Set media volume in Cast mode
- * @param {Boolean} mute A boolean
- */
+ };
+
+ /**
+ * Set media volume in Cast mode
+ * @param {Boolean} mute A boolean
+ */
CastPlayer.prototype.setReceiverVolume = function (mute, vol) {
-
+
if (!this.currentMediaSession) {
return;
- }
-
+ }
+
if (!mute) {
- this.currentVolume = vol || 1;
- this.session.setReceiverVolumeLevel(this.currentVolume,
- this.mediaCommandSuccessCallback.bind(this),
- this.errorHandler);
- }
- else {
- this.session.setReceiverMuted(true,
- this.mediaCommandSuccessCallback.bind(this),
+ this.currentVolume = vol || 1;
+ this.session.setReceiverVolumeLevel(this.currentVolume,
+ this.mediaCommandSuccessCallback.bind(this),
this.errorHandler);
}
- };
-
- /**
- * Toggle mute CC
- */
+ else {
+ this.session.setReceiverMuted(true,
+ this.mediaCommandSuccessCallback.bind(this),
+ this.errorHandler);
+ }
+ };
+
+ /**
+ * Toggle mute CC
+ */
CastPlayer.prototype.toggleMute = function () {
if (this.audio == true) {
this.mute();
- }
+ }
else {
this.unMute();
}
- };
-
- /**
- * Mute CC
- */
+ };
+
+ /**
+ * Mute CC
+ */
CastPlayer.prototype.mute = function () {
- this.audio = false;
+ this.audio = false;
this.setReceiverVolume(true);
- };
-
- /**
- * Unmute CC
- */
+ };
+
+ /**
+ * Unmute CC
+ */
CastPlayer.prototype.unMute = function () {
- this.audio = true;
+ this.audio = true;
this.setReceiverVolume(false);
- };
-
-
- /**
- * media seek function in either Cast or local mode
- * @param {Event} e An event object from seek
- */
+ };
+
+
+ /**
+ * media seek function in either Cast or local mode
+ * @param {Event} e An event object from seek
+ */
CastPlayer.prototype.seekMedia = function (event) {
- var pos = parseInt(event);
-
- var curr = pos / 10000000;
-
+ var pos = parseInt(event);
+
+ var curr = pos / 10000000;
+
if (this.castPlayerState != PLAYER_STATE.PLAYING && this.castPlayerState != PLAYER_STATE.PAUSED) {
return;
- }
-
- this.currentMediaTime = curr;
- console.log('Seeking ' + this.currentMediaSession.sessionId + ':' +
- this.currentMediaSession.mediaSessionId + ' to ' + curr);
- var request = new chrome.cast.media.SeekRequest();
- request.currentTime = this.currentMediaTime;
- this.currentMediaSession.seek(request,
- this.onSeekSuccess.bind(this, 'media seek done'),
- this.errorHandler);
+ }
+
+ this.currentMediaTime = curr;
+ console.log('Seeking ' + this.currentMediaSession.sessionId + ':' +
+ this.currentMediaSession.mediaSessionId + ' to ' + curr);
+ var request = new chrome.cast.media.SeekRequest();
+ request.currentTime = this.currentMediaTime;
+ this.currentMediaSession.seek(request,
+ this.onSeekSuccess.bind(this, 'media seek done'),
+ this.errorHandler);
this.castPlayerState = PLAYER_STATE.SEEKING;
- };
-
- /**
- * Callback function for seek success
- * @param {String} info A string that describe seek event
- */
+ };
+
+ /**
+ * Callback function for seek success
+ * @param {String} info A string that describe seek event
+ */
CastPlayer.prototype.onSeekSuccess = function (info) {
- console.log(info);
+ console.log(info);
this.castPlayerState = PLAYER_STATE.PLAYING;
- };
-
- /**
- * Callback function for media command success
- */
+ };
+
+ /**
+ * Callback function for media command success
+ */
CastPlayer.prototype.mediaCommandSuccessCallback = function (info, e) {
console.log(info);
- };
-
- /**
- * Update progress bar when there is a media status update
- * @param {Object} e An media status update object
- */
+ };
+
+ /**
+ * Update progress bar when there is a media status update
+ * @param {Object} e An media status update object
+ */
CastPlayer.prototype.updateProgressBar = function (e) {
+
+ console.log('CastPlayer.updateProgressBar');
+
if (e.idleReason == 'FINISHED' && e.playerState == 'IDLE') {
- clearInterval(this.timer);
- this.castPlayerState = PLAYER_STATE.STOPPED;
+ clearInterval(this.timer);
+ this.castPlayerState = PLAYER_STATE.STOPPED;
if (e.idleReason == 'FINISHED') {
$(this).trigger("/playback/complete", e);
}
- }
- else {
- var p = Number(e.currentTime / this.currentMediaSession.media.duration + 1).toFixed(3);
- this.progressFlag = false;
- setTimeout(this.setProgressFlag.bind(this), 1000); // don't update progress in 1 second
}
- };
-
- /**
- * Set progressFlag with a timeout of 1 second to avoid UI update
- * until a media status update from receiver
- */
+ else {
+ var p = Number(e.currentTime / this.currentMediaSession.media.duration + 1).toFixed(3);
+ this.progressFlag = false;
+ setTimeout(this.setProgressFlag.bind(this), 1000); // don't update progress in 1 second
+ }
+ };
+
+ /**
+ * Set progressFlag with a timeout of 1 second to avoid UI update
+ * until a media status update from receiver
+ */
CastPlayer.prototype.setProgressFlag = function () {
this.progressFlag = true;
- };
-
- /**
- * Update progress bar based on timer
- */
+ };
+
+ /**
+ * Update progress bar based on timer
+ */
CastPlayer.prototype.updateProgressBarByTimer = function () {
+
+ console.log('CastPlayer.updateProgressBarByTimer');
+
if (!this.currentMediaTime) {
this.currentMediaDuration = this.session.media[0].currentTime;
- }
-
+ }
+
if (!this.currentMediaDuration) {
this.currentMediaDuration = this.session.media[0].media.customData.runTimeTicks;
- }
-
- var pp = 0;
+ }
+
+ var pp = 0;
if (this.currentMediaDuration > 0) {
pp = Number(this.currentMediaTime / this.currentMediaDuration).toFixed(3);
- }
-
- if (this.progressFlag) {
- // don't update progress if it's been updated on media status update event
- $(this).trigger("/playback/update",
+ }
+
+ if (this.progressFlag) {
+ // don't update progress if it's been updated on media status update event
+ $(this).trigger("/playback/update",
[{
- positionTicks: this.currentMediaTime * 10000000,
+ positionTicks: this.currentMediaTime * 10000000,
runtimeTicks: this.currentMediaDuration
}]);
- }
-
+ }
+
if (pp > 100 || this.castPlayerState == PLAYER_STATE.IDLE) {
- clearInterval(this.timer);
- this.deviceState = DEVICE_STATE.IDLE;
- this.castPlayerState = PLAYER_STATE.IDLE;
+ clearInterval(this.timer);
+ this.deviceState = DEVICE_STATE.IDLE;
+ this.castPlayerState = PLAYER_STATE.IDLE;
$(this).trigger("/playback/complete", true);
}
- };
-
- /**
- * @param {function} A callback function for the fucntion to start timer
- */
+ };
+
+ /**
+ * @param {function} A callback function for the fucntion to start timer
+ */
CastPlayer.prototype.startProgressTimer = function () {
if (this.timer) {
- clearInterval(this.timer);
+ clearInterval(this.timer);
this.timer = null;
- }
-
- // start progress timer
+ }
+
+ // start progress timer
this.timer = setInterval(this.incrementMediaTimeHandler, this.timerStep);
- };
-
- // Create Cast Player
- var castPlayer = new CastPlayer();
-
- function getCustomData(item, mediaSourceId, startTimeTicks) {
-
- return {
-
- serverAddress: ApiClient.serverAddress(),
- itemId: item.Id,
- userId: Dashboard.getCurrentUserId(),
- deviceName: ApiClient.deviceName(),
- //deviceId: ApiClient.deviceId(),
- startTimeTicks: startTimeTicks || 0,
- runTimeTicks: item.RunTimeTicks
- };
-
- }
-
- function translateItemsForPlayback(items) {
+ };
- var deferred = $.Deferred();
-
- var firstItem = items[0];
- var promise;
-
- if (firstItem.Type == "Playlist") {
-
- promise = self.getItemsForPlayback({
- ParentId: firstItem.Id,
- });
- }
- else if (firstItem.Type == "MusicArtist") {
-
- promise = self.getItemsForPlayback({
- Artists: firstItem.Name,
- Filters: "IsNotFolder",
- Recursive: true,
- SortBy: "SortName",
- MediaTypes: "Audio"
- });
-
- }
- else if (firstItem.Type == "MusicGenre") {
-
- promise = self.getItemsForPlayback({
- Genres: firstItem.Name,
- Filters: "IsNotFolder",
- Recursive: true,
- SortBy: "SortName",
- MediaTypes: "Audio"
- });
- }
- else if (firstItem.IsFolder) {
-
- promise = self.getItemsForPlayback({
- ParentId: firstItem.Id,
- Filters: "IsNotFolder",
- Recursive: true,
- SortBy: "SortName",
- MediaTypes: "Audio,Video"
- });
- }
-
- if (promise) {
- promise.done(function (result) {
-
- deferred.resolveWith(null, [result.Items]);
- });
- } else {
- deferred.resolveWith(null, [items]);
- }
-
- return deferred.promise();
- }
+ // Create Cast Player
+ var castPlayer = new CastPlayer();
function chromecastPlayer() {
-
- var self = this;
-
- var getItemFields = "MediaSources,Chapters";
-
- self.name = PlayerName;
-
- self.isPaused = false;
-
- self.isMuted = false;
-
- self.positionTicks = 0;
-
- self.runtimeTicks = 0;
-
- $(castPlayer).on("/playback/complete", function (e) {
-
- var state = self.getPlayerStateInternal();
-
- $(self).trigger("playbackstop", [state]);
-
- });
-
- $(castPlayer).on("/playback/update", function (e, data) {
-
- self.positionTicks = data.positionTicks;
- self.runtimeTicks = data.runtimeTicks;
-
- var state = self.getPlayerStateInternal();
-
- $(self).trigger("positionchange", [state]);
- });
-
+
+ var self = this;
+
+ var getItemFields = "MediaSources,Chapters";
+
+ // MediaController needs this
+ self.name = PlayerName;
+
+ self.isPaused = false;
+
+ self.isMuted = false;
+
+ self.positionTicks = 0;
+
+ self.runtimeTicks = 0;
+
+ self.getItemsForPlayback = function (query) {
+
+ var userId = Dashboard.getCurrentUserId();
+
+ query.Limit = query.Limit || 100;
+ query.Fields = getItemFields;
+ query.ExcludeLocationTypes = "Virtual";
+
+ return ApiClient.getItems(userId, query);
+ };
+
+ self.translateItemsForPlayback = function(items) {
+
+ var deferred = $.Deferred();
+
+ var firstItem = items[0];
+ var promise;
+
+ if (firstItem.Type == "Playlist") {
+
+ promise = self.getItemsForPlayback({
+ ParentId: firstItem.Id,
+ });
+ } else if (firstItem.Type == "MusicArtist") {
+
+ promise = self.getItemsForPlayback({
+ Artists: firstItem.Name,
+ Filters: "IsNotFolder",
+ Recursive: true,
+ SortBy: "SortName",
+ MediaTypes: "Audio"
+ });
+
+ } else if (firstItem.Type == "MusicGenre") {
+
+ promise = self.getItemsForPlayback({
+ Genres: firstItem.Name,
+ Filters: "IsNotFolder",
+ Recursive: true,
+ SortBy: "SortName",
+ MediaTypes: "Audio"
+ });
+ } else if (firstItem.IsFolder) {
+
+ promise = self.getItemsForPlayback({
+ ParentId: firstItem.Id,
+ Filters: "IsNotFolder",
+ Recursive: true,
+ SortBy: "SortName",
+ MediaTypes: "Audio,Video"
+ });
+ }
+
+ if (promise) {
+ promise.done(function(result) {
+
+ deferred.resolveWith(null, [result.Items]);
+ });
+ } else {
+ deferred.resolveWith(null, [items]);
+ }
+
+ return deferred.promise();
+ };
+
+ //$(castPlayer).on("/playback/complete", function (e) {
+
+ // var state = self.getPlayerStateInternal();
+
+ // $(self).trigger("playbackstop", [state]);
+
+ //});
+
+ //$(castPlayer).on("/playback/update", function (e, data) {
+
+ // self.positionTicks = data.positionTicks;
+ // self.runtimeTicks = data.runtimeTicks;
+
+ // var state = self.getPlayerStateInternal();
+
+ // $(self).trigger("positionchange", [state]);
+ //});
+
self.play = function (options) {
Dashboard.getCurrentUser().done(function (user) {
if (options.items) {
- translateItemsForPlayback(options.items).done(function (items) {
+ self.translateItemsForPlayback(options.items).done(function (items) {
self.playWithIntros(items, options, user);
});
@@ -700,7 +731,7 @@
}).done(function (result) {
- translateItemsForPlayback(result.Items).done(function (items) {
+ self.translateItemsForPlayback(result.Items).done(function (items) {
self.playWithIntros(items, options, user);
});
@@ -716,10 +747,10 @@
var firstItem = items[0];
- if (options.startPositionTicks || firstItem.MediaType !== 'Video' || !self.canAutoPlayVideo()) {
+ if (options.startPositionTicks || firstItem.MediaType !== 'Video') {
self.playWithCommand(options, 'PlayNow');
-
- }
+ return;
+ }
ApiClient.getJSON(ApiClient.getUrl('Users/' + user.Id + '/Items/' + firstItem.Id + '/Intros')).done(function (intros) {
@@ -731,19 +762,29 @@
self.playWithCommand = function (options, command) {
- castPlayer.loadMedia(Dashboard.getCurrentUserId(), options, command);
- };
-
+ if (!options.items) {
+ ApiClient.getItem(Dashboard.getCurrentUserId(), options.ids[0]).done(function(item) {
+
+ options.items = [item];
+ self.playWithCommand(options, command);
+ });
+
+ return;
+ }
+
+ castPlayer.loadMedia(options, command);
+ };
+
self.unpause = function () {
- self.isPaused = !self.isPaused;
+ self.isPaused = !self.isPaused;
castPlayer.playMedia();
- };
-
+ };
+
self.pause = function () {
- self.isPaused = true;
+ self.isPaused = true;
castPlayer.pauseMedia();
- };
-
+ };
+
self.shuffle = function (id) {
var userId = Dashboard.getCurrentUserId();
@@ -846,183 +887,185 @@
});
};
-
+
self.canQueueMediaType = function (mediaType) {
return mediaType == "Audio";
- };
-
+ };
+
self.queue = function (options) {
self.playWithCommnd(options, 'PlayLast');
- };
-
+ };
+
self.queueNext = function (options) {
self.playWithCommand(options, 'PlayNext');
- };
-
+ };
+
self.stop = function () {
castPlayer.stopMedia();
- };
-
+ };
+
self.displayContent = function (options) {
-
- };
-
+
+ };
+
self.mute = function () {
- self.isMuted = true;
+ self.isMuted = true;
castPlayer.mute();
- };
-
+ };
+
self.unMute = function () {
- self.isMuted = false;
+ self.isMuted = false;
castPlayer.unMute();
- };
-
+ };
+
self.toggleMute = function () {
castPlayer.toggleMute();
- };
-
+ };
+
self.getTargets = function () {
-
- var targets = [];
-
+
+ var targets = [];
+
if (castPlayer.hasReceivers) {
targets.push(self.getCurrentTargetInfo());
- }
-
+ }
+
return targets;
-
- };
-
+
+ };
+
self.getCurrentTargetInfo = function () {
-
- var appName = null;
+
+ var appName = null;
+
if (castPlayer.session && castPlayer.session.receiver && castPlayer.session.receiver.friendlyName) {
appName = castPlayer.session.receiver.friendlyName;
- }
-
+ }
+
return {
- name: PlayerName,
- id: PlayerName,
- playerName: self.name, // TODO: PlayerName == self.name, so do we need to use either/or?
- playableMediaTypes: ["Audio", "Video"],
- isLocalPlayer: false,
- appName: appName,
- supportedCommands: ["VolumeUp",
- "VolumeDown",
- "Mute",
- "Unmute",
- "ToggleMute",
- "SetVolume",
+ name: PlayerName,
+ id: PlayerName,
+ playerName: PlayerName,
+ playableMediaTypes: ["Audio", "Video"],
+ isLocalPlayer: false,
+ appName: PlayerName,
+ deviceName: appName,
+ supportedCommands: ["VolumeUp",
+ "VolumeDown",
+ "Mute",
+ "Unmute",
+ "ToggleMute",
+ "SetVolume",
"DisplayContent"]
};
- };
-
+ };
+
self.seek = function (position) {
castPlayer.seekMedia(position);
- };
-
+ };
+
self.nextTrack = function () {
- };
-
+ };
+
self.previousTrack = function () {
- };
-
- self.beginPlayerUpdates = function () {
- // Setup polling here
- };
-
- self.endPlayerUpdates = function () {
- // Stop polling here
- };
-
+ };
+
+ self.beginPlayerUpdates = function () {
+ // Setup polling here
+ };
+
+ self.endPlayerUpdates = function () {
+ // Stop polling here
+ };
+
self.volumeDown = function () {
- var vol = castPlayer.volumeLevel - 0.02;
+ var vol = castPlayer.volumeLevel - 0.02;
castPlayer.setReceiverVolume(false, vol / 100);
- };
-
+ };
+
self.volumeUp = function () {
- var vol = castPlayer.volumeLevel + 0.02;
+ var vol = castPlayer.volumeLevel + 0.02;
castPlayer.setReceiverVolume(false, vol / 100);
- };
-
+ };
+
self.setVolume = function (vol) {
castPlayer.setReceiverVolume(false, vol / 100);
- };
-
+ };
+
self.getPlayerState = function () {
-
- var deferred = $.Deferred();
-
- var result = self.getPlayerStateInternal();
-
- deferred.resolveWith(null, [result]);
-
+
+ var deferred = $.Deferred();
+
+ var result = self.getPlayerStateInternal();
+
+ deferred.resolveWith(null, [result]);
+
return deferred.promise();
- };
-
+ };
+
self.getPlayerStateInternal = function () {
-
+
var state = {
PlayState: {
-
- CanSeek: self.runtimeTicks && self.positionTicks > 0,
- PositionTicks: self.positionTicks,
- VolumeLevel: castPlayer.currentVolume * 100,
- IsPaused: self.isPaused,
- IsMuted: self.isMuted
-
- // TODO: Implement
- // AudioStreamIndex: null,
- // SubtitleStreamIndex: null,
- // PlayMethod: 'DirectStream' or 'Transcode'
+
+ CanSeek: self.runtimeTicks && self.positionTicks > 0,
+ PositionTicks: self.positionTicks,
+ VolumeLevel: castPlayer.currentVolume * 100,
+ IsPaused: self.isPaused,
+ IsMuted: self.isMuted
+
+ // TODO: Implement
+ // AudioStreamIndex: null,
+ // SubtitleStreamIndex: null,
+ // PlayMethod: 'DirectStream' or 'Transcode'
}
- };
-
- // TODO: Implement
- var isPlaying = false;
-
- if (isPlaying) {
-
- //state.PlayState.MediaSourceId = 'xxx';
-
+ };
+
+ // TODO: Implement
+ var isPlaying = false;
+
+ if (isPlaying) {
+
+ //state.PlayState.MediaSourceId = 'xxx';
+
state.NowPlayingItem = {
-
- RunTimeTicks: self.runtimeTicks,
+
+ RunTimeTicks: self.runtimeTicks,
Name: 'Chromecast'
- };
-
- var nowPlayingItem = state.NowPlayingItem;
-
- // TODO: Fill in these properties using chromecast mediainfo and/or custom data
- //nowPlayingItem.Id = item.Id;
- //nowPlayingItem.MediaType = item.MediaType;
- //nowPlayingItem.Type = item.Type;
- //nowPlayingItem.Name = item.Name;
-
- //nowPlayingItem.IndexNumber = item.IndexNumber;
- //nowPlayingItem.IndexNumberEnd = item.IndexNumberEnd;
- //nowPlayingItem.ParentIndexNumber = item.ParentIndexNumber;
- //nowPlayingItem.ProductionYear = item.ProductionYear;
- //nowPlayingItem.PremiereDate = item.PremiereDate;
- //nowPlayingItem.SeriesName = item.SeriesName;
- //nowPlayingItem.Album = item.Album;
- //nowPlayingItem.Artists = item.Artists;
-
- }
-
+ };
+
+ var nowPlayingItem = state.NowPlayingItem;
+
+ // TODO: Fill in these properties using chromecast mediainfo and/or custom data
+ //nowPlayingItem.Id = item.Id;
+ //nowPlayingItem.MediaType = item.MediaType;
+ //nowPlayingItem.Type = item.Type;
+ //nowPlayingItem.Name = item.Name;
+
+ //nowPlayingItem.IndexNumber = item.IndexNumber;
+ //nowPlayingItem.IndexNumberEnd = item.IndexNumberEnd;
+ //nowPlayingItem.ParentIndexNumber = item.ParentIndexNumber;
+ //nowPlayingItem.ProductionYear = item.ProductionYear;
+ //nowPlayingItem.PremiereDate = item.PremiereDate;
+ //nowPlayingItem.SeriesName = item.SeriesName;
+ //nowPlayingItem.Album = item.Album;
+ //nowPlayingItem.Artists = item.Artists;
+
+ }
+
return state;
};
- }
-
- //MediaController.registerPlayer(new chromecastPlayer());
-
- //$(MediaController).on('playerchange', function () {
-
- // if (MediaController.getPlayerInfo().name == PlayerName) {
- // if (castPlayer.deviceState != DEVICE_STATE.ACTIVE && castPlayer.isInitialized) {
- // castPlayer.launchApp();
- // }
- // }
- //});
-
+ }
+
+ MediaController.registerPlayer(new chromecastPlayer());
+
+ $(MediaController).on('playerchange', function () {
+
+ if (MediaController.getPlayerInfo().name == PlayerName) {
+ if (castPlayer.deviceState != DEVICE_STATE.ACTIVE && castPlayer.isInitialized) {
+ castPlayer.launchApp();
+ }
+ }
+ });
+
})(window, window.chrome, console);
\ No newline at end of file
diff --git a/dashboard-ui/scripts/edititemimages.js b/dashboard-ui/scripts/edititemimages.js
index b05e6b0407..92855e4648 100644
--- a/dashboard-ui/scripts/edititemimages.js
+++ b/dashboard-ui/scripts/edititemimages.js
@@ -310,7 +310,7 @@
html += '
';
- html += '
';
+ html += '
';
html += '
';
diff --git a/dashboard-ui/scripts/extensions.js b/dashboard-ui/scripts/extensions.js
index 4710c46ae2..712980d8b4 100644
--- a/dashboard-ui/scripts/extensions.js
+++ b/dashboard-ui/scripts/extensions.js
@@ -330,7 +330,7 @@ function parseISO8601Date(s, options) {
}
return new Date(ms);
-};
+}
// jqm.page.params.js - version 0.1
// Copyright (c) 2011, Kin Blas
diff --git a/dashboard-ui/scripts/itembynamedetailpage.js b/dashboard-ui/scripts/itembynamedetailpage.js
index aebfffc85e..fc6e2c7cbe 100644
--- a/dashboard-ui/scripts/itembynamedetailpage.js
+++ b/dashboard-ui/scripts/itembynamedetailpage.js
@@ -70,6 +70,8 @@
currentItem = item;
+ Backdrops.setBackdrops(page, [item]);
+
renderHeader(page, item, context);
var name = item.Name;
@@ -97,7 +99,7 @@
var editImagesHref = user.Configuration.IsAdministrator ? 'edititemimages.html' + editQuery : null;
- $('#itemImage', page).html(LibraryBrowser.getDetailImageHtml(item, editImagesHref));
+ $('#itemImage', page).html(LibraryBrowser.getDetailImageHtml(item, editImagesHref, true));
if (user.Configuration.IsAdministrator && item.LocationType !== "Offline") {
$('.btnEdit', page).show();
@@ -162,49 +164,49 @@
if (item.MovieCount) {
html += '
';
- html += '
';
+ html += '
';
}
if (item.SeriesCount) {
html += '
';
- html += '
';
+ html += '
';
}
if (item.EpisodeCount) {
html += '
';
- html += '
';
+ html += '
';
}
if (item.TrailerCount) {
html += '
';
- html += '
';
+ html += '
';
}
if (item.GameCount) {
html += '
';
- html += '
';
+ html += '
';
}
if (item.AlbumCount) {
html += '
';
- html += '
';
+ html += '
';
}
if (item.SongCount) {
html += '
';
- html += '
';
+ html += '
';
}
if (item.MusicVideoCount) {
html += '
';
- html += '
';
+ html += '
';
}
html += '';
@@ -321,7 +323,7 @@
function renderDetails(page, item, context) {
- LibraryBrowser.renderDetailPageBackdrop(page, item);
+ //LibraryBrowser.renderDetailPageBackdrop(page, item);
LibraryBrowser.renderOverview($('.itemOverview', page), item);
renderUserDataIcons(page, item);
@@ -472,22 +474,17 @@
}
else if (query.IncludeItemTypes == "MusicAlbum") {
- html = LibraryBrowser.getPosterViewHtml({
+ html = LibraryBrowser.getListViewHtml({
items: result.Items,
- shape: "square",
- context: 'music',
- showTitle: true,
- showParentTitle: true
+ smallIcon: true
});
}
else {
- html = LibraryBrowser.getPosterViewHtml({
+ html = LibraryBrowser.getListViewHtml({
items: result.Items,
- shape: "square",
- showTitle: true,
- centerText: true
+ smallIcon: true
});
}
diff --git a/dashboard-ui/scripts/itemdetailpage.js b/dashboard-ui/scripts/itemdetailpage.js
index ff3a0369b3..776d54763d 100644
--- a/dashboard-ui/scripts/itemdetailpage.js
+++ b/dashboard-ui/scripts/itemdetailpage.js
@@ -726,7 +726,9 @@
$('#childrenContent', page).html(LibraryBrowser.getListViewHtml({
items: result.Items,
- smallIcon: true
+ smallIcon: true,
+ showIndex: true,
+ index: 'disc'
})).trigger('create').createCardMenus();
diff --git a/dashboard-ui/scripts/librarybrowser.js b/dashboard-ui/scripts/librarybrowser.js
index 4147354b1e..ea5534e9b2 100644
--- a/dashboard-ui/scripts/librarybrowser.js
+++ b/dashboard-ui/scripts/librarybrowser.js
@@ -27,7 +27,7 @@
getDefaultItemsView: function (view, mobileView) {
- return view;
+ return $.browser.mobile ? mobileView : view;
},
@@ -578,9 +578,14 @@
},
- getListViewIndex: function (item, sortBy) {
+ getListViewIndex: function (item, options) {
- sortBy = (sortBy || '').toLowerCase();
+ if (options.index == 'disc') {
+
+ return item.ParentIndexNumber == null ? '' : 'Disc ' + item.ParentIndexNumber;
+ }
+
+ var sortBy = (options.sortBy || '').toLowerCase();
var code, name;
if (sortBy.indexOf('sortname') == 0) {
@@ -666,7 +671,8 @@
var html = '';
if (options.showIndex !== false) {
- var itemGroupTitle = LibraryBrowser.getListViewIndex(item, options.sortBy);
+
+ var itemGroupTitle = LibraryBrowser.getListViewIndex(item, options);
if (itemGroupTitle != groupTitle) {
@@ -2026,7 +2032,7 @@
});
},
- getDetailImageHtml: function (item, href) {
+ getDetailImageHtml: function (item, href, preferThumb) {
var imageTags = item.ImageTags || {};
@@ -2040,7 +2046,15 @@
var imageHeight = 280;
- if (imageTags.Primary) {
+ if (preferThumb && imageTags.Thumb) {
+
+ url = ApiClient.getScaledImageUrl(item.Id, {
+ type: "Thumb",
+ maxHeight: imageHeight,
+ tag: item.ImageTags.Thumb
+ });
+ }
+ else if (imageTags.Primary) {
url = ApiClient.getScaledImageUrl(item.Id, {
type: "Primary",
@@ -2263,6 +2277,12 @@
$(this).attr("target", "_blank");
});
+ if (overview) {
+ elem.removeClass('empty');
+ } else {
+ elem.addClass('empty');
+ }
+
},
renderStudios: function (elem, item, context) {
diff --git a/dashboard-ui/scripts/librarymenu.js b/dashboard-ui/scripts/librarymenu.js
index 62d142e823..35b17d0b73 100644
--- a/dashboard-ui/scripts/librarymenu.js
+++ b/dashboard-ui/scripts/librarymenu.js
@@ -254,7 +254,8 @@
} else {
$('.btnCast').removeClass('btnDefaultCast').addClass('btnActiveCast');
- $('.headerSelectedPlayer').html(info.deviceName || info.name);
+
+ $('.headerSelectedPlayer').html((info.deviceName || info.name));
}
}
diff --git a/dashboard-ui/scripts/livetvguide.js b/dashboard-ui/scripts/livetvguide.js
index 2683edf63c..bb92ded4e7 100644
--- a/dashboard-ui/scripts/livetvguide.js
+++ b/dashboard-ui/scripts/livetvguide.js
@@ -396,6 +396,10 @@
start.setHours(0, 0, 0, 0);
end.setHours(0, 0, 0, 0);
+ if (start.getTime() >= end.getTime()) {
+ end.setDate(start.getDate() + 1);
+ }
+
start = new Date(Math.max(today, start));
var html = '';
@@ -417,7 +421,10 @@
var val = elem.val();
var date = new Date();
- date.setTime(parseInt(val));
+
+ if (val) {
+ date.setTime(parseInt(val));
+ }
changeDate(page, date);
}
diff --git a/dashboard-ui/scripts/mediacontroller.js b/dashboard-ui/scripts/mediacontroller.js
index e6ec325a33..a7bcd237b1 100644
--- a/dashboard-ui/scripts/mediacontroller.js
+++ b/dashboard-ui/scripts/mediacontroller.js
@@ -439,7 +439,7 @@
var mirror = (!target.isLocalPlayer && target.supportedCommands.indexOf('DisplayContent') != -1) ? 'true' : 'false';
- html += '
';
+ html += '
';
html += '