diff --git a/lib/filter-master.js b/lib/filter-master.js new file mode 100644 index 00000000..3a7e4a67 --- /dev/null +++ b/lib/filter-master.js @@ -0,0 +1,49 @@ +function FilterMaster(worker) { + this.waiting = {}; + this.worker = worker; + this.id = 0; + + this.worker.on("message", this.handleMessage.bind(this)); +} + +FilterMaster.prototype.filterMessage = function (channel, message, cb) { + var req = { + cmd: "filter", + channel: channel.name, + message: message, + id: this.id++ + }; + + var resdata = { + cb: cb, + channel: channel, + message: message, + time: Date.now() + }; + + this.waiting[req.id] = resdata; + this.worker.send(req); +}; + +FilterMaster.prototype.handleMessage = function (data) { + if (data.cmd === "filterResult") { + var res = this.waiting[data.id]; + if (!res) return; + delete this.waiting[data.id]; + + if (data.error) { + // TODO log error + return; + } + + res.cb(data.message); + } else if (data.cmd === "needFilterData") { + var res = this.waiting[data.id]; + if (!res) return; + + var data = { + filters: res.channel.modules.filters.filters.pack(), + channel: res.channel.name, + + } +}; diff --git a/lib/filter-worker.js b/lib/filter-worker.js new file mode 100644 index 00000000..5658030f --- /dev/null +++ b/lib/filter-worker.js @@ -0,0 +1,84 @@ +var FilterList = require("./channel/filters").FilterList; + +function FilterWorker() { + this.cache = {}; +} + +FilterWorker.prototype.cacheData = function (channel, filters, convertLinks) { + this.cache[channel] = { + filters: new FilterList(filters), + convertLinks: convertLinks + }; +}; + +FilterWorker.prototype.removeData = function (channel) { + if (this.cache.hasOwnProperty(channel)) { + delete this.cache[channel]; + } +}; + +FilterWorker.prototype.hasData = function (channel) { + return this.cache.hasOwnProperty(channel); +}; + +const link = /(\w+:\/\/(?:[^:\/\[\]\s]+|\[[0-9a-f:]+\])(?::\d+)?(?:\/[^\/\s]*)*)/ig; +FilterWorker.prototype.filterMessage = function (channel, msg) { + if (!this.hasData(channel)) { + throw new Error("Missing channel data"); + } + + var parts = msg.split(link); + var filters = this.cache[channel].filters; + var convertLinks = this.cache[channel].convertLinks; + + for (var j = 0; j < parts.length; j++) { + /* substring is a URL */ + if (convertLinks && parts[j].match(link)) { + var original = parts[j]; + parts[j] = filters.exec(parts[j], { filterlinks: true }); + + /* no filters changed the URL, apply link filter */ + if (parts[j] === original) { + parts[j] = url.format(url.parse(parts[j])); + parts[j] = parts[j].replace(link, "$1"); + } + + } else { + /* substring is not a URL */ + parts[j] = filters.exec(parts[j], { filterlinks: false }); + } + } + + msg = parts.join(""); +}; + +var procWorker = new FilterWorker(); +process.on("message", function (data) { + if (data.cmd === "addChannel") { + procWorker.cacheData(data.channel.toLowerCase(), data.filters, data.convertLinks); + } else if (data.cmd === "delChannel") { + procWorker.removeData(data.channel.toLowerCase()); + } else if (data.cmd === "filter") { + try { + var filtered = procWorker.filterMessage(data.channel.toLowerCase(), data.message); + process.send({ + cmd: "filterResult", + id: data.id, + message: filtered + }); + } catch (err) { + if (err.message === "Missing channel data") { + process.send({ + cmd: "needFilterData", + id: data.id + }); + } else { + process.send({ + cmd: "filterResult", + id: data.id, + error: err + }); + } + } + } +}); diff --git a/lib/get-info.js b/lib/get-info.js index b67bdbe9..c4cf20e6 100644 --- a/lib/get-info.js +++ b/lib/get-info.js @@ -726,6 +726,16 @@ var Getters = { data[kv[0]] = kv[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."; + } + + return callback(reason); + } + if (!data.hasOwnProperty("title")) { return callback("Returned HTML is missing the video title. Are you " + "sure the video is done processing?");