UNPKG

mtl

Version:

Utility for filing TV shows into a sorted library based on metadata from filenames

169 lines (163 loc) 5.5 kB
var _ = require("underscore"); var fs = require("fs"); var path = require("path"); var request = require("request"); var PATTERNS = require("./patterns"); var SPLIT_WORDS_REGEX = /\W+/g; var regexes = {}; var matchTitles = {}; var getRegex = function(title) { var r = regexes[title]; if (!r) { r = new RegExp("^" + title.split(SPLIT_WORDS_REGEX).join("\\W") + ".*", "i"); regexes[title] = r; } return r; } var getMatchTitle = function(title) { var m = matchTitles[title]; if (!m) { m = title.split(SPLIT_WORDS_REGEX).join(" "); matchTitles[title] = m; } return m; } /** *Get a nice clean name your grandma would be happy to use as a directory name. *allows () */ var getDirTitle = function(title) { return title.split(/[^a-zA-Z0-9\(\)]+/g).join(" "); } var mtl = { getOps: function(source, target) { return mtl.identifyDestinations( mtl.identifyVideos(mtl.getFiles(source)), mtl.getDirs(target)); }, doMoves: function(source, target, ops, dry) { if (!ops) throw "no ops provided"; var newDirs = []; for (var dir in ops) { var dirPath = path.join(target, dir); newDirs.push(dirPath); if (!dry && !fs.existsSync(dirPath)) { //console.info("Creating directory: %s", dirPath); fs.mkdirSync(dirPath); } var files = ops[dir]; //console.info("file: %j from ops %j with key %s", files, ops, dir); files.forEach(function(file) { var sourcePath = path.join(source, file); var destPath = path.join(dirPath, file); if (fs.existsSync(destPath)) { //console.warn("%s exists, skipping", destPath); } else { if (!dry) fs.renameSync(sourcePath, destPath); } }); } return newDirs; }, /** * * @param {Array || string} files - absolute paths to file(s) to process * @returns {unresolved} */ identifyVideos: function(files) { var output = {}; files = typeof files === "object" ? files : [files]; //console.info("identifying files %j",files); files.forEach(function(f) { //TODO filter filetype here PATTERNS.forEach(function(p) { var match = p.exec(f); if (match != null) { output[f] = { title: match[1], season: match[2], episode: match[3], format: match[4] }; return false; } }); }); //console.info(output); return output; }, /** * * @param {Array} videos - output from identify videos * @param {type} target - list of target folders filename (no paths) * @returns {mtl.identifyDestinations.Anonym$1} */ identifyDestinations: function(videos, target) { //console.info("identifying destination for vids %j in %j", videos, target); var moves = {}; var createDirs = []; for (var filename in videos) { var meta = videos[filename]; //console.info("metadata for %s : %j", filename, meta); var regex = getRegex(meta.title); var dirName = null; for (var i in target) { var t = target[i]; var matchTitle = getMatchTitle(t); var test = regex.test(matchTitle); //console.info("matching %s with pattern -%s- against -%s- with result %s",filename, matchTitle,regex,test); if (test) { dirName = t; break; } } if (!dirName) { dirName = getDirTitle(meta.title); if (createDirs.indexOf(dirName) < 0) { createDirs.push(dirName); } } moves[dirName] = moves[dirName] || []; moves[dirName].push(filename); } return { move: moves, create: createDirs } }, refreshXBMC: function(url, cb) { //TODO more tolerant url handling url += "/jsonrpc"; var payload = {"jsonrpc": "2.0", "method": "VideoLibrary.Scan", "id": 1}; request.post({ url: url, body: JSON.stringify(payload) }, function(error, response, body) { if (!error && response.statusCode == 200) { //console.log("Triggered XBMC update"); //console.log(body); } else { console.error("XBMC update failed with error %s", error); console.error(response); } if (cb) cb(); }); }, getDirs: function(target) { return _.filter(fs.readdirSync(target), function(f) { return fs.statSync(path.join(target, f)).isDirectory(); }); }, getFiles: function(source) { if (fs.statSync(source).isFile()) { return [path.basename(source)]; } return _.filter(fs.readdirSync(source), function(f) { return fs.statSync(path.join(source, f)).isFile(); }); } }; module.exports = mtl;