diff --git a/player/dailymotion.coffee b/player/dailymotion.coffee new file mode 100644 index 00000000..58b0c035 --- /dev/null +++ b/player/dailymotion.coffee @@ -0,0 +1,105 @@ +window.DailymotionPlayer = class DailymotionPlayer extends Player + constructor: (data) -> + if not (this instanceof DailymotionPlayer) + return new DailymotionPlayer(data) + + @setMediaProperties(data) + @initialVolumeSet = false + + waitUntilDefined(window, 'DM', => + removeOld() + + params = + autoplay: 1 + wmode: if USEROPTS.wmode_transparent then 'transparent' else 'opaque' + logo: 0 + + quality = @mapQuality(USEROPTS.default_quality) + if quality != 'auto' + params.quality = quality + + @dm = DM.player('ytapiplayer', + video: data.id + width: parseInt(VWIDTH, 10) + height: parseInt(VHEIGHT, 10) + params: params + ) + + @dm.addEventListener('apiready', => + @dm.ready = true + @dm.addEventListener('ended', -> + if CLIENT.leader + socket.emit('playNext') + ) + + @dm.addEventListener('pause', => + @paused = true + if CLIENT.leader + sendVideoUpdate() + ) + + @dm.addEventListener('playing', => + @paused = false + if CLIENT.leader + sendVideoUpdate() + + if not @initialVolumeSet + @setVolume(VOLUME) + @initialVolumeSet = true + ) + ) + ) + + load: (data) -> + @setMediaProperties(data) + if @dm and @dm.ready + @dm.load(data.id) + @dm.seek(data.currentTime) + else + console.error('WTF? DailymotionPlayer::load() called but dm is not ready') + + pause: -> + if @dm and @dm.ready + @paused = true + @dm.pause() + + play: -> + if @dm and @dm.ready + @paused = false + @dm.play() + + seekTo: (time) -> + if @dm and @dm.ready + @dm.seek(time) + + setVolume: (volume) -> + if @dm and @dm.ready + @dm.setVolume(volume) + + getTime: (cb) -> + if @dm and @dm.ready + cb(@dm.currentTime) + else + cb(0) + + getVolume: (cb) -> + if @dm and @dm.ready + if @dm.muted + cb(0) + else + volume = @dm.volume + # There was once a bug in Dailymotion where it sometimes gave back + # volumes in the wrong range. Not sure if this is still a necessary + # check. + if volume > 1 + volume /= 100 + cb(volume) + else + cb(VOLUME) + + mapQuality: (quality) -> + switch String(quality) + when '240', '480', '720', '1080' then String(quality) + when '360' then '380' + when 'best' then '1080' + else 'auto' diff --git a/player/update.coffee b/player/update.coffee index 536315d8..4a22c42f 100644 --- a/player/update.coffee +++ b/player/update.coffee @@ -1,6 +1,7 @@ TYPE_MAP = yt: YouTubePlayer vi: VimeoPlayer + dm: DailymotionPlayer window.loadMediaPlayer = (data) -> if data.type of TYPE_MAP diff --git a/player/youtube.coffee b/player/youtube.coffee index bd3e1dcb..7c94f8a9 100644 --- a/player/youtube.coffee +++ b/player/youtube.coffee @@ -9,7 +9,7 @@ window.YouTubePlayer = class YouTubePlayer extends Player waitUntilDefined(window, 'YT', => # Even after window.YT is defined, YT.Player may not be, which causes a - # "YT.Player is not a constructor" error occasionally + # 'YT.Player is not a constructor' error occasionally waitUntilDefined(YT, 'Player', => removeOld() @@ -94,15 +94,15 @@ window.YouTubePlayer = class YouTubePlayer extends Player return ytQuality = switch String(quality) - when "240" then "small" - when "360" then "medium" - when "480" then "large" - when "720" then "hd720" - when "1080" then "hd1080" - when "best" then "highres" - else "auto" + when '240' then 'small' + when '360' then 'medium' + when '480' then 'large' + when '720' then 'hd720' + when '1080' then 'hd1080' + when 'best' then 'highres' + else 'auto' - if ytQuality != "auto" + if ytQuality != 'auto' @yt.setPlaybackQuality(ytQuality) getTime: (cb) -> diff --git a/www/js/player-new.js b/www/js/player-new.js index 543a3234..cc5d9cc1 100644 --- a/www/js/player-new.js +++ b/www/js/player-new.js @@ -1,5 +1,5 @@ (function() { - var Player, TYPE_MAP, VimeoPlayer, YouTubePlayer, + var DailymotionPlayer, Player, TYPE_MAP, VimeoPlayer, YouTubePlayer, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; @@ -262,23 +262,23 @@ } ytQuality = (function() { switch (String(quality)) { - case "240": - return "small"; - case "360": - return "medium"; - case "480": - return "large"; - case "720": - return "hd720"; - case "1080": - return "hd1080"; - case "best": - return "highres"; + case '240': + return 'small'; + case '360': + return 'medium'; + case '480': + return 'large'; + case '720': + return 'hd720'; + case '1080': + return 'hd1080'; + case 'best': + return 'highres'; default: - return "auto"; + return 'auto'; } })(); - if (ytQuality !== "auto") { + if (ytQuality !== 'auto') { return this.yt.setPlaybackQuality(ytQuality); } }; @@ -307,9 +307,147 @@ })(Player); + window.DailymotionPlayer = DailymotionPlayer = (function(superClass) { + extend(DailymotionPlayer, superClass); + + function DailymotionPlayer(data) { + if (!(this instanceof DailymotionPlayer)) { + return new DailymotionPlayer(data); + } + this.setMediaProperties(data); + this.initialVolumeSet = false; + waitUntilDefined(window, 'DM', (function(_this) { + return function() { + var params, quality; + removeOld(); + params = { + autoplay: 1, + wmode: USEROPTS.wmode_transparent ? 'transparent' : 'opaque', + logo: 0 + }; + quality = _this.mapQuality(USEROPTS.default_quality); + if (quality !== 'auto') { + params.quality = quality; + } + _this.dm = DM.player('ytapiplayer', { + video: data.id, + width: parseInt(VWIDTH, 10), + height: parseInt(VHEIGHT, 10), + params: params + }); + return _this.dm.addEventListener('apiready', function() { + _this.dm.ready = true; + _this.dm.addEventListener('ended', function() { + if (CLIENT.leader) { + return socket.emit('playNext'); + } + }); + _this.dm.addEventListener('pause', function() { + _this.paused = true; + if (CLIENT.leader) { + return sendVideoUpdate(); + } + }); + return _this.dm.addEventListener('playing', function() { + _this.paused = false; + if (CLIENT.leader) { + sendVideoUpdate(); + } + if (!_this.initialVolumeSet) { + _this.setVolume(VOLUME); + return _this.initialVolumeSet = true; + } + }); + }); + }; + })(this)); + } + + DailymotionPlayer.prototype.load = function(data) { + this.setMediaProperties(data); + if (this.dm && this.dm.ready) { + this.dm.load(data.id); + return this.dm.seek(data.currentTime); + } else { + return console.error('WTF? DailymotionPlayer::load() called but dm is not ready'); + } + }; + + DailymotionPlayer.prototype.pause = function() { + if (this.dm && this.dm.ready) { + this.paused = true; + return this.dm.pause(); + } + }; + + DailymotionPlayer.prototype.play = function() { + if (this.dm && this.dm.ready) { + this.paused = false; + return this.dm.play(); + } + }; + + DailymotionPlayer.prototype.seekTo = function(time) { + if (this.dm && this.dm.ready) { + return this.dm.seek(time); + } + }; + + DailymotionPlayer.prototype.setVolume = function(volume) { + if (this.dm && this.dm.ready) { + return this.dm.setVolume(volume); + } + }; + + DailymotionPlayer.prototype.getTime = function(cb) { + if (this.dm && this.dm.ready) { + return cb(this.dm.currentTime); + } else { + return cb(0); + } + }; + + DailymotionPlayer.prototype.getVolume = function(cb) { + var volume; + if (this.dm && this.dm.ready) { + if (this.dm.muted) { + return cb(0); + } else { + volume = this.dm.volume; + if (volume > 1) { + volume /= 100; + } + return cb(volume); + } + } else { + return cb(VOLUME); + } + }; + + DailymotionPlayer.prototype.mapQuality = function(quality) { + switch (String(quality)) { + case '240': + case '480': + case '720': + case '1080': + return String(quality); + case '360': + return '380'; + case 'best': + return '1080'; + default: + return 'auto'; + } + }; + + return DailymotionPlayer; + + })(Player); + TYPE_MAP = { yt: YouTubePlayer, - vi: VimeoPlayer + vi: VimeoPlayer, + dm: DailymotionPlayer }; window.loadMediaPlayer = function(data) {