¶ fsItems modulerequire all the things fancy aligned require block.. |
var _ = require('underscore');
var fs = require('./fs');
var path = require('path');
var async = require('async');
var format = require('string-format');
var config = require('./config');
var getConductor = require('./getConductor');
var Walker = require('./walkDepth');
var log = require('./log');
var s = require('string');
var Contravention = require('./Contravention');
|
|
declaration block |
var Item;
var Directory;
var File;
|
¶ configdeal with configuration options specific to this module
|
config.push({
options: {
output: [
'o',
'output directory',
'string',
'inPlace'
],
otherExtensions: [
false,
'other extensions for files you\'d like to keep. eg: \'jpg, sfv\'',
'string'
]
},
validation: function(config) {
|
|
fix lower case p cludges |
if (config.output == 'inplace') {
config.output = 'inPlace';
}
|
|
check output path |
if (
(config.output != 'inPlace') &&
(!fs.existsSync(config.output))
) {
log.throwError('output directory does not exist');
}
|
|
convert otherExtensions to array |
if (_.isString(config.otherExtensions)) {
config.otherExtensions = config.otherExtensions.replace(' ', '');
config.otherExtensions = config.otherExtensions.split(',');
} else {
config.otherExtensions = [];
}
config.otherExtensions = _.union(
config.otherExtensions,
[ 'nfo' ]
);
}
});
|
¶ Item ClassItem is the parent class for Directory and File Class, it takes care of some commonly used properties: consider a path like
class
classdesc
common properties and methods for Directory and File classes
Params
properties
object
Properties to attach to instance
properties.path
string
relative or absolute path to item
properties.stat
Object
A stat object as generated by
fs.stat
|
Item = function(properties) {
_.extend(this, { meta: {} }, properties);
if (!/^\//.exec(this.path)) {
this.path = path.join(process.cwd(), this.path);
}
if (!fs.existsSync(this.path)) {
log.throwError('path does not exist');
}
if (!this.stat) {
this.stat = fs.statSync(this.path);
}
this.setPath(this.path);
this.determineLogName();
this.determineType();
log.silly(JSON.stringify({
path: this.path,
type: this.type,
extname: this.extname,
basename: this.basename,
dirname: this.dirname,
logName: this.logName
}, null, ' '));
};
|
¶ Item.determineLogNamecreate a nice string suitable for log files.. because usenet release file names are so unwieldy...
|
Item.prototype.determineLogName = function() {
var logName;
var match;
var length = 20;
|
|
Discard everything from 3 consecutive digits (year, 720p 1080p etc) |
match = /^(.*?)[0-9]{3}/.exec(this.basename);
logName = match ? match[1] : this.basename;
|
|
Discard non word |
logName = logName.replace(/\W/g, '');
|
|
Attach extension |
logName += this.extname ? '.' + this.extname : '';
if (logName.length < length) {
logName = s(logName).padRight(length).s;
} else {
|
|
this was the best way I could think of to right align the extensions.. sorry. Join the first bit to the last bit with '...' in between |
logName = [
logName.slice(0, length - (this.extname.length + 3)),
this.extname ? logName.slice(this.extname.length * -1) : ''
].join('...');
}
this.logName = logName;
};
|
¶ Item.prototype.determineTypesets Item.type property to a string which describes the type of this instance |
Item.prototype.determineType = function() {
var media;
var subtitle;
var other;
var tests;
media = ['mkv', 'mp4', 'avi'];
subtitle = ['sub', 'srt'];
other = config.otherExtensions;
|
|
define tests, each property will return a boolean not super efficient because all tests are run on each instance, even if the first one is true. The only alternative I could think of was a long winded if else if structure |
tests = {
subdirectory: this.stat.isDirectory() && this.parent,
directory: this.stat.isDirectory() && !this.parent,
media: _.contains(media, this.extname),
subtitle: _.contains(subtitle, this.extname),
other: _.contains(other, this.extname)
};
this.type = _.findKey(tests, function(value, key) {
return value;
}) || 'junk';
};
|
¶ Directory Classthe directory class contains:
I'd like to limit the directory class to these concepts to avoid it becoming some sort of god class. instantiate with the same params as Item Class class
classdesc
object describing a directory
¶ directory.meta
|
Directory = function() {
Item.apply(this, arguments);
_.defaults(
this,
{
ignoreMetaCache: false,
ignoreTmdbCache: false,
children: []
}
);
};
|
|
these two lines are the only way I could reliably extend a class from
another's prototype. |
Directory.prototype = Object.create(Item.prototype);
Directory.prototype.constructor = Directory;
|
¶ Directory.prototype.setPaththis method simply sets the Params
folderPath
string
absolute or relative path
|
Directory.prototype.setPath = function(folderPath) {
this.path = folderPath;
this.extname = '';
this.basename = path.basename(this.path);
this.dirname = path.dirname(this.path);
}
|
¶ Directory.prototype.getChildrenuse a walker to get children of this directory ¶ directory.childrenevery instance of Params
callback
function
|
Directory.prototype.getChildren = function(callback) {
var folder = this;
new Walker(
this.path,
{
on: {
file: function(parent, child, stat, next) {
var file;
file = new File({
path: path.join(parent, child),
stat: stat,
parent: folder
});
folder.children.push(file);
next();
},
directory: function(parent, child, stat, next) {
var directory;
directory = new Directory({
path: path.join(parent, child),
stat: stat,
parent: folder
});
|
|
No need to call getChildren here because this walker will recurse. |
folder.children.push(directory);
next();
}
},
callback: function(err) {
if (err) {
callback(err);
}
if (!_.findWhere(folder.children, {type: 'media'})) {
new Contravention(folder, 'noMedia');
}
callback();
}
}
);
};
|
¶ Directory.prototype.mvToTempbasically just append Params
callback
function
|
Directory.prototype.mvToTemp = function(callback) {
var directory = this;
var target;
target = this.path.slice(0, -1) + '.temp' + path.sep;
fs.mv(this.path, target, function(err) {
if (err) {
throw err;
}
directory.setPath(target);
if (!config.dry) {
_.each(directory.children, function(child) {
child.setParent(target);
});
}
callback();
});
};
|
¶ Directory.prototype.mvToOutputthis doesn't actually move child files, nor does it purge the this.children, it simply reassigns this.path to the output directory, and deletes the old directory Params
callback
function
|
Directory.prototype.mvToOutput = function(callback) {
var directory = this;
var target;
target = this.getOutputPath();
fs.rmdir(this.path, function(err) {
if (err) {
throw err;
}
directory.setPath(target);
callback();
});
};
|
¶ Directory.prototype.createOutputPathbasically mkdirp |
Directory.prototype.createOutputPath = function() {
fs.mkdirpSync(this.getOutputPath());
};
|
¶ Directory.prototype.getCanonicalBasenamecanonical as in 'according to convention', so wer'e going to apply the user defined format to the movie name to generate a canonical name |
Directory.prototype.getCanonicalBasename = function() {
var canonicalBasename;
if (this.canonicalBasename) {
return this.canonicalBasename;
}
canonicalBasename = format(config['directoryFormat'], this.meta);
canonicalBasename = s(canonicalBasename).stripPunctuation().s;
this.canonicalBasename = canonicalBasename;
return canonicalBasename;
};
|
¶ Directory.prototype.getOutputPathattaches the appropriate target parent folder to the canonical basename |
Directory.prototype.getOutputPath = function() {
var outputPath;
if (this.outputPath) {
return this.outputPath;
}
if (config.output == 'inPlace') {
outputPath = path.join(this.dirname, this.getCanonicalBasename());
} else {
outputPath = path.join(config.output, this.getCanonicalBasename());
}
this.outputPath = outputPath;
return outputPath;
};
|
¶ Directory.prototype.hasErrorA convenience method to save rewriting these conditionals.. used by plugins quite a lot. Params
name
string
The error name, see Contravention object
|
Directory.prototype.hasError = function(name) {
if (!name) {
return (this.meta.contravention);
}
return (
(this.meta.contravention) &&
(this.meta.contravention.name == name)
);
};
|
¶ Directory.prototype.setParentconvenience method which basically wraps Params
parentPath
string
Path to parent directory
|
Directory.prototype.setParent = function(parentPath) {
log.silly(this.logName, '| setParent');
this.setPath(path.join(parentPath, this.basename));
};
|
¶ File Classthe file class contains:
instantiate with the same params as Item Class As with the directory class, methods & properties stored on this class should be limited to the above to avoid creating a god class. |
File = function() {
Item.apply(this, arguments);
}
File.prototype = Object.create(Item.prototype);
File.prototype.constructor = File;
|
¶ File.prototype.setPathset
Params
filePath
string
the file path (absolute or relative)
|
File.prototype.setPath = function(filePath) {
this.path = filePath;
this.extname = path.extname(filePath);
this.filename = path.basename(filePath);
this.basename = path.basename(filePath, this.extname);
this.extname = this.extname.slice(1);
this.dirname = path.dirname(filePath);
};
|
¶ File.prototype.setParentconvenience method which basically wraps Params
parentPath
string
Path to parent directory
|
File.prototype.setParent = function(parentPath) {
log.silly(this.logName, '| setParent');
this.setPath(path.join(parentPath, this.filename));
};
|
¶ File.prototype.getCanonicalFilenamegenerates file name according to format defined in options. |
File.prototype.getCanonicalFilename = function() {
var canonicalName;
var basename;
basename = format(config['fileFormat'], this.parent.meta);
basename = s(basename).stripPunctuation().s;
canonicalName = [
basename,
this.suffix,
'.',
this.extname
].join('');
return canonicalName;
};
|
¶ File.prototype.getOutputPathsimple wrapper to attach canonical to destination path |
File.prototype.getOutputPath = function() {
return path.join(
this.parent.getOutputPath(),
this.getCanonicalFilename()
);
};
|
File.prototype.mvToOutput = function(callback) {
var file = this;
var output = this.getOutputPath();
fs.mv(this.path, output, {mkdirp: true}, function(err) {
if (err) {
throw err;
}
file.setPath(output);
callback();
});
};
|
|
¶ module.exportsjust the |
module.exports = {
Directory: Directory,
File: File
}
|