diff --git a/dashboard-ui/apiclient/apiclient.js b/dashboard-ui/apiclient/apiclient.js index b8ff5c569..74a1debbe 100644 --- a/dashboard-ui/apiclient/apiclient.js +++ b/dashboard-ui/apiclient/apiclient.js @@ -482,6 +482,63 @@ }); }; + self.getDownloadSpeed = function (byteSize) { + + var url = self.getUrl('Playback/BitrateTest', { + + Size: byteSize + }); + + var now = new Date().getTime(); + + var deferred = DeferredBuilder.Deferred(); + + self.get(url).done(function () { + + var responseTime = new Date().getTime() - now; + responseTime /= 1000; + var bytesPerSecond = byteSize / responseTime; + + deferred.resolveWith(null, [bytesPerSecond]); + + }).fail(function () { + + deferred.reject(); + }); + + return deferred.promise(); + }; + + self.detectBitrate = function () { + + var deferred = DeferredBuilder.Deferred(); + + // First try a small amount so that we don't hang up their mobile connection + self.getDownloadSpeed(1000000).done(function (bitrate) { + + if (bitrate < 3000000) { + deferred.resolveWith(null, [Math.round(bitrate * .8)]); + } else { + + // If that produced a fairly high speed, try again with a larger size to get a more accurate result + self.getDownloadSpeed(2000000).done(function (bitrate) { + + deferred.resolveWith(null, [Math.round(bitrate * .8)]); + + }).fail(function () { + + deferred.reject(); + }); + } + + }).fail(function () { + + deferred.reject(); + }); + + return deferred.promise(); + }; + /** * Gets an item from the server * Omit itemId to get the root folder. @@ -492,7 +549,7 @@ throw new Error("null itemId"); } - var url = userId ? + var url = userId ? self.getUrl("Users/" + userId + "/Items/" + itemId) : self.getUrl("Items/" + itemId); diff --git a/dashboard-ui/cordova/android/immersive.js b/dashboard-ui/cordova/android/immersive.js index 705349884..5fd62e6dc 100644 --- a/dashboard-ui/cordova/android/immersive.js +++ b/dashboard-ui/cordova/android/immersive.js @@ -32,51 +32,6 @@ //// Hide system UI and keep it hidden (Android 4.4+ only) //AndroidFullScreen.immersiveMode(onSuccess, onError); - var currentPlayer; - - function onPlaybackStart(e, state) { - - var player = this; - - if (player.isLocalPlayer && state.NowPlayingItem && state.NowPlayingItem.MediaType == 'Video') { - AndroidFullScreen.immersiveMode(onSuccess, onError); - } - } - - function onPlaybackStopped(e, state) { - - var player = this; - - if (player.isLocalPlayer && state.NowPlayingItem && state.NowPlayingItem.MediaType == 'Video') { - - if (!AppSettings.enableFullScreen()) { - AndroidFullScreen.showSystemUI(onSuccess, onError); - } - } - } - - function bindToPlayer(player) { - - releaseCurrentPlayer(); - - currentPlayer = player; - - if (!player.isLocalPlayer) { - return; - } - - $(player).on('playbackstart', onPlaybackStart) - .on('playbackstop', onPlaybackStopped); - } - - function releaseCurrentPlayer() { - - if (currentPlayer) { - - $(currentPlayer).off('playbackstart', onPlaybackStart).off('playbackstop', onPlaybackStopped); - } - } - function updateFromSetting(leaveFullScreen) { if (AppSettings.enableFullScreen()) { @@ -91,13 +46,6 @@ Logger.log('binding fullscreen to MediaController'); - $(MediaController).on('playerchange', function () { - - bindToPlayer(MediaController.getCurrentPlayer()); - }); - - bindToPlayer(MediaController.getCurrentPlayer()); - updateFromSetting(false); $(AppSettings).on('settingupdated', function (e, key) { diff --git a/dashboard-ui/cordova/android/vlcplayer.js b/dashboard-ui/cordova/android/vlcplayer.js index 5c69051bb..a9e92ca01 100644 --- a/dashboard-ui/cordova/android/vlcplayer.js +++ b/dashboard-ui/cordova/android/vlcplayer.js @@ -95,11 +95,22 @@ return; } + var tIndex = val.indexOf('#t='); + var startPosMs = 0; + + if (tIndex != -1) { + startPosMs = val.substring(tIndex + 3); + startPosMs = parseFloat(startPosMs) * 1000; + } + if (options.type == 'audio') { AndroidVlcPlayer.playAudioVlc(val, JSON.stringify(item), JSON.stringify(mediaSource), posterUrl); } else { - AndroidVlcPlayer.playVideoVlc(val, JSON.stringify(item), JSON.stringify(mediaSource), posterUrl); + + var playbackStartInfo = {}; + + AndroidVlcPlayer.playVideoVlc(val, startPosMs, item.Name, JSON.stringify(mediaSource), JSON.stringify(playbackStartInfo)); } playerState.currentSrc = val; @@ -175,6 +186,17 @@ return deferred.promise(); }; + self.onActivityClosed = function (wasStopped, hasError, endPositionMs) { + + playerState.currentTime = endPositionMs; + + if (wasStopped) { + MediaPlayer.stop(false); + } + + self.report('playbackstop', playerState.duration, endPositionMs, false, 100); + }; + window.AudioRenderer.Current = self; window.VideoRenderer.Current = self; } diff --git a/dashboard-ui/cordova/imagestore.js b/dashboard-ui/cordova/imagestore.js index 838b2bafb..aab7b0092 100644 --- a/dashboard-ui/cordova/imagestore.js +++ b/dashboard-ui/cordova/imagestore.js @@ -57,7 +57,7 @@ // Use the embedded server for iOS8, and also if we don't know the iOS version, just to be safe //if ($.browser.iOSVersion == 8 || !$.browser.iOSVersion) { - //return url.replace('file://', ''); + return url.replace('file://', ''); } } return url; diff --git a/dashboard-ui/movietrailers.html b/dashboard-ui/movietrailers.html index 7c6f137fc..3416f1546 100644 --- a/dashboard-ui/movietrailers.html +++ b/dashboard-ui/movietrailers.html @@ -4,7 +4,7 @@ Emby -
+
info${TabSuggestions} @@ -22,7 +22,7 @@
- +
diff --git a/dashboard-ui/scripts/librarymenu.js b/dashboard-ui/scripts/librarymenu.js index 26c9f6428..ca3e923a5 100644 --- a/dashboard-ui/scripts/librarymenu.js +++ b/dashboard-ui/scripts/librarymenu.js @@ -545,6 +545,10 @@ } return false; + }, + + onHardwareMenuButtonClick: function () { + openMainDrawer(); } }; @@ -939,7 +943,7 @@ $.fn.createHoverTouch = function () { var backUrl; $(document).on('pagebeforeshow', ".page", function () { - + if (getWindowUrl() != backUrl) { backUrl = null; } diff --git a/dashboard-ui/scripts/mediaplayer-video.js b/dashboard-ui/scripts/mediaplayer-video.js index 6739be8a9..940327da7 100644 --- a/dashboard-ui/scripts/mediaplayer-video.js +++ b/dashboard-ui/scripts/mediaplayer-video.js @@ -626,8 +626,8 @@ html += ''; html += '
'; - html += ''; - html += ''; + html += ''; + html += ''; // Embedding onclicks due to issues not firing in cordova safari html += ''; @@ -652,12 +652,12 @@ html += '
'; html += '
'; // nowPlayingInfo - html += ''; + html += ''; html += ''; html += ''; - html += ''; + html += ''; html += ''; @@ -933,8 +933,11 @@ unbindEventsForPlayback(mediaRenderer); }; - self.playVideo = function (item, mediaSource, startPosition) { + self.playVideo = function (item, mediaSource, startPosition, callback) { + //ApiClient.detectBitrate().done(function (b) { + // alert(b); + //}); requirejs(['videorenderer'], function () { var streamInfo = self.createStreamInfo('Video', item, mediaSource, startPosition); @@ -953,11 +956,11 @@ Dashboard.hideLoadingMsg(); }).done(function () { - self.playVideoInternal(item, mediaSource, startPosition, streamInfo); + self.playVideoInternal(item, mediaSource, startPosition, streamInfo, callback); }); } else { - self.playVideoInternal(item, mediaSource, startPosition, streamInfo); + self.playVideoInternal(item, mediaSource, startPosition, streamInfo, callback); } }); }; @@ -966,7 +969,7 @@ return true; } - self.playVideoInternal = function (item, mediaSource, startPosition, streamInfo) { + self.playVideoInternal = function (item, mediaSource, startPosition, streamInfo, callback) { var videoUrl = streamInfo.url; var contentType = streamInfo.mimeType; @@ -990,7 +993,7 @@ //show stop button $('#video-playButton', videoControls).hide(); $('#video-pauseButton', videoControls).show(); - $('.videoTrackControl').hide(); + $('.videoTrackControl').visible(false); var videoElement = $('#videoElement', mediaPlayerContainer); @@ -1140,7 +1143,7 @@ self.updateNowPlayingInfo(item); - mediaRenderer.init().done(function() { + mediaRenderer.init().done(function () { var textStreams = subtitleStreams.filter(function (s) { return s.DeliveryMethod == 'External'; @@ -1166,6 +1169,10 @@ if (videoUrl.indexOf('.m3u8') == -1) { mediaRenderer.unpause(); } + + if (callback) { + callback(); + } }); }; @@ -1180,7 +1187,7 @@ } if (length < 2) { - $('.videoTrackControl').hide(); + $('.videoTrackControl').visible(false); return; } @@ -1202,7 +1209,8 @@ nextTrackButton.removeAttribute('disabled'); } - $('.videoTrackControl', controls).show(); + $(previousTrackButton).visible(true); + $(nextTrackButton).visible(true); }; } diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index c485caf1b..17db13d29 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -975,16 +975,12 @@ if (item.MediaType === "Video") { requirejs(['videorenderer'], function () { - self.playVideo(item, self.currentMediaSource, startPosition); + self.playVideo(item, self.currentMediaSource, startPosition, callback); }); } else if (item.MediaType === "Audio") { - playAudio(item, self.currentMediaSource, startPosition); - } - - if (callback) { - callback(); + playAudio(item, self.currentMediaSource, startPosition, callback); } } @@ -1720,10 +1716,14 @@ self.setCurrentTime(currentTicks); } - function playAudio(item, mediaSource, startPositionTicks) { + function playAudio(item, mediaSource, startPositionTicks, callback) { requirejs(['audiorenderer'], function () { playAudioInternal(item, mediaSource, startPositionTicks); + + if (callback) { + callback(); + } }); } diff --git a/dashboard-ui/scripts/musicalbumartists.js b/dashboard-ui/scripts/musicalbumartists.js index 4c94c155a..d98d3be6d 100644 --- a/dashboard-ui/scripts/musicalbumartists.js +++ b/dashboard-ui/scripts/musicalbumartists.js @@ -4,27 +4,44 @@ var view = LibraryBrowser.getDefaultItemsView('Poster', 'Poster'); - // The base query options - var query = { + var data = {}; - SortBy: "SortName", - SortOrder: "Ascending", - Recursive: true, - Fields: "PrimaryImageAspectRatio,SortName,DateCreated,SyncInfo,ItemCounts", - StartIndex: 0, - ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb" - }; + function getQuery() { + + var key = getSavedQueryKey(); + var pageData = data[key]; + + if (!pageData) { + pageData = data[key] = { + query: { + SortBy: "SortName", + SortOrder: "Ascending", + Recursive: true, + Fields: "PrimaryImageAspectRatio,SortName,DateCreated,SyncInfo,ItemCounts", + StartIndex: 0, + ImageTypeLimit: 1, + EnableImageTypes: "Primary,Backdrop,Banner,Thumb", + Limit: LibraryBrowser.getDefaultPageSize() + } + }; + + pageData.query.ParentId = LibraryMenu.getTopParentId(); + LibraryBrowser.loadSavedQueryValues(key, pageData.query); + } + return pageData.query; + } function getSavedQueryKey() { - return 'musicartists' + (query.ParentId || ''); + return getWindowUrl(); } function reloadItems(page) { Dashboard.showLoadingMsg(); + var query = getQuery(); + ApiClient.getAlbumArtists(Dashboard.getCurrentUserId(), query).done(function (result) { // Scroll back up so they can see the results from the beginning @@ -100,13 +117,15 @@ }); LibraryBrowser.saveQueryValues(getSavedQueryKey(), query); - + LibraryBrowser.setLastRefreshed(page); Dashboard.hideLoadingMsg(); }); } function updateFilterControls(page) { + var query = getQuery(); + $('.chkStandardFilter', page).each(function () { var filters = "," + (query.Filters || ""); @@ -129,6 +148,8 @@ filtersLoaded = true; + var query = getQuery(); + QueryFilters.loadFilters(page, Dashboard.getCurrentUserId(), query, function () { reloadItems(page); @@ -147,6 +168,8 @@ $('.chkStandardFilter', this).on('change', function () { + var query = getQuery(); + var filterName = this.getAttribute('data-filter'); var filters = query.Filters || ""; @@ -164,6 +187,8 @@ $('.alphabetPicker', this).on('alphaselect', function (e, character) { + var query = getQuery(); + query.NameStartsWithOrGreater = character; query.StartIndex = 0; @@ -171,6 +196,8 @@ }).on('alphaclear', function (e) { + var query = getQuery(); + query.NameStartsWithOrGreater = ''; reloadItems(page); @@ -186,6 +213,8 @@ }); $('#selectPageSize', page).on('change', function () { + var query = getQuery(); + query.Limit = parseInt(this.value); query.StartIndex = 0; reloadItems(page); @@ -194,29 +223,20 @@ }).on('pagebeforeshowready', "#musicAlbumArtistsPage", function () { var page = this; - query.ParentId = LibraryMenu.getTopParentId(); + var query = getQuery(); - var limit = LibraryBrowser.getDefaultPageSize(pageSizeKey, 100); - - // If the default page size has changed, the start index will have to be reset - if (limit != query.Limit) { - query.Limit = limit; - query.StartIndex = 0; - } - - var viewkey = getSavedQueryKey(); - - LibraryBrowser.loadSavedQueryValues(viewkey, query); QueryFilters.onPageShow(page, query); - LibraryBrowser.getSavedViewSetting(viewkey).done(function (val) { + if (LibraryBrowser.needsRefresh(page)) { + LibraryBrowser.getSavedViewSetting(getSavedQueryKey()).done(function (val) { - if (val) { - $('#selectView', page).val(val).selectmenu('refresh').trigger('change'); - } else { - reloadItems(page); - } - }); + if (val) { + $('#selectView', page).val(val).selectmenu('refresh').trigger('change'); + } else { + reloadItems(page); + } + }); + } updateFilterControls(this); }); diff --git a/dashboard-ui/scripts/musicalbums.js b/dashboard-ui/scripts/musicalbums.js index 057a3dd9e..17393c65a 100644 --- a/dashboard-ui/scripts/musicalbums.js +++ b/dashboard-ui/scripts/musicalbums.js @@ -2,19 +2,6 @@ var view = LibraryBrowser.getDefaultItemsView('Poster', 'Poster'); - // The base query options - var query = { - - SortBy: "AlbumArtist,SortName", - SortOrder: "Ascending", - IncludeItemTypes: "MusicAlbum", - Recursive: true, - Fields: "PrimaryImageAspectRatio,SortName,SyncInfo", - StartIndex: 0, - ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb" - }; - var data = {}; function getQuery() { @@ -295,12 +282,11 @@ var page = this; - var viewKey = getSavedQueryKey(); - LibraryBrowser.loadSavedQueryValues(viewKey, query); + var query = getQuery(); QueryFilters.onPageShow(page, query); if (LibraryBrowser.needsRefresh(page)) { - LibraryBrowser.getSavedViewSetting(viewKey).done(function (val) { + LibraryBrowser.getSavedViewSetting(getSavedQueryKey()).done(function (val) { if (val) { $('#selectView', page).val(val).selectmenu('refresh').trigger('change'); diff --git a/dashboard-ui/scripts/mypreferenceslanguages.js b/dashboard-ui/scripts/mypreferenceslanguages.js index 6fa0492cd..f06ff2354 100644 --- a/dashboard-ui/scripts/mypreferenceslanguages.js +++ b/dashboard-ui/scripts/mypreferenceslanguages.js @@ -78,6 +78,9 @@ ApiClient.updateUserConfiguration(user.Id, user.Configuration).done(function () { Dashboard.alert(Globalize.translate('SettingsSaved')); + + }).always(function () { + Dashboard.hideLoadingMsg(); }); } diff --git a/dashboard-ui/scripts/sections.js b/dashboard-ui/scripts/sections.js index be88c415a..1e17dc1e8 100644 --- a/dashboard-ui/scripts/sections.js +++ b/dashboard-ui/scripts/sections.js @@ -151,11 +151,7 @@ if (items.length) { html += '
'; - html += '

' + Globalize.translate('HeaderLatestMedia') + '

'; - - if (user.Policy.EnableUserPreferenceAccess && !AppInfo.isNativeApp) { - html += '' + Globalize.translate('ButtonEdit') + ''; - } + html += '

' + Globalize.translate('HeaderLatestMedia') + '

'; html += '
'; @@ -239,11 +235,7 @@ var cssClass = index !== 0 ? 'listHeader' : 'listHeader'; html += '
'; - html += '

' + Globalize.translate('HeaderMyMedia') + '

'; - - if (user.Policy.EnableUserPreferenceAccess && !AppInfo.isNativeApp) { - html += '' + Globalize.translate('ButtonEdit') + ''; - } + html += '

' + Globalize.translate('HeaderMyMedia') + '

'; html += '
'; diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js index cff1c09cc..678c1a5da 100644 --- a/dashboard-ui/scripts/site.js +++ b/dashboard-ui/scripts/site.js @@ -2063,9 +2063,7 @@ var AppInfo = {}; function initCordovaWithDeviceId(deferred, deviceId) { - if ($.browser.android) { - require(['cordova/imagestore']); - } + require(['cordova/imagestore']); var capablities = Dashboard.capabilities();