improve import by URL feature. closes #171

* Drop dependency on temp module
 * Download files to music-folder/.tmp/ before moving them.
 * Don't watch folders that start with a '.'
 * Don't allow generated paths to start with a '.'

Fixes import file race condition.

Prevents needless file copy operation when importing in situations where
the music directory is in a different device than /tmp.
This commit is contained in:
Andrew Kelley 2014-03-26 17:17:07 -07:00
parent 4e560b93e8
commit 5c8f45b6e9
3 changed files with 39 additions and 16 deletions

View file

@ -1,6 +1,7 @@
var groove = require('groove'); var groove = require('groove');
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var util = require('util'); var util = require('util');
var mkdirp = require('mkdirp');
var fs = require('fs'); var fs = require('fs');
var uuid = require('uuid'); var uuid = require('uuid');
var path = require('path'); var path = require('path');
@ -16,7 +17,6 @@ var safePath = require('./safe_path');
var PassThrough = require('stream').PassThrough; var PassThrough = require('stream').PassThrough;
var url = require('url'); var url = require('url');
var superagent = require('superagent'); var superagent = require('superagent');
var temp = require('temp').track();
module.exports = Player; module.exports = Player;
@ -382,6 +382,7 @@ Player.prototype.refreshFilesIndex = function(args, cb) {
var dirEntry = self.getOrCreateDir(dirName, stat); var dirEntry = self.getOrCreateDir(dirName, stat);
if (fullDirPath === dirWithSlash) return; // ignore root search path if (fullDirPath === dirWithSlash) return; // ignore root search path
var baseName = path.basename(dirName); var baseName = path.basename(dirName);
if (isFileIgnored(baseName)) return;
var parentDirName = path.dirname(dirName); var parentDirName = path.dirname(dirName);
if (parentDirName === '.') parentDirName = ''; if (parentDirName === '.') parentDirName = '';
var parentDirEntry = self.getOrCreateDir(parentDirName); var parentDirEntry = self.getOrCreateDir(parentDirName);
@ -629,21 +630,43 @@ Player.prototype.importUrl = function(urlString, cb) {
var self = this; var self = this;
cb = cb || logIfError; cb = cb || logIfError;
var parsedUrl = url.parse(urlString); var tmpDir = path.join(self.musicDirectory, '.tmp');
var remoteFilename = path.basename(parsedUrl.pathname); var destPath = path.join(tmpDir, uuid() + path.extname(urlString));
var req = superagent.get(urlString);
var ws = temp.createWriteStream({suffix: path.extname(urlString)});
req.pipe(ws);
ws.on('close', function(){
self.importFile(ws.path, remoteFilename, cleanAndCb);
});
ws.on('error', cleanAndCb);
req.on('error', cleanAndCb);
function cleanAndCb(err, dbFile) { mkdirp(tmpDir, function(err) {
temp.cleanup(); if (err) return cb(err);
cb(err, dbFile);
} var parsedUrl = url.parse(urlString);
var remoteFilename = path.basename(parsedUrl.pathname);
var ws = fs.createWriteStream(destPath);
var calledCallback = false;
var req = superagent.get(urlString);
req.pipe(ws);
ws.on('close', function(){
if (calledCallback) return;
self.importFile(ws.path, remoteFilename, function(err, dbFile) {
if (err) {
cleanAndCb(err);
} else {
calledCallback = true;
cb(null, dbFile);
}
});
});
ws.on('error', cleanAndCb);
req.on('error', cleanAndCb);
function cleanAndCb(err) {
fs.unlink(destPath, function(err) {
if (err) {
console.warn("Unable to clean up temp file:", err.stack);
}
});
if (calledCallback) return;
calledCallback = true;
cb(err);
}
});
function logIfError(err) { function logIfError(err) {
if (err) { if (err) {

View file

@ -6,5 +6,6 @@ function safePath(string) {
string = string.replace(/[<>:"\/\\|?*%]/g, "_"); string = string.replace(/[<>:"\/\\|?*%]/g, "_");
string = string.substring(0, MAX_LEN); string = string.substring(0, MAX_LEN);
string = string.replace(/\.$/, "_"); string = string.replace(/\.$/, "_");
string = string.replace(/^\./, "_");
return string; return string;
} }

View file

@ -34,7 +34,6 @@
"uuid": "~1.4.1", "uuid": "~1.4.1",
"music-library-index": "^1.1.0", "music-library-index": "^1.1.0",
"keese": "~1.0.0", "keese": "~1.0.0",
"temp": "~0.7.0",
"ws": "~0.4.31", "ws": "~0.4.31",
"jsondiffpatch": "~0.1.4", "jsondiffpatch": "~0.1.4",
"connect-static": "^1.1.0", "connect-static": "^1.1.0",