diff --git a/build-player.js b/build-player.js new file mode 100644 index 00000000..0e82b334 --- /dev/null +++ b/build-player.js @@ -0,0 +1,29 @@ +var coffee = require('coffee-script'); +var fs = require('fs'); +var path = require('path'); + +var order = [ + 'base.coffee', + 'vimeo.coffee', + 'youtube.coffee', + 'dailymotion.coffee', + 'videojs.coffee', + 'raw-file.coffee', + 'soundcloud.coffee', + 'embed.coffee', + 'twitch.coffee', + 'livestream.com.coffee', + 'custom-embed.coffee', + 'rtmp.coffee', + 'hitbox.coffee', + 'ustream.coffee', + 'imgur.coffee', + 'update.coffee' +]; + +var buffer = ''; +order.forEach(function (file) { + buffer += fs.readFileSync(path.join('player', file)) + '\n'; +}); + +fs.writeFileSync(path.join('www', 'js', 'player.js'), coffee.compile(buffer)); diff --git a/lib/channel/mediarefresher.js b/lib/channel/mediarefresher.js index bb3def8a..6d4d7428 100644 --- a/lib/channel/mediarefresher.js +++ b/lib/channel/mediarefresher.js @@ -1,3 +1,4 @@ +var Vimeo = require("cytube-mediaquery/lib/provider/vimeo"); var ChannelModule = require("./module"); var Config = require("../config"); var InfoGetter = require("../get-info"); @@ -7,6 +8,7 @@ function MediaRefresherModule(channel) { ChannelModule.apply(this, arguments); this._interval = false; this._media = null; + this._playlist = channel.modules.playlist; } MediaRefresherModule.prototype = Object.create(ChannelModule.prototype); @@ -15,18 +17,26 @@ MediaRefresherModule.prototype.onPreMediaChange = function (data, cb) { if (this._interval) clearInterval(this._interval); this._media = data; + var pl = this._playlist; switch (data.type) { case "gd": + pl._refreshing = true; return this.initGoogleDocs(data, function () { + + pl._refreshing = false; cb(null, ChannelModule.PASSTHROUGH); }); case "gp": + pl._refreshing = true; return this.initGooglePlus(data, function () { + pl._refreshing = false; cb(null, ChannelModule.PASSTHROUGH); }); case "vi": + pl._refreshing = true; return this.initVimeo(data, function () { + pl._refreshing = false; cb(null, ChannelModule.PASSTHROUGH); }); default: @@ -55,18 +65,20 @@ MediaRefresherModule.prototype.initVimeo = function (data, cb) { var self = this; self.channel.activeLock.lock(); - InfoGetter.vimeoWorkaround(data.id, function (hack) { - if (self.dead || self.channel.dead) { + Vimeo.extract(data.id).then(function (direct) { + if (self.dead || self.channel.dead) return; - } if (self._media === data) { + data.meta.direct = direct; self.channel.logger.log("[mediarefresher] Refreshed vimeo video with ID " + data.id); - data.meta.direct = hack; } self.channel.activeLock.release(); + if (cb) cb(); + }).catch(function (err) { + Logger.errlog.log("Unexpected vimeo::extract() fail: " + err.stack); if (cb) cb(); }); }; diff --git a/lib/channel/playlist.js b/lib/channel/playlist.js index 327d1323..3a38b3f4 100644 --- a/lib/channel/playlist.js +++ b/lib/channel/playlist.js @@ -3,11 +3,11 @@ var AsyncQueue = require("../asyncqueue"); var Media = require("../media"); var util = require("../utilities"); var InfoGetter = require("../get-info"); -var vimeoWorkaround = InfoGetter.vimeoWorkaround; var Config = require("../config"); var Flags = require("../flags"); var db = require("../database"); var Logger = require("../logger"); +var CustomEmbedFilter = require("../customembed").filter; const MAX_ITEMS = Config.get("playlist.max-items"); @@ -90,7 +90,7 @@ function PlaylistModule(channel) { this._leadInterval = false; this._lastUpdate = 0; this._counter = 0; - this._gdRefreshTimer = false; + this._refreshing = false; if (this.channel.modules.chat) { this.channel.modules.chat.registerCommand("/clean", this.handleClean.bind(this)); @@ -110,6 +110,16 @@ PlaylistModule.prototype.load = function (data) { var i = 0; playlist.pos = parseInt(playlist.pos); playlist.pl.forEach(function (item) { + if (item.media.type === "cu" && item.media.id.indexOf("cu:") !== 0) { + try { + item.media = CustomEmbedFilter(item.media.id); + } catch (e) { + return; + } + } else if (item.media.type === "gd" || item.media.type === "gp") { + delete item.media.meta.gpdirect; + } + var m = new Media(item.media.id, item.media.title, item.media.seconds, item.media.type, item.media.meta || {}); var newitem = new PlaylistItem(m, { @@ -133,10 +143,8 @@ PlaylistModule.prototype.load = function (data) { PlaylistModule.prototype.save = function (data) { var arr = this.items.toArray().map(function (item) { - /* Clear Google Docs and Vimeo meta */ + /* Clear Google Docs/Google+ and Vimeo meta */ if (item.media && item.media.meta) { - delete item.media.meta.object; - delete item.media.meta.params; delete item.media.meta.direct; } return item; @@ -167,11 +175,6 @@ PlaylistModule.prototype.unload = function () { this._leadInterval = false; } - if (this._gdRefreshTimer) { - clearInterval(this._gdRefreshTimer); - this._gdRefreshTimer = false; - } - this.channel = null; }; @@ -265,7 +268,7 @@ PlaylistModule.prototype.sendPlaylist = function (users) { }; PlaylistModule.prototype.sendChangeMedia = function (users) { - if (!this.current || !this.current.media) { + if (!this.current || !this.current.media || this._refreshing) { return; } @@ -1116,8 +1119,6 @@ PlaylistModule.prototype.refreshGoogleDocs = function (cb) { } var abort = function () { - clearInterval(self._gdRefreshTimer); - self._gdRefreshTimer = false; if (self.current) { self.current.media.meta.object = self.current.media.meta.object || null; self.current.media.meta.failed = true; diff --git a/lib/customembed.js b/lib/customembed.js index e5e7ef90..c2923f16 100644 --- a/lib/customembed.js +++ b/lib/customembed.js @@ -1,22 +1,96 @@ -const allowed = ["iframe", "object", "param", "embed"]; -const tag_re = /<\s*\/?\s*([a-z]+)(\s*([a-z]+)\s*=\s*('[^']*'|"[^"]*"|[^"'>]*))*\s*>/ig; +var cheerio = require("cheerio"); +var crypto = require("crypto"); +var Media = require("./media"); -function filter(str) { - if (typeof str !== "string") { - return ""; +function sha256(input) { + var hash = crypto.createHash("sha256"); + hash.update(input); + return hash.digest("base64"); +} + +function filter(input) { + var $ = cheerio.load(input, { xmlMode: true }); + var meta = getMeta($); + var id = "cu:" + sha256(input); + + return new Media(id, "Custom Media", "--:--", "cu", meta); +} + +function getMeta($) { + var tag = $("embed"); + if (tag.length !== 0) { + return filterEmbed(tag[0]); + } + tag = $("object"); + if (tag.length !== 0) { + return filterObject(tag[0]); + } + tag = $("iframe"); + if (tag.length !== 0) { + return filterIframe(tag[0]); } - str = str.replace(tag_re, function (match, tag) { - if(!~allowed.indexOf(tag.toLowerCase())) { - return match.replace("<", "<").replace(">", ">"); + throw new Error("Invalid embed. Input must be an