diff --git a/build-player.js b/build-player.js
index 0e82b334..d02f3536 100644
--- a/build-player.js
+++ b/build-player.js
@@ -18,6 +18,7 @@ var order = [
'hitbox.coffee',
'ustream.coffee',
'imgur.coffee',
+ 'gdrive-youtube.coffee',
'update.coffee'
];
diff --git a/player/embed.coffee b/player/embed.coffee
index b42d965a..85c85dbc 100644
--- a/player/embed.coffee
+++ b/player/embed.coffee
@@ -37,6 +37,7 @@ window.EmbedPlayer = class EmbedPlayer extends Player
object = $('').attr(
type: 'application/x-shockwave-flash'
data: embed.src
+ wmode: 'opaque'
)
genParam('allowfullscreen', 'true').appendTo(object)
genParam('allowscriptaccess', 'always').appendTo(object)
diff --git a/player/gdrive-youtube.coffee b/player/gdrive-youtube.coffee
new file mode 100644
index 00000000..37aa08a2
--- /dev/null
+++ b/player/gdrive-youtube.coffee
@@ -0,0 +1,103 @@
+window.GoogleDriveYouTubePlayer = class GoogleDriveYouTubePlayer extends Player
+ constructor: (data) ->
+ if not (this instanceof GoogleDriveYouTubePlayer)
+ return new GoogleDriveYouTubePlayer(data)
+
+ @setMediaProperties(data)
+ @init(data)
+
+ init: (data) ->
+ embed = $('').attr(
+ type: 'application/x-shockwave-flash'
+ src: "https://www.youtube.com/get_player?docid=#{data.id}&ps=docs\
+ &partnerid=30&enablejsapi=1&cc_load_policy=1\
+ &auth_timeout=86400000000"
+ flashvars: 'autoplay=1&playerapiid=uniquePlayerId'
+ wmode: 'opaque'
+ allowscriptaccess: 'always'
+ )
+ removeOld(embed)
+
+ window.onYouTubePlayerReady = =>
+ if PLAYER != this
+ return
+
+ @yt = embed[0]
+ window.gdriveStateChange = @onStateChange.bind(this)
+ @yt.addEventListener('onStateChange', 'gdriveStateChange')
+ @onReady()
+
+ load: (data) ->
+ @setMediaProperties(data)
+ @init(data)
+
+ onReady: ->
+ @yt.ready = true
+ @setVolume(VOLUME)
+ @setQuality(USEROPTS.default_quality)
+
+ onStateChange: (ev) ->
+ if PLAYER != this
+ return
+
+ if (ev == YT.PlayerState.PAUSED and not @paused) or
+ (ev == YT.PlayerState.PLAYING and @paused)
+ @paused = (ev == YT.PlayerState.PAUSED)
+ if CLIENT.leader
+ sendVideoUpdate()
+
+ if ev == YT.PlayerState.ENDED and CLIENT.leader
+ socket.emit('playNext')
+
+ play: ->
+ @paused = false
+ if @yt and @yt.ready
+ @yt.playVideo()
+
+ pause: ->
+ @paused = true
+ if @yt and @yt.ready
+ @yt.pauseVideo()
+
+ seekTo: (time) ->
+ if @yt and @yt.ready
+ @yt.seekTo(time, true)
+
+ setVolume: (volume) ->
+ if @yt and @yt.ready
+ if volume > 0
+ # If the player is muted, even if the volume is set,
+ # the player remains muted
+ @yt.unMute()
+ @yt.setVolume(volume * 100)
+
+ setQuality: (quality) ->
+ if not @yt or not @yt.ready
+ 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'
+
+ if ytQuality != 'auto'
+ @yt.setPlaybackQuality(ytQuality)
+
+ getTime: (cb) ->
+ if @yt and @yt.ready
+ cb(@yt.getCurrentTime())
+ else
+ cb(0)
+
+ getVolume: (cb) ->
+ if @yt and @yt.ready
+ if @yt.isMuted()
+ cb(0)
+ else
+ cb(@yt.getVolume() / 100)
+ else
+ cb(VOLUME)
diff --git a/player/update.coffee b/player/update.coffee
index 6231c4c1..25bf546a 100644
--- a/player/update.coffee
+++ b/player/update.coffee
@@ -2,7 +2,7 @@ TYPE_MAP =
yt: YouTubePlayer
vi: VimeoPlayer
dm: DailymotionPlayer
- gd: VideoJSPlayer
+ gd: GoogleDriveYouTubePlayer
gp: VideoJSPlayer
fi: FilePlayer
jw: FilePlayer
@@ -16,7 +16,7 @@ TYPE_MAP =
im: ImgurPlayer
window.loadMediaPlayer = (data) ->
- if data.meta.direct
+ if data.meta.direct and data.type != 'gd'
try
window.PLAYER = new VideoJSPlayer(data)
catch e
diff --git a/www/js/player.js b/www/js/player.js
index 2ce598eb..e7efe95b 100644
--- a/www/js/player.js
+++ b/www/js/player.js
@@ -1,5 +1,5 @@
(function() {
- var CUSTOM_EMBED_WARNING, CustomEmbedPlayer, DEFAULT_ERROR, DailymotionPlayer, EmbedPlayer, FilePlayer, HITBOX_ERROR, HitboxPlayer, ImgurPlayer, LivestreamPlayer, Player, RTMPPlayer, SoundCloudPlayer, TYPE_MAP, TwitchPlayer, USTREAM_ERROR, UstreamPlayer, VideoJSPlayer, VimeoPlayer, YouTubePlayer, codecToMimeType, genParam, sortSources,
+ var CUSTOM_EMBED_WARNING, CustomEmbedPlayer, DEFAULT_ERROR, DailymotionPlayer, EmbedPlayer, FilePlayer, GoogleDriveYouTubePlayer, HITBOX_ERROR, HitboxPlayer, ImgurPlayer, LivestreamPlayer, Player, RTMPPlayer, SoundCloudPlayer, TYPE_MAP, TwitchPlayer, USTREAM_ERROR, UstreamPlayer, VideoJSPlayer, VimeoPlayer, YouTubePlayer, codecToMimeType, genParam, sortSources,
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;
@@ -851,7 +851,8 @@
var key, object, ref, value;
object = $('').attr({
type: 'application/x-shockwave-flash',
- data: embed.src
+ data: embed.src,
+ wmode: 'opaque'
});
genParam('allowfullscreen', 'true').appendTo(object);
genParam('allowscriptaccess', 'always').appendTo(object);
@@ -1099,11 +1100,152 @@
})(EmbedPlayer);
+ window.GoogleDriveYouTubePlayer = GoogleDriveYouTubePlayer = (function(superClass) {
+ extend(GoogleDriveYouTubePlayer, superClass);
+
+ function GoogleDriveYouTubePlayer(data) {
+ if (!(this instanceof GoogleDriveYouTubePlayer)) {
+ return new GoogleDriveYouTubePlayer(data);
+ }
+ this.setMediaProperties(data);
+ this.init(data);
+ }
+
+ GoogleDriveYouTubePlayer.prototype.init = function(data) {
+ var embed;
+ embed = $('').attr({
+ type: 'application/x-shockwave-flash',
+ src: "https://www.youtube.com/get_player?docid=" + data.id + "&ps=docs&partnerid=30&enablejsapi=1&cc_load_policy=1&auth_timeout=86400000000",
+ flashvars: 'autoplay=1&playerapiid=uniquePlayerId',
+ wmode: 'opaque',
+ allowscriptaccess: 'always'
+ });
+ removeOld(embed);
+ return window.onYouTubePlayerReady = (function(_this) {
+ return function() {
+ if (PLAYER !== _this) {
+ return;
+ }
+ _this.yt = embed[0];
+ window.gdriveStateChange = _this.onStateChange.bind(_this);
+ _this.yt.addEventListener('onStateChange', 'gdriveStateChange');
+ return _this.onReady();
+ };
+ })(this);
+ };
+
+ GoogleDriveYouTubePlayer.prototype.load = function(data) {
+ this.setMediaProperties(data);
+ return this.init(data);
+ };
+
+ GoogleDriveYouTubePlayer.prototype.onReady = function() {
+ this.yt.ready = true;
+ this.setVolume(VOLUME);
+ return this.setQuality(USEROPTS.default_quality);
+ };
+
+ GoogleDriveYouTubePlayer.prototype.onStateChange = function(ev) {
+ if (PLAYER !== this) {
+ return;
+ }
+ if ((ev === YT.PlayerState.PAUSED && !this.paused) || (ev === YT.PlayerState.PLAYING && this.paused)) {
+ this.paused = ev === YT.PlayerState.PAUSED;
+ if (CLIENT.leader) {
+ sendVideoUpdate();
+ }
+ }
+ if (ev === YT.PlayerState.ENDED && CLIENT.leader) {
+ return socket.emit('playNext');
+ }
+ };
+
+ GoogleDriveYouTubePlayer.prototype.play = function() {
+ this.paused = false;
+ if (this.yt && this.yt.ready) {
+ return this.yt.playVideo();
+ }
+ };
+
+ GoogleDriveYouTubePlayer.prototype.pause = function() {
+ this.paused = true;
+ if (this.yt && this.yt.ready) {
+ return this.yt.pauseVideo();
+ }
+ };
+
+ GoogleDriveYouTubePlayer.prototype.seekTo = function(time) {
+ if (this.yt && this.yt.ready) {
+ return this.yt.seekTo(time, true);
+ }
+ };
+
+ GoogleDriveYouTubePlayer.prototype.setVolume = function(volume) {
+ if (this.yt && this.yt.ready) {
+ if (volume > 0) {
+ this.yt.unMute();
+ }
+ return this.yt.setVolume(volume * 100);
+ }
+ };
+
+ GoogleDriveYouTubePlayer.prototype.setQuality = function(quality) {
+ var ytQuality;
+ if (!this.yt || !this.yt.ready) {
+ return;
+ }
+ 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';
+ default:
+ return 'auto';
+ }
+ })();
+ if (ytQuality !== 'auto') {
+ return this.yt.setPlaybackQuality(ytQuality);
+ }
+ };
+
+ GoogleDriveYouTubePlayer.prototype.getTime = function(cb) {
+ if (this.yt && this.yt.ready) {
+ return cb(this.yt.getCurrentTime());
+ } else {
+ return cb(0);
+ }
+ };
+
+ GoogleDriveYouTubePlayer.prototype.getVolume = function(cb) {
+ if (this.yt && this.yt.ready) {
+ if (this.yt.isMuted()) {
+ return cb(0);
+ } else {
+ return cb(this.yt.getVolume() / 100);
+ }
+ } else {
+ return cb(VOLUME);
+ }
+ };
+
+ return GoogleDriveYouTubePlayer;
+
+ })(Player);
+
TYPE_MAP = {
yt: YouTubePlayer,
vi: VimeoPlayer,
dm: DailymotionPlayer,
- gd: VideoJSPlayer,
+ gd: GoogleDriveYouTubePlayer,
gp: VideoJSPlayer,
fi: FilePlayer,
jw: FilePlayer,
@@ -1119,7 +1261,7 @@
window.loadMediaPlayer = function(data) {
var e;
- if (data.meta.direct) {
+ if (data.meta.direct && data.type !== 'gd') {
try {
return window.PLAYER = new VideoJSPlayer(data);
} catch (_error) {
diff --git a/www/js/util.js b/www/js/util.js
index fd13a2e7..38994699 100644
--- a/www/js/util.js
+++ b/www/js/util.js
@@ -1910,13 +1910,18 @@ function waitUntilDefined(obj, key, fn) {
}
function hidePlayer() {
+ /* 2015-09-16
+ * Originally used to hide the player while a modal was open because of
+ * certain flash videos that always rendered on top. Seems to no longer
+ * be an issue. Uncomment this if it is.
if (!PLAYER) return;
$("#ytapiplayer").hide();
+ */
}
function unhidePlayer() {
- $("#ytapiplayer").show();
+ //$("#ytapiplayer").show();
}
function chatDialog(div) {