diff --git a/dashboard-ui/bower_components/emby-apiclient/.bower.json b/dashboard-ui/bower_components/emby-apiclient/.bower.json index c0cb08e97c..e6e9126268 100644 --- a/dashboard-ui/bower_components/emby-apiclient/.bower.json +++ b/dashboard-ui/bower_components/emby-apiclient/.bower.json @@ -16,12 +16,12 @@ }, "devDependencies": {}, "ignore": [], - "version": "1.0.13", - "_release": "1.0.13", + "version": "1.0.15", + "_release": "1.0.15", "_resolution": { "type": "version", - "tag": "1.0.13", - "commit": "50abac508289fd4db77f6d52ba1ee351b57baec2" + "tag": "1.0.15", + "commit": "2b89c4815135e6acef56ec14d56ad0a1d7551e00" }, "_source": "git://github.com/MediaBrowser/Emby.ApiClient.Javascript.git", "_target": "~1.0.3", diff --git a/dashboard-ui/bower_components/emby-apiclient/events.js b/dashboard-ui/bower_components/emby-apiclient/events.js index fabec6f0d0..39ed006f5f 100644 --- a/dashboard-ui/bower_components/emby-apiclient/events.js +++ b/dashboard-ui/bower_components/emby-apiclient/events.js @@ -2,22 +2,20 @@ function getCallbacks(obj, name) { - ensureCallbacks(obj, name); - - return obj._callbacks[name]; - } - - function ensureCallbacks(obj, name) { - if (!obj) { throw new Error("obj cannot be null!"); } obj._callbacks = obj._callbacks || {}; - if (!obj._callbacks[name]) { + var list = obj._callbacks[name]; + + if (!list) { obj._callbacks[name] = []; + list = obj._callbacks[name]; } + + return list; } return { @@ -26,17 +24,17 @@ var list = getCallbacks(obj, eventName); - if (list.indexOf(fn) == -1) { - list.push(fn); - } + list.push(fn); }, off: function (obj, eventName, fn) { var list = getCallbacks(obj, eventName); - obj._callbacks[name] = list.filter(function (i) { - return i != fn; - }); + + var i = list.indexOf(fn); + if (i != -1) { + list.splice(i, 1); + } }, trigger: function (obj, eventName) { @@ -53,7 +51,9 @@ eventArgs.push(additionalArgs[i]); } - getCallbacks(obj, eventName).forEach(function (c) { + var callbacks = getCallbacks(obj, eventName).slice(0); + + callbacks.forEach(function (c) { c.apply(obj, eventArgs); }); } diff --git a/dashboard-ui/bower_components/polymer/.bower.json b/dashboard-ui/bower_components/polymer/.bower.json index 6cb5d92767..b3a07a70af 100644 --- a/dashboard-ui/bower_components/polymer/.bower.json +++ b/dashboard-ui/bower_components/polymer/.bower.json @@ -24,14 +24,14 @@ "web-component-tester": "*" }, "private": true, - "homepage": "https://github.com/Polymer/polymer", + "homepage": "https://github.com/polymer/polymer", "_release": "1.2.3", "_resolution": { "type": "version", "tag": "v1.2.3", "commit": "aa535d1675342007cbf64dc9c66497cf74cbc616" }, - "_source": "git://github.com/Polymer/polymer.git", + "_source": "git://github.com/polymer/polymer.git", "_target": "^1.0.0", - "_originalSource": "Polymer/polymer" + "_originalSource": "polymer/polymer" } \ No newline at end of file diff --git a/dashboard-ui/components/tvproviders/schedulesdirect.js b/dashboard-ui/components/tvproviders/schedulesdirect.js index 06cd8cb91a..64f7b4894e 100644 --- a/dashboard-ui/components/tvproviders/schedulesdirect.js +++ b/dashboard-ui/components/tvproviders/schedulesdirect.js @@ -162,7 +162,7 @@ if (options.showConfirmation !== false) { Dashboard.processServerConfigurationUpdateResult(); } - $(self).trigger('submitted'); + Events.trigger(self, 'submitted'); }, function () { Dashboard.hideLoadingMsg(); diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js index 067d8caca3..d3a14928ec 100644 --- a/dashboard-ui/scripts/chromecast.js +++ b/dashboard-ui/scripts/chromecast.js @@ -483,7 +483,7 @@ } }; - $(castPlayer).on("connect", function (e) { + Events.on(castPlayer, "connect", function (e) { MediaController.setActivePlayer(PlayerName, self.getCurrentTargetInfo()); @@ -492,7 +492,7 @@ self.lastPlayerData = {}; }); - $(castPlayer).on("playbackstart", function (e, data) { + Events.on(castPlayer, "playbackstart", function (e, data) { Logger.log('cc: playbackstart'); @@ -502,7 +502,7 @@ Events.trigger(self, "playbackstart", [state]); }); - $(castPlayer).on("playbackstop", function (e, data) { + Events.on(castPlayer, "playbackstop", function (e, data) { Logger.log('cc: playbackstop'); var state = self.getPlayerStateInternal(data); @@ -513,7 +513,7 @@ self.lastPlayerData = {}; }); - $(castPlayer).on("playbackprogress", function (e, data) { + Events.on(castPlayer, "playbackprogress", function (e, data) { Logger.log('cc: positionchange'); var state = self.getPlayerStateInternal(data); diff --git a/dashboard-ui/scripts/htmlmediarenderer.js b/dashboard-ui/scripts/htmlmediarenderer.js index 2db1973821..89cc7cf50f 100644 --- a/dashboard-ui/scripts/htmlmediarenderer.js +++ b/dashboard-ui/scripts/htmlmediarenderer.js @@ -26,7 +26,7 @@ function onEnded() { showStatusBar(); - $(self).trigger('ended'); + Events.trigger(self, 'ended'); } function onTimeUpdate() { @@ -46,50 +46,58 @@ // } //} - $(self).trigger('timeupdate'); + Events.trigger(self, 'timeupdate'); } function onVolumeChange() { - $(self).trigger('volumechange'); + Events.trigger(self, 'volumechange'); } - function onOneAudioPlaying() { + function onOneAudioPlaying(e) { + + var elem = e.target; + elem.removeEventListener('playing', onOneAudioPlaying); $('.mediaPlayerAudioContainer').hide(); } function onPlaying() { - $(self).trigger('playing'); + Events.trigger(self, 'playing'); } function onPlay() { - $(self).trigger('play'); + Events.trigger(self, 'play'); } function onPause() { - $(self).trigger('pause'); + Events.trigger(self, 'pause'); } function onClick() { - $(self).trigger('click'); + Events.trigger(self, 'click'); } function onDblClick() { - $(self).trigger('dblclick'); + Events.trigger(self, 'dblclick'); } - function onError() { + function onError(e) { - var errorCode = this.error ? this.error.code : ''; + var elem = e.target; + var errorCode = elem.error ? elem.error.code : ''; Logger.log('Media element error code: ' + errorCode); showStatusBar(); - $(self).trigger('error'); + Events.trigger(self, 'error'); } - function onLoadedMetadata() { + function onLoadedMetadata(e) { + + var elem = e.target; + + elem.removeEventListener('loadedmetadata', onLoadedMetadata); if (!hlsPlayer) { - this.play(); + elem.play(); } } @@ -119,14 +127,17 @@ return 0; } - function onOneVideoPlaying() { + function onOneVideoPlaying(e) { hideStatusBar(); + var element = e.target; + element.removeEventListener('playing', onOneVideoPlaying); + var requiresNativeControls = !self.enableCustomVideoControls(); if (requiresNativeControls) { - $(this).attr('controls', 'controls'); + $(element).attr('controls', 'controls'); } if (requiresSettingStartTimeOnStart) { @@ -138,7 +149,6 @@ if (startPositionInSeekParam && src.indexOf('.m3u8') != -1) { var delay = browserInfo.safari ? 2500 : 0; - var element = this; if (delay) { setTimeout(function () { element.currentTime = startPositionInSeekParam; @@ -173,15 +183,18 @@ elem = $('.mediaPlayerAudio'); } - return $(elem) - .on('timeupdate', onTimeUpdate) - .on('ended', onEnded) - .on('volumechange', onVolumeChange) - .one('playing', onOneAudioPlaying) - .on('play', onPlay) - .on('pause', onPause) - .on('playing', onPlaying) - .on('error', onError)[0]; + elem = elem[0]; + + elem.addEventListener('playing', onOneAudioPlaying); + elem.addEventListener('timeupdate', onTimeUpdate); + elem.addEventListener('ended', onEnded); + elem.addEventListener('volumechange', onVolumeChange); + elem.addEventListener('error', onError); + elem.addEventListener('pause', onPause); + elem.addEventListener('play', onPlay); + elem.addEventListener('playing', onPlaying); + + return elem; } function enableHlsPlayer(src) { @@ -221,18 +234,24 @@ var elem = $('#videoElement', '#videoPlayer').prepend(html); - return $('.itemVideo', elem) - .one('.loadedmetadata', onLoadedMetadata) - .one('playing', onOneVideoPlaying) - .on('timeupdate', onTimeUpdate) - .on('ended', onEnded) - .on('volumechange', onVolumeChange) - .on('play', onPlay) - .on('pause', onPause) - .on('playing', onPlaying) - .on('click', onClick) - .on('dblclick', onDblClick) - .on('error', onError)[0]; + var itemVideo = $('.itemVideo', elem)[0]; + + itemVideo.addEventListener('loadedmetadata', onLoadedMetadata); + itemVideo.addEventListener('playing', onOneVideoPlaying); + + itemVideo.addEventListener('timeupdate', onTimeUpdate); + itemVideo.addEventListener('ended', onEnded); + itemVideo.addEventListener('volumechange', onVolumeChange); + + itemVideo.addEventListener('voluplaymechange', onPlay); + itemVideo.addEventListener('pause', onPause); + itemVideo.addEventListener('playing', onPlaying); + + itemVideo.addEventListener('click', onClick); + itemVideo.addEventListener('dblclick', onDblClick); + itemVideo.addEventListener('error', onError); + + return itemVideo; } // Save this for when playback stops, because querying the time at that point might return 0 @@ -384,7 +403,7 @@ setTracks(elem, tracks); - $(elem).one("loadedmetadata", onLoadedMetadata); + elem.addEventListener("loadedmetadata", onLoadedMetadata); playNow = true; } diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index a98deb44ff..7d689060c2 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -543,6 +543,10 @@ self.playNextAfterEnded = function () { + console.log('playNextAfterEnded'); + + Events.off(this, 'ended', self.playNextAfterEnded); + self.nextTrack(); }; @@ -661,16 +665,18 @@ Events.off(mediaRenderer, 'ended', self.onPlaybackStopped); Events.off(mediaRenderer, 'ended', self.playNextAfterEnded); - $(mediaRenderer).one("play", function () { + function onPlayingOnce() { + Events.off(this, "play", onPlayingOnce); Events.on(this, 'ended', self.onPlaybackStopped); - $(this).one('ended', self.playNextAfterEnded); + Events.on(this, 'ended', self.playNextAfterEnded); self.startProgressInterval(); sendProgressUpdate(); + } - }); + Events.on(mediaRenderer, "play", onPlayingOnce); if (self.currentItem.MediaType == "Video") { ApiClient.stopActiveEncodings(playSessionId).then(function () { @@ -1550,25 +1556,23 @@ if (mediaRenderer) { - mediaRenderer.stop(); - Events.off(mediaRenderer, 'ended', self.playNextAfterEnded); - $(mediaRenderer).one("ended", function () { - - $(this).off('.mediaplayerevent'); - - this.cleanup(destroyRenderer); - - self.currentMediaRenderer = null; - self.currentItem = null; - self.currentMediaSource = null; - self.currentSubtitleStreamIndex = null; - self.streamInfo = {}; - - }); + mediaRenderer.stop(); Events.trigger(mediaRenderer, "ended"); + //self.onPlaybackStopped.call(mediaRenderer); + + // TODO: Unbind video events + unBindAudioEvents(mediaRenderer); + + mediaRenderer.cleanup(destroyRenderer); + + self.currentMediaRenderer = null; + self.currentItem = null; + self.currentMediaSource = null; + self.currentSubtitleStreamIndex = null; + self.streamInfo = {}; } else { self.currentMediaRenderer = null; @@ -1583,6 +1587,14 @@ } }; + function unBindAudioEvents(mediaRenderer) { + + Events.off(mediaRenderer, "volumechange", onVolumeChange); + Events.off(mediaRenderer, "pause", onPause); + Events.off(mediaRenderer, "playing", onPlaying); + Events.off(mediaRenderer, "timeupdate", onTimeUpdate); + } + self.isPlaying = function () { return self.playlist.length > 0; }; @@ -1767,8 +1779,8 @@ var mediaRenderer = this; - Events.off(mediaRenderer, '.mediaplayerevent'); - + // TODO: Unbind other events + unBindAudioEvents(mediaRenderer); Events.off(mediaRenderer, 'ended', self.onPlaybackStopped); var item = self.currentItem; @@ -1790,6 +1802,8 @@ self.onPlaystateChange = function (mediaRenderer) { + console.log('mediaplayer onPlaystateChange'); + var state = self.getPlayerStateInternal(mediaRenderer, self.currentItem, self.currentMediaSource); Events.trigger(self, 'playstatechange', [state]); @@ -1939,44 +1953,24 @@ poster: self.getPosterUrl(item) }); - Events.on(mediaRenderer, "volumechange.mediaplayerevent", function () { + function onPlayingOnce() { - Logger.log('audio element event: volumechange'); - - self.onVolumeChanged(this); - - }); - - $(mediaRenderer).one("playing.mediaplayerevent", function () { + Events.off(mediaRenderer, "playing", onPlayingOnce); Logger.log('audio element event: playing'); // For some reason this is firing at the start, so don't bind until playback has begun - Events.on(this, 'ended', self.onPlaybackStopped); + Events.on(mediaRenderer, 'ended', self.onPlaybackStopped); + Events.on(mediaRenderer, 'ended', self.playNextAfterEnded); - $(this).one('ended', self.playNextAfterEnded); + self.onPlaybackStart(mediaRenderer, item, mediaSource); + } - self.onPlaybackStart(this, item, mediaSource); - - }).on("pause.mediaplayerevent", function () { - - Logger.log('audio element event: pause'); - - self.onPlaystateChange(this); - - // In the event timeupdate isn't firing, at least we can update when this happens - self.setCurrentTime(self.getCurrentTicks()); - - }).on("playing.mediaplayerevent", function () { - - Logger.log('audio element event: playing'); - - self.onPlaystateChange(this); - - // In the event timeupdate isn't firing, at least we can update when this happens - self.setCurrentTime(self.getCurrentTicks()); - - }).on("timeupdate.mediaplayerevent", onTimeUpdate); + Events.on(mediaRenderer, "volumechange", onVolumeChange); + Events.on(mediaRenderer, "playing", onPlayingOnce); + Events.on(mediaRenderer, "pause", onPause); + Events.on(mediaRenderer, "playing", onPlaying); + Events.on(mediaRenderer, "timeupdate", onTimeUpdate); self.currentMediaRenderer = mediaRenderer; self.currentDurationTicks = self.currentMediaSource.RunTimeTicks; @@ -1994,6 +1988,34 @@ }); } + function onVolumeChange() { + Logger.log('audio element event: pause'); + + self.onPlaystateChange(this); + + // In the event timeupdate isn't firing, at least we can update when this happens + self.setCurrentTime(self.getCurrentTicks()); + } + + function onPause() { + + Logger.log('audio element event: pause'); + + self.onPlaystateChange(this); + + // In the event timeupdate isn't firing, at least we can update when this happens + self.setCurrentTime(self.getCurrentTicks()); + } + + function onPlaying() { + Logger.log('audio element event: playing'); + + self.onPlaystateChange(this); + + // In the event timeupdate isn't firing, at least we can update when this happens + self.setCurrentTime(self.getCurrentTicks()); + } + var getItemFields = "MediaSources,Chapters"; self.tryPair = function (target) { diff --git a/dashboard-ui/scripts/nowplayingbar.js b/dashboard-ui/scripts/nowplayingbar.js index d28889fe0a..a730c205da 100644 --- a/dashboard-ui/scripts/nowplayingbar.js +++ b/dashboard-ui/scripts/nowplayingbar.js @@ -591,8 +591,8 @@ Events.off(currentPlayer, 'playbackstart', onPlaybackStart); Events.off(currentPlayer, 'playbackstop', onPlaybackStopped); - Events.off(currentPlayer, 'volumechange', onStateChanged); - Events.off(currentPlayer, 'playstatechange', onVolumeChanged); + Events.off(currentPlayer, 'volumechange', onVolumeChanged); + Events.off(currentPlayer, 'playstatechange', onStateChanged); Events.off(currentPlayer, 'positionchange', onStateChanged); currentPlayer.endPlayerUpdates(); @@ -635,8 +635,8 @@ Events.on(player, 'playbackstart', onPlaybackStart); Events.on(player, 'playbackstop', onPlaybackStopped); - Events.on(player, 'volumechange', onStateChanged); - Events.on(player, 'playstatechange', onVolumeChanged); + Events.on(player, 'volumechange', onVolumeChanged); + Events.on(player, 'playstatechange', onStateChanged); Events.on(player, 'positionchange', onStateChanged); } diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js index e3e72c12ea..c5beccef38 100644 --- a/dashboard-ui/scripts/site.js +++ b/dashboard-ui/scripts/site.js @@ -2047,10 +2047,6 @@ var AppInfo = {}; deps.push('connectionmanagerfactory'); deps.push('credentialprovider'); - if (AppInfo.isNativeApp && browserInfo.android) { - require(['cordova/android/logging']); - } - deps.push('appstorage'); deps.push('scripts/mediaplayer'); deps.push('scripts/appsettings'); diff --git a/dashboard-ui/strings/javascript/javascript.json b/dashboard-ui/strings/javascript/javascript.json index 30cd05121d..9789586b81 100644 --- a/dashboard-ui/strings/javascript/javascript.json +++ b/dashboard-ui/strings/javascript/javascript.json @@ -947,5 +947,6 @@ "FreeAppsFeatureDescription": "Enjoy free access to select Emby apps for your devices.", "HeaderCinemaMode": "Cinema Mode", "CinemaModeFeatureDescription": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the feature.", - "CoverArt": "Cover Art" + "CoverArt": "Cover Art", + "ButtonOff": "Off" }