mirror of https://github.com/calzoneman/sync.git
Start working on VideoJS for Google Drive
This commit is contained in:
parent
daf2463a6a
commit
fe9ebfa6b1
109
lib/get-info.js
109
lib/get-info.js
|
@ -7,7 +7,7 @@ var CustomEmbedFilter = require("./customembed").filter;
|
||||||
var Server = require("./server");
|
var Server = require("./server");
|
||||||
var Config = require("./config");
|
var Config = require("./config");
|
||||||
var ffmpeg = require("./ffmpeg");
|
var ffmpeg = require("./ffmpeg");
|
||||||
require("cytube-mediaquery"); // Initialize sourcemaps
|
var mediaquery = require("cytube-mediaquery");
|
||||||
var YouTube = require("cytube-mediaquery/lib/provider/youtube");
|
var YouTube = require("cytube-mediaquery/lib/provider/youtube");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -62,6 +62,17 @@ var urlRetrieve = function (transport, options, callback) {
|
||||||
req.end();
|
req.end();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var mediaTypeMap = {
|
||||||
|
"youtube": "yt",
|
||||||
|
"googledrive": "gd",
|
||||||
|
"google+": "gp"
|
||||||
|
};
|
||||||
|
|
||||||
|
function convertMedia(media) {
|
||||||
|
return new Media(media.id, media.title, media.duration, mediaTypeMap[media.type],
|
||||||
|
media.meta);
|
||||||
|
}
|
||||||
|
|
||||||
var Getters = {
|
var Getters = {
|
||||||
/* youtube.com */
|
/* youtube.com */
|
||||||
yt: function (id, callback) {
|
yt: function (id, callback) {
|
||||||
|
@ -506,96 +517,16 @@ var Getters = {
|
||||||
|
|
||||||
/* google docs */
|
/* google docs */
|
||||||
gd: function (id, callback) {
|
gd: function (id, callback) {
|
||||||
/* WARNING: hacks inbound */
|
var data = {
|
||||||
var options = {
|
type: "googledrive",
|
||||||
host: "docs.google.com",
|
kind: "single",
|
||||||
path: "/file/d/" + id + "/get_video_info?sle=true",
|
id: id
|
||||||
port: 443
|
|
||||||
};
|
};
|
||||||
|
|
||||||
urlRetrieve(https, options, function (status, res) {
|
mediaquery.lookup(data).then(function (video) {
|
||||||
switch (status) {
|
callback(null, convertMedia(video));
|
||||||
case 200:
|
}).catch(function (err) {
|
||||||
break; /* Request is OK, skip to handling data */
|
callback(err.message || err);
|
||||||
case 400:
|
|
||||||
return callback("Invalid request", null);
|
|
||||||
case 403:
|
|
||||||
return callback("Private video", null);
|
|
||||||
case 404:
|
|
||||||
return callback("Video not found", null);
|
|
||||||
case 500:
|
|
||||||
case 503:
|
|
||||||
return callback("Service unavailable", null);
|
|
||||||
default:
|
|
||||||
return callback("HTTP " + status, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
var data = {};
|
|
||||||
res.split("&").forEach(function (urlparam) {
|
|
||||||
var pair = urlparam.split("=").map(decodeURIComponent).map(
|
|
||||||
function (s) { return s.replace(/\+/g, ' '); });
|
|
||||||
data[pair[0]] = pair[1];
|
|
||||||
});
|
|
||||||
|
|
||||||
if (data.hasOwnProperty("reason")) {
|
|
||||||
var reason = data.reason;
|
|
||||||
if (reason.indexOf("Unable to play this video at this time.") === 0) {
|
|
||||||
reason = "There is currently a bug with Google Drive which prevents playback " +
|
|
||||||
"of videos 1 hour long or longer.";
|
|
||||||
} else if (reason.indexOf(
|
|
||||||
"You must be signed in to access this video") >= 0) {
|
|
||||||
reason = "This video is not shared properly";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return callback(reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.hasOwnProperty("title")) {
|
|
||||||
return callback("Returned HTML is missing the video title. Are you " +
|
|
||||||
"sure the video is done processing?");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.hasOwnProperty("length_seconds")) {
|
|
||||||
return callback("Returned HTML is missing the video duration. Are you " +
|
|
||||||
"sure the video is done processing?");
|
|
||||||
}
|
|
||||||
|
|
||||||
var title = data.title;
|
|
||||||
var seconds = parseInt(data.length_seconds);
|
|
||||||
|
|
||||||
var videos = {};
|
|
||||||
data.fmt_stream_map.split(",").forEach(function (stream) {
|
|
||||||
var parts = stream.split("|");
|
|
||||||
videos[parts[0]] = parts[1];
|
|
||||||
});
|
|
||||||
|
|
||||||
var direct = {};
|
|
||||||
|
|
||||||
for (var key in GOOGLE_PREFERENCE) {
|
|
||||||
for (var i = 0; i < GOOGLE_PREFERENCE[key].length; i++) {
|
|
||||||
var format = GOOGLE_PREFERENCE[key][i];
|
|
||||||
|
|
||||||
if (format in videos) {
|
|
||||||
direct[key] = {
|
|
||||||
url: videos[format],
|
|
||||||
contentType: CONTENT_TYPES[format]
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Object.keys(direct).length === 0) {
|
|
||||||
return callback("No valid links could be extracted", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(null, new Media(id, title, seconds, "gd", { gpdirect: direct }));
|
|
||||||
} catch (e) {
|
|
||||||
return callback("Failed to parse Google Docs output", null);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ TYPE_MAP =
|
||||||
yt: YouTubePlayer
|
yt: YouTubePlayer
|
||||||
vi: VimeoPlayer
|
vi: VimeoPlayer
|
||||||
dm: DailymotionPlayer
|
dm: DailymotionPlayer
|
||||||
|
gd: VideoJSPlayer
|
||||||
|
|
||||||
window.loadMediaPlayer = (data) ->
|
window.loadMediaPlayer = (data) ->
|
||||||
if data.type of TYPE_MAP
|
if data.type of TYPE_MAP
|
||||||
|
|
|
@ -1,6 +1,121 @@
|
||||||
class VideoJSPlayer extends Player
|
sortSources = (sources) ->
|
||||||
constructor: (data) ->
|
if not sources
|
||||||
|
console.error('sortSources() called with null source list')
|
||||||
|
return []
|
||||||
|
|
||||||
load: (data) ->
|
qualities = ['1080', '720', '480', '360', '240']
|
||||||
|
pref = String(USEROPTS.default_quality)
|
||||||
|
idx = qualities.indexOf(pref)
|
||||||
|
if idx < 0
|
||||||
|
pref = '480'
|
||||||
|
|
||||||
|
qualityOrder = qualities.slice(idx).concat(qualities.slice(0, idx))
|
||||||
|
sourceOrder = []
|
||||||
|
flvOrder = []
|
||||||
|
for quality in qualityOrder
|
||||||
|
if quality of sources
|
||||||
|
flv = []
|
||||||
|
nonflv = []
|
||||||
|
sources[quality].forEach((source) ->
|
||||||
|
if source.contentType == 'flv'
|
||||||
|
flv.push(source)
|
||||||
|
else
|
||||||
|
nonflv.push(source)
|
||||||
|
)
|
||||||
|
sourceOrder = sourceOrder.concat(nonflv)
|
||||||
|
flvOrder = flvOrder.concat(flv)
|
||||||
|
|
||||||
|
return sourceOrder.concat(flvOrder).map((source) ->
|
||||||
|
type: "video/#{source.contentType}"
|
||||||
|
src: source.link
|
||||||
|
)
|
||||||
|
|
||||||
|
window.VideoJSPlayer = class VideoJSPlayer extends Player
|
||||||
|
constructor: (data) ->
|
||||||
|
if not (this instanceof VideoJSPlayer)
|
||||||
|
return new VideoJSPlayer(data)
|
||||||
|
|
||||||
|
@setMediaProperties(data)
|
||||||
|
|
||||||
|
waitUntilDefined(window, 'videojs', =>
|
||||||
video = $('<video/>')
|
video = $('<video/>')
|
||||||
.addClass('video-js vjs-default-skin embed-responsive-item')
|
.addClass('video-js vjs-default-skin embed-responsive-item')
|
||||||
|
.attr(width: '100%', height: '100%')
|
||||||
|
removeOld(video)
|
||||||
|
|
||||||
|
sources = sortSources(data.meta.direct)
|
||||||
|
if sources.length == 0
|
||||||
|
# Temporary fix for race condition caused by channel playlist
|
||||||
|
# sending a changeMedia in onPostUserJoin before mediarefresher
|
||||||
|
# has refreshed it.
|
||||||
|
# TODO: Actually fix this on the server side rather than this
|
||||||
|
# hack.
|
||||||
|
@mediaType = null
|
||||||
|
return
|
||||||
|
|
||||||
|
sources.forEach((source) ->
|
||||||
|
$('<source/>').attr('src', source.src)
|
||||||
|
.attr('type', source.type)
|
||||||
|
.appendTo(video)
|
||||||
|
)
|
||||||
|
|
||||||
|
@player = videojs(video[0], autoplay: true, controls: true)
|
||||||
|
@player.ready(=>
|
||||||
|
@player.on('ended', ->
|
||||||
|
if CLIENT.leader
|
||||||
|
socket.emit('playNext')
|
||||||
|
)
|
||||||
|
|
||||||
|
@player.on('pause', =>
|
||||||
|
@paused = true
|
||||||
|
if CLIENT.leader
|
||||||
|
sendVideoUpdate()
|
||||||
|
)
|
||||||
|
|
||||||
|
@player.on('play', =>
|
||||||
|
@paused = false
|
||||||
|
if CLIENT.leader
|
||||||
|
sendVideoUpdate()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
load: (data) ->
|
||||||
|
@setMediaProperties(data)
|
||||||
|
if @player
|
||||||
|
@player.src(sortSources(data.meta.direct))
|
||||||
|
else
|
||||||
|
console.log('VideoJSPlayer::load() called but @player is undefined')
|
||||||
|
|
||||||
|
play: ->
|
||||||
|
@paused = false
|
||||||
|
if @player and @player.readyState() > 0
|
||||||
|
@player.play()
|
||||||
|
|
||||||
|
pause: ->
|
||||||
|
@paused = true
|
||||||
|
if @player and @player.readyState() > 0
|
||||||
|
@player.pause()
|
||||||
|
|
||||||
|
seekTo: (time) ->
|
||||||
|
if @player and @player.readyState() > 0
|
||||||
|
@player.currentTime(time)
|
||||||
|
|
||||||
|
setVolume: (volume) ->
|
||||||
|
if @player and @player.readyState() > 0
|
||||||
|
@player.volume(volume)
|
||||||
|
|
||||||
|
getTime: (cb) ->
|
||||||
|
if @player and @player.readyState() > 0
|
||||||
|
cb(@player.currentTime())
|
||||||
|
else
|
||||||
|
cb(0)
|
||||||
|
|
||||||
|
getVolume: (cb) ->
|
||||||
|
if @player and @player.readyState() > 0
|
||||||
|
if @player.muted()
|
||||||
|
cb(0)
|
||||||
|
else
|
||||||
|
cb(@player.volume())
|
||||||
|
else
|
||||||
|
cb(VOLUME)
|
||||||
|
|
|
@ -4,6 +4,7 @@ html(lang="en")
|
||||||
include head
|
include head
|
||||||
mixin head()
|
mixin head()
|
||||||
link(href="//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css", rel="stylesheet")
|
link(href="//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css", rel="stylesheet")
|
||||||
|
link(rel="stylesheet", href="https://vjs.zencdn.net/4.12/video-js.css")
|
||||||
body
|
body
|
||||||
#wrap
|
#wrap
|
||||||
nav.navbar.navbar-inverse.navbar-fixed-top(role="navigation")
|
nav.navbar.navbar-inverse.navbar-fixed-top(role="navigation")
|
||||||
|
@ -228,3 +229,4 @@ html(lang="en")
|
||||||
script(defer, src="/js/sc.js")
|
script(defer, src="/js/sc.js")
|
||||||
script(defer, src="/js/froogaloop.min.js")
|
script(defer, src="/js/froogaloop.min.js")
|
||||||
script(defer, src="/js/swf.js")
|
script(defer, src="/js/swf.js")
|
||||||
|
script(defer, src="https://vjs.zencdn.net/4.12/video.js")
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
(function() {
|
(function() {
|
||||||
var DailymotionPlayer, Player, TYPE_MAP, VimeoPlayer, YouTubePlayer,
|
var DailymotionPlayer, Player, TYPE_MAP, VideoJSPlayer, VimeoPlayer, YouTubePlayer, 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; },
|
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;
|
hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
|
@ -444,10 +444,160 @@
|
||||||
|
|
||||||
})(Player);
|
})(Player);
|
||||||
|
|
||||||
|
sortSources = function(sources) {
|
||||||
|
var flv, flvOrder, i, idx, len, nonflv, pref, qualities, quality, qualityOrder, sourceOrder;
|
||||||
|
if (!sources) {
|
||||||
|
console.error('sortSources() called with null source list');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
qualities = ['1080', '720', '480', '360', '240'];
|
||||||
|
pref = String(USEROPTS.default_quality);
|
||||||
|
idx = qualities.indexOf(pref);
|
||||||
|
if (idx < 0) {
|
||||||
|
pref = '480';
|
||||||
|
}
|
||||||
|
qualityOrder = qualities.slice(idx).concat(qualities.slice(0, idx));
|
||||||
|
sourceOrder = [];
|
||||||
|
flvOrder = [];
|
||||||
|
for (i = 0, len = qualityOrder.length; i < len; i++) {
|
||||||
|
quality = qualityOrder[i];
|
||||||
|
if (quality in sources) {
|
||||||
|
flv = [];
|
||||||
|
nonflv = [];
|
||||||
|
sources[quality].forEach(function(source) {
|
||||||
|
if (source.contentType === 'flv') {
|
||||||
|
return flv.push(source);
|
||||||
|
} else {
|
||||||
|
return nonflv.push(source);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sourceOrder = sourceOrder.concat(nonflv);
|
||||||
|
flvOrder = flvOrder.concat(flv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sourceOrder.concat(flvOrder).map(function(source) {
|
||||||
|
return {
|
||||||
|
type: "video/" + source.contentType,
|
||||||
|
src: source.link
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
window.VideoJSPlayer = VideoJSPlayer = (function(superClass) {
|
||||||
|
extend(VideoJSPlayer, superClass);
|
||||||
|
|
||||||
|
function VideoJSPlayer(data) {
|
||||||
|
if (!(this instanceof VideoJSPlayer)) {
|
||||||
|
return new VideoJSPlayer(data);
|
||||||
|
}
|
||||||
|
this.setMediaProperties(data);
|
||||||
|
waitUntilDefined(window, 'videojs', (function(_this) {
|
||||||
|
return function() {
|
||||||
|
var sources, video;
|
||||||
|
video = $('<video/>').addClass('video-js vjs-default-skin embed-responsive-item').attr({
|
||||||
|
width: '100%',
|
||||||
|
height: '100%'
|
||||||
|
});
|
||||||
|
removeOld(video);
|
||||||
|
sources = sortSources(data.meta.direct);
|
||||||
|
if (sources.length === 0) {
|
||||||
|
_this.mediaType = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sources.forEach(function(source) {
|
||||||
|
return $('<source/>').attr('src', source.src).attr('type', source.type).appendTo(video);
|
||||||
|
});
|
||||||
|
_this.player = videojs(video[0], {
|
||||||
|
autoplay: true,
|
||||||
|
controls: true
|
||||||
|
});
|
||||||
|
return _this.player.ready(function() {
|
||||||
|
_this.player.on('ended', function() {
|
||||||
|
if (CLIENT.leader) {
|
||||||
|
return socket.emit('playNext');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_this.player.on('pause', function() {
|
||||||
|
_this.paused = true;
|
||||||
|
if (CLIENT.leader) {
|
||||||
|
return sendVideoUpdate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return _this.player.on('play', function() {
|
||||||
|
_this.paused = false;
|
||||||
|
if (CLIENT.leader) {
|
||||||
|
return sendVideoUpdate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoJSPlayer.prototype.load = function(data) {
|
||||||
|
this.setMediaProperties(data);
|
||||||
|
if (this.player) {
|
||||||
|
return this.player.src(sortSources(data.meta.direct));
|
||||||
|
} else {
|
||||||
|
return console.log('VideoJSPlayer::load() called but @player is undefined');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
VideoJSPlayer.prototype.play = function() {
|
||||||
|
this.paused = false;
|
||||||
|
if (this.player && this.player.readyState() > 0) {
|
||||||
|
return this.player.play();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
VideoJSPlayer.prototype.pause = function() {
|
||||||
|
this.paused = true;
|
||||||
|
if (this.player && this.player.readyState() > 0) {
|
||||||
|
return this.player.pause();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
VideoJSPlayer.prototype.seekTo = function(time) {
|
||||||
|
if (this.player && this.player.readyState() > 0) {
|
||||||
|
return this.player.currentTime(time);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
VideoJSPlayer.prototype.setVolume = function(volume) {
|
||||||
|
if (this.player && this.player.readyState() > 0) {
|
||||||
|
return this.player.volume(volume);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
VideoJSPlayer.prototype.getTime = function(cb) {
|
||||||
|
if (this.player && this.player.readyState() > 0) {
|
||||||
|
return cb(this.player.currentTime());
|
||||||
|
} else {
|
||||||
|
return cb(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
VideoJSPlayer.prototype.getVolume = function(cb) {
|
||||||
|
if (this.player && this.player.readyState() > 0) {
|
||||||
|
if (this.player.muted()) {
|
||||||
|
return cb(0);
|
||||||
|
} else {
|
||||||
|
return cb(this.player.volume());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return cb(VOLUME);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return VideoJSPlayer;
|
||||||
|
|
||||||
|
})(Player);
|
||||||
|
|
||||||
TYPE_MAP = {
|
TYPE_MAP = {
|
||||||
yt: YouTubePlayer,
|
yt: YouTubePlayer,
|
||||||
vi: VimeoPlayer,
|
vi: VimeoPlayer,
|
||||||
dm: DailymotionPlayer
|
dm: DailymotionPlayer,
|
||||||
|
gd: VideoJSPlayer
|
||||||
};
|
};
|
||||||
|
|
||||||
window.loadMediaPlayer = function(data) {
|
window.loadMediaPlayer = function(data) {
|
||||||
|
|
Loading…
Reference in New Issue