From 3f50019539f10d491bbb05c064fbf96e08676a7d Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Mon, 7 Apr 2014 09:26:48 -0700 Subject: [PATCH 01/25] Additional cast params --- ApiClient.js | 26 +++++++++++++++----------- dashboard-ui/scripts/chromecast.js | 14 ++++++++------ dashboard-ui/scripts/mediaplayer.js | 2 +- dashboard-ui/scripts/remotecontrol.js | 4 +++- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/ApiClient.js b/ApiClient.js index c937c28ee6..1a526d8a18 100644 --- a/ApiClient.js +++ b/ApiClient.js @@ -3846,7 +3846,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi * @param {String} userId * @param {String} itemId */ - self.reportPlaybackProgress = function (userId, itemId, mediaSourceId, positionTicks, isPaused, isMuted) { + self.reportPlaybackProgress = function (userId, itemId, mediaSourceId, params) { if (!userId) { throw new Error("null userId"); @@ -3862,25 +3862,29 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi var msgData = itemId; - msgData += "|" + (positionTicks == null ? "" : positionTicks); - msgData += "|" + (isPaused == null ? "" : isPaused); - msgData += "|" + (isMuted == null ? "" : isMuted); + msgData += "|" + (params.positionTicks == null ? "" : params.positionTicks); + msgData += "|" + (params.isPaused == null ? "" : params.isPaused); + msgData += "|" + (params.isMuted == null ? "" : params.isMuted); msgData += "|" + (mediaSourceId == null ? "" : mediaSourceId); + msgData += "|" + (params.audioStreamIndex == null ? "" : params.audioStreamIndex); + msgData += "|" + (params.subtitleStreamIndex == null ? "" : params.subtitleStreamIndex); + msgData += "|" + (params.volumeLevel == null ? "" : params.volumeLevel); + self.sendWebSocketMessage("PlaybackProgress", msgData); deferred.resolveWith(null, []); return deferred.promise(); } - var params = { - isPaused: isPaused, - isMuted: isMuted - }; + ////var params = { + //// isPaused: isPaused, + //// isMuted: isMuted + ////}; - if (positionTicks) { - params.positionTicks = positionTicks; - } + ////if (positionTicks) { + //// params.positionTicks = positionTicks; + ////} if (mediaSourceId) { params.mediaSourceId = mediaSourceId; diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js index d2b7f5d159..b39bf2d542 100644 --- a/dashboard-ui/scripts/chromecast.js +++ b/dashboard-ui/scripts/chromecast.js @@ -89,7 +89,7 @@ // v1 Id AE4DA10A // v2 Id 472F0435 - var applicationID = 'AE4DA10A'; + var applicationID = '472F0435'; // request session var sessionRequest = new chrome.cast.SessionRequest(applicationID); @@ -420,7 +420,7 @@ }; } - function getCustomData(item, mediaSourceId, startTimeTicks) { + function getCustomData(item, mediaSourceId, startTimeTicks, audioStreamIndex, subtitleStreamIndex) { return { @@ -429,7 +429,9 @@ userId: Dashboard.getCurrentUserId(), deviceName: ApiClient.deviceName(), //deviceId: ApiClient.deviceId(), - startTimeTicks: startTimeTicks || 0 + startTimeTicks: startTimeTicks || 0, + audioStreamIndex: audioStreamIndex, + subtitleStreamIndex: subtitleStreamIndex }; } @@ -613,7 +615,7 @@ var castMediaInfo = new chrome.cast.media.MediaInfo(streamUrl); - castMediaInfo.customData = getCustomData(item, mediaInfo.mediaSource.Id, startTimeTicks); + castMediaInfo.customData = getCustomData(item, mediaInfo.mediaSource.Id, startTimeTicks, audioStreamIndex, subtitleStreamIndex); castMediaInfo.metadata = getMetadata(item); if (mediaInfo.streamContainer == 'm3u8') { @@ -630,8 +632,8 @@ this.castPlayerState = PLAYER_STATE.LOADING; this.session.loadMedia(request, - this.onMediaDiscovered.bind(this, 'loadMedia'), - this.onLoadMediaError.bind(this)); + this.onMediaDiscovered.bind(this, 'loadMedia'), + this.onLoadMediaError.bind(this)); }; /** diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index 299a94e8ab..7916f36571 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -950,7 +950,7 @@ function sendProgressUpdate(itemId, mediaSourceId) { - ApiClient.reportPlaybackProgress(Dashboard.getCurrentUserId(), itemId, mediaSourceId, self.getCurrentTicks(), currentMediaElement.paused, currentMediaElement.volume == 0); + ApiClient.reportPlaybackProgress(Dashboard.getCurrentUserId(), itemId, mediaSourceId, { positionTicks: self.getCurrentTicks(), isPaused: currentMediaElement.paused, isMuted: currentMediaElement.volume == 0 }); } function clearProgressInterval() { diff --git a/dashboard-ui/scripts/remotecontrol.js b/dashboard-ui/scripts/remotecontrol.js index 35add5b195..ba622794f6 100644 --- a/dashboard-ui/scripts/remotecontrol.js +++ b/dashboard-ui/scripts/remotecontrol.js @@ -349,7 +349,7 @@ // don't display the current session sessions = sessions.filter(function (s) { - return s.DeviceId != deviceId && s.SupportsRemoteControl; + return s.DeviceId != deviceId && (s.SupportsRemoteControl || s.Client == "Chromecast"); }); var elem = $('#selectSession', popup); @@ -403,6 +403,8 @@ self.showMenu = function (options) { ApiClient.getSessions(sessionQuery).done(function (sessions) { + console.log("showMenu", sessions); + showMenu(sessions, options); }); From b7e743b6a433e1fe15a9f60e216d8f412644866e Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Mon, 7 Apr 2014 12:12:16 -0700 Subject: [PATCH 02/25] Undo some changes --- ApiClient.js | 22 +++++++++++----------- dashboard-ui/scripts/chromecast.js | 5 +++-- dashboard-ui/scripts/mediaplayer.js | 2 +- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/ApiClient.js b/ApiClient.js index 1a526d8a18..74f989fc07 100644 --- a/ApiClient.js +++ b/ApiClient.js @@ -3846,7 +3846,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi * @param {String} userId * @param {String} itemId */ - self.reportPlaybackProgress = function (userId, itemId, mediaSourceId, params) { + self.reportPlaybackProgress = function (userId, itemId, mediaSourceId, positionTicks, isPaused, isMuted) { if (!userId) { throw new Error("null userId"); @@ -3867,9 +3867,9 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi msgData += "|" + (params.isMuted == null ? "" : params.isMuted); msgData += "|" + (mediaSourceId == null ? "" : mediaSourceId); - msgData += "|" + (params.audioStreamIndex == null ? "" : params.audioStreamIndex); - msgData += "|" + (params.subtitleStreamIndex == null ? "" : params.subtitleStreamIndex); - msgData += "|" + (params.volumeLevel == null ? "" : params.volumeLevel); + ////msgData += "|" + (params.audioStreamIndex == null ? "" : params.audioStreamIndex); + ////msgData += "|" + (params.subtitleStreamIndex == null ? "" : params.subtitleStreamIndex); + ////msgData += "|" + (params.volumeLevel == null ? "" : params.volumeLevel); self.sendWebSocketMessage("PlaybackProgress", msgData); @@ -3877,14 +3877,14 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi return deferred.promise(); } - ////var params = { - //// isPaused: isPaused, - //// isMuted: isMuted - ////}; + var params = { + isPaused: isPaused, + isMuted: isMuted + }; - ////if (positionTicks) { - //// params.positionTicks = positionTicks; - ////} + if (positionTicks) { + params.positionTicks = positionTicks; + } if (mediaSourceId) { params.mediaSourceId = mediaSourceId; diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js index 4c0c593337..d233949fbc 100644 --- a/dashboard-ui/scripts/chromecast.js +++ b/dashboard-ui/scripts/chromecast.js @@ -643,8 +643,9 @@ this.castPlayerState = PLAYER_STATE.LOADING; this.session.loadMedia(request, - this.onMediaDiscovered.bind(this, 'loadMedia'), - this.onLoadMediaError.bind(this)); + this.onMediaDiscovered.bind(this, 'loadMedia'), + this.onLoadMediaError.bind(this) + ); }; /** diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index 5c67d97987..516c10cde1 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -961,7 +961,7 @@ function sendProgressUpdate(itemId, mediaSourceId) { - ApiClient.reportPlaybackProgress(Dashboard.getCurrentUserId(), itemId, mediaSourceId, { positionTicks: self.getCurrentTicks(), isPaused: currentMediaElement.paused, isMuted: currentMediaElement.volume == 0 }); + ApiClient.reportPlaybackProgress(Dashboard.getCurrentUserId(), itemId, mediaSourceId, self.getCurrentTicks(), currentMediaElement.paused, currentMediaElement.volume == 0); } function clearProgressInterval() { From 2365becc148fa8a1c519507b6ec7a3b21d530dc6 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Tue, 8 Apr 2014 11:22:03 -0700 Subject: [PATCH 03/25] Enabled lazy load of poster images This should make initial load of the movies page a little more responsive for larger libraries. This can be used on any page loading images. --- dashboard-ui/css/librarybrowser.css | 5 ++ dashboard-ui/scripts/librarybrowser.js | 13 +++- dashboard-ui/scripts/movies.js | 11 +++- .../thirdparty/jquery.unveil-custom.js | 62 +++++++++++++++++++ 4 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 dashboard-ui/thirdparty/jquery.unveil-custom.js diff --git a/dashboard-ui/css/librarybrowser.css b/dashboard-ui/css/librarybrowser.css index a65d8a37dc..e97f9d215b 100644 --- a/dashboard-ui/css/librarybrowser.css +++ b/dashboard-ui/css/librarybrowser.css @@ -1144,6 +1144,11 @@ a.itemTag:hover { margin-left: .5em; } +.lazy { + opacity: 0; + transition: opacity .3s ease-in; +} + @media all and (min-height: 500px) { .alphabetPicker { diff --git a/dashboard-ui/scripts/librarybrowser.js b/dashboard-ui/scripts/librarybrowser.js index 6c18da00f3..c94937596f 100644 --- a/dashboard-ui/scripts/librarybrowser.js +++ b/dashboard-ui/scripts/librarybrowser.js @@ -433,6 +433,8 @@ options.shape = options.shape || "portrait"; + options.lazy = options.lazy || false; + var html = ""; var primaryImageAspectRatio = options.shape == 'auto' ? LibraryBrowser.getAveragePrimaryImageAspectRatio(items) : null; @@ -668,7 +670,7 @@ var style = ""; - if (imgUrl) { + if (imgUrl && !options.lazy) { style += 'background-image:url(\'' + imgUrl + '\');'; } @@ -681,9 +683,16 @@ imageCssClass += " coveredPosterItemImage"; } + var dataSrc = ""; + + if (options.lazy) { + imageCssClass += " lazy"; + dataSrc = ' data-src="' + imgUrl + '"'; + } + var progressHtml = options.showProgress === false ? '' : LibraryBrowser.getItemProgressBarHtml(item); - html += '
'; + html += '
'; html += '
'; diff --git a/dashboard-ui/scripts/movies.js b/dashboard-ui/scripts/movies.js index 4f44bbe16b..4e0a2dc72c 100644 --- a/dashboard-ui/scripts/movies.js +++ b/dashboard-ui/scripts/movies.js @@ -56,7 +56,8 @@ context: 'movies', showTitle: true, centerText: true, - selectionPanel: true + selectionPanel: true, + lazy: true }); $('.itemsContainer', page).removeClass('timelineItemsContainer'); } @@ -383,4 +384,12 @@ updateFilterControls(this); }); + $(function () { + $("body").on("create", function () { + $(".lazy").unveil(200, function () { + this.style.opacity = 1; + }); + }); + }); + })(jQuery, document); \ No newline at end of file diff --git a/dashboard-ui/thirdparty/jquery.unveil-custom.js b/dashboard-ui/thirdparty/jquery.unveil-custom.js new file mode 100644 index 0000000000..79f275a309 --- /dev/null +++ b/dashboard-ui/thirdparty/jquery.unveil-custom.js @@ -0,0 +1,62 @@ +/** + * jQuery Unveil + * A very lightweight jQuery plugin to lazy load images + * http://luis-almeida.github.com/unveil + * + * Licensed under the MIT license. + * Copyright 2013 Luís Almeida + * https://github.com/luis-almeida + */ + +; (function ($) { + + $.fn.unveil = function (threshold, callback) { + + var $w = $(window), + th = threshold || 0, + retina = window.devicePixelRatio > 1, + attrib = retina ? "data-src-retina" : "data-src", + images = this, + loaded; + + this.one("unveil", function () { + var elemType = $(this).get(0).tagName; + var source = this.getAttribute(attrib); + source = source || this.getAttribute("data-src"); + if (source) { + if (elemType === "DIV") { + this.style.backgroundImage = "url('" + source + "')"; + } else { + this.setAttribute("src", source); + } + if (typeof callback === "function") callback.call(this); + } + }); + + function unveil() { + var inview = images.filter(function () { + var $e = $(this); + if ($e.is(":hidden")) return; + + var wt = $w.scrollTop(), + wb = wt + $w.height(), + et = $e.offset().top, + eb = et + $e.height(); + + return eb >= wt - th && et <= wb + th; + }); + + loaded = inview.trigger("unveil"); + images = images.not(loaded); + } + + $w.scroll(unveil); + $w.resize(unveil); + + unveil(); + + return this; + + }; + +})(window.jQuery || window.Zepto); \ No newline at end of file From cfe02b9cfe8bf02c43294784e46d28e7d5ef879a Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Tue, 8 Apr 2014 11:25:45 -0700 Subject: [PATCH 04/25] Removed api client changes --- ApiClient.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/ApiClient.js b/ApiClient.js index dbc7ca6d75..6109faf91b 100644 --- a/ApiClient.js +++ b/ApiClient.js @@ -3865,15 +3865,11 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi var msgData = itemId; - msgData += "|" + (params.positionTicks == null ? "" : params.positionTicks); - msgData += "|" + (params.isPaused == null ? "" : params.isPaused); - msgData += "|" + (params.isMuted == null ? "" : params.isMuted); + msgData += "|" + (positionTicks == null ? "" : params.positionTicks); + msgData += "|" + (isPaused == null ? "" : params.isPaused); + msgData += "|" + (isMuted == null ? "" : params.isMuted); msgData += "|" + (mediaSourceId == null ? "" : mediaSourceId); - ////msgData += "|" + (params.audioStreamIndex == null ? "" : params.audioStreamIndex); - ////msgData += "|" + (params.subtitleStreamIndex == null ? "" : params.subtitleStreamIndex); - ////msgData += "|" + (params.volumeLevel == null ? "" : params.volumeLevel); - self.sendWebSocketMessage("PlaybackProgress", msgData); deferred.resolveWith(null, []); From 95686255f5127e6cc5164b913dbfd566de1b24f0 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Tue, 8 Apr 2014 11:28:25 -0700 Subject: [PATCH 05/25] Removed api client changes --- ApiClient.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ApiClient.js b/ApiClient.js index 6109faf91b..a4c4d97830 100644 --- a/ApiClient.js +++ b/ApiClient.js @@ -3865,9 +3865,9 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi var msgData = itemId; - msgData += "|" + (positionTicks == null ? "" : params.positionTicks); - msgData += "|" + (isPaused == null ? "" : params.isPaused); - msgData += "|" + (isMuted == null ? "" : params.isMuted); + msgData += "|" + (positionTicks == null ? "" : positionTicks); + msgData += "|" + (isPaused == null ? "" : isPaused); + msgData += "|" + (isMuted == null ? "" : isMuted); msgData += "|" + (mediaSourceId == null ? "" : mediaSourceId); self.sendWebSocketMessage("PlaybackProgress", msgData); From afcaea8b0cc9aee9e103b81a507a8ab1b8ead6af Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Tue, 8 Apr 2014 11:32:03 -0700 Subject: [PATCH 06/25] Undo changes --- dashboard-ui/scripts/chromecast.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js index d233949fbc..bca82b8327 100644 --- a/dashboard-ui/scripts/chromecast.js +++ b/dashboard-ui/scripts/chromecast.js @@ -89,7 +89,7 @@ // v1 Id AE4DA10A // v2 Id 472F0435 - var applicationID = '472F0435'; + var applicationID = 'AE4DA10A'; // request session var sessionRequest = new chrome.cast.SessionRequest(applicationID); @@ -429,7 +429,7 @@ }; } - function getCustomData(item, mediaSourceId, startTimeTicks, audioStreamIndex, subtitleStreamIndex) { + function getCustomData(item, mediaSourceId, startTimeTicks) { return { @@ -438,9 +438,7 @@ userId: Dashboard.getCurrentUserId(), deviceName: ApiClient.deviceName(), //deviceId: ApiClient.deviceId(), - startTimeTicks: startTimeTicks || 0, - audioStreamIndex: audioStreamIndex, - subtitleStreamIndex: subtitleStreamIndex + startTimeTicks: startTimeTicks || 0 }; } @@ -626,7 +624,7 @@ var castMediaInfo = new chrome.cast.media.MediaInfo(streamUrl); - castMediaInfo.customData = getCustomData(item, mediaInfo.mediaSource.Id, startTimeTicks, audioStreamIndex, subtitleStreamIndex); + castMediaInfo.customData = getCustomData(item, mediaInfo.mediaSource.Id, startTimeTicks); castMediaInfo.metadata = getMetadata(item); if (mediaInfo.streamContainer == 'm3u8') { @@ -643,9 +641,8 @@ this.castPlayerState = PLAYER_STATE.LOADING; this.session.loadMedia(request, - this.onMediaDiscovered.bind(this, 'loadMedia'), - this.onLoadMediaError.bind(this) - ); + this.onMediaDiscovered.bind(this, 'loadMedia'), + this.onLoadMediaError.bind(this)); }; /** From e4e14908b8ad9f2befaa66b56a9b96a9cdd46800 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Tue, 8 Apr 2014 11:33:25 -0700 Subject: [PATCH 07/25] Undo changes --- dashboard-ui/scripts/remotecontrol.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dashboard-ui/scripts/remotecontrol.js b/dashboard-ui/scripts/remotecontrol.js index ba622794f6..6df582fb44 100644 --- a/dashboard-ui/scripts/remotecontrol.js +++ b/dashboard-ui/scripts/remotecontrol.js @@ -349,7 +349,7 @@ // don't display the current session sessions = sessions.filter(function (s) { - return s.DeviceId != deviceId && (s.SupportsRemoteControl || s.Client == "Chromecast"); + return s.DeviceId != deviceId && (s.SupportsRemoteControl); }); var elem = $('#selectSession', popup); @@ -403,8 +403,6 @@ self.showMenu = function (options) { ApiClient.getSessions(sessionQuery).done(function (sessions) { - console.log("showMenu", sessions); - showMenu(sessions, options); }); From 874c0ce0272974c6e5650425169bebcc24ffe945 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Tue, 8 Apr 2014 11:34:49 -0700 Subject: [PATCH 08/25] Undo changes --- dashboard-ui/scripts/remotecontrol.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashboard-ui/scripts/remotecontrol.js b/dashboard-ui/scripts/remotecontrol.js index 6df582fb44..35add5b195 100644 --- a/dashboard-ui/scripts/remotecontrol.js +++ b/dashboard-ui/scripts/remotecontrol.js @@ -349,7 +349,7 @@ // don't display the current session sessions = sessions.filter(function (s) { - return s.DeviceId != deviceId && (s.SupportsRemoteControl); + return s.DeviceId != deviceId && s.SupportsRemoteControl; }); var elem = $('#selectSession', popup); From 32c1badcd9b5f795ae5df1e7bacdcca9e1129449 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Tue, 8 Apr 2014 16:12:09 -0700 Subject: [PATCH 09/25] Video fixes Variable collision caused some issues - sorted --- dashboard-ui/scripts/mediaplayer-video.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dashboard-ui/scripts/mediaplayer-video.js b/dashboard-ui/scripts/mediaplayer-video.js index 5569a461e2..9d7c1a93df 100644 --- a/dashboard-ui/scripts/mediaplayer-video.js +++ b/dashboard-ui/scripts/mediaplayer-video.js @@ -872,18 +872,18 @@ $('#video-fullscreenButton', videoControls).show(); } - var videoElement = $("video", videoElement); + var video = $("video", videoElement); initialVolume = localStorage.getItem("volume") || 0.5; - videoElement.each(function () { + video.each(function () { this.volume = initialVolume; }); self.volumeSlider.val(initialVolume).slider('refresh'); self.updateVolumeButtons(initialVolume); - videoElement.on("volumechange", function (e) { + video.on("volumechange", function (e) { var muted = this.muted; @@ -899,13 +899,13 @@ }).on("play.once", function () { - videoElement.off("play.once"); + video.off("play.once"); }).on("playing.once", function () { self.updateCanClientSeek(this); - videoElement.off("playing.once"); + video.off("playing.once"); ApiClient.reportPlaybackStart(Dashboard.getCurrentUserId(), item.Id, mediaSource.Id, true, item.MediaType); @@ -1037,7 +1037,7 @@ currentItem = item; currentMediaSource = mediaSource; - return videoElement[0]; + return video[0]; } }; })(); \ No newline at end of file From a500f154d8c4f22c25fb7276e13de434c08f3b35 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Wed, 9 Apr 2014 16:58:09 -0700 Subject: [PATCH 10/25] Cast updates --- dashboard-ui/css/mediaplayer-video.css | 4 +- dashboard-ui/scripts/chromecast.js | 197 +++++++++++++++++------- dashboard-ui/scripts/mediacontroller.js | 16 ++ dashboard-ui/scripts/site.js | 28 ++-- 4 files changed, 176 insertions(+), 69 deletions(-) diff --git a/dashboard-ui/css/mediaplayer-video.css b/dashboard-ui/css/mediaplayer-video.css index 14f8b7b40d..814bc66e39 100644 --- a/dashboard-ui/css/mediaplayer-video.css +++ b/dashboard-ui/css/mediaplayer-video.css @@ -139,7 +139,7 @@ text-align: left; margin-left: 0; right: 0; - bottom: 83px; + bottom: 85px; } /* Media queries @@ -259,7 +259,7 @@ } #mediaPlayer #videoControls .mediaPlayerFlyout { - bottom: 148px; + bottom: 150px; } } diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js index bca82b8327..1df3d958cd 100644 --- a/dashboard-ui/scripts/chromecast.js +++ b/dashboard-ui/scripts/chromecast.js @@ -66,6 +66,17 @@ 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"; + this.initializeCastPlayer(); }; @@ -617,6 +628,8 @@ return; } + this.currentMediaOffset = startTimeTicks; + var maxBitrate = 12000000; var mediaInfo = getMediaSourceInfo(user, item, maxBitrate, mediaSourceId, audioStreamIndex, subtitleStreamIndex); @@ -653,40 +666,62 @@ console.log("chromecast new media session ID:" + mediaSession.mediaSessionId + ' (' + how + ')'); this.currentMediaSession = mediaSession; + this.currentMediaTime = this.session.media[0].currentTime; + if (how == 'loadMedia') { this.castPlayerState = PLAYER_STATE.PLAYING; + clearInterval(this.timer); + this.startProgressTimer(this.incrementMediaTime); } if (how == 'activeSession') { this.castPlayerState = this.session.media[0].playerState; - this.currentMediaTime = this.session.media[0].currentTime; } if (this.castPlayerState == PLAYER_STATE.PLAYING) { // start progress timer - //this.startProgressTimer(this.incrementMediaTime); + this.startProgressTimer(this.incrementMediaTime); } this.currentMediaSession.addUpdateListener(this.onMediaStatusUpdate.bind(this)); + this.currentMediaDuration = this.currentMediaSession.media.duration; - //this.currentMediaDuration = this.currentMediaSession.media.duration; - //var duration = this.currentMediaDuration; - //var hr = parseInt(duration / 3600); - //duration -= hr * 3600; - //var min = parseInt(duration / 60); - //var sec = parseInt(duration % 60); - //if (hr > 0) { - // duration = hr + ":" + min + ":" + sec; - //} - //else { - // if (min > 0) { - // duration = min + ":" + sec; - // } - // else { - // duration = sec; - // } - //} - //document.getElementById("duration").innerHTML = duration; + var playTime = document.getElementById(this.playback); + if (!playTime) { + // Set duration time + var totalTime = document.getElementById(this.duration); + totalTime.innerHTML = " / " + formatTime(this.currentMediaDuration); + + // Set play time + playTime = document.createElement("div"); + playTime.id = this.playback; + playTime.className = "currentTime"; + playTime.style.marginRight = "5px"; + totalTime.parentNode.insertBefore(playTime, totalTime); + playTime.innerHTML = formatTime(this.currentMediaTime); + } + }; + + function formatTime(duration) { + var hr = parseInt(duration / 3600); + duration -= hr * 3600; + var min = parseInt(duration / 60); + var sec = parseInt(duration % 60); + + hr = "" + hr; + min = "" + min; + sec = "" + sec; + var hh = pad(hr); + var mm = pad(min); + var ss = pad(sec); + + duration = hh + ":" + mm + ":" + ss; + + return duration; + }; + + function pad(s) { + return "00".substring(0, 2 - s.length) + s; }; /** @@ -707,7 +742,7 @@ this.castPlayerState = PLAYER_STATE.IDLE; } console.log("chromecast updating media"); - //this.updateProgressBar(e); + this.updateProgressBarByTimer(); }; /** @@ -745,6 +780,7 @@ this.currentMediaSession.addUpdateListener(this.onMediaStatusUpdate.bind(this)); this.castPlayerState = PLAYER_STATE.PLAYING; // start progress timer + clearInterval(this.timer); this.startProgressTimer(this.incrementMediaTime); break; case PLAYER_STATE.IDLE: @@ -850,18 +886,9 @@ */ CastPlayer.prototype.seekMedia = function (event) { var pos = parseInt(event.offsetX); - var pi = document.getElementById("progress_indicator"); - var p = document.getElementById("progress"); - if (event.currentTarget.id == 'progress_indicator') { - var curr = parseInt(this.currentMediaTime + this.currentMediaDuration * pos / PROGRESS_BAR_WIDTH); - var pp = parseInt(pi.style.marginLeft) + pos; - var pw = parseInt(p.style.width) + pos; - } - else { - var curr = parseInt(pos * this.currentMediaDuration / PROGRESS_BAR_WIDTH); - var pp = pos - 21 - PROGRESS_BAR_WIDTH; - var pw = pos; - } + var p = document.getElementById(this.progressBar); + var curr = parseInt(this.currentMediaTime + this.currentMediaDuration * pos); + var pw = parseInt(p.value) + pos; if (this.castPlayerState != PLAYER_STATE.PLAYING && this.castPlayerState != PLAYER_STATE.PAUSED) { return; @@ -899,20 +926,16 @@ * @param {Object} e An media status update object */ CastPlayer.prototype.updateProgressBar = function (e) { - var p = document.getElementById("progress"); - var pi = document.getElementById("progress_indicator"); + var p = document.getElementById(this.progressBar); if (e.idleReason == 'FINISHED' && e.playerState == 'IDLE') { - p.style.width = '0px'; - pi.style.marginLeft = -21 - PROGRESS_BAR_WIDTH + 'px'; + p.value = 0; clearInterval(this.timer); this.castPlayerState = PLAYER_STATE.STOPPED; } else { - p.style.width = Math.ceil(PROGRESS_BAR_WIDTH * e.currentTime / this.currentMediaSession.media.duration + 1) + 'px'; + p.value = 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 - var pp = Math.ceil(PROGRESS_BAR_WIDTH * e.currentTime / this.currentMediaSession.media.duration); - pi.style.marginLeft = -21 - PROGRESS_BAR_WIDTH + pp + 'px'; } }; @@ -928,47 +951,73 @@ * Update progress bar based on timer */ CastPlayer.prototype.updateProgressBarByTimer = function () { - var p = document.getElementById("progress"); - if (isNaN(parseInt(p.style.width))) { - p.style.width = 0; + var p = document.getElementById(this.progressBar); + if (isNaN(parseInt(p.value))) { + p.value = 0; } + if (this.currentMediaDuration > 0) { - var pp = Math.floor(PROGRESS_BAR_WIDTH * this.currentMediaTime / this.currentMediaDuration); + var pp = Number(this.currentMediaTime / this.currentMediaDuration).toFixed(3); + var startTime = this.currentMediaOffset / 10000000; + document.getElementById(this.playback).innerHTML = formatTime(startTime + this.currentMediaTime); } if (this.progressFlag) { // don't update progress if it's been updated on media status update event - p.style.width = pp + 'px'; - var pi = document.getElementById("progress_indicator"); - pi.style.marginLeft = -21 - PROGRESS_BAR_WIDTH + pp + 'px'; + p.value = pp; } - if (pp > PROGRESS_BAR_WIDTH) { + if (pp > 100) { clearInterval(this.timer); this.deviceState = DEVICE_STATE.IDLE; this.castPlayerState = PLAYER_STATE.IDLE; } }; + /** + * @param {function} A callback function for the fucntion to start timer + */ + CastPlayer.prototype.startProgressTimer = function(callback) { + if(this.timer) { + clearInterval(this.timer); + this.timer = null; + } + + // start progress timer + this.timer = setInterval(callback.bind(this), this.timerStep); + }; + var castPlayer = new CastPlayer(); - function chromecastPlayer() { + function chromecastPlayer(castPlayer) { var self = this; self.name = PlayerName; + self.isPaused = false; + self.play = function (options) { - if (options.items) { + $("#nowPlayingBar", "#footer").show(); + if (self.isPaused) { + + console.log("unpause"); + self.isPaused = !self.isPaused; + castPlayer.playMedia(); + + } else if (options.items) { + + console.log("play1", options); Dashboard.getCurrentUser().done(function (user) { - castPlayer.loadMedia(user, options.items[0], options.startTimeTicks); + castPlayer.loadMedia(user, options.items[0], options.startPositionTicks); }); } else { + console.log("play2"); var userId = Dashboard.getCurrentUserId(); var query = {}; @@ -988,6 +1037,18 @@ }; + self.unpause = function () { + console.log("unpause"); + self.isPaused = !self.isPaused; + castPlayer.playMedia(); + }; + + self.pause = function () { + console.log("pause"); + self.isPaused = true; + castPlayer.pauseMedia(); + }; + self.shuffle = function (id) { self.play({ ids: [id] }); }; @@ -1005,7 +1066,9 @@ }; self.stop = function () { - castPlayer.stop(); + console.log("stop"); + $("#nowPlayingBar", "#footer").hide(); + castPlayer.stopMedia(); }; self.canQueueMediaType = function (mediaType) { @@ -1051,9 +1114,37 @@ appName: appName }; }; + + self.setCurrentTime = function (ticks, item, updateSlider) { + + // Convert to ticks + ticks = Math.floor(ticks); + + var timeText = Dashboard.getDisplayTime(ticks); + + if (self.currentDurationTicks) { + + timeText += " / " + Dashboard.getDisplayTime(self.currentDurationTicks); + + if (updateSlider) { + var percent = ticks / self.currentDurationTicks; + percent *= 100; + + self.positionSlider.val(percent).slider('enable').slider('refresh'); + } + } else { + self.positionSlider.slider('disable').slider('refresh'); + } + + self.currentTimeElement.html(timeText); + }; + + self.changeStream = function (position) { + console.log("seek", position); + }; } - MediaController.registerPlayer(new chromecastPlayer()); + MediaController.registerPlayer(new chromecastPlayer(castPlayer)); $(MediaController).on('playerchange', function () { diff --git a/dashboard-ui/scripts/mediacontroller.js b/dashboard-ui/scripts/mediacontroller.js index 074bc880f1..3c9bd1f1af 100644 --- a/dashboard-ui/scripts/mediacontroller.js +++ b/dashboard-ui/scripts/mediacontroller.js @@ -174,6 +174,22 @@ return p.isDefaultPlayer; })[0]; }; + + self.pause = function () { + currentPlayer.pause(); + }; + + self.stop = function () { + currentPlayer.stop(); + }; + + self.unpause = function () { + currentPlayer.unpause(); + }; + + self.seek = function (position) { + self.changeStream(position); + }; } window.MediaController = new mediaController(); diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js index 79b298ef05..477ba60119 100644 --- a/dashboard-ui/scripts/site.js +++ b/dashboard-ui/scripts/site.js @@ -1330,42 +1330,42 @@ $(function () { footerHtml += '
'; footerHtml += '
'; footerHtml += 'Playlist'; - footerHtml += ''; - footerHtml += ''; - footerHtml += ''; + footerHtml += ''; + footerHtml += ''; + footerHtml += ''; footerHtml += '
'; - footerHtml += ''; - footerHtml += ''; + footerHtml += ''; + footerHtml += ''; footerHtml += '
'; - footerHtml += ''; + footerHtml += ''; footerHtml += '
'; - footerHtml += '
'; + footerHtml += '
'; footerHtml += '
'; - footerHtml += ''; - footerHtml += ''; + footerHtml += ''; + footerHtml += ''; footerHtml += '
'; footerHtml += ''; footerHtml += '
'; - footerHtml += ''; + footerHtml += ''; footerHtml += '
'; - footerHtml += ''; + footerHtml += ''; footerHtml += '
'; - footerHtml += ''; + footerHtml += ''; footerHtml += '
'; - footerHtml += ''; + footerHtml += ''; footerHtml += '
'; - footerHtml += ''; + footerHtml += ''; footerHtml += '
'; From f893f175cb952901f2731f19cd812efdc56aaaf5 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Wed, 9 Apr 2014 20:47:57 -0700 Subject: [PATCH 11/25] Lazy loading enabled All pages with lots of images now have lazy loading enabled. The "animation" was removed since it made for a bit of an odd experience one the 2nd visit to a page. On pages with lots of images this has a nice impact as it only loads the images that the user can see initially. As a user scrolls it loads the next ones up. It saves a lot of extra requests initially. --- dashboard-ui/css/librarybrowser.css | 5 ----- dashboard-ui/scripts/episodes.js | 3 ++- dashboard-ui/scripts/moviecollections.js | 3 ++- dashboard-ui/scripts/moviepeople.js | 3 ++- dashboard-ui/scripts/movies.js | 17 ++++++----------- dashboard-ui/scripts/musicalbumartists.js | 3 ++- dashboard-ui/scripts/musicartists.js | 9 ++++++++- dashboard-ui/scripts/musicgenres.js | 7 ++++--- dashboard-ui/scripts/site.js | 7 +++++-- dashboard-ui/scripts/tvpeople.js | 3 ++- dashboard-ui/scripts/tvshows.js | 12 ++++++++---- 11 files changed, 41 insertions(+), 31 deletions(-) diff --git a/dashboard-ui/css/librarybrowser.css b/dashboard-ui/css/librarybrowser.css index 1defe8d9b1..cbb232c96d 100644 --- a/dashboard-ui/css/librarybrowser.css +++ b/dashboard-ui/css/librarybrowser.css @@ -1144,11 +1144,6 @@ a.itemTag:hover { margin-left: .5em; } -.lazy { - opacity: 0; - transition: opacity .3s ease-in; -} - @media all and (min-height: 500px) { .alphabetPicker { diff --git a/dashboard-ui/scripts/episodes.js b/dashboard-ui/scripts/episodes.js index d596716ffc..6f2dc42e30 100644 --- a/dashboard-ui/scripts/episodes.js +++ b/dashboard-ui/scripts/episodes.js @@ -34,7 +34,8 @@ showTitle: true, showParentTitle: true, overlayText: true, - selectionPanel: true + selectionPanel: true, + lazy: true }); $('.itemsContainer', page).removeClass('timelineItemsContainer'); diff --git a/dashboard-ui/scripts/moviecollections.js b/dashboard-ui/scripts/moviecollections.js index 8a04646073..8985316792 100644 --- a/dashboard-ui/scripts/moviecollections.js +++ b/dashboard-ui/scripts/moviecollections.js @@ -33,7 +33,8 @@ shape: "portrait", context: 'movies', showTitle: true, - centerText: true + centerText: true, + lazy: true }); html += LibraryBrowser.getPagingHtml(query, result.TotalRecordCount); diff --git a/dashboard-ui/scripts/moviepeople.js b/dashboard-ui/scripts/moviepeople.js index 3e35afca1c..0ef500846b 100644 --- a/dashboard-ui/scripts/moviepeople.js +++ b/dashboard-ui/scripts/moviepeople.js @@ -34,7 +34,8 @@ context: 'movies', showTitle: true, showItemCounts: true, - coverImage: true + coverImage: true, + lazy: true }); html += LibraryBrowser.getPagingHtml(query, result.TotalRecordCount, false, [], false); diff --git a/dashboard-ui/scripts/movies.js b/dashboard-ui/scripts/movies.js index 4e0a2dc72c..e3d2689c8d 100644 --- a/dashboard-ui/scripts/movies.js +++ b/dashboard-ui/scripts/movies.js @@ -35,7 +35,8 @@ shape: "backdrop", preferThumb: true, context: 'movies', - selectionPanel: true + selectionPanel: true, + lazy: true }); $('.itemsContainer', page).removeClass('timelineItemsContainer'); } @@ -45,7 +46,8 @@ items: result.Items, shape: "banner", preferBanner: true, - context: 'movies' + context: 'movies', + lazy: true }); $('.itemsContainer', page).removeClass('timelineItemsContainer'); } @@ -69,7 +71,8 @@ showTitle: true, timeline: true, centerText: true, - selectionPanel: true + selectionPanel: true, + lazy: true }); $('.itemsContainer', page).addClass('timelineItemsContainer'); } @@ -384,12 +387,4 @@ updateFilterControls(this); }); - $(function () { - $("body").on("create", function () { - $(".lazy").unveil(200, function () { - this.style.opacity = 1; - }); - }); - }); - })(jQuery, document); \ No newline at end of file diff --git a/dashboard-ui/scripts/musicalbumartists.js b/dashboard-ui/scripts/musicalbumartists.js index 26f7b070b0..a53c140035 100644 --- a/dashboard-ui/scripts/musicalbumartists.js +++ b/dashboard-ui/scripts/musicalbumartists.js @@ -32,7 +32,8 @@ context: 'music', showTitle: true, coverImage: true, - centerText: true + centerText: true, + lazy: true }); html += LibraryBrowser.getPagingHtml(query, result.TotalRecordCount); diff --git a/dashboard-ui/scripts/musicartists.js b/dashboard-ui/scripts/musicartists.js index 60d2fe572a..142bfaa3b2 100644 --- a/dashboard-ui/scripts/musicartists.js +++ b/dashboard-ui/scripts/musicartists.js @@ -31,7 +31,8 @@ context: 'music', showTitle: true, coverImage: true, - centerText: true + centerText: true, + lazy: true }); html += LibraryBrowser.getPagingHtml(query, result.TotalRecordCount); @@ -119,4 +120,10 @@ updateFilterControls(this); }); + $(function () { + $("body").on("create", function () { + $(".lazy").unveil(200); + }); + }); + })(jQuery, document); \ No newline at end of file diff --git a/dashboard-ui/scripts/musicgenres.js b/dashboard-ui/scripts/musicgenres.js index 51e38e50f7..a0aa9331c4 100644 --- a/dashboard-ui/scripts/musicgenres.js +++ b/dashboard-ui/scripts/musicgenres.js @@ -32,7 +32,8 @@ preferThumb: true, context: 'music', showItemCounts: true, - centerText: true + centerText: true, + lazy: true }); html += LibraryBrowser.getPagingHtml(query, result.TotalRecordCount); @@ -55,8 +56,8 @@ reloadItems(page); }); - LibraryBrowser.saveQueryValues('musicgenres', query); - + LibraryBrowser.saveQueryValues('musicgenres', query); + Dashboard.hideLoadingMsg(); }); } diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js index 72e192ac27..ddc4e42d00 100644 --- a/dashboard-ui/scripts/site.js +++ b/dashboard-ui/scripts/site.js @@ -1386,6 +1386,10 @@ $(function () { ApiClient.closeWebSocket(); } }); + + $("body").on("create", function () { + $(".lazy").unveil(200); + }); }); Dashboard.jQueryMobileInit(); @@ -1427,5 +1431,4 @@ $(document).on('pagebeforeshow', ".page", function () { if (!ApiClient.isWebSocketOpen()) { Dashboard.refreshSystemInfoFromServer(); } -}); - +}); \ No newline at end of file diff --git a/dashboard-ui/scripts/tvpeople.js b/dashboard-ui/scripts/tvpeople.js index e8a573ac9a..d434886be1 100644 --- a/dashboard-ui/scripts/tvpeople.js +++ b/dashboard-ui/scripts/tvpeople.js @@ -34,7 +34,8 @@ context: 'tv', showTitle: true, showItemCounts: true, - coverImage: true + coverImage: true, + lazy: true }); html += LibraryBrowser.getPagingHtml(query, result.TotalRecordCount, false, [], false); diff --git a/dashboard-ui/scripts/tvshows.js b/dashboard-ui/scripts/tvshows.js index 2e751fa82e..96635ea906 100644 --- a/dashboard-ui/scripts/tvshows.js +++ b/dashboard-ui/scripts/tvshows.js @@ -34,7 +34,8 @@ items: result.Items, shape: "backdrop", preferThumb: true, - context: 'tv' + context: 'tv', + lazy: true }); $('.itemsContainer', page).removeClass('timelineItemsContainer'); @@ -45,7 +46,8 @@ items: result.Items, shape: "banner", preferBanner: true, - context: 'tv' + context: 'tv', + lazy: true }); $('.itemsContainer', page).removeClass('timelineItemsContainer'); } @@ -56,7 +58,8 @@ shape: "portrait", context: 'tv', showTitle: true, - centerText: true + centerText: true, + lazy: true }); $('.itemsContainer', page).removeClass('timelineItemsContainer'); } @@ -67,7 +70,8 @@ shape: "portrait", context: 'tv', timeline: true, - showTitle: true + showTitle: true, + lazy: true }); $('.itemsContainer', page).addClass('timelineItemsContainer'); From df87f66b8d352221cdeff988bc85eba79f2f2ac1 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Wed, 9 Apr 2014 20:48:51 -0700 Subject: [PATCH 12/25] "People" fix People that aren't in a file/show had an empty line that resulted in staggered layout, so I added a non-breaking space for consistent layout --- dashboard-ui/scripts/librarybrowser.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dashboard-ui/scripts/librarybrowser.js b/dashboard-ui/scripts/librarybrowser.js index c94937596f..3220196744 100644 --- a/dashboard-ui/scripts/librarybrowser.js +++ b/dashboard-ui/scripts/librarybrowser.js @@ -765,6 +765,10 @@ var itemCountHtml = LibraryBrowser.getItemCountsHtml(options, item); + if (item.Type == "Person" && !itemCountHtml) { + itemCountHtml = " "; + } + if (itemCountHtml) { html += "
"; html += itemCountHtml; From e8084be0db8e60e278e00efa29431344b65a651b Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Wed, 9 Apr 2014 21:12:04 -0700 Subject: [PATCH 13/25] More cast and lazy load updates --- dashboard-ui/scripts/mediacontroller.js | 8 ++++++++ dashboard-ui/scripts/musicalbums.js | 6 ++++-- dashboard-ui/scripts/playlist.js | 4 ++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/dashboard-ui/scripts/mediacontroller.js b/dashboard-ui/scripts/mediacontroller.js index 3c9bd1f1af..e7222338dc 100644 --- a/dashboard-ui/scripts/mediacontroller.js +++ b/dashboard-ui/scripts/mediacontroller.js @@ -190,6 +190,14 @@ self.seek = function (position) { self.changeStream(position); }; + + self.currentPlaylistIndex = function (i) { + self.currentPlaylistIndex(i); + }; + + self.removeFromPlaylist = function (i) { + self.removeFromPlaylist(i); + }; } window.MediaController = new mediaController(); diff --git a/dashboard-ui/scripts/musicalbums.js b/dashboard-ui/scripts/musicalbums.js index 523835ba29..003e046761 100644 --- a/dashboard-ui/scripts/musicalbums.js +++ b/dashboard-ui/scripts/musicalbums.js @@ -34,7 +34,8 @@ shape: "square", context: 'music', showTitle: true, - showParentTitle: true + showParentTitle: true, + lazy: true }); $('.itemsContainer', page).removeClass('timelineItemsContainer'); } @@ -45,7 +46,8 @@ context: 'music', showTitle: true, showParentTitle: true, - timeline: true + timeline: true, + lazy: true }); $('.itemsContainer', page).addClass('timelineItemsContainer'); } diff --git a/dashboard-ui/scripts/playlist.js b/dashboard-ui/scripts/playlist.js index 187767152d..10c6b2d9bf 100644 --- a/dashboard-ui/scripts/playlist.js +++ b/dashboard-ui/scripts/playlist.js @@ -65,14 +65,14 @@ var index = parseInt(this.getAttribute('data-index')); - MediaPlayer.currentPlaylistIndex(index); + MediaController.currentPlaylistIndex(index); reloadPlaylist(page); }).on('click', '.lnkRemove', function () { var index = parseInt(this.getAttribute('data-index')); - MediaPlayer.removeFromPlaylist(index); + MediaController.removeFromPlaylist(index); reloadPlaylist(page); }); From dc2fc2f857370a1b3061228eccd7696dcbb2bead Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Wed, 9 Apr 2014 21:26:06 -0700 Subject: [PATCH 14/25] Cast playback time update --- dashboard-ui/scripts/chromecast.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js index 1df3d958cd..05121aa77a 100644 --- a/dashboard-ui/scripts/chromecast.js +++ b/dashboard-ui/scripts/chromecast.js @@ -628,7 +628,7 @@ return; } - this.currentMediaOffset = startTimeTicks; + this.currentMediaOffset = startTimeTicks || 0; var maxBitrate = 12000000; var mediaInfo = getMediaSourceInfo(user, item, maxBitrate, mediaSourceId, audioStreamIndex, subtitleStreamIndex); @@ -827,6 +827,10 @@ this.onError.bind(this)); this.castPlayerState = PLAYER_STATE.STOPPED; clearInterval(this.timer); + var playTime = document.getElementById(this.playback); + if (playTime) { + playTime.parentNode.removeChild(playTime); + } }; /** @@ -958,8 +962,12 @@ if (this.currentMediaDuration > 0) { var pp = Number(this.currentMediaTime / this.currentMediaDuration).toFixed(3); + var startTime = this.currentMediaOffset / 10000000; - document.getElementById(this.playback).innerHTML = formatTime(startTime + this.currentMediaTime); + var playTime = document.getElementById(this.playback); + if (playTime) { + playTime.innerHTML = formatTime(startTime + this.currentMediaTime); + } } if (this.progressFlag) { From 6805109fb400e4b0fcbf3ab4a8c6a63cc09b9984 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Thu, 10 Apr 2014 04:12:48 -0700 Subject: [PATCH 15/25] Cast audio playback enhancements * Instant mix works, but not sure about managing the mix * Shuffle _should_ work, but same thing with mgmt Receiver page has also been enhanced for music playback. --- dashboard-ui/scripts/chromecast.js | 314 +++++++++++++++--- dashboard-ui/scripts/mediacontroller.js | 38 ++- dashboard-ui/scripts/playlist.js | 2 +- .../thirdparty/jquery.ba-tinypubsub.min.js | 4 + 4 files changed, 307 insertions(+), 51 deletions(-) create mode 100644 dashboard-ui/thirdparty/jquery.ba-tinypubsub.min.js diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js index 05121aa77a..51ad1ee90c 100644 --- a/dashboard-ui/scripts/chromecast.js +++ b/dashboard-ui/scripts/chromecast.js @@ -100,7 +100,7 @@ // v1 Id AE4DA10A // v2 Id 472F0435 - var applicationID = 'AE4DA10A'; + var applicationID = '472F0435'; // request session var sessionRequest = new chrome.cast.SessionRequest(applicationID); @@ -456,6 +456,8 @@ function getMetadata(item) { + console.log("md item", item); + var metadata = {}; if (item.Type == 'Episode') { @@ -523,7 +525,7 @@ else if (item.MediaType == 'Movie') { metadata = new chrome.cast.media.MovieMediaMetadata(); - metadata.type = chrome.cast.media.MetadataType.MUSIC_TRACK; + metadata.type = chrome.cast.media.MetadataType.MOVIE; if (item.ProductionYear) { metadata.releaseYear = item.ProductionYear; @@ -889,7 +891,7 @@ * @param {Event} e An event object from seek */ CastPlayer.prototype.seekMedia = function (event) { - var pos = parseInt(event.offsetX); + var pos = parseInt(event); var p = document.getElementById(this.progressBar); var curr = parseInt(this.currentMediaTime + this.currentMediaDuration * pos); var pw = parseInt(p.value) + pos; @@ -935,6 +937,10 @@ p.value = 0; clearInterval(this.timer); this.castPlayerState = PLAYER_STATE.STOPPED; + if (e.idleReason == 'FINISHED') { + $.publish("/playback/complete", e); + console.log("playback complete", e); + } } else { p.value = Number(e.currentTime / this.currentMediaSession.media.duration + 1).toFixed(3); @@ -975,10 +981,12 @@ p.value = pp; } - if (pp > 100) { + if (pp > 100 || this.castPlayerState == PLAYER_STATE.IDLE) { clearInterval(this.timer); this.deviceState = DEVICE_STATE.IDLE; this.castPlayerState = PLAYER_STATE.IDLE; + $.publish("/playback/complete", true); + console.log("playback complete"); } }; @@ -1001,31 +1009,111 @@ var self = this; + var isPositionSliderActive = false; + self.name = PlayerName; self.isPaused = false; + self.playlist = []; + + self.playlistIndex = 0; + + $.subscribe("/playback/complete", function (e) { + if (self.playlistIndex < (self.playlist.items || []).length) { + self.play(self.playlist); + } + }); + + ////$(".positionSlider", "#footer").off("slidestart slidestop") + //// .on('slidestart', function (e) { + //// isPositionSliderActive = true; + ////}).on('slidestop', positionSliderChange); + + ////function positionSliderChange() { + //// isPositionSliderActive = false; + //// var newPercent = parseInt(this.value); + //// self.changeStream(newPercent); + ////} + + function getItemsForPlayback(query) { + var userId = Dashboard.getCurrentUserId(); + + query.Limit = query.Limit || 100; + query.Fields = getItemFields; + query.ExcludeLocationTypes = "Virtual"; + + return ApiClient.getItems(userId, query); + }; + + function queueItems (items) { + for (var i = 0, length = items.length; i < length; i++) { + self.playlist.push(items[i]); + } + }; + + function queueItemsNext(items) { + var insertIndex = 1; + for (var i = 0, length = items.length; i < length; i++) { + self.playlist.splice(insertIndex, 0, items[i]); + insertIndex++; + } + }; + + function translateItemsForPlayback(items) { + var deferred = $.Deferred(); + var firstItem = items[0]; + var promise; + if (firstItem.IsFolder) { + promise = self.getItemsForPlayback({ + ParentId: firstItem.Id, + Filters: "IsNotFolder", + Recursive: true, + SortBy: "SortName", + MediaTypes: "Audio,Video" + }); + } + 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" + }); + } + + if (promise) { + promise.done(function (result) { + deferred.resolveWith(null, [result.Items]); + }); + } else { + deferred.resolveWith(null, [items]); + } + + return deferred.promise(); + }; + self.play = function (options) { - + console.log("play", options); $("#nowPlayingBar", "#footer").show(); - if (self.isPaused) { - - console.log("unpause"); self.isPaused = !self.isPaused; castPlayer.playMedia(); - } else if (options.items) { - - console.log("play1", options); Dashboard.getCurrentUser().done(function (user) { - - castPlayer.loadMedia(user, options.items[0], options.startPositionTicks); + castPlayer.loadMedia(user, options.items[self.playlistIndex++], options.startPositionTicks); }); - } else { - - console.log("play2"); var userId = Dashboard.getCurrentUserId(); var query = {}; @@ -1035,14 +1123,10 @@ query.Ids = options.ids.join(','); ApiClient.getItems(userId, query).done(function (result) { - options.items = result.Items; - self.play(options); - }); } - }; self.unpause = function () { @@ -1058,37 +1142,135 @@ }; self.shuffle = function (id) { - self.play({ ids: [id] }); + var userId = Dashboard.getCurrentUserId(); + ApiClient.getItem(userId, id).done(function (item) { + var query = { + UserId: userId, + Fields: getItemFields, + Limit: 50, + Filters: "IsNotFolder", + Recursive: true, + SortBy: "Random" + }; + + if (item.IsFolder) { + query.ParentId = id; + } + else if (item.Type == "MusicArtist") { + query.MediaTypes = "Audio"; + query.Artists = item.Name; + } + else if (item.Type == "MusicGenre") { + query.MediaTypes = "Audio"; + query.Genres = item.Name; + } else { + return; + } + + self.getItemsForPlayback(query).done(function (result) { + self.playlist = { items: result.Items }; + console.log("shuffle items", result.Items); + self.play(self.playlist); + }); + }); }; self.instantMix = function (id) { - self.play({ ids: [id] }); - }; + var userId = Dashboard.getCurrentUserId(); + ApiClient.getItem(userId, id).done(function (item) { + var promise; + var getItemFields = "MediaSources,Chapters"; + var mixLimit = 3; - self.queue = function (options) { + if (item.Type == "MusicArtist") { + promise = ApiClient.getInstantMixFromArtist(name, { + UserId: userId, + Fields: getItemFields, + Limit: mixLimit + }); + } + else if (item.Type == "MusicGenre") { + promise = ApiClient.getInstantMixFromMusicGenre(name, { + UserId: userId, + Fields: getItemFields, + Limit: mixLimit + }); + } + else if (item.Type == "MusicAlbum") { + promise = ApiClient.getInstantMixFromAlbum(id, { + UserId: userId, + Fields: getItemFields, + Limit: mixLimit + }); + } + else if (item.Type == "Audio") { + promise = ApiClient.getInstantMixFromSong(id, { + UserId: userId, + Fields: getItemFields, + Limit: mixLimit + }); + } + else { + return; + } - }; - - self.queueNext = function (options) { - - }; - - self.stop = function () { - console.log("stop"); - $("#nowPlayingBar", "#footer").hide(); - castPlayer.stopMedia(); + promise.done(function (result) { + self.playlist = { items: result.Items }; + console.log("instant mix items", result.Items); + self.play(self.playlist); + }); + }); }; self.canQueueMediaType = function (mediaType) { + return mediaType == "Audio"; + }; - return false; + self.queue = function (options) { + Dashboard.getCurrentUser().done(function (user) { + if (options.items) { + translateItemsForPlayback(options.items).done(function (items) { + queueItems(items); + }); + } else { + getItemsForPlayback({ + Ids: options.ids.join(',') + }).done(function (result) { + translateItemsForPlayback(result.Items).done(function (items) { + queueItems(items); + }); + }); + } + }); + }; + + self.queueNext = function (options) { + Dashboard.getCurrentUser().done(function (user) { + if (options.items) { + queueItemsNext(options.items); + } else { + self.getItemsForPlayback({ + Ids: options.ids.join(',') + }).done(function (result) { + options.items = result.Items; + queueItemsNext(options.items); + }); + } + }); + }; + + self.stop = function () { + $("#nowPlayingBar", "#footer").hide(); + self.playlist = []; + self.playlistIndex = 0; + castPlayer.stopMedia(); }; self.mute = function () { castPlayer.mute(); }; - self.unMute = function () { + self.unmute = function () { castPlayer.unMute(); }; @@ -1097,18 +1279,13 @@ }; self.getTargets = function () { - var targets = []; - targets.push(self.getCurrentTargetInfo()); - return targets; }; self.getCurrentTargetInfo = function () { - var appName = null; - if (castPlayer.session && castPlayer.session.receiver && castPlayer.session.friendlyName) { appName = castPlayer.session.friendlyName; } @@ -1124,20 +1301,14 @@ }; self.setCurrentTime = function (ticks, item, updateSlider) { - // Convert to ticks ticks = Math.floor(ticks); - var timeText = Dashboard.getDisplayTime(ticks); - if (self.currentDurationTicks) { - timeText += " / " + Dashboard.getDisplayTime(self.currentDurationTicks); - if (updateSlider) { var percent = ticks / self.currentDurationTicks; percent *= 100; - self.positionSlider.val(percent).slider('enable').slider('refresh'); } } else { @@ -1149,6 +1320,55 @@ self.changeStream = function (position) { console.log("seek", position); + ////castPlayer.seekMedia(position); + }; + + self.removeFromPlaylist = function (i) { + self.playlist.remove(i); + }; + + self.currentPlaylistIndex = function (i) { + if (i == null) { + return currentPlaylistIndex; + } + + var newItem = self.playlist[i]; + + Dashboard.getCurrentUser().done(function (user) { + self.playInternal(newItem, 0, user); + currentPlaylistIndex = i; + }); + }; + + self.nextTrack = function () { + var newIndex = currentPlaylistIndex + 1; + var newItem = self.playlist[newIndex]; + + if (newItem) { + Dashboard.getCurrentUser().done(function (user) { + self.playInternal(newItem, 0, user); + currentPlaylistIndex = newIndex; + }); + } + }; + + self.previousTrack = function () { + var newIndex = currentPlaylistIndex - 1; + if (newIndex >= 0) { + var newItem = self.playlist[newIndex]; + if (newItem) { + Dashboard.getCurrentUser().done(function (user) { + self.playInternal(newItem, 0, user); + currentPlaylistIndex = newIndex; + }); + } + } + }; + + self.volumeDown = function () { + }; + + self.volumeUp = function () { }; } diff --git a/dashboard-ui/scripts/mediacontroller.js b/dashboard-ui/scripts/mediacontroller.js index e7222338dc..c755df654f 100644 --- a/dashboard-ui/scripts/mediacontroller.js +++ b/dashboard-ui/scripts/mediacontroller.js @@ -188,15 +188,47 @@ }; self.seek = function (position) { - self.changeStream(position); + currentPlayer.changeStream(position); }; self.currentPlaylistIndex = function (i) { - self.currentPlaylistIndex(i); + currentPlayer.currentPlaylistIndex(i); }; self.removeFromPlaylist = function (i) { - self.removeFromPlaylist(i); + currentPlayer.removeFromPlaylist(i); + }; + + self.nextTrack = function () { + currentPlayer.nextTrack(); + }; + + self.previousTrack = function () { + currentPlayer.previousTrack(); + }; + + self.mute = function () { + currentPlayer.mute(); + }; + + self.unmute = function () { + currentPlayer.unmute(); + }; + + self.toggleMute = function () { + currentPlayer.toggleMute(); + }; + + self.volumeDown = function () { + currentPlayer.volumeDown(); + }; + + self.volumeUp = function () { + currentPlayer.volumeUp(); + }; + + self.shuffle = function (id) { + currentPlayer.shuffle(id); }; } diff --git a/dashboard-ui/scripts/playlist.js b/dashboard-ui/scripts/playlist.js index 10c6b2d9bf..651a4d2104 100644 --- a/dashboard-ui/scripts/playlist.js +++ b/dashboard-ui/scripts/playlist.js @@ -17,7 +17,7 @@ html += ''; - $.each(MediaPlayer.playlist, function (i, item) { + $.each(MediaController.playlist, function (i, item) { var name = LibraryBrowser.getPosterViewDisplayName(item); diff --git a/dashboard-ui/thirdparty/jquery.ba-tinypubsub.min.js b/dashboard-ui/thirdparty/jquery.ba-tinypubsub.min.js new file mode 100644 index 0000000000..9c552b4bc7 --- /dev/null +++ b/dashboard-ui/thirdparty/jquery.ba-tinypubsub.min.js @@ -0,0 +1,4 @@ +/* jQuery Tiny Pub/Sub - v0.7 - 10/27/2011 + * http://benalman.com/ + * Copyright (c) 2011 "Cowboy" Ben Alman; Licensed MIT, GPL */ +(function (a) { var b = a({}); a.subscribe = function () { b.on.apply(b, arguments) }, a.unsubscribe = function () { b.off.apply(b, arguments) }, a.publish = function () { b.trigger.apply(b, arguments) } })(jQuery) \ No newline at end of file From d14503c09a11e7d96fb5330b60c78c4f028c2736 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 10 Apr 2014 11:06:54 -0400 Subject: [PATCH 16/25] beginning dlna server --- dashboard-ui/css/detailtable.css | 5 +++++ dashboard-ui/css/librarybrowser.css | 6 ++---- dashboard-ui/itemdetails.html | 7 +++---- dashboard-ui/scripts/itembynamedetailpage.js | 3 ++- dashboard-ui/scripts/itemdetailpage.js | 2 +- dashboard-ui/scripts/librarybrowser.js | 21 ++++++++++---------- dashboard-ui/scripts/mediaplayer-video.js | 2 +- dashboard-ui/scripts/songs.js | 1 + 8 files changed, 25 insertions(+), 22 deletions(-) diff --git a/dashboard-ui/css/detailtable.css b/dashboard-ui/css/detailtable.css index 5111c8dae7..5bc058f096 100644 --- a/dashboard-ui/css/detailtable.css +++ b/dashboard-ui/css/detailtable.css @@ -56,6 +56,11 @@ white-space: nowrap; } +.detailTableButtonsCell button { + margin-top: 0; + margin-bottom: 0; +} + .detailTableButtonsCell button + button { margin-left: .5em; } diff --git a/dashboard-ui/css/librarybrowser.css b/dashboard-ui/css/librarybrowser.css index cbb232c96d..80f23b85c4 100644 --- a/dashboard-ui/css/librarybrowser.css +++ b/dashboard-ui/css/librarybrowser.css @@ -590,7 +590,7 @@ a.itemTag:hover { } .lblDetailTab { - font-size: 16px!important; + font-size: 15px!important; font-weight: 400!important; font-family: 'Open Sans'; padding: .5em 1em; @@ -710,14 +710,12 @@ a.itemTag:hover { } .itemBackdrop { - background-image: none!important; height: auto; } .itemBackdropContent { position: static; - padding: 1em 1em 0; - background-color: transparent; + padding: 1em 1em .5em; } .itemDetailImage { diff --git a/dashboard-ui/itemdetails.html b/dashboard-ui/itemdetails.html index 6a3c280f00..d51220ae4b 100644 --- a/dashboard-ui/itemdetails.html +++ b/dashboard-ui/itemdetails.html @@ -138,19 +138,18 @@ ${ButtonPlay} ${ButtonEdit}
+

+

${ButtonPrevious} ${ButtonNext} -

-

-
-
+
diff --git a/dashboard-ui/scripts/itembynamedetailpage.js b/dashboard-ui/scripts/itembynamedetailpage.js index 9310224b65..3ded84809f 100644 --- a/dashboard-ui/scripts/itembynamedetailpage.js +++ b/dashboard-ui/scripts/itembynamedetailpage.js @@ -426,7 +426,8 @@ html += LibraryBrowser.getSongTableHtml(result.Items, { showAlbum: true, - showArtist: true + showArtist: true, + showAlbumArtist: true }); } diff --git a/dashboard-ui/scripts/itemdetailpage.js b/dashboard-ui/scripts/itemdetailpage.js index 4122b9740a..a6402773f1 100644 --- a/dashboard-ui/scripts/itemdetailpage.js +++ b/dashboard-ui/scripts/itemdetailpage.js @@ -912,7 +912,7 @@ $('#themeSongsCollapsible', page).show(); - $('#themeSongsContent', page).html(LibraryBrowser.getSongTableHtml(result.Items, { showArtist: true, showAlbum: true })).trigger('create'); + $('#themeSongsContent', page).html(LibraryBrowser.getSongTableHtml(result.Items, { showArtist: true, showAlbum: true, showAlbumArtist: true })).trigger('create'); } else { $('#themeSongsCollapsible', page).hide(); } diff --git a/dashboard-ui/scripts/librarybrowser.js b/dashboard-ui/scripts/librarybrowser.js index 6c18da00f3..f71a426a52 100644 --- a/dashboard-ui/scripts/librarybrowser.js +++ b/dashboard-ui/scripts/librarybrowser.js @@ -185,14 +185,17 @@ html += ''; html += LibraryBrowser.getSongHeaderCellHtml('', '', options.enableColumnSorting); - html += LibraryBrowser.getSongHeaderCellHtml('', '', options.enableColumnSorting); + html += LibraryBrowser.getSongHeaderCellHtml('Disc', 'desktopColumn', options.enableColumnSorting); + html += LibraryBrowser.getSongHeaderCellHtml('#', 'desktopColumn', options.enableColumnSorting); html += LibraryBrowser.getSongHeaderCellHtml('Track', '', options.enableColumnSorting, 'Name', options.sortBy, options.sortOrder); if (options.showAlbum) { html += LibraryBrowser.getSongHeaderCellHtml('Album', '', options.enableColumnSorting, 'Album,SortName', options.sortBy, options.sortOrder); } if (options.showArtist) { - html += LibraryBrowser.getSongHeaderCellHtml('Artist', '', options.enableColumnSorting, 'Artist,Album,SortName', options.sortBy, options.sortOrder); + html += LibraryBrowser.getSongHeaderCellHtml('Artist', 'tabletColumn', options.enableColumnSorting, 'Artist,Album,SortName', options.sortBy, options.sortOrder); + } + if (options.showAlbumArtist) { html += LibraryBrowser.getSongHeaderCellHtml('Album Artist', 'tabletColumn', options.enableColumnSorting, 'AlbumArtist,Album,SortName', options.sortBy, options.sortOrder); } @@ -214,12 +217,8 @@ html += ''; html += ''; - var num = item.IndexNumber; - - if (num && item.ParentIndexNumber) { - num = item.ParentIndexNumber + "." + num; - } - html += '' + (num || "") + ''; + html += '' + (item.ParentIndexNumber || "") + ''; + html += '' + (item.IndexNumber || "") + ''; html += '' + (item.Name || "") + ''; @@ -237,14 +236,14 @@ var artistLinksHtml = LibraryBrowser.getArtistLinksHtml(item.Artists); - html += '' + artistLinksHtml + ''; + html += '' + artistLinksHtml + ''; } else { - html += ''; + html += ''; } } - if (options.showArtist) { + if (options.showAlbumArtist) { if (item.AlbumArtist) { diff --git a/dashboard-ui/scripts/mediaplayer-video.js b/dashboard-ui/scripts/mediaplayer-video.js index 66d94bd5aa..1b5e513efa 100644 --- a/dashboard-ui/scripts/mediaplayer-video.js +++ b/dashboard-ui/scripts/mediaplayer-video.js @@ -649,7 +649,7 @@ } // Just use the first audio stream - return audioStreams[0].Index; + return audioStreams.length ? audioStreams[0].Index : null; } function getVideoQualityOptions(mediaStreams) { diff --git a/dashboard-ui/scripts/songs.js b/dashboard-ui/scripts/songs.js index 8dd595c3cc..09c6c579df 100644 --- a/dashboard-ui/scripts/songs.js +++ b/dashboard-ui/scripts/songs.js @@ -50,6 +50,7 @@ html += LibraryBrowser.getSongTableHtml(result.Items, { showAlbum: true, showArtist: true, + showAlbumArtist: true, enableColumnSorting: true, sortBy: query.SortBy, sortOrder: query.SortOrder From 305646fa63f735f3dad727941f4324dc7ad587b2 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 10 Apr 2014 11:33:42 -0400 Subject: [PATCH 17/25] move lazy script --- dashboard-ui/scripts/librarybrowser.js | 8 ++++++-- dashboard-ui/scripts/musicartists.js | 6 ------ dashboard-ui/scripts/site.js | 4 ---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/dashboard-ui/scripts/librarybrowser.js b/dashboard-ui/scripts/librarybrowser.js index 6468b53de0..a2fc2608ae 100644 --- a/dashboard-ui/scripts/librarybrowser.js +++ b/dashboard-ui/scripts/librarybrowser.js @@ -1,5 +1,11 @@ var LibraryBrowser = (function (window, document, $, screen, localStorage) { + $(function() { + $("body").on("create", function () { + $(".lazy").unveil(200); + }); + }); + var defaultBackground = "#333"; return { @@ -432,8 +438,6 @@ options.shape = options.shape || "portrait"; - options.lazy = options.lazy || false; - var html = ""; var primaryImageAspectRatio = options.shape == 'auto' ? LibraryBrowser.getAveragePrimaryImageAspectRatio(items) : null; diff --git a/dashboard-ui/scripts/musicartists.js b/dashboard-ui/scripts/musicartists.js index 142bfaa3b2..a19d6581fa 100644 --- a/dashboard-ui/scripts/musicartists.js +++ b/dashboard-ui/scripts/musicartists.js @@ -120,10 +120,4 @@ updateFilterControls(this); }); - $(function () { - $("body").on("create", function () { - $(".lazy").unveil(200); - }); - }); - })(jQuery, document); \ No newline at end of file diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js index ddc4e42d00..7605914f35 100644 --- a/dashboard-ui/scripts/site.js +++ b/dashboard-ui/scripts/site.js @@ -1386,10 +1386,6 @@ $(function () { ApiClient.closeWebSocket(); } }); - - $("body").on("create", function () { - $(".lazy").unveil(200); - }); }); Dashboard.jQueryMobileInit(); From ad3f285dedeb37b21ece74fb77365cf95bdfbef5 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 10 Apr 2014 11:49:46 -0400 Subject: [PATCH 18/25] remove chromecast ui --- dashboard-ui/css/mediaplayer-video.css | 6 +- dashboard-ui/scripts/chromecast.js | 113 ++++++++++++------------- dashboard-ui/scripts/site.js | 30 +++---- 3 files changed, 74 insertions(+), 75 deletions(-) diff --git a/dashboard-ui/css/mediaplayer-video.css b/dashboard-ui/css/mediaplayer-video.css index 814bc66e39..49e3855e5e 100644 --- a/dashboard-ui/css/mediaplayer-video.css +++ b/dashboard-ui/css/mediaplayer-video.css @@ -139,7 +139,7 @@ text-align: left; margin-left: 0; right: 0; - bottom: 85px; + bottom: 83px; } /* Media queries @@ -259,7 +259,7 @@ } #mediaPlayer #videoControls .mediaPlayerFlyout { - bottom: 150px; + bottom: 148px; } } @@ -370,4 +370,4 @@ .cursor-inactive { cursor: none; -} +} \ No newline at end of file diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js index 51ad1ee90c..4001400a33 100644 --- a/dashboard-ui/scripts/chromecast.js +++ b/dashboard-ui/scripts/chromecast.js @@ -688,20 +688,20 @@ this.currentMediaSession.addUpdateListener(this.onMediaStatusUpdate.bind(this)); this.currentMediaDuration = this.currentMediaSession.media.duration; - var playTime = document.getElementById(this.playback); - if (!playTime) { - // Set duration time - var totalTime = document.getElementById(this.duration); - totalTime.innerHTML = " / " + formatTime(this.currentMediaDuration); + //var playTime = document.getElementById(this.playback); + //if (!playTime) { + // // Set duration time + // var totalTime = document.getElementById(this.duration); + // totalTime.innerHTML = " / " + formatTime(this.currentMediaDuration); - // Set play time - playTime = document.createElement("div"); - playTime.id = this.playback; - playTime.className = "currentTime"; - playTime.style.marginRight = "5px"; - totalTime.parentNode.insertBefore(playTime, totalTime); - playTime.innerHTML = formatTime(this.currentMediaTime); - } + // // Set play time + // playTime = document.createElement("div"); + // playTime.id = this.playback; + // playTime.className = "currentTime"; + // playTime.style.marginRight = "5px"; + // totalTime.parentNode.insertBefore(playTime, totalTime); + // playTime.innerHTML = formatTime(this.currentMediaTime); + //} }; function formatTime(duration) { @@ -829,10 +829,10 @@ this.onError.bind(this)); this.castPlayerState = PLAYER_STATE.STOPPED; clearInterval(this.timer); - var playTime = document.getElementById(this.playback); - if (playTime) { - playTime.parentNode.removeChild(playTime); - } + //var playTime = document.getElementById(this.playback); + //if (playTime) { + // playTime.parentNode.removeChild(playTime); + //} }; /** @@ -892,9 +892,8 @@ */ CastPlayer.prototype.seekMedia = function (event) { var pos = parseInt(event); - var p = document.getElementById(this.progressBar); + var curr = parseInt(this.currentMediaTime + this.currentMediaDuration * pos); - var pw = parseInt(p.value) + pos; if (this.castPlayerState != PLAYER_STATE.PLAYING && this.castPlayerState != PLAYER_STATE.PAUSED) { return; @@ -932,21 +931,21 @@ * @param {Object} e An media status update object */ CastPlayer.prototype.updateProgressBar = function (e) { - var p = document.getElementById(this.progressBar); - if (e.idleReason == 'FINISHED' && e.playerState == 'IDLE') { - p.value = 0; - clearInterval(this.timer); - this.castPlayerState = PLAYER_STATE.STOPPED; - if (e.idleReason == 'FINISHED') { - $.publish("/playback/complete", e); - console.log("playback complete", e); - } - } - else { - p.value = 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 - } + //var p = document.getElementById(this.progressBar); + //if (e.idleReason == 'FINISHED' && e.playerState == 'IDLE') { + // p.value = 0; + // clearInterval(this.timer); + // this.castPlayerState = PLAYER_STATE.STOPPED; + // if (e.idleReason == 'FINISHED') { + // $.publish("/playback/complete", e); + // console.log("playback complete", e); + // } + //} + //else { + // p.value = 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 + //} }; /** @@ -961,33 +960,33 @@ * Update progress bar based on timer */ CastPlayer.prototype.updateProgressBarByTimer = function () { - var p = document.getElementById(this.progressBar); - if (isNaN(parseInt(p.value))) { - p.value = 0; - } + //var p = document.getElementById(this.progressBar); + //if (isNaN(parseInt(p.value))) { + // p.value = 0; + //} - if (this.currentMediaDuration > 0) { - var pp = Number(this.currentMediaTime / this.currentMediaDuration).toFixed(3); + //if (this.currentMediaDuration > 0) { + // var pp = Number(this.currentMediaTime / this.currentMediaDuration).toFixed(3); - var startTime = this.currentMediaOffset / 10000000; - var playTime = document.getElementById(this.playback); - if (playTime) { - playTime.innerHTML = formatTime(startTime + this.currentMediaTime); - } - } + // var startTime = this.currentMediaOffset / 10000000; + // var playTime = document.getElementById(this.playback); + // if (playTime) { + // playTime.innerHTML = formatTime(startTime + this.currentMediaTime); + // } + //} - if (this.progressFlag) { - // don't update progress if it's been updated on media status update event - p.value = pp; - } + //if (this.progressFlag) { + // // don't update progress if it's been updated on media status update event + // p.value = pp; + //} - if (pp > 100 || this.castPlayerState == PLAYER_STATE.IDLE) { - clearInterval(this.timer); - this.deviceState = DEVICE_STATE.IDLE; - this.castPlayerState = PLAYER_STATE.IDLE; - $.publish("/playback/complete", true); - console.log("playback complete"); - } + //if (pp > 100 || this.castPlayerState == PLAYER_STATE.IDLE) { + // clearInterval(this.timer); + // this.deviceState = DEVICE_STATE.IDLE; + // this.castPlayerState = PLAYER_STATE.IDLE; + // $.publish("/playback/complete", true); + // console.log("playback complete"); + //} }; /** diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js index 7605914f35..55c6300821 100644 --- a/dashboard-ui/scripts/site.js +++ b/dashboard-ui/scripts/site.js @@ -1330,42 +1330,42 @@ $(function () { footerHtml += '
'; footerHtml += '
'; footerHtml += 'Playlist'; - footerHtml += ''; - footerHtml += ''; - footerHtml += ''; + footerHtml += ''; + footerHtml += ''; + footerHtml += ''; footerHtml += '
'; - footerHtml += ''; - footerHtml += ''; + footerHtml += ''; + footerHtml += ''; footerHtml += '
'; - footerHtml += ''; + footerHtml += ''; footerHtml += '
'; - footerHtml += '
'; + footerHtml += '
'; footerHtml += '
'; - footerHtml += ''; - footerHtml += ''; + footerHtml += ''; + footerHtml += ''; footerHtml += '
'; footerHtml += ''; footerHtml += '
'; - footerHtml += ''; + footerHtml += ''; footerHtml += '
'; - footerHtml += ''; + footerHtml += ''; footerHtml += '
'; - footerHtml += ''; + footerHtml += ''; footerHtml += '
'; - footerHtml += ''; + footerHtml += ''; footerHtml += '
'; - footerHtml += ''; + footerHtml += ''; footerHtml += '
'; @@ -1376,7 +1376,7 @@ $(function () { var footerElem = $('#footer', document.body); footerElem.trigger('create'); - + $(window).on("beforeunload", function () { // Close the connection gracefully when possible From bd697d36fc267d18fe86891ac24a6ac0992585cf Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 11 Apr 2014 11:36:25 -0400 Subject: [PATCH 19/25] extract nowplayingbar into standalone widget to work with any player --- dashboard-ui/css/mediaplayer-video.css | 91 ++- dashboard-ui/css/mediaplayer.css | 189 ++----- dashboard-ui/scripts/chromecast.js | 25 +- dashboard-ui/scripts/edititempeople.js | 2 +- dashboard-ui/scripts/itemdetailpage.js | 2 +- dashboard-ui/scripts/librarymenu.js | 2 +- dashboard-ui/scripts/mediacontroller.js | 7 +- dashboard-ui/scripts/mediaplayer-video.js | 100 +++- dashboard-ui/scripts/mediaplayer.js | 524 +++++++++--------- dashboard-ui/scripts/nowplayingbar.js | 359 ++++++++++++ dashboard-ui/scripts/site.js | 51 +- dashboard-ui/scripts/userimagepage.js | 2 +- dashboard-ui/scripts/userprofilespage.js | 2 +- .../thirdparty/jquery.ba-tinypubsub.min.js | 4 - .../thirdparty/mediabrowser.apiclient.js | 234 +------- 15 files changed, 879 insertions(+), 715 deletions(-) create mode 100644 dashboard-ui/scripts/nowplayingbar.js delete mode 100644 dashboard-ui/thirdparty/jquery.ba-tinypubsub.min.js rename ApiClient.js => dashboard-ui/thirdparty/mediabrowser.apiclient.js (93%) diff --git a/dashboard-ui/css/mediaplayer-video.css b/dashboard-ui/css/mediaplayer-video.css index 49e3855e5e..f3fc57bcdb 100644 --- a/dashboard-ui/css/mediaplayer-video.css +++ b/dashboard-ui/css/mediaplayer-video.css @@ -111,7 +111,7 @@ #mediaPlayer .ui-slider-handle { height: 12px !important; - margin-top: -7px !important; + margin-top: -7px !important; } #videoPlayer.fullscreenVideo #videoControls { @@ -212,10 +212,6 @@ /****************************************/ @media all and (max-width: 1200px), all and (max-height: 720px) { - #videoControls .nowPlayingMediaInfo { - display: none; - } - #videoControls .currentTime { margin-right: 0; min-width: 120px; @@ -370,4 +366,87 @@ .cursor-inactive { cursor: none; -} \ No newline at end of file +} + +.mediaFlyoutContainer { + display: inline-block; +} + +.mediaPlayerFlyout { + width: 200px; + color: #000; + background-color: #fff; + border: 1px solid #999; + position: absolute; + z-index: 99999; + bottom: 78px; + margin-left: -125px; + max-height: 300px; + overflow-y: auto; + font-size: 13px; +} + +.chaptersFlyout, .audioTracksFlyout { + width: 250px; + margin-left: -150px; +} + +.mediaFlyoutOption { + display: block; + text-decoration: none; + color: #000; + border-bottom: 1px solid #eee; + cursor: pointer; +} + + .mediaFlyoutOption:hover, .mediaFlyoutOption:focus { + background-color: #eee; + } + +.selectedMediaFlyoutOption { + background-color: #d9F4FF; + background-image: url(images/media/selected.png); + background-repeat: no-repeat; + background-position: right top; + background-size: 16px 16px; +} + +.mediaFlyoutOptionImage { + display: inline-block; + width: 15%; + vertical-align: middle; +} + + .mediaFlyoutOptionImage + .mediaFlyoutOptionContent { + vertical-align: top; + display: inline-block; + width: 85%; + } + +.chaptersFlyout .mediaFlyoutOptionImage { + width: 40%; +} + + .chaptersFlyout .mediaFlyoutOptionImage + .mediaFlyoutOptionContent { + width: 60%; + } + +.mediaFlyoutOptionName { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + padding-left: 5px; + font-size: 13px; + font-weight: normal; +} + +.mediaFlyoutOptionSecondaryText { + font-size: 13px; + color: #333; + font-weight: normal; + margin-top: 3px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + padding-left: 5px; +} diff --git a/dashboard-ui/css/mediaplayer.css b/dashboard-ui/css/mediaplayer.css index c1a1e176db..c44552e70c 100644 --- a/dashboard-ui/css/mediaplayer.css +++ b/dashboard-ui/css/mediaplayer.css @@ -1,21 +1,9 @@ /* Now playing bar */ .nowPlayingBar { - padding: 6px 0 20px 0; + padding: 10px 0 14px 0; border-top: 2px solid green; } - .nowPlayingBar .barBackground { - border-top: 2px solid green; - position: absolute; - margin: -8px -0.5em -22px !important; - width: 100%; - height: 100%; - } - - .nowPlayingBar > *:not(#mediaElement):not(.mediaFlyoutContainer):not(.barBackground ) { - position: relative; - } - .nowPlayingBarImage { vertical-align: bottom; } @@ -29,27 +17,32 @@ position: relative; } -.nowPlayingMediaInfo div { - display: inline-block; -} - -.nowPlayingMediaInfo a { - margin-right: .25em; -} - - -.nowPlayingMediaInfo { - display: inline-block; -} - .nowPlayingText { - position: relative; - top: -3px; - margin-left: 3px; - margin-right: 2em; + display: inline-block; font-weight: normal; + position: relative; + top: -7px; + margin-left: 3px; + max-width: 200px; + overflow: hidden; + margin-right: 2em; + white-space: nowrap; } +.nowPlayingDoubleText { + top: 0; +} + +.nowPlayingImage { + display: inline-block; +} + + .nowPlayingImage img { + height: 40px; + margin-right: .5em; + vertical-align: bottom; + } + .mediaButton img { height: 24px; } @@ -60,7 +53,6 @@ top: -10px; max-width: 110px; margin-right: 2em; - font-size: 14px; font-weight: normal; } @@ -127,125 +119,27 @@ input[type="range"]::-ms-fill-upper { } @media all and (max-width: 800px) { - #nowPlayingBar .volumeButton, #nowPlayingBar .volumeSliderContainer, #nowPlayingBar .muteButton, #nowPlayingBar .unmuteButton, #nowPlayingBar .nowPlayingMediaInfo { - display: none; /*!important;*/ - } -} -@media all and (max-width: 650px) { - #nowPlayingBar .nowPlayingMediaInfo { - display: none; - } -} - -@media all and (max-width: 600px) { - #nowPlayingBar .chaptersButton, #nowPlayingBar .audioTracksButton { - display: none; /*!important;*/ + #nowPlayingBar .mediaButton { + margin-top: 0; + margin-bottom: 0; } - #nowPlayingBar .positionSliderContainer, #nowPlayingBar .currentTime { - top: 0!important; - position: relative!important; - } -} + #nowPlayingBar .mediaButton:not(#playButton):not(#pauseButton) { + display: none; + } -@media all and (max-width: 500px) { - #nowPlayingBar .positionSliderContainer { - width: 80px; + #nowPlayingBar #playButton, #nowPlayingBar #pauseButton { + float: right; } - #nowPlayingBar .previousTrackButton, #nowPlayingBar .nextTrackButton { - display: none; /*!important;*/ - } -} - -@media all and (max-width: 400px) { - #nowPlayingBar .playlistButton { - display: none; /*!important;*/ - } -} - -.mediaFlyoutContainer { - display: inline-block; -} - -.mediaPlayerFlyout { - width: 200px; - color: #000; - background-color: #fff; - border: 1px solid #999; - position: absolute; - z-index: 99999; - bottom: 78px; - margin-left: -125px; - max-height: 300px; - overflow-y: auto; - font-size: 13px; -} - -.chaptersFlyout,.audioTracksFlyout { - width: 250px; - margin-left: -150px; -} - -.mediaFlyoutOption { - display: block; - text-decoration: none; - color: #000; - border-bottom: 1px solid #eee; - cursor: pointer; -} - - .mediaFlyoutOption:hover, .mediaFlyoutOption:focus { - background-color: #eee; + #nowPlayingBar .currentTime, #nowPlayingBar .positionSliderContainer, #nowPlayingBar .volumeSliderContainer, #nowPlayingBar .muteButton, #nowPlayingBar .unmuteButton { + display: none !important; } -.selectedMediaFlyoutOption { - background-color: #d9F4FF; - background-image: url(images/media/selected.png); - background-repeat: no-repeat; - background-position: right top; - background-size: 16px 16px; -} - -.mediaFlyoutOptionImage { - display: inline-block; - width: 15%; - vertical-align: middle; -} - - .mediaFlyoutOptionImage + .mediaFlyoutOptionContent { - vertical-align: top; - display: inline-block; - width: 85%; + .nowPlayingBar { + padding: 10px 5px 10px 0; } - -.chaptersFlyout .mediaFlyoutOptionImage { - width: 40%; -} - - .chaptersFlyout .mediaFlyoutOptionImage + .mediaFlyoutOptionContent { - width: 60%; - } - -.mediaFlyoutOptionName { - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - padding-left: 5px; - font-size: 13px; - font-weight: normal; -} - -.mediaFlyoutOptionSecondaryText { - font-size: 13px; - color: #333; - font-weight: normal; - margin-top: 3px; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - padding-left: 5px; } @media (min-width: 1440px) { @@ -253,3 +147,16 @@ input[type="range"]::-ms-fill-upper { width: 300px; } } + +.mediaPlayerAudioContainer { + position: fixed; + top: 40%; + text-align: center; + left: 0; + right: 0; +} + +.mediaPlayerAudioContainerInner { + padding: 1em; + background: #222; +} diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js index 4001400a33..792185d9be 100644 --- a/dashboard-ui/scripts/chromecast.js +++ b/dashboard-ui/scripts/chromecast.js @@ -241,6 +241,7 @@ }; function getCodecLimits() { + return { maxVideoAudioChannels: 6, @@ -608,7 +609,7 @@ url += '&maxheight=' + codecLimits.maxHeight; url += '&videoCodec=h264'; - url += '&audioCodec=aac'; + url += '&audioCodec=aac,mp3'; url += '&audiosamplerate=' + codecLimits.maxSampleRate; url += '&mediasourceid=' + mediaSourceInfo.mediaSource.Id; @@ -1004,7 +1005,7 @@ var castPlayer = new CastPlayer(); - function chromecastPlayer(castPlayer) { + function chromecastPlayer() { var self = this; @@ -1018,11 +1019,11 @@ self.playlistIndex = 0; - $.subscribe("/playback/complete", function (e) { - if (self.playlistIndex < (self.playlist.items || []).length) { - self.play(self.playlist); - } - }); + //$.subscribe("/playback/complete", function (e) { + // if (self.playlistIndex < (self.playlist.items || []).length) { + // self.play(self.playlist); + // } + //}); ////$(".positionSlider", "#footer").off("slidestart slidestop") //// .on('slidestart', function (e) { @@ -1043,13 +1044,13 @@ query.ExcludeLocationTypes = "Virtual"; return ApiClient.getItems(userId, query); - }; + } function queueItems (items) { for (var i = 0, length = items.length; i < length; i++) { self.playlist.push(items[i]); } - }; + } function queueItemsNext(items) { var insertIndex = 1; @@ -1057,7 +1058,7 @@ self.playlist.splice(insertIndex, 0, items[i]); insertIndex++; } - }; + } function translateItemsForPlayback(items) { var deferred = $.Deferred(); @@ -1100,7 +1101,7 @@ } return deferred.promise(); - }; + } self.play = function (options) { console.log("play", options); @@ -1371,7 +1372,7 @@ }; } - MediaController.registerPlayer(new chromecastPlayer(castPlayer)); + MediaController.registerPlayer(new chromecastPlayer()); $(MediaController).on('playerchange', function () { diff --git a/dashboard-ui/scripts/edititempeople.js b/dashboard-ui/scripts/edititempeople.js index 6c026f4837..91a4ee6822 100644 --- a/dashboard-ui/scripts/edititempeople.js +++ b/dashboard-ui/scripts/edititempeople.js @@ -57,7 +57,7 @@ if (person.PrimaryImageTag) { imgUrl = ApiClient.getPersonImageUrl(person.Name, { - height: 280, + width: 150, tag: person.PrimaryImageTag, type: "primary" }); diff --git a/dashboard-ui/scripts/itemdetailpage.js b/dashboard-ui/scripts/itemdetailpage.js index a6402773f1..19c4e97ec3 100644 --- a/dashboard-ui/scripts/itemdetailpage.js +++ b/dashboard-ui/scripts/itemdetailpage.js @@ -1238,7 +1238,7 @@ if (cast.PrimaryImageTag) { imgUrl = ApiClient.getPersonImageUrl(cast.Name, { - width: 130, + width: 100, tag: cast.PrimaryImageTag, type: "primary" }); diff --git a/dashboard-ui/scripts/librarymenu.js b/dashboard-ui/scripts/librarymenu.js index 9610733899..6b9e03168a 100644 --- a/dashboard-ui/scripts/librarymenu.js +++ b/dashboard-ui/scripts/librarymenu.js @@ -31,7 +31,7 @@ if (user.PrimaryImageTag) { var url = ApiClient.getUserImageUrl(user.Id, { - height: 40, + height: 24, tag: user.PrimaryImageTag, type: "Primary" }); diff --git a/dashboard-ui/scripts/mediacontroller.js b/dashboard-ui/scripts/mediacontroller.js index c755df654f..74672e59a0 100644 --- a/dashboard-ui/scripts/mediacontroller.js +++ b/dashboard-ui/scripts/mediacontroller.js @@ -175,6 +175,11 @@ })[0]; }; + self.getCurrentPlayer = function () { + + return currentPlayer; + }; + self.pause = function () { currentPlayer.pause(); }; @@ -188,7 +193,7 @@ }; self.seek = function (position) { - currentPlayer.changeStream(position); + currentPlayer.seek(position); }; self.currentPlaylistIndex = function (i) { diff --git a/dashboard-ui/scripts/mediaplayer-video.js b/dashboard-ui/scripts/mediaplayer-video.js index 1a7395a0a0..ba7fef777d 100644 --- a/dashboard-ui/scripts/mediaplayer-video.js +++ b/dashboard-ui/scripts/mediaplayer-video.js @@ -23,6 +23,13 @@ var idleState = true; var remoteFullscreen = false; + var muteButton = null; + var unmuteButton = null; + var volumeSlider = null; + var positionSlider; + var isPositionSliderActive; + var currentTimeElement; + self.initVideoPlayer = function () { video = playVideo(item, mediaSource, startPosition, user); return video; @@ -66,7 +73,7 @@ self.resetEnhancements = function () { $("#mediaPlayer").hide(); $('#videoPlayer').removeClass('fullscreenVideo'); - $("#videoControls").removeClass("inactive") + $("#videoControls").removeClass("inactive"); $("video").remove(); $("html").css("cursor", "default"); $(".ui-loader").hide(); @@ -155,7 +162,38 @@ } }); + function onPositionSliderChange() { + + isPositionSliderActive = false; + + var newPercent = parseInt(this.value); + + var newPositionTicks = (newPercent / 100) * currentMediaSource.RunTimeTicks; + + self.changeStream(Math.floor(newPositionTicks)); + } + $(function () { + + var parent = $("#mediaPlayer"); + muteButton = $('.muteButton', parent); + unmuteButton = $('.unmuteButton', parent); + currentTimeElement = $('.currentTime', parent); + + positionSlider = $(".positionSlider", parent).on('slidestart', function (e) { + + isPositionSliderActive = true; + + }).on('slidestop', onPositionSliderChange); + + volumeSlider = $('.volumeSlider', parent).on('slidestop', function () { + + var vol = this.value; + + updateVolumeButtons(vol); + self.setVolume(vol * 100); + }); + $('#video-chaptersFlyout').on('click', '.mediaFlyoutOption', function () { var ticks = parseInt(this.getAttribute('data-positionticks')); @@ -264,6 +302,17 @@ }, 4000); } + function updateVolumeButtons(vol) { + + if (vol) { + muteButton.show(); + unmuteButton.hide(); + } else { + muteButton.hide(); + unmuteButton.show(); + } + } + function requestFullScreen(element) { // Supports most browsers and their versions. @@ -729,7 +778,7 @@ return options; } - + function playVideo(item, mediaSource, startPosition, user) { var mediaStreams = mediaSource.MediaStreams || []; @@ -771,7 +820,10 @@ videoBitrate: mp4Quality.videoBitrate, audioBitrate: mp4Quality.audioBitrate, VideoCodec: mp4Quality.videoCodec, - AudioCodec: mp4Quality.audioCodec + AudioCodec: mp4Quality.audioCodec, + + // None of the browsers seem to like this + EnableAutoStreamCopy: false })) + seekParam; @@ -781,7 +833,8 @@ AudioCodec: 'Vorbis', maxWidth: webmQuality.maxWidth, videoBitrate: webmQuality.videoBitrate, - audioBitrate: webmQuality.audioBitrate + audioBitrate: webmQuality.audioBitrate, + EnableAutoStreamCopy: false })) + seekParam; @@ -874,42 +927,26 @@ var video = $("video", videoElement); - initialVolume = localStorage.getItem("volume") || 0.5; + initialVolume = self.getSavedVolume(); video.each(function () { this.volume = initialVolume; }); - self.volumeSlider.val(initialVolume).slider('refresh'); - self.updateVolumeButtons(initialVolume); + volumeSlider.val(initialVolume).slider('refresh'); + updateVolumeButtons(initialVolume); video.on("volumechange", function (e) { - var muted = this.muted; - var vol = this.volume; - if (!muted && this.volume > 0) { - localStorage.setItem("volume", vol); - } - - this.muted = this.volume == 0; - - self.updateVolumeButtons(vol); - - }).on("play.once", function () { - - video.off("play.once"); + updateVolumeButtons(vol); }).on("playing.once", function () { - self.updateCanClientSeek(this); - video.off("playing.once"); - ApiClient.reportPlaybackStart(Dashboard.getCurrentUserId(), item.Id, mediaSource.Id, true, item.MediaType); - - self.startProgressInterval(item.Id, mediaSource.Id); + self.onPlaybackStart(this, item, mediaSource); }).on("pause", function (e) { @@ -939,9 +976,9 @@ }).on("timeupdate", function () { - if (!self.isPositionSliderActive) { + if (!isPositionSliderActive) { - self.setCurrentTime(self.getCurrentTicks(this), item, true); + self.setCurrentTime(self.getCurrentTicks(this), positionSlider, currentTimeElement); } }).on("error", function () { @@ -995,8 +1032,13 @@ $(".ui-loader").hide(); $("html").css("cursor", "default"); - }).on("ended.playbackstopped", self.onPlaybackStopped) - .on('ended.playnext', self.playNextAfterEnded); + }).on("ended.playbackstopped", function () { + + currentTimeElement.empty(); + + self.onPlaybackStopped.call(this); + + }).on('ended.playnext', self.playNextAfterEnded); // Stop playback on browser back button nav $(window).on("popstate", function () { diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index 516c10cde1..37da88a433 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -13,12 +13,6 @@ var currentPlaylistIndex = 0; self.currentDurationTicks = null; - self.currentTimeElement = null; - self.unmuteButton = null; - self.muteButton = null; - self.positionSlider = null; - self.isPositionSliderActive = null; - self.volumeSlider = null; self.startTimeTicksOffset = null; self.playlist = []; @@ -45,22 +39,11 @@ canClientSeek = duration && !isNaN(duration) && duration != Number.POSITIVE_INFINITY && duration != Number.NEGATIVE_INFINITY; }; - self.updateVolumeButtons = function (vol) { - - if (vol) { - self.muteButton.show().prop("disabled", false); - self.unmuteButton.hide().prop("disabled", true); - } else { - self.muteButton.hide().prop("disabled", true); - self.unmuteButton.show().prop("disabled", false); - } - }; - self.getCurrentTicks = function (mediaElement) { return Math.floor(10000000 * (mediaElement || currentMediaElement).currentTime) + self.startTimeTicksOffset; }; - self.clearPauseStop = function() { + self.clearPauseStop = function () { if (self.pauseStop) { console.log('clearing pause stop timer'); @@ -69,31 +52,6 @@ } }; - self.onPlaybackStopped = function () { - - self.clearPauseStop(); - - $(this).off('ended.playbackstopped'); - - self.currentTimeElement.empty(); - - var endTime = this.currentTime; - - clearProgressInterval(); - - var position = Math.floor(10000000 * endTime) + self.startTimeTicksOffset; - - ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentItem.Id, currentMediaSource.Id, position); - - if (currentItem.MediaType == "Video") { - ApiClient.stopActiveEncodings(); - if (self.isFullScreen()) { - self.exitFullScreen(); - } - self.resetEnhancements(); - } - }; - self.playNextAfterEnded = function () { $(this).off('ended.playnext'); @@ -210,7 +168,7 @@ } }; - self.setCurrentTime = function (ticks, item, updateSlider) { + self.setCurrentTime = function (ticks, positionSlider, currentTimeElement) { // Convert to ticks ticks = Math.floor(ticks); @@ -221,17 +179,28 @@ timeText += " / " + Dashboard.getDisplayTime(self.currentDurationTicks); - if (updateSlider) { + if (positionSlider) { + var percent = ticks / self.currentDurationTicks; percent *= 100; - self.positionSlider.val(percent).slider('enable').slider('refresh'); + positionSlider.val(percent).slider('enable').slider('refresh'); } } else { - self.positionSlider.slider('disable').slider('refresh'); + + if (positionSlider) { + + positionSlider.slider('disable').slider('refresh'); + } } - self.currentTimeElement.html(timeText); + if (currentTimeElement) { + currentTimeElement.html(timeText); + } + + var state = self.getPlayerState(currentMediaElement, currentItem, currentMediaSource); + + $(self).trigger('positionchange', [state]); }; self.canPlayVideoDirect = function (mediaSource, videoStream, audioStream, subtitleStream, maxWidth, bitrate) { @@ -459,8 +428,6 @@ var mediaElement; - var mediaControls = $('#nowPlayingBar'); - if (item.MediaType === "Video") { currentItem = item; @@ -470,15 +437,12 @@ mediaElement = self.initVideoPlayer(); self.currentDurationTicks = currentMediaSource.RunTimeTicks; - mediaControls = $("#videoControls"); - } else if (item.MediaType === "Audio") { currentItem = item; currentMediaSource = getOptimalMediaSource(item.MediaType, item.MediaSources); mediaElement = playAudio(item, currentMediaSource, startPosition); - mediaControls.show(); self.currentDurationTicks = currentMediaSource.RunTimeTicks; @@ -488,36 +452,50 @@ currentMediaElement = mediaElement; - //display image and title - var imageTags = item.ImageTags || {}; - var html = ''; + if (item.MediaType === "Video") { + + self.updateNowPlayingInfo(item); + } + }; + + self.updateNowPlayingInfo = function (item) { + + if (!item) { + throw new Error('item cannot be null'); + } + + var mediaControls = $("#videoControls"); + + var state = self.getPlayerState(currentMediaElement, item, currentMediaSource); var url = ""; - if (imageTags.Primary) { + if (state.primaryImageTag) { - url = ApiClient.getImageUrl(item.Id, { + url = ApiClient.getImageUrl(state.primaryImageItemId, { type: "Primary", height: 80, - tag: item.ImageTags.Primary + tag: state.primaryImageTag }); } - else if (item.BackdropImageTags && item.BackdropImageTags.length) { + else if (state.backdropImageTag) { - url = ApiClient.getImageUrl(item.Id, { + url = ApiClient.getImageUrl(state.backdropItemId, { type: "Backdrop", height: 80, - tag: item.BackdropImageTags[0] + tag: state.backdropImageTag, + index: 0 }); - } else if (imageTags.Thumb) { - url = ApiClient.getImageUrl(item.Id, { + } else if (state.thumbImageTag) { + + url = ApiClient.getImageUrl(state.thumbImageItemId, { type: "Thumb", height: 80, - tag: item.ImageTags.Thumb + tag: state.thumbImageTag }); - } + else if (item.Type == "TvChannel" || item.Type == "Recording") { url = "css/images/items/detail/tv.png"; } @@ -528,40 +506,19 @@ url = "css/images/items/detail/video.png"; } - var name = item.Name; - var seriesName = ''; + var name = state.itemName; - // Channel number - if (item.Number) { - name = item.Number + ' ' + name; - } - if (item.IndexNumber != null) { - name = item.IndexNumber + " - " + name; - } - if (item.ParentIndexNumber != null) { - name = item.ParentIndexNumber + "." + name; - } - if (item.SeriesName || item.Album || item.ProductionYear) { - seriesName = item.SeriesName || item.Album || item.ProductionYear; - } - if (item.CurrentProgram) { - seriesName = item.CurrentProgram.Name; + var nowPlayingTextElement = $('.nowPlayingText', mediaControls); + + if (state.itemSubName) { + name += '
' + state.itemSubName; + nowPlayingTextElement.addClass('nowPlayingDoubleText'); + } else { + nowPlayingTextElement.removeClass('nowPlayingDoubleText'); } - var href = LibraryBrowser.getHref(item.CurrentProgram || item); - - var nowPlayingText = (name ? name + "\n" : "") + (seriesName || "---"); - if (item.SeriesName || item.Album || item.CurrentProgram) { - nowPlayingText = (seriesName ? seriesName : "") + "\n" + (name || "---"); - } - - // Fix for apostrophes and quotes - var htmlTitle = trimTitle(nowPlayingText).replace(/'/g, ''').replace(/"/g, '"'); - html += "
" + htmlTitle +
-                "
"; - html += "
" + titleHtml(nowPlayingText) + "
"; - - $('.nowPlayingMediaInfo', mediaControls).html(html); + $('.nowPlayingImage', mediaControls).html(''); + nowPlayingTextElement.html(name); }; self.getItemsForPlayback = function (query) { @@ -727,51 +684,65 @@ self.mute = function () { - if (currentMediaElement) { - currentMediaElement.volume = 0; - currentMediaElement.muted = true; - self.volumeSlider.val(0).slider('refresh'); - } + self.setVolume(0); }; - self.unmute = function () { + self.unMute = function () { - if (currentMediaElement) { - var volume = localStorage.getItem("volume") || self.volumeSlider.val(); - currentMediaElement.volume = volume; - currentMediaElement.muted = false; - self.volumeSlider.val(volume).slider('refresh'); - } + self.setVolume(self.getSavedVolume() * 100); }; self.toggleMute = function () { if (currentMediaElement) { - var volume = localStorage.getItem("volume") || self.volumeSlider.val(); - currentMediaElement.volume = currentMediaElement.volume ? 0 : volume; - currentMediaElement.muted = currentMediaElement.volume == 0; - self.volumeSlider.val(volume).slider('refresh'); + + if (currentMediaElement.volume) { + self.mute(); + } else { + self.unMute(); + } } }; self.volumeDown = function () { if (currentMediaElement) { - currentMediaElement.volume = Math.max(currentMediaElement.volume - .02, 0); - localStorage.setItem("volume", currentMediaElement.volume); - self.volumeSlider.val(currentMediaElement.volume).slider('refresh'); + self.setVolume(Math.max(currentMediaElement.volume - .02, 0) * 100); } }; self.volumeUp = function () { if (currentMediaElement) { - currentMediaElement.volume = Math.min(currentMediaElement.volume + .02, 1); - localStorage.setItem("volume", currentMediaElement.volume); - self.volumeSlider.val(currentMediaElement.volume).slider('refresh'); + self.setVolume(Math.min(currentMediaElement.volume + .02, 1) * 100); } }; + // Sets volume using a 0-100 scale + self.setVolume = function (val) { + + if (currentMediaElement) { + + currentMediaElement.volume = val / 100; + + self.onVolumeChanged(currentMediaElement); + + self.saveVolume(); + } + }; + + self.saveVolume = function (val) { + + if (val) { + localStorage.setItem("volume", val); + } + + }; + + self.getSavedVolume = function () { + return localStorage.getItem("volume") || 0.5; + }; + self.shuffle = function (id) { var userId = Dashboard.getCurrentUserId(); @@ -882,7 +853,12 @@ $(elem).off("ended.playnext").on("ended", function () { - $(this).remove(); + $(this).off(); + + if (this.tagName.toLowerCase() != 'audio') { + $(this).remove(); + } + elem.src = ""; currentMediaElement = null; @@ -893,8 +869,6 @@ self.exitFullScreen(); } self.resetEnhancements(); - } else { - $('#nowPlayingBar').hide(); } }; @@ -902,55 +876,150 @@ return currentMediaElement; }; - self.bindPositionSlider = function () { - self.positionSlider.on('slidestart', function (e) { + self.getPlayerState = function (playerElement, item, mediaSource) { - self.isPositionSliderActive = true; + var itemName = ''; + var itemSubName = ''; - }).on('slidestop', onPositionSliderChange); + if (item) { + + var name = item.Name; + var seriesName = ''; + + // Channel number + if (item.Number) { + name = item.Number + ' ' + name; + } + if (item.IndexNumber != null) { + name = item.IndexNumber + " - " + name; + } + if (item.ParentIndexNumber != null) { + name = item.ParentIndexNumber + "." + name; + } + + if (item.CurrentProgram) { + seriesName = item.CurrentProgram.Name; + } + else if (item.SeriesName || item.Album || item.ProductionYear) { + seriesName = item.SeriesName || item.Album || item.ProductionYear; + } + + if (seriesName) { + itemName = item.SeriesName || item.Album || item.CurrentProgram; + itemSubName = name; + } else { + itemName = name; + } + } + + var state = { + itemId: item.Id, + mediaSourceId: mediaSource.Id, + volumeLevel: playerElement.volume * 100, + isMuted: playerElement.volume == 0, + isPaused: playerElement.paused, + runtimeTicks: mediaSource.RunTimeTicks, + positionTicks: self.getCurrentTicks(playerElement), + canSeek: mediaSource.RunTimeTicks && mediaSource.RunTimeTicks > 0, + mediaType: item.MediaType, + itemName: itemName, + itemSubName: itemSubName, + itemType: item.Type + }; + + var imageTags = item.ImageTags || {}; + + if (imageTags.Primary) { + + state.primaryImageItemId = item.Id; + state.primaryImageTag = imageTags.Primary; + } + + if (item.BackdropImageTags && item.BackdropImageTags.length) { + + state.backdropItemId = item.Id; + state.backdropImageTag = item.BackdropImageTags[0]; + } + + if (imageTags.Thumb) { + + state.thumbItemId = item.Id; + state.thumbImageTag = imageTags.Thumb; + } + + return state; }; - self.bindVolumeSlider = function () { - self.volumeSlider.on('slidestop', function () { + self.onPlaybackStart = function (playerElement, item, mediaSource) { - var vol = this.value; + self.updateCanClientSeek(playerElement); - self.updateVolumeButtons(vol); - currentMediaElement.volume = vol; - }); + ApiClient.reportPlaybackStart(Dashboard.getCurrentUserId(), item.Id, mediaSource.Id, true, item.MediaType); + + self.startProgressInterval(item.Id, mediaSource.Id); + + var state = self.getPlayerState(playerElement, item, mediaSource); + + $(self).trigger('playbackstart', [state]); + }; + + self.onVolumeChanged = function (playerElement) { + + self.saveVolume(playerElement.volume); + + var state = self.getPlayerState(playerElement, currentItem, currentMediaSource); + + $(self).trigger('volumechange', [state]); + }; + + self.onPlaybackStopped = function () { + + self.clearPauseStop(); + + var playerElement = this; + + $(playerElement).off('ended.playbackstopped'); + + var endTime = playerElement.currentTime; + + clearProgressInterval(); + + var position = Math.floor(10000000 * endTime) + self.startTimeTicksOffset; + + var item = currentItem; + var mediaSource = currentMediaSource; + + ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), item.Id, mediaSource.Id, position); + + if (item.MediaType == "Video") { + ApiClient.stopActiveEncodings(); + if (self.isFullScreen()) { + self.exitFullScreen(); + } + self.resetEnhancements(); + } + + var state = self.getPlayerState(playerElement, item, mediaSource); + + $(self).trigger('playbackstop', [state]); + }; + + self.onPlaystateChange = function (playerElement) { + + var state = self.getPlayerState(playerElement, currentItem, currentMediaSource); + + $(self).trigger('playstatechange', [state]); }; $(window).on("beforeunload popstate", function () { - var item = currentItem; - var media = currentMediaElement; - // Try to report playback stopped before the browser closes - if (item && media && currentProgressInterval) { + if (currentItem && currentMediaElement && currentProgressInterval) { - var endTime = currentMediaElement.currentTime; - - var position = Math.floor(10000000 * endTime) + self.startTimeTicksOffset; - - ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentItem.Id, currentMediaSource.Id, position); + self.onPlaybackStopped.call(currentMediaElement); } }); - $(function () { - initPlayer(); - }); - - function initPlayer() { - self.muteButton = $('.muteButton'); - self.unmuteButton = $('.unmuteButton'); - self.currentTimeElement = $('.currentTime'); - self.volumeSlider = $('.volumeSlider'); - self.positionSlider = $(".positionSlider"); - - self.bindVolumeSlider(); - self.bindPositionSlider(); - } - function replaceQueryString(url, param, value) { var re = new RegExp("([?|&])" + param + "=.*?(&|$)", "i"); if (url.match(re)) @@ -977,15 +1046,30 @@ return testableVideoElement.canPlayType('video/webm').replace(/no/, ''); } - function onPositionSliderChange() { + function getAudioElement() { - self.isPositionSliderActive = false; + var elem = $('.mediaPlayerAudio'); - var newPercent = parseInt(this.value); + if (elem.length) { + return elem; + } - var newPositionTicks = (newPercent / 100) * currentMediaSource.RunTimeTicks; + var html = ''; - self.changeStream(Math.floor(newPositionTicks)); + var requiresControls = $.browser.android || ($.browser.webkit && !$.browser.chrome); + + if (requiresControls) { + html += '
';; + } else { + html += ''; + + $(document.body).append(html); + + return $('.mediaPlayerAudio'); } function playAudio(item, mediaSource, startPositionTicks) { @@ -1003,18 +1087,10 @@ audioCodec: 'mp3' })); - var aacUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.aac', $.extend({}, baseParams, { - audioCodec: 'aac' - })); - - var webmUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.webm', $.extend({}, baseParams, { - audioCodec: 'Vorbis' - })); - var mediaStreams = mediaSource.MediaStreams; var isStatic = false; - var seekParam = isStatic && startPositionTicks ? '#t=' + (startPositionTicks / 10000000) : ''; + var seekParam = startPositionTicks ? '#t=' + (startPositionTicks / 10000000) : ''; for (var i = 0, length = mediaStreams.length; i < length; i++) { @@ -1024,11 +1100,7 @@ var container = (mediaSource.Container || '').toLowerCase(); // Stream statically when possible - if (container == 'aac' && stream.BitRate <= 256000) { - aacUrl += "&static=true" + seekParam; - isStatic = true; - } - else if (container == 'mp3' && stream.BitRate <= 256000) { + if (container == 'mp3' && stream.BitRate <= 256000) { mp3Url += "&static=true" + seekParam; isStatic = true; } @@ -1038,91 +1110,39 @@ self.startTimeTicksOffset = isStatic ? 0 : startPositionTicks; - var html = ''; + var initialVolume = self.getSavedVolume(); - var requiresControls = $.browser.android || ($.browser.webkit && !$.browser.chrome); + return getAudioElement().each(function () { - // Can't autoplay in these browsers so we need to use the full controls - if (requiresControls) { - html += '
'; // video-advanced-controls diff --git a/dashboard-ui/thirdparty/mediabrowser.apiclient.js b/dashboard-ui/thirdparty/mediabrowser.apiclient.js index e735ed47e5..a6c08509d5 100644 --- a/dashboard-ui/thirdparty/mediabrowser.apiclient.js +++ b/dashboard-ui/thirdparty/mediabrowser.apiclient.js @@ -2314,9 +2314,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi throw new Error("itemId cannot be empty"); } - options = options || { - - }; + options = options || {}; var url = "Items/" + itemId + "/Images/" + options.type; From 2835534c6db211a60fc9c62a6793aa10b27d61f1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 12 Apr 2014 13:27:53 -0400 Subject: [PATCH 21/25] control remote players with now playing bar --- dashboard-ui/scripts/chromecast.js | 25 +++ dashboard-ui/scripts/mediacontroller.js | 27 ++- dashboard-ui/scripts/mediaplayer.js | 109 ++++++---- dashboard-ui/scripts/nowplayingbar.js | 57 +++--- dashboard-ui/scripts/remotecontrol.js | 189 +++++++++++++++++- .../thirdparty/mediabrowser.apiclient.js | 26 ++- 6 files changed, 342 insertions(+), 91 deletions(-) diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js index 792185d9be..2f75ed9e47 100644 --- a/dashboard-ui/scripts/chromecast.js +++ b/dashboard-ui/scripts/chromecast.js @@ -1010,6 +1010,7 @@ var self = this; var isPositionSliderActive = false; + var currentPlaylistIndex; self.name = PlayerName; @@ -1365,11 +1366,35 @@ } }; + self.beginPlayerUpdates = function () { + // Setup polling here + }; + + self.endPlayerUpdates = function () { + // Stop polling here + }; + self.volumeDown = function () { }; self.volumeUp = function () { }; + + self.getPlayerState = function () { + + var deferred = $.Deferred(); + + var result = self.getPlayerStateInternal(); + + deferred.resolveWith(null, [result]); + + return deferred.promise(); + }; + + self.getPlayerStateInternal = function () { + + return {}; + }; } MediaController.registerPlayer(new chromecastPlayer()); diff --git a/dashboard-ui/scripts/mediacontroller.js b/dashboard-ui/scripts/mediacontroller.js index 74672e59a0..da61ab2c46 100644 --- a/dashboard-ui/scripts/mediacontroller.js +++ b/dashboard-ui/scripts/mediacontroller.js @@ -43,12 +43,12 @@ $(self).trigger('playerchange'); }; - self.setDefaultPlayerActive = function() { + self.setDefaultPlayerActive = function () { self.setActivePlayer(self.getDefaultPlayer()); }; self.removeActivePlayer = function (name) { - + if (self.getPlayerInfo().name == name) { self.setDefaultPlayerActive(); } @@ -78,7 +78,7 @@ } - targets = targets.sort(function(a,b) { + targets = targets.sort(function (a, b) { var aVal = a.isLocalPlayer ? 0 : 1; var bVal = b.isLocalPlayer ? 0 : 1; @@ -241,14 +241,12 @@ function onWebSocketMessageReceived(e, msg) { - var localPlayer = msg.MessageType === "Play" || - msg.MessageType === "Playstate" || - msg.MessageType === "GeneralCommand" ? - MediaController.getLocalPlayer() : - null; + var localPlayer; if (msg.MessageType === "Play") { + localPlayer = MediaController.getLocalPlayer(); + if (msg.Data.PlayCommand == "PlayNext") { localPlayer.queueNext({ ids: msg.Data.ItemIds }); } @@ -268,6 +266,8 @@ } else if (msg.MessageType === "Playstate") { + localPlayer = MediaController.getLocalPlayer(); + if (msg.Data.Command === 'Stop') { localPlayer.stop(); } @@ -286,14 +286,13 @@ else if (msg.Data.Command === 'PreviousTrack') { localPlayer.previousTrack(); } - else if (msg.Data.Command === 'Fullscreen') { - localPlayer.remoteFullscreen(); - } } else if (msg.MessageType === "GeneralCommand") { var cmd = msg.Data; + localPlayer = MediaController.getLocalPlayer(); + if (cmd.Name === 'Mute') { localPlayer.mute(); } @@ -309,6 +308,12 @@ else if (cmd.Name === 'ToggleMute') { localPlayer.toggleMute(); } + else if (msg.Data.Command === 'Fullscreen') { + localPlayer.remoteFullscreen(); + } + else if (msg.Data.Command === 'SetVolume') { + localPlayer.setVolume(cmd.Arguments.Volume); + } } } diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index c583fad7fd..dafa956312 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -169,7 +169,7 @@ }); if (currentItem.MediaType == "Video") { - ApiClient.stopActiveEncodings().done(function() { + ApiClient.stopActiveEncodings().done(function () { self.startTimeTicksOffset = ticks; element.src = currentSrc; @@ -213,7 +213,7 @@ currentTimeElement.html(timeText); } - var state = self.getPlayerState(currentMediaElement, currentItem, currentMediaSource); + var state = self.getPlayerStateInternal(currentMediaElement, currentItem, currentMediaSource); $(self).trigger('positionchange', [state]); }; @@ -481,7 +481,7 @@ var mediaControls = $("#videoControls"); - var state = self.getPlayerState(currentMediaElement, item, currentMediaSource); + var state = self.getPlayerStateInternal(currentMediaElement, item, currentMediaSource); var url = ""; @@ -865,6 +865,8 @@ elem.pause(); + var isVideo = currentItem.MediaType == "Video"; + $(elem).off("ended.playnext").on("ended", function () { $(this).off(); @@ -875,10 +877,12 @@ elem.src = ""; currentMediaElement = null; + currentItem = null; + currentMediaSource = null; }).trigger("ended"); - if (currentItem.MediaType == "Video") { + if (isVideo) { if (self.isFullScreen()) { self.exitFullScreen(); } @@ -890,13 +894,46 @@ return currentMediaElement; }; - self.getPlayerState = function (playerElement, item, mediaSource) { + self.getPlayerState = function() { - var itemName = ''; - var itemSubName = ''; + var deferred = $.Deferred(); + + var result = self.getPlayerStateInternal(currentMediaElement, currentItem, currentMediaSource); + + deferred.resolveWith(null, [result]); + + return deferred.promise(); + }; + + self.getPlayerStateInternal = function (playerElement, item, mediaSource) { + + var state = {}; + + if (playerElement) { + + state.volumeLevel = playerElement.volume * 100; + state.isMuted = playerElement.volume == 0; + state.isPaused = playerElement.paused; + state.positionTicks = self.getCurrentTicks(playerElement); + } + + if (mediaSource) { + + state.mediaSourceId = mediaSource.Id; + state.runtimeTicks = mediaSource.RunTimeTicks; + + state.canSeek = mediaSource.RunTimeTicks && mediaSource.RunTimeTicks > 0; + } if (item) { + state.itemId = item.Id; + state.mediaType = item.MediaType; + state.itemType = item.Type; + + var itemName = ''; + var itemSubName = ''; + var name = item.Name; var seriesName = ''; @@ -928,46 +965,42 @@ if (!itemSubName && item.ProductionYear) { itemSubName = item.ProductionYear; } - } - var state = { - itemId: item.Id, - mediaSourceId: mediaSource.Id, - volumeLevel: playerElement.volume * 100, - isMuted: playerElement.volume == 0, - isPaused: playerElement.paused, - runtimeTicks: mediaSource.RunTimeTicks, - positionTicks: self.getCurrentTicks(playerElement), - canSeek: mediaSource.RunTimeTicks && mediaSource.RunTimeTicks > 0, - mediaType: item.MediaType, - itemName: itemName, - itemSubName: itemSubName, - itemType: item.Type - }; + var imageTags = item.ImageTags || {}; - var imageTags = item.ImageTags || {}; + if (imageTags.Primary) { - if (imageTags.Primary) { + state.primaryImageItemId = item.Id; + state.primaryImageTag = imageTags.Primary; + } - state.primaryImageItemId = item.Id; - state.primaryImageTag = imageTags.Primary; - } + if (item.BackdropImageTags && item.BackdropImageTags.length) { - if (item.BackdropImageTags && item.BackdropImageTags.length) { + state.backdropItemId = item.Id; + state.backdropImageTag = item.BackdropImageTags[0]; + } - state.backdropItemId = item.Id; - state.backdropImageTag = item.BackdropImageTags[0]; - } + if (imageTags.Thumb) { - if (imageTags.Thumb) { + state.thumbItemId = item.Id; + state.thumbImageTag = imageTags.Thumb; + } - state.thumbItemId = item.Id; - state.thumbImageTag = imageTags.Thumb; + state.itemName = itemName; + state.itemSubName = itemSubName; } return state; }; + self.beginPlayerUpdates = function () { + // Nothing to setup here + }; + + self.endPlayerUpdates = function () { + // Nothing to setup here + }; + self.onPlaybackStart = function (playerElement, item, mediaSource) { self.updateCanClientSeek(playerElement); @@ -976,7 +1009,7 @@ self.startProgressInterval(item.Id, mediaSource.Id); - var state = self.getPlayerState(playerElement, item, mediaSource); + var state = self.getPlayerStateInternal(playerElement, item, mediaSource); $(self).trigger('playbackstart', [state]); }; @@ -985,7 +1018,7 @@ self.saveVolume(playerElement.volume); - var state = self.getPlayerState(playerElement, currentItem, currentMediaSource); + var state = self.getPlayerStateInternal(playerElement, currentItem, currentMediaSource); $(self).trigger('volumechange', [state]); }; @@ -1017,14 +1050,14 @@ self.resetEnhancements(); } - var state = self.getPlayerState(playerElement, item, mediaSource); + var state = self.getPlayerStateInternal(playerElement, item, mediaSource); $(self).trigger('playbackstop', [state]); }; self.onPlaystateChange = function (playerElement) { - var state = self.getPlayerState(playerElement, currentItem, currentMediaSource); + var state = self.getPlayerStateInternal(playerElement, currentItem, currentMediaSource); $(self).trigger('playstatechange', [state]); }; diff --git a/dashboard-ui/scripts/nowplayingbar.js b/dashboard-ui/scripts/nowplayingbar.js index cb93b6aa1c..33422bafea 100644 --- a/dashboard-ui/scripts/nowplayingbar.js +++ b/dashboard-ui/scripts/nowplayingbar.js @@ -154,6 +154,13 @@ function updatePlayerState(state) { + if (state.itemName) { + showNowPlayingBar(); + } else { + hideNowPlayingBar(); + return; + } + lastPlayerState = state; if (!muteButton) { @@ -211,6 +218,8 @@ } currentTimeElement.html(timeText); + + updateNowPlayingInfo(state); } function updateNowPlayingInfo(state) { @@ -271,24 +280,13 @@ var player = this; - if (player.isDefaultPlayer && state.mediaType == 'Video') { - return; - } + player.beginPlayerUpdates(); - showNowPlayingBar(); - - updatePlayerState(state); - updateNowPlayingInfo(state); + onStateChanged.call(player, e, state); } - var nowPlayingBarTimeout; function showNowPlayingBar() { - if (nowPlayingBarTimeout) { - clearTimeout(nowPlayingBarTimeout); - nowPlayingBarTimeout = null; - } - var nowPlayingBar = getNowPlayingBar(); nowPlayingBar.show(); @@ -296,24 +294,21 @@ function hideNowPlayingBar() { - if (nowPlayingBarTimeout) { - clearTimeout(nowPlayingBarTimeout); - nowPlayingBarTimeout = null; - } - // Use a timeout to prevent the bar from hiding and showing quickly // in the event of a stop->play command - nowPlayingBarTimeout = setTimeout(function () { - getNowPlayingBar().hide(); - }, 500); + getNowPlayingBar().hide(); } function onPlaybackStopped(e, state) { + var player = this; + + player.endPlayerUpdates(); + hideNowPlayingBar(); } - function onVolumeChanged(e, state) { + function onStateChanged(e, state) { var player = this; @@ -329,7 +324,10 @@ if (currentPlayer) { $(currentPlayer).off('.nowplayingbar'); + currentPlayer.endPlayerUpdates(); currentPlayer = null; + + hideNowPlayingBar(); } } @@ -339,11 +337,20 @@ currentPlayer = player; + player.getPlayerState().done(function (state) { + + if (state.itemName) { + player.beginPlayerUpdates(); + } + + onStateChanged.call(player, null, state); + }); + $(player).on('playbackstart.nowplayingbar', onPlaybackStart) .on('playbackstop.nowplayingbar', onPlaybackStopped) - .on('volumechange.nowplayingbar', onVolumeChanged) - .on('playstatechange.nowplayingbar', onVolumeChanged) - .on('positionchange.nowplayingbar', onVolumeChanged); + .on('volumechange.nowplayingbar', onStateChanged) + .on('playstatechange.nowplayingbar', onStateChanged) + .on('positionchange.nowplayingbar', onStateChanged); } $(function () { diff --git a/dashboard-ui/scripts/remotecontrol.js b/dashboard-ui/scripts/remotecontrol.js index 35add5b195..a97c02f1ee 100644 --- a/dashboard-ui/scripts/remotecontrol.js +++ b/dashboard-ui/scripts/remotecontrol.js @@ -96,14 +96,14 @@ var id = $('#selectSession', popup).val(); - ApiClient.sendSystemCommand(id, 'GoHome'); + ApiClient.sendCommand(id, 'GoHome'); }); $('.btnGoToSettings', popup).on('click', function () { var id = $('#selectSession', popup).val(); - ApiClient.sendSystemCommand(id, 'GoToSettings'); + ApiClient.sendCommand(id, 'GoToSettings'); }); $('.btnSendMessage', popup).on('click', function () { @@ -129,21 +129,21 @@ var id = $('#selectSession', popup).val(); - ApiClient.sendSystemCommand(id, 'VolumeDown'); + ApiClient.sendCommand(id, 'VolumeDown'); }); $('.btnVolumeUp', popup).on('click', function () { var id = $('#selectSession', popup).val(); - ApiClient.sendSystemCommand(id, 'VolumeUp'); + ApiClient.sendCommand(id, 'VolumeUp'); }); $('.btnToggleMute', popup).on('click', function () { var id = $('#selectSession', popup).val(); - ApiClient.sendSystemCommand(id, 'ToggleMute'); + ApiClient.sendCommand(id, 'ToggleMute'); }); $('.btnStop', popup).on('click', function () { @@ -432,6 +432,20 @@ ApiClient.sendPlayCommand(sessionId, remoteOptions); } + function sendPlayStateCommand(command, options) { + + var sessionId = MediaController.getPlayerInfo().id; + + ApiClient.sendPlayStateCommand(sessionId, command, options); + } + + function sendCommand(command, options) { + + var sessionId = MediaController.getPlayerInfo().id; + + ApiClient.sendCommand(sessionId, command, options); + } + function remoteControlPlayer() { var self = this; @@ -469,19 +483,114 @@ }; self.stop = function () { + sendPlayStateCommand('stop'); + }; + self.nextTrack = function () { + sendPlayStateCommand('nextTrack'); + }; + + self.previousTrack = function () { + sendPlayStateCommand('previousTrack'); + }; + + self.seek = function (positionTicks) { + sendPlayStateCommand('seek', + { + SeekPositionTicks: positionTicks + }); + }; + + self.pause = function () { + sendPlayStateCommand('Pause'); + }; + + self.unpause = function () { + sendPlayStateCommand('Unpause'); }; self.mute = function () { - + sendCommand('Mute'); }; self.unMute = function () { - + sendCommand('Unmnute'); }; self.toggleMute = function () { + sendCommand('ToggleMute'); + }; + self.setVolume = function (vol) { + sendCommand('SetVolume', { + + Volume: vol + + }); + }; + + self.getPlayerState = function () { + + var deferred = $.Deferred(); + + ApiClient.getSessions().done(function (sessions) { + + var currentTargetId = MediaController.getPlayerInfo().id; + + // Update existing data + //updateSessionInfo(popup, msg.Data); + var session = sessions.filter(function (s) { + return s.Id == currentTargetId; + })[0]; + + if (session) { + session = getPlayerState(session); + } + + deferred.resolveWith(null, [session]); + }); + + return deferred.promise(); + }; + + function subscribeToPlayerUpdates() { + + if (ApiClient.isWebSocketOpen()) { + + ApiClient.sendWebSocketMessage("SessionsStart", "100,700"); + } + } + + function unsubscribeFromPlayerUpdates() { + + if (ApiClient.isWebSocketOpen()) { + + ApiClient.sendWebSocketMessage("SessionsStop"); + } + } + + var playerListenerCount = 0; + self.beginPlayerUpdates = function () { + + if (playerListenerCount <= 0) { + + playerListenerCount = 0; + + subscribeToPlayerUpdates(); + } + + playerListenerCount++; + }; + + self.endPlayerUpdates = function () { + + playerListenerCount--; + + if (playerListenerCount <= 0) { + + unsubscribeFromPlayerUpdates(); + playerListenerCount = 0; + } }; self.getTargets = function () { @@ -521,11 +630,67 @@ }; } - MediaController.registerPlayer(new remoteControlPlayer()); + var player = new remoteControlPlayer(); + + MediaController.registerPlayer(player); + + function getPlayerState(session) { + + var state = { + volumeLevel: session.VolumeLevel, + isMuted: session.IsMuted, + isPaused: session.IsPaused, + canSeek: session.CanSeek + }; + + var item = session.NowPlayingItem; + + if (item) { + + state.itemId = item.Id; + state.itemType = item.Type; + state.mediaType = item.MediaType; + state.runtimeTicks = item.RunTimeTicks; + state.mediaSource = item.MediaSourceId; + state.positionTicks = session.NowPlayingPositionTicks || 0; + + state.itemName = item.Name; + + state.primaryImageItemId = item.PrimaryImageItemId; + state.primaryImageTag = item.PrimaryImageTag; + + state.backdropItemId = item.BackdropItemId; + state.backdropImageTag = item.BackdropImageTag; + + state.thumbItemId = item.ThumbItemId; + state.thumbImageTag = item.ThumbImageTag; + } + + return state; + } + + function firePlaybackEvent(name, session) { + + $(player).trigger(name, [getPlayerState(session)]); + } function onWebSocketMessageReceived(e, msg) { - if (msg.MessageType === "SessionEnded") { + if (msg.MessageType === "Sessions") { + + var currentTargetId = MediaController.getPlayerInfo().id; + + // Update existing data + //updateSessionInfo(popup, msg.Data); + var session = msg.Data.filter(function (s) { + return s.Id == currentTargetId; + })[0]; + + if (session) { + firePlaybackEvent('playstatechange', session); + } + } + else if (msg.MessageType === "SessionEnded") { console.log("Server reports another session ended"); @@ -533,6 +698,12 @@ MediaController.setDefaultPlayerActive(); } } + else if (msg.MessageType === "PlaybackStart") { + firePlaybackEvent('playbackstart', msg.Data); + } + else if (msg.MessageType === "PlaybackStopped") { + firePlaybackEvent('playbackstop', msg.Data); + } } $(ApiClient).on("websocketmessage", onWebSocketMessageReceived); diff --git a/dashboard-ui/thirdparty/mediabrowser.apiclient.js b/dashboard-ui/thirdparty/mediabrowser.apiclient.js index a6c08509d5..71c59924a6 100644 --- a/dashboard-ui/thirdparty/mediabrowser.apiclient.js +++ b/dashboard-ui/thirdparty/mediabrowser.apiclient.js @@ -2197,13 +2197,13 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi dataType: "json" }); }; - + function normalizeImageOptions(options) { var ratio = window.devicePixelRatio; - + if (ratio) { - + if (options.width) { options.width = options.width * ratio; } @@ -2253,7 +2253,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi delete options.index; normalizeImageOptions(options); - + return self.getUrl(url, options); }; @@ -3794,7 +3794,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi }); }; - self.sendSystemCommand = function (sessionId, command) { + self.sendCommand = function (sessionId, command, options) { if (!sessionId) { throw new Error("null sessionId"); @@ -3804,12 +3804,22 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi throw new Error("null command"); } - var url = self.getUrl("Sessions/" + sessionId + "/System/" + command); + var url = self.getUrl("Sessions/" + sessionId + "/Command"); - return self.ajax({ + var ajaxOptions = { type: "POST", url: url - }); + }; + + options = { + Arguments: options || {}, + Name: command + }; + + ajaxOptions.data = JSON.stringify(options); + ajaxOptions.contentType = "application/json"; + + return self.ajax(ajaxOptions); }; self.sendMessageCommand = function (sessionId, options) { From 9f83edf9ec7de9a8021988656cda55a1e48b151e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 13 Apr 2014 13:27:13 -0400 Subject: [PATCH 22/25] add new mirror mode --- dashboard-ui/css/mediaplayer-video.css | 2 +- dashboard-ui/css/mediaplayer.css | 10 +- dashboard-ui/scripts/chromecast.js | 16 +- dashboard-ui/scripts/itembynamedetailpage.js | 17 +- dashboard-ui/scripts/itemdetailpage.js | 12 +- dashboard-ui/scripts/itemlistpage.js | 9 +- dashboard-ui/scripts/librarybrowser.js | 2 +- dashboard-ui/scripts/livetvchannel.js | 11 +- dashboard-ui/scripts/livetvprogram.js | 11 +- dashboard-ui/scripts/livetvrecording.js | 11 +- dashboard-ui/scripts/mediacontroller.js | 81 ++++++++- dashboard-ui/scripts/mediaplayer.js | 164 +++++++++++------- dashboard-ui/scripts/nowplayingbar.js | 14 +- dashboard-ui/scripts/remotecontrol.js | 33 +++- dashboard-ui/scripts/site.js | 46 ++++- dashboard-ui/scripts/supporterpage.js | 32 +--- dashboard-ui/supporter.html | 8 +- .../thirdparty/mediabrowser.apiclient.js | 28 ++- 18 files changed, 316 insertions(+), 191 deletions(-) diff --git a/dashboard-ui/css/mediaplayer-video.css b/dashboard-ui/css/mediaplayer-video.css index 917de36a0e..8ad83120f7 100644 --- a/dashboard-ui/css/mediaplayer-video.css +++ b/dashboard-ui/css/mediaplayer-video.css @@ -106,7 +106,7 @@ #mediaPlayer .ui-slider-track, .nowPlayingBar .ui-slider-track { border-color: #2ad !important; - height: 8px!important; + height: 2px!important; } #mediaPlayer .ui-slider-handle, .nowPlayingBar .ui-slider-handle { diff --git a/dashboard-ui/css/mediaplayer.css b/dashboard-ui/css/mediaplayer.css index 911fbf333e..a6d05f8f65 100644 --- a/dashboard-ui/css/mediaplayer.css +++ b/dashboard-ui/css/mediaplayer.css @@ -1,6 +1,6 @@ /* Now playing bar */ .nowPlayingBar { - padding: 10px 0 14px 0; + padding: 6px 0 14px 0; border-top: 2px solid green; } @@ -30,7 +30,7 @@ } .nowPlayingDoubleText { - top: 0; + top: -3px; } .nowPlayingImage { @@ -57,7 +57,7 @@ } .nowPlayingBar .currentTime { - top: -12px; + top: -15px; } .mediaSlider { @@ -75,8 +75,8 @@ width: 130px; } -#nowPlayingBar .positionSliderContainer { - margin-top: 10px; +#nowPlayingBar .sliderContainer { + margin-top: 14px; } .volumeSliderContainer { diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js index 2f75ed9e47..53a379f9e2 100644 --- a/dashboard-ui/scripts/chromecast.js +++ b/dashboard-ui/scripts/chromecast.js @@ -1267,6 +1267,10 @@ castPlayer.stopMedia(); }; + self.displayContent = function (options) { + + }; + self.mute = function () { castPlayer.mute(); }; @@ -1280,12 +1284,19 @@ }; self.getTargets = function () { + var targets = []; - targets.push(self.getCurrentTargetInfo()); + + if (castPlayer.hasReceivers) { + targets.push(self.getCurrentTargetInfo()); + } + return targets; + }; self.getCurrentTargetInfo = function () { + var appName = null; if (castPlayer.session && castPlayer.session.receiver && castPlayer.session.friendlyName) { appName = castPlayer.session.friendlyName; @@ -1297,7 +1308,8 @@ playerName: self.name, playableMediaTypes: ["Audio", "Video"], isLocalPlayer: false, - appName: appName + appName: appName, + supportedCommands: [] }; }; diff --git a/dashboard-ui/scripts/itembynamedetailpage.js b/dashboard-ui/scripts/itembynamedetailpage.js index 3ded84809f..f51044bf7c 100644 --- a/dashboard-ui/scripts/itembynamedetailpage.js +++ b/dashboard-ui/scripts/itembynamedetailpage.js @@ -66,18 +66,11 @@ renderDetails(page, item); renderTabs(page, item); - if (ApiClient.isWebSocketOpen()) { + $(page).trigger('displayingitem', [{ - var vals = [item.Type, item.Id, item.Name]; - - var context = getParameterByName('context'); - - if (context) { - vals.push(vals); - } - - ApiClient.sendWebSocketMessage("Context", vals.join('|')); - } + item: item, + context: getParameterByName('context') + }]); Dashboard.getCurrentUser().done(function (user) { @@ -403,7 +396,7 @@ }; query = $.extend(query, options || {}); - + if (query.IncludeItemTypes == "Audio") { query.SortBy = "Album,SortName"; } diff --git a/dashboard-ui/scripts/itemdetailpage.js b/dashboard-ui/scripts/itemdetailpage.js index 19c4e97ec3..d04719e6ee 100644 --- a/dashboard-ui/scripts/itemdetailpage.js +++ b/dashboard-ui/scripts/itemdetailpage.js @@ -75,11 +75,11 @@ } if (!item.LocalTrailerCount && item.RemoteTrailers.length && item.PlayAccess == 'Full') { - + $('.btnPlayExternalTrailer', page).removeClass('hide').attr('href', item.RemoteTrailers[0].Url); } else { - + $('.btnPlayExternalTrailer', page).addClass('hide').attr('href', '#'); } @@ -120,9 +120,11 @@ setPeopleHeader(page, item); - if (ApiClient.isWebSocketOpen()) { - ApiClient.sendWebSocketMessage("Context", [item.Type, item.Id, item.Name, context].join('|')); - } + $(page).trigger('displayingitem', [{ + + item: item, + context: context + }]); Dashboard.hideLoadingMsg(); }); diff --git a/dashboard-ui/scripts/itemlistpage.js b/dashboard-ui/scripts/itemlistpage.js index 39cbc0caca..1d0194d4ef 100644 --- a/dashboard-ui/scripts/itemlistpage.js +++ b/dashboard-ui/scripts/itemlistpage.js @@ -93,9 +93,10 @@ Dashboard.setPageTitle(name); - if (ApiClient.isWebSocketOpen()) { - ApiClient.sendWebSocketMessage("Context", [item.Type, item.Id, item.Name].join('|')); - } + $(page).trigger('displayingitem', [{ + + item: item + }]); }); @@ -203,7 +204,7 @@ }).on('pageshow', "#itemListPage", function () { var page = this; - + query.Limit = LibraryBrowser.getDefaultPageSize(); query.ParentId = getParameterByName('parentId'); query.Filters = ""; diff --git a/dashboard-ui/scripts/librarybrowser.js b/dashboard-ui/scripts/librarybrowser.js index a2fc2608ae..4b35cd709d 100644 --- a/dashboard-ui/scripts/librarybrowser.js +++ b/dashboard-ui/scripts/librarybrowser.js @@ -672,7 +672,7 @@ html += ''; var style = ""; - + options.lazy = false; if (imgUrl && !options.lazy) { style += 'background-image:url(\'' + imgUrl + '\');'; } diff --git a/dashboard-ui/scripts/livetvchannel.js b/dashboard-ui/scripts/livetvchannel.js index 12b93a7c9c..4ce429f77c 100644 --- a/dashboard-ui/scripts/livetvchannel.js +++ b/dashboard-ui/scripts/livetvchannel.js @@ -135,14 +135,11 @@ $('.userDataIcons', page).html(LibraryBrowser.getUserDataIconsHtml(item)); - if (ApiClient.isWebSocketOpen()) { + $(page).trigger('displayingitem', [{ - var vals = [item.Type, item.Id, item.Name]; - - vals.push('livetv'); - - ApiClient.sendWebSocketMessage("Context", vals.join('|')); - } + item: item, + context: 'livetv' + }]); Dashboard.getCurrentUser().done(function (user) { diff --git a/dashboard-ui/scripts/livetvprogram.js b/dashboard-ui/scripts/livetvprogram.js index 6c8e4f30bb..5e5e1070ac 100644 --- a/dashboard-ui/scripts/livetvprogram.js +++ b/dashboard-ui/scripts/livetvprogram.js @@ -50,14 +50,11 @@ LiveTvHelpers.renderMiscProgramInfo($('.miscTvProgramInfo', page), item); - if (ApiClient.isWebSocketOpen()) { + $(page).trigger('displayingitem', [{ - var vals = [item.Type, item.Id, item.Name]; - - vals.push('livetv'); - - ApiClient.sendWebSocketMessage("Context", vals.join('|')); - } + item: item, + context: 'livetv' + }]); if (item.TimerId) { $('#cancelRecordingButtonContainer', page).show(); diff --git a/dashboard-ui/scripts/livetvrecording.js b/dashboard-ui/scripts/livetvrecording.js index 6ecf639520..23ba53e22a 100644 --- a/dashboard-ui/scripts/livetvrecording.js +++ b/dashboard-ui/scripts/livetvrecording.js @@ -55,14 +55,11 @@ LiveTvHelpers.renderMiscProgramInfo($('.miscTvProgramInfo', page), item); - if (ApiClient.isWebSocketOpen()) { + $(page).trigger('displayingitem', [{ - var vals = [item.Type, item.Id, item.Name]; - - vals.push('livetv'); - - ApiClient.sendWebSocketMessage("Context", vals.join('|')); - } + item: item, + context: 'livetv' + }]); $('.recordingStatus', page).html('Status:   ' + item.Status); diff --git a/dashboard-ui/scripts/mediacontroller.js b/dashboard-ui/scripts/mediacontroller.js index da61ab2c46..0cd0de6dbf 100644 --- a/dashboard-ui/scripts/mediacontroller.js +++ b/dashboard-ui/scripts/mediacontroller.js @@ -1,11 +1,26 @@ (function ($, window) { + var enableMirrorMode; + var currentDisplayInfo; + + function mirrorItem(info) { + + var item = info.item; + + MediaController.getCurrentPlayer().displayContent({ + + itemName: item.Name, + itemId: item.Id, + itemType: item.Type, + context: info.context + }); + } + function mediaController() { var self = this; var currentPlayer; var currentTargetInfo; - var players = []; self.registerPlayer = function (player) { @@ -308,11 +323,11 @@ else if (cmd.Name === 'ToggleMute') { localPlayer.toggleMute(); } - else if (msg.Data.Command === 'Fullscreen') { + else if (cmd.Name === 'Fullscreen') { localPlayer.remoteFullscreen(); } - else if (msg.Data.Command === 'SetVolume') { - localPlayer.setVolume(cmd.Arguments.Volume); + else if (cmd.Name === 'SetVolume') { + localPlayer.setVolume(parseFloat(cmd.Arguments.Volume)); } } } @@ -324,7 +339,9 @@ var playerInfo = MediaController.getPlayerInfo(); var html = ''; - html += '

Select Player:

'; + html += '
'; + + html += '

Select Player:

'; html += '
'; for (var i = 0, length = targets.length; i < length; i++) { @@ -336,7 +353,9 @@ var isChecked = target.id == playerInfo.id; var checkedHtml = isChecked ? ' checked="checked"' : ''; - html += ''; + var mirror = (!target.isLocalPlayer && target.supportedCommands.indexOf('DisplayContent') != -1) ? 'true' : 'false'; + + html += ''; html += '

Support the Media Browser Team

- Help ensure the continued development of this product by donating a minimum of $10 (greater amounts greatly appreciated). A portion of all donations will be contributed to other free tools we depend on. + Help ensure the continued development of this project by donating. A portion of all donations will be contributed to other free tools we depend on.

-
diff --git a/dashboard-ui/thirdparty/mediabrowser.apiclient.js b/dashboard-ui/thirdparty/mediabrowser.apiclient.js index 71c59924a6..9c9aebcbe5 100644 --- a/dashboard-ui/thirdparty/mediabrowser.apiclient.js +++ b/dashboard-ui/thirdparty/mediabrowser.apiclient.js @@ -1728,6 +1728,16 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi }); }; + self.reportCapabilities = function (options) { + + var url = self.getUrl("Sessions/Capabilities", options); + + return self.ajax({ + type: "POST", + url: url + }); + }; + self.updateItemImageIndex = function (itemId, itemType, itemName, imageType, imageIndex, newIndex) { if (!imageType) { @@ -3758,24 +3768,6 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi }); }; - self.sendBrowseCommand = function (sessionId, options) { - - if (!sessionId) { - throw new Error("null sessionId"); - } - - if (!options) { - throw new Error("null options"); - } - - var url = self.getUrl("Sessions/" + sessionId + "/Viewing", options); - - return self.ajax({ - type: "POST", - url: url - }); - }; - self.sendPlayCommand = function (sessionId, options) { if (!sessionId) { From b8c3e8c777694d3fb7df534d3a48d32013535391 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 13 Apr 2014 14:25:22 -0400 Subject: [PATCH 23/25] fixes for chrome 35 --- dashboard-ui/css/mediaplayer-video.css | 35 ++++++++++++----------- dashboard-ui/scripts/mediaplayer-video.js | 6 ++-- dashboard-ui/scripts/mediaplayer.js | 3 +- dashboard-ui/scripts/site.js | 1 - 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/dashboard-ui/css/mediaplayer-video.css b/dashboard-ui/css/mediaplayer-video.css index 8ad83120f7..2244f255c1 100644 --- a/dashboard-ui/css/mediaplayer-video.css +++ b/dashboard-ui/css/mediaplayer-video.css @@ -26,15 +26,15 @@ .itemVideo { background-color: #000; - margin: 20px 20px 80px; + margin: 5px 5px 75px; width: 320px; height: 181px; } #videoControls { z-index: 99999; - padding: 0 20px 5px; - height: 80px; + padding: 0 5px 5px; + height: 75px; position: absolute; top: auto; right: 0; @@ -54,7 +54,7 @@ #videoControls #video-basic-controls { position: absolute; - top: 30px; + top: 25px; left: 20px; bottom: 0; width: 600px; @@ -63,7 +63,7 @@ #videoControls #video-advanced-controls { position: absolute; - top: 30px; + top: 25px; right: 20px; bottom: 0; width: 400px; @@ -142,6 +142,11 @@ bottom: 85px; } +#mediaPlayer .volumeSliderContainer { + position: relative; + top: 5px; +} + /* Media queries ***************************************/ @@ -191,10 +196,6 @@ margin-left: -550px; margin-top: -329px; } - - #video-videoPlayerMenuButton { - display: none; - } } @media all and (min-width: 1440px) and (min-height: 720px) { @@ -245,10 +246,6 @@ width: 250px; } - #mediaPlayer #video-basic-controls .volumeSliderContainer { - margin-top: 8px; - } - #mediaPlayer #video-basic-controls, #mediaPlayer #video-advanced-controls { width: 200px; height: 120px; @@ -269,14 +266,18 @@ } } -@media all and (max-width: 500px) { - #mediaPlayer .previousTrackButton, #mediaPlayer .nextTrackButton { +@media all and (max-width: 600px) { + #mediaPlayer .volumeSliderContainer, #mediaPlayer .muteButton, #mediaPlayer .unmuteButton { + display: none!important; + } + + #mediaPlayer .nowPlayingImage, #mediaPlayer .nowPlayingText { display: none!important; } } -@media all and (max-width: 400px) { - #mediaPlayer .playlistButton { +@media all and (max-width: 500px) { + #mediaPlayer .previousTrackButton, #mediaPlayer .nextTrackButton { display: none!important; } } diff --git a/dashboard-ui/scripts/mediaplayer-video.js b/dashboard-ui/scripts/mediaplayer-video.js index bb2610dc35..31df976809 100644 --- a/dashboard-ui/scripts/mediaplayer-video.js +++ b/dashboard-ui/scripts/mediaplayer-video.js @@ -32,6 +32,7 @@ self.initVideoPlayer = function () { video = playVideo(item, mediaSource, startPosition, user); + return video; }; @@ -861,9 +862,9 @@ // Can't autoplay in these browsers so we need to use the full controls if (requiresControls) { - html += '