diff --git a/config.template.yaml b/config.template.yaml index 1daea6ee..efb10a4d 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -167,6 +167,11 @@ contacts: title: 'Developer' email: 'cyzon@cytu.be' +playlist: + max-items: 4000 + # How often (in seconds), mediaUpdate packets are broadcast to clients + update-interval: 5 + # If set to true, when the ipThrottle and lastguestlogin rate limiters are cleared # periodically, the garbage collector will be invoked immediately. # The server must be invoked with node --expose-gc index.js for this to have any effect. @@ -179,6 +184,5 @@ channel-blacklist: [] # If you have ffmpeg installed, you can query metadata from raw files, allowing # server-synched raw file playback. This requires the following: # * ffmpeg must be installed on the server -# * you must install the fluent-ffmpeg module (npm install fluent-ffmpeg@~1.7.2) ffmpeg: enabled: false diff --git a/lib/ffmpeg.js b/lib/ffmpeg.js index 3176f204..921cbb6b 100644 --- a/lib/ffmpeg.js +++ b/lib/ffmpeg.js @@ -1,20 +1,6 @@ var Logger = require("./logger"); var Config = require("./config"); -var ffprobe; -var enabled = false; - -function init() { - if (Config.get("ffmpeg.enabled")) { - try { - ffprobe = require("fluent-ffmpeg").ffprobe; - Logger.syslog.log("Enabling raw file support with fluent-ffmpeg"); - enabled = true; - } catch (e) { - Logger.errlog.log("Failed to load fluent-ffmpeg. Did you remember to " + - "execute `npm install fluent-ffmpeg` ?"); - } - } -} +var spawn = require("child_process").spawn; var acceptedCodecs = { "mov/h264": true, @@ -34,11 +20,7 @@ var audioOnlyContainers = { }; exports.query = function (filename, cb) { - if (!ffprobe) { - init(); - } - - if (!enabled) { + if (!Config.get("ffmpeg.enabled")) { return cb("Raw file playback is not enabled on this server"); } @@ -49,7 +31,11 @@ exports.query = function (filename, cb) { ffprobe(filename, function (err, meta) { if (err) { - return cb("Unable to query file data with ffmpeg"); + if (meta.stderr && meta.stderr.match(/Protocol not found/)) { + return cb("Link uses a protocol unsupported by this server's ffmpeg"); + } else { + return cb("Unable to query file data with ffmpeg"); + } } meta = parse(meta); @@ -92,7 +78,7 @@ exports.query = function (filename, cb) { filename.split(":")[0] + " protocol."); } else { return cb("Parsed metadata did not contain a valid video or audio stream. " + - "Either the file is invalid or it has a format unsupported by " + + "Either the file is invalid or it has a format unsupported by " + "this server's version of ffmpeg."); } }); @@ -132,3 +118,46 @@ function parse(meta) { data.seconds = Math.ceil(parseFloat(meta.format.duration)); return data; } + +function ffprobe(filename, cb) { + var ff = spawn("ffprobe", ["-show_streams", "-show_format", filename]); + + var outbuf = ""; + var errbuf = ""; + ff.stdout.on("data", function (data) { + outbuf += data; + }); + ff.stderr.on("data", function (data) { + errbuf += data; + }); + + ff.on("close", function (code) { + if (code !== 0) { + return cb("ffprobe exited with nonzero exit code", { stderr: errbuf }); + } + + var lines = outbuf.split("\n"); + var streams = []; + var format = {}; + var data = {}; + lines.forEach(function (line) { + if (line.match(/\[stream\]|\[format\]/i)) { + return; + } else if (line.match(/\[\/stream\]/i)) { + streams.push(data); + data = {}; + } else if (line.match(/\[\/format\]/i)) { + format = data; + data = {}; + } else { + var kv = line.split("="); + data[kv[0]] = kv[1]; + } + }); + + cb(null, { + streams: streams, + format: format + }); + }); +} diff --git a/lib/server.js b/lib/server.js index eb033473..70dfeb70 100644 --- a/lib/server.js +++ b/lib/server.js @@ -9,7 +9,7 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -const VERSION = "3.2.1"; +const VERSION = "3.2.2"; var singleton = null; var Config = require("./config"); diff --git a/package.json b/package.json index 79d9ea5d..b6337ca6 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Calvin Montgomery", "name": "CyTube", "description": "Online media synchronizer and chat", - "version": "3.2.1", + "version": "3.2.2", "repository": { "url": "http://github.com/calzoneman/sync" },