mirror of
https://github.com/taobataoma/meanTorrent.git
synced 2026-01-15 11:52:23 +01:00
569 lines
14 KiB
JavaScript
569 lines
14 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Module dependencies
|
|
*/
|
|
var path = require('path'),
|
|
config = require(path.resolve('./config/config')),
|
|
mongoose = require('mongoose'),
|
|
errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller')),
|
|
multer = require('multer'),
|
|
User = mongoose.model('User'),
|
|
Peer = mongoose.model('Peer'),
|
|
Torrent = mongoose.model('Torrent'),
|
|
fs = require('fs'),
|
|
nt = require('nt'),
|
|
benc = require('bncode'),
|
|
async = require('async'),
|
|
validator = require('validator'),
|
|
tmdb = require('moviedb')(config.meanTorrentConfig.tmdbConfig.key);
|
|
|
|
/**
|
|
* get movie info from tmdb
|
|
*/
|
|
exports.movieinfo = function (req, res) {
|
|
console.log('------- API: movieinfo --------------------');
|
|
console.log(req.params);
|
|
|
|
tmdb.movieInfo({
|
|
id: req.params.tmdbid,
|
|
language: req.params.language,
|
|
append_to_response: 'credits,images,alternative_titles,release_dates',
|
|
include_image_language: req.params.language + ',null'
|
|
}, function (err, info) {
|
|
if (err) {
|
|
res.status(900).send(err);
|
|
} else {
|
|
res.json(info);
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* upload torrent file
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.upload = function (req, res) {
|
|
var user = req.user;
|
|
var createUploadFilename = require(path.resolve('./config/lib/multer')).createUploadFilename;
|
|
var getUploadDestination = require(path.resolve('./config/lib/multer')).getUploadDestination;
|
|
var fileFilter = require(path.resolve('./config/lib/multer')).torrentFileFilter;
|
|
var torrentinfo = null;
|
|
|
|
var storage = multer.diskStorage({
|
|
destination: getUploadDestination,
|
|
filename: createUploadFilename
|
|
});
|
|
|
|
var upload = multer({
|
|
storage: storage,
|
|
fileFilter: fileFilter,
|
|
limits: config.uploads.torrent.file.limits
|
|
}).single('newTorrentFile');
|
|
|
|
if (user) {
|
|
uploadFile()
|
|
.then(checkAnnounce)
|
|
.then(checkHash)
|
|
.then(function () {
|
|
res.status(200).send(torrentinfo);
|
|
})
|
|
.catch(function (err) {
|
|
res.status(422).send(err);
|
|
});
|
|
} else {
|
|
res.status(401).send({
|
|
message: 'User is not signed in'
|
|
});
|
|
}
|
|
|
|
function uploadFile() {
|
|
return new Promise(function (resolve, reject) {
|
|
upload(req, res, function (uploadError) {
|
|
if (uploadError) {
|
|
var message = errorHandler.getErrorMessage(uploadError);
|
|
|
|
if (uploadError.code === 'LIMIT_FILE_SIZE') {
|
|
message = 'Torrent file too large. Maximum size allowed is ' + (config.uploads.torrent.file.limits.fileSize / (1024 * 1024)).toFixed(2) + ' Mb files.';
|
|
}
|
|
|
|
//reject(errorHandler.getErrorMessage(uploadError));
|
|
reject(message);
|
|
} else {
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function checkAnnounce() {
|
|
return new Promise(function (resolve, reject) {
|
|
console.log(req.file.filename);
|
|
var newfile = config.uploads.torrent.file.dest + req.file.filename;
|
|
nt.read(newfile, function (err, torrent) {
|
|
var message = '';
|
|
|
|
if (err) {
|
|
message = 'Read torrent file faild';
|
|
reject(message);
|
|
} else {
|
|
if (!config.meanTorrentConfig.announce.open_tracker) {
|
|
if (torrent.metadata.announce !== config.meanTorrentConfig.announce.url) {
|
|
console.log(torrent.metadata.announce);
|
|
message = 'ANNOUNCE_URL_ERROR';
|
|
|
|
fs.unlink(newfile, function (unlinkError) {
|
|
if (unlinkError) {
|
|
console.log(unlinkError);
|
|
message = 'Error occurred while deleting torrent file';
|
|
reject(message);
|
|
}
|
|
});
|
|
reject(message);
|
|
}
|
|
}
|
|
torrentinfo = torrent.metadata;
|
|
torrentinfo.info_hash = torrent.infoHash();
|
|
torrentinfo.filename = req.file.filename;
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function checkHash() {
|
|
return new Promise(function (resolve, reject) {
|
|
var newfile = config.uploads.torrent.file.dest + req.file.filename;
|
|
var message = '';
|
|
|
|
if (torrentinfo.info_hash === '' || !torrentinfo.info_hash) {
|
|
message = 'INFO_HASH_IS_EMPTY';
|
|
reject(message);
|
|
} else {
|
|
Torrent.findOne({
|
|
info_hash: torrentinfo.info_hash
|
|
}).exec(function (err, torrent) {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
if (torrent) {
|
|
message = 'INFO_HASH_ALREADY_EXISTS';
|
|
|
|
fs.unlink(newfile, function (unlinkError) {
|
|
if (unlinkError) {
|
|
console.log(unlinkError);
|
|
message = 'Error occurred while deleting torrent file';
|
|
reject(message);
|
|
}
|
|
});
|
|
|
|
reject(message);
|
|
} else {
|
|
resolve();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
* download a torrent file
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.download = function (req, res) {
|
|
var torrent_data = null;
|
|
var filePath = config.uploads.torrent.file.dest + req.torrent.torrent_filename;
|
|
var stat = fs.statSync(filePath);
|
|
|
|
fs.exists(filePath, function (exists) {
|
|
if (exists) {
|
|
getTorrentFileData(filePath)
|
|
.then(function () {
|
|
//var options = {
|
|
// root: path.join(__dirname, '../../../../'),
|
|
// headers: {
|
|
// 'Content-Type': 'application/x-bittorrent',
|
|
// 'Content-Disposition': 'attachment; filename=' + config.meanTorrentConfig.announce.announce_prefix + req.torrent.torrent_filename,
|
|
// 'Content-Length': stat.size
|
|
// }
|
|
//};
|
|
//res.sendFile(filePath, options);
|
|
|
|
res.set('Content-Type', 'application/x-bittorrent');
|
|
res.set('Content-Disposition', 'attachment; filename=' + config.meanTorrentConfig.announce.announce_prefix + req.torrent.torrent_filename);
|
|
res.set('Content-Length', stat.size);
|
|
|
|
res.send(benc.encode(torrent_data));
|
|
|
|
//res.writeHead(200, {
|
|
// 'Content-Type': 'application/octet-stream',
|
|
// 'Content-Disposition': 'attachment; filename=' + config.meanTorrentConfig.announce.announce_prefix + req.torrent.torrent_filename,
|
|
// 'Content-Length': stat.size
|
|
//});
|
|
//fs.createReadStream(filePath).pipe(res);
|
|
})
|
|
.catch(function (err) {
|
|
res.status(422).send(err);
|
|
});
|
|
} else {
|
|
res.status(422).send({
|
|
message: 'FILE_DOES_NOT_EXISTS'
|
|
});
|
|
}
|
|
});
|
|
|
|
function getTorrentFileData(file) {
|
|
return new Promise(function (resolve, reject) {
|
|
nt.read(file, function (err, torrent) {
|
|
var message = '';
|
|
|
|
if (err) {
|
|
message = 'Read torrent file faild';
|
|
reject(message);
|
|
} else {
|
|
if (!config.meanTorrentConfig.announce.open_tracker) {
|
|
var announce = config.meanTorrentConfig.announce.url + '/' + req.user.passkey;
|
|
torrent.metadata.announce = announce;
|
|
}
|
|
torrent_data = torrent.metadata;
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* create a torrent
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.create = function (req, res) {
|
|
var torrent = new Torrent(req.body);
|
|
torrent.user = req.user;
|
|
|
|
torrent.save(function (err) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
res.json(torrent);
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* read a torrent
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.read = function (req, res) {
|
|
// convert mongoose document to JSON
|
|
var torrent = req.torrent ? req.torrent.toJSON() : {};
|
|
|
|
// Add a custom field to the Article, for determining if the current User is the "owner".
|
|
// NOTE: This field is NOT persisted to the database, since it doesn't exist in the Article model.
|
|
torrent.isCurrentUserOwner = !!(req.user && torrent.user && torrent.user._id.toString() === req.user._id.toString());
|
|
|
|
res.json(torrent);
|
|
};
|
|
|
|
/**
|
|
* update a torrent
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.update = function (req, res) {
|
|
var torrent = req.torrent;
|
|
|
|
torrent.info_hash = req.body.info_hash;
|
|
torrent.tmdb_id = req.body.tmdb_id;
|
|
|
|
// ********** add other fileds value ***************
|
|
|
|
torrent.save(function (err) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
res.json(torrent);
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* setSaleType
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.setSaleType = function (req, res) {
|
|
var torrent = req.torrent;
|
|
|
|
if (req.params.saleType) {
|
|
var gbit = Math.ceil(torrent.torrent_size / config.meanTorrentConfig.torrentSalesType.expires.size);
|
|
torrent.torrent_sale_status = req.params.saleType;
|
|
torrent.torrent_sale_expires = Date.now() + gbit * config.meanTorrentConfig.torrentSalesType.expires.time;
|
|
|
|
torrent.save(function (err) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
res.json(torrent);
|
|
}
|
|
});
|
|
} else {
|
|
return res.status(422).send({
|
|
message: 'params saleType error'
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* setReviewedStatus
|
|
* @param req
|
|
* @param res
|
|
* @returns {*}
|
|
*/
|
|
exports.setReviewedStatus = function (req, res) {
|
|
var torrent = req.torrent;
|
|
|
|
torrent.torrent_status = 'reviewed';
|
|
|
|
torrent.save(function (err) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
res.json(torrent);
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* delete a torrent
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.delete = function (req, res) {
|
|
var torrent = req.torrent;
|
|
|
|
torrent.remove(function (err) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
res.json(torrent);
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* list all torrents
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.list = function (req, res) {
|
|
var skip = 0;
|
|
var limit = 0;
|
|
var status = 'reviewed';
|
|
var stype = 'movie';
|
|
var release = undefined;
|
|
var tagsA = [];
|
|
var keysA = [];
|
|
|
|
if (req.query.skip !== undefined) {
|
|
skip = parseInt(req.query.skip, 10);
|
|
}
|
|
if (req.query.limit !== undefined) {
|
|
limit = parseInt(req.query.limit, 10);
|
|
}
|
|
if (req.query.torrent_status !== undefined) {
|
|
status = req.query.torrent_status;
|
|
}
|
|
if (req.query.torrent_type !== undefined) {
|
|
stype = req.query.torrent_type;
|
|
}
|
|
if (req.query.torrent_release !== undefined) {
|
|
release = req.query.torrent_release;
|
|
}
|
|
if (req.query.torrent_tags !== undefined) {
|
|
var tagsS = req.query.torrent_tags + '';
|
|
var tagsT = tagsS.split(',');
|
|
|
|
tagsT.forEach(function (it) {
|
|
tagsA.push(it + '');
|
|
});
|
|
}
|
|
if (req.query.keys !== undefined && req.query.keys.length > 0) {
|
|
var keysS = req.query.keys + '';
|
|
var keysT = keysS.split(' ');
|
|
|
|
keysT.forEach(function (it) {
|
|
if (!isNaN(it)) {
|
|
if (it > 1900 && it < 2050) {
|
|
release = it;
|
|
}
|
|
} else {
|
|
var ti = new RegExp(it, 'i');
|
|
keysA.push(ti);
|
|
}
|
|
});
|
|
}
|
|
|
|
var condition = {};
|
|
if (status !== 'all') {
|
|
condition.torrent_status = status;
|
|
}
|
|
if (stype !== 'all') {
|
|
condition.torrent_type = stype;
|
|
}
|
|
|
|
if (tagsA.length > 0) {
|
|
condition.torrent_tags = {$all: tagsA};
|
|
}
|
|
if (release !== undefined) {
|
|
condition.torrent_release = release;
|
|
}
|
|
if (keysA.length > 0) {
|
|
condition.$or = [
|
|
{torrent_filename: {'$all': keysA}},
|
|
{torrent_title: {'$all': keysA}},
|
|
{torrent_original_title: {'$all': keysA}}
|
|
];
|
|
}
|
|
|
|
console.log(JSON.stringify(condition));
|
|
|
|
|
|
var countQuery = function (callback) {
|
|
Torrent.count(condition, function (err, count) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
callback(null, count);
|
|
}
|
|
});
|
|
};
|
|
|
|
var findQuery = function (callback) {
|
|
Torrent.find(condition)
|
|
.sort('-createdat')
|
|
.populate('user', 'displayName')
|
|
.skip(skip)
|
|
.limit(limit)
|
|
.exec(function (err, torrents) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
callback(null, torrents);
|
|
}
|
|
});
|
|
};
|
|
|
|
async.parallel([countQuery, findQuery], function (err, results) {
|
|
if (err) {
|
|
return res.status(422).send(err);
|
|
} else {
|
|
res.json({rows: results[1], total: results[0]});
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Torrent middleware
|
|
*/
|
|
exports.torrentByID = function (req, res, next, id) {
|
|
|
|
if (!mongoose.Types.ObjectId.isValid(id)) {
|
|
return res.status(400).send({
|
|
message: 'TORRENT_ID_INVALID'
|
|
});
|
|
}
|
|
|
|
var findTorrents = function (callback) {
|
|
Torrent.findById(id)
|
|
.populate('user', 'displayName profileImageURL')
|
|
.populate({
|
|
path: '_replies.user',
|
|
select: 'displayName profileImageURL uploaded downloaded',
|
|
model: 'User'
|
|
})
|
|
.populate({
|
|
path: '_replies._replies.user',
|
|
select: 'displayName profileImageURL uploaded downloaded',
|
|
model: 'User'
|
|
})
|
|
.populate({
|
|
path: '_subtitles',
|
|
populate: {
|
|
path: 'user',
|
|
select: 'displayName profileImageURL'
|
|
}
|
|
})
|
|
.populate({
|
|
path: '_peers',
|
|
populate: {
|
|
path: 'user',
|
|
select: 'displayName profileImageURL'
|
|
}
|
|
})
|
|
.exec(function (err, torrent) {
|
|
if (err) {
|
|
callback(err);
|
|
} else if (!torrent) {
|
|
callback(new Error('No torrent with that id has been found'));
|
|
}
|
|
callback(null, torrent);
|
|
});
|
|
};
|
|
|
|
var findOtherTorrents = function (torrent, callback) {
|
|
var condition = {};
|
|
condition.torrent_status = 'reviewed';
|
|
condition.torrent_type = 'movie';
|
|
condition.torrent_tmdb_id = torrent.torrent_tmdb_id;
|
|
|
|
console.log(condition);
|
|
|
|
var fields = 'user torrent_filename torrent_release torrent_tags torrent_seeds torrent_leechers torrent_finished torrent_size torrent_sale_status torrent_sale_expires createdat';
|
|
|
|
Torrent.find(condition, fields)
|
|
.sort('-createdat')
|
|
.populate('user', 'displayName')
|
|
.exec(function (err, torrents) {
|
|
if (err) {
|
|
callback(err);
|
|
} else {
|
|
torrent._other_torrents.splice(0, torrent._other_torrents.length);
|
|
torrents.forEach(function (t) {
|
|
if (!t._id.equals(torrent._id)) {
|
|
torrent._other_torrents.push(t.toJSON());
|
|
}
|
|
});
|
|
callback(null, torrent);
|
|
}
|
|
});
|
|
};
|
|
|
|
async.waterfall([findTorrents, findOtherTorrents], function (err, torrent) {
|
|
if (err) {
|
|
next(err);
|
|
} else {
|
|
req.torrent = torrent;
|
|
next();
|
|
}
|
|
});
|
|
};
|
|
|