mirror of
https://github.com/taobataoma/meanTorrent.git
synced 2026-01-16 20:32:21 +01:00
1978 lines
52 KiB
JavaScript
1978 lines
52 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Module dependencies
|
|
*/
|
|
var path = require('path'),
|
|
config = require(path.resolve('./config/config')),
|
|
mongoose = require('mongoose'),
|
|
common = require(path.resolve('./config/lib/common')),
|
|
errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller')),
|
|
multer = require('multer'),
|
|
moment = require('moment'),
|
|
User = mongoose.model('User'),
|
|
Maker = mongoose.model('Maker'),
|
|
Peer = mongoose.model('Peer'),
|
|
Subtitle = mongoose.model('Subtitle'),
|
|
Thumb = mongoose.model('Thumb'),
|
|
Rating = mongoose.model('Rating'),
|
|
Torrent = mongoose.model('Torrent'),
|
|
Complete = mongoose.model('Complete'),
|
|
Forum = mongoose.model('Forum'),
|
|
Topic = mongoose.model('Topic'),
|
|
objectId = require('mongodb').ObjectId,
|
|
fs = require('fs'),
|
|
nt = require('nt'),
|
|
benc = require('bncode'),
|
|
scrape = require(path.resolve('./config/lib/scrape')),
|
|
async = require('async'),
|
|
validator = require('validator'),
|
|
tmdb = require('moviedb')(config.meanTorrentConfig.tmdbConfig.key),
|
|
traceLogCreate = require(path.resolve('./config/lib/tracelog')).create,
|
|
scoreUpdate = require(path.resolve('./config/lib/score')).update;
|
|
|
|
var traceConfig = config.meanTorrentConfig.trace;
|
|
var scoreConfig = config.meanTorrentConfig.score;
|
|
var thumbsUpScore = config.meanTorrentConfig.score.thumbsUpScore;
|
|
var ircConfig = config.meanTorrentConfig.ircAnnounce;
|
|
var itemsPerPageConfig = config.meanTorrentConfig.itemsPerPage;
|
|
var vsprintf = require('sprintf-js').vsprintf;
|
|
|
|
var mtDebug = require(path.resolve('./config/lib/debug'));
|
|
var serverMessage = require(path.resolve('./config/lib/server-message'));
|
|
var serverNoticeConfig = config.meanTorrentConfig.serverNotice;
|
|
|
|
const PEERSTATE_SEEDER = 'seeder';
|
|
const PEERSTATE_LEECHER = 'leecher';
|
|
|
|
/**
|
|
* get movie info from tmdb
|
|
*/
|
|
exports.movieinfo = function (req, res) {
|
|
mtDebug.debugGreen('------- API: movieinfo --------------------');
|
|
mtDebug.debugGreen(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);
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* searchmovie
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.searchmovie = function (req, res) {
|
|
mtDebug.debugGreen('------- API: searchMovie --------------------');
|
|
mtDebug.debugGreen(req.params);
|
|
|
|
var type = req.query.type;
|
|
|
|
if (type === 'movie') {
|
|
tmdb.searchMovie({
|
|
language: req.params.language,
|
|
query: req.query.query
|
|
}, function (err, info) {
|
|
if (err) {
|
|
res.status(900).send(err);
|
|
} else {
|
|
res.json(info);
|
|
}
|
|
});
|
|
} else if (type === 'tvserial') {
|
|
tmdb.searchTv({
|
|
language: req.params.language,
|
|
query: req.query.query
|
|
}, function (err, info) {
|
|
if (err) {
|
|
res.status(900).send(err);
|
|
} else {
|
|
res.json(info);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* get tv info from tmdb
|
|
*/
|
|
exports.tvinfo = function (req, res) {
|
|
mtDebug.debugGreen('------- API: tvinfo --------------------');
|
|
mtDebug.debugGreen(req.params);
|
|
|
|
tmdb.tvInfo({
|
|
id: req.params.tmdbid,
|
|
language: req.params.language,
|
|
append_to_response: 'credits,images,alternative_titles',
|
|
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);
|
|
|
|
if (req.file && req.file.filename) {
|
|
var newfile = config.uploads.torrent.file.temp + req.file.filename;
|
|
if (fs.existsSync(newfile)) {
|
|
mtDebug.debugRed(err);
|
|
mtDebug.debugRed('ERROR: DELETE TEMP TORRENT FILE: ' + newfile);
|
|
fs.unlinkSync(newfile);
|
|
}
|
|
}
|
|
});
|
|
} 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(message);
|
|
} else {
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function checkAnnounce() {
|
|
return new Promise(function (resolve, reject) {
|
|
mtDebug.debugGreen(req.file.filename);
|
|
var newfile = config.uploads.torrent.file.temp + 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.privateTorrentCmsMode) {
|
|
//if (torrent.metadata.announce !== config.meanTorrentConfig.announce.url) {
|
|
// mtDebug.debugGreen(torrent.metadata.announce);
|
|
// message = 'ANNOUNCE_URL_ERROR';
|
|
//
|
|
// reject(message);
|
|
//}
|
|
|
|
//force change announce url to config value
|
|
var announce = config.meanTorrentConfig.announce.url;
|
|
torrent.metadata.announce = announce;
|
|
|
|
var cws = fs.createWriteStream(newfile);
|
|
cws.write(benc.encode(torrent.metadata));
|
|
cws.end();
|
|
}
|
|
torrentinfo = torrent.metadata;
|
|
torrentinfo.info_hash = torrent.infoHash();
|
|
torrentinfo.filename = req.file.filename;
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function checkHash() {
|
|
return new Promise(function (resolve, reject) {
|
|
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';
|
|
|
|
reject(message);
|
|
} else {
|
|
resolve();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* uploadTorrentCover
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.uploadTorrentCover = function (req, res) {
|
|
var user = req.user;
|
|
var createUploadCoverImageFilename = require(path.resolve('./config/lib/multer')).createUploadCoverImageFilename;
|
|
var getUploadCoverImageDestination = require(path.resolve('./config/lib/multer')).getUploadCoverImageDestination;
|
|
var fileFilter = require(path.resolve('./config/lib/multer')).imageFileFilter;
|
|
var coverInfo = {};
|
|
|
|
var storage = multer.diskStorage({
|
|
destination: getUploadCoverImageDestination,
|
|
filename: createUploadCoverImageFilename
|
|
});
|
|
|
|
var upload = multer({
|
|
storage: storage,
|
|
fileFilter: fileFilter,
|
|
limits: config.uploads.torrent.cover.limits
|
|
}).single('newTorrentCoverFile');
|
|
|
|
if (user) {
|
|
uploadFile()
|
|
.then(function () {
|
|
res.status(200).send(coverInfo);
|
|
})
|
|
.catch(function (err) {
|
|
res.status(422).send(err);
|
|
mtDebug.debugRed(err);
|
|
|
|
if (req.file && req.file.filename) {
|
|
var newfile = config.uploads.torrent.cover.temp + req.file.filename;
|
|
if (fs.existsSync(newfile)) {
|
|
mtDebug.debugRed(err);
|
|
mtDebug.debugRed('ERROR: DELETE TEMP COVER FILE: ' + newfile);
|
|
fs.unlinkSync(newfile);
|
|
}
|
|
}
|
|
});
|
|
} 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 = 'Cover image file too large. Maximum size allowed is ' + (config.uploads.torrent.cover.limits.fileSize / (1024 * 1024)).toFixed(2) + ' Mb files.';
|
|
}
|
|
|
|
reject(message);
|
|
} else {
|
|
coverInfo.filename = req.file.filename;
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* uploadTorrentImage
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.uploadTorrentImage = function (req, res) {
|
|
var user = req.user;
|
|
var createUploadTorrentImageFilename = require(path.resolve('./config/lib/multer')).createUploadTorrentImageFilename;
|
|
var getUploadTorrentImageDestination = require(path.resolve('./config/lib/multer')).getUploadTorrentImageDestination;
|
|
var fileFilter = require(path.resolve('./config/lib/multer')).imageFileFilter;
|
|
var imageInfo = {};
|
|
|
|
var storage = multer.diskStorage({
|
|
destination: getUploadTorrentImageDestination,
|
|
filename: createUploadTorrentImageFilename
|
|
});
|
|
|
|
var upload = multer({
|
|
storage: storage,
|
|
fileFilter: fileFilter,
|
|
limits: config.uploads.torrent.cover.limits
|
|
}).single('newTorrentImageFile');
|
|
|
|
if (user) {
|
|
uploadFile()
|
|
.then(function () {
|
|
res.status(200).send(imageInfo);
|
|
})
|
|
.catch(function (err) {
|
|
res.status(422).send(err);
|
|
mtDebug.debugRed(err);
|
|
|
|
if (req.file && req.file.filename) {
|
|
var newfile = config.uploads.torrent.image.temp + req.file.filename;
|
|
if (fs.existsSync(newfile)) {
|
|
mtDebug.debugRed(err);
|
|
mtDebug.debugRed('ERROR: DELETE TEMP TORRENT IMAGE FILE: ' + newfile);
|
|
fs.unlinkSync(newfile);
|
|
}
|
|
}
|
|
});
|
|
} 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 image file too large. Maximum size allowed is ' + (config.uploads.torrent.image.limits.fileSize / (1024 * 1024)).toFixed(2) + ' Mb files.';
|
|
}
|
|
|
|
reject(message);
|
|
} else {
|
|
imageInfo.filename = req.file.filename;
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* announceEdit
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.announceEdit = 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 torrent_data = 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(function () {
|
|
var filePath = config.uploads.torrent.file.temp + req.file.filename;
|
|
|
|
fs.exists(filePath, function (exists) {
|
|
if (exists) {
|
|
var stat = fs.statSync(filePath);
|
|
getTorrentFileData(filePath)
|
|
.then(function () {
|
|
res.set('Content-Type', 'application/x-bittorrent');
|
|
res.set('Content-Disposition', 'attachment; filename=' + encodeURI(req.file.filename));
|
|
res.set('Content-Length', stat.size);
|
|
|
|
res.send(benc.encode(torrent_data));
|
|
})
|
|
.catch(function (err) {
|
|
res.status(422).send(err);
|
|
});
|
|
} else {
|
|
res.status(422).send({
|
|
message: 'FILE_DOES_NOT_EXISTS'
|
|
});
|
|
}
|
|
});
|
|
})
|
|
.catch(function (err) {
|
|
|
|
res.status(422).send(err);
|
|
|
|
if (req.file && req.file.filename) {
|
|
var newfile = config.uploads.torrent.file.temp + req.file.filename;
|
|
if (fs.existsSync(newfile)) {
|
|
mtDebug.debugRed(err);
|
|
mtDebug.debugRed('ERROR: DELETE TEMP TORRENT FILE: ' + newfile);
|
|
fs.unlinkSync(newfile);
|
|
}
|
|
}
|
|
});
|
|
} 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(message);
|
|
} else {
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
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 {
|
|
var announce = config.meanTorrentConfig.announce.url;
|
|
torrent.metadata.announce = announce;
|
|
torrent.metadata.comment = req.query.comment;
|
|
torrent_data = torrent.metadata;
|
|
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;
|
|
|
|
if (req.torrent.torrent_vip && !req.user.isVip) {
|
|
return res.status(701).send({
|
|
message: 'SERVER.ONLY_VIP_CAN_DOWNLOAD'
|
|
});
|
|
} else if (req.user.status === 'banned') {
|
|
return res.status(702).send({
|
|
message: 'SERVER.CAN_NOT_DOWNLOAD_BANNED'
|
|
});
|
|
} else if (req.user.status === 'idle') {
|
|
return res.status(703).send({
|
|
message: 'SERVER.CAN_NOT_DOWNLOAD_IDLE'
|
|
});
|
|
} else {
|
|
fs.exists(filePath, function (exists) {
|
|
if (exists) {
|
|
var stat = fs.statSync(filePath);
|
|
getTorrentFileData(filePath)
|
|
.then(function () {
|
|
res.set('Content-Type', 'application/x-bittorrent');
|
|
res.set('Content-Disposition', 'attachment; filename=' + config.meanTorrentConfig.announce.announcePrefix + encodeURI(req.torrent.torrent_filename));
|
|
res.set('Content-Length', stat.size);
|
|
|
|
res.send(benc.encode(torrent_data));
|
|
})
|
|
.catch(function (err) {
|
|
mtDebug.debugRed(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.privateTorrentCmsMode) {
|
|
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);
|
|
//mtDebug.debugGreen(req.body);
|
|
|
|
torrent.user = req.user;
|
|
|
|
//replace content path
|
|
var tmp = config.uploads.torrent.image.temp.substr(1);
|
|
var dst = config.uploads.torrent.image.dest.substr(1);
|
|
|
|
var regex = new RegExp(tmp, 'g');
|
|
torrent.resource_detail_info.overview = torrent.resource_detail_info.overview.replace(regex, dst);
|
|
|
|
//mtDebug.debugGreen(torrent);
|
|
|
|
//move temp torrent file to dest directory
|
|
var oldPath = config.uploads.torrent.file.temp + req.body.torrent_filename;
|
|
var newPath = config.uploads.torrent.file.dest + req.body.torrent_filename;
|
|
move(oldPath, newPath, function (err) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: 'MOVE_TORRENT_FILE_ERROR'
|
|
});
|
|
} else {
|
|
//move temp cover image file to dest directory
|
|
if (req.body.resource_detail_info.cover) {
|
|
var cv = req.body.resource_detail_info.cover;
|
|
var oc = config.uploads.torrent.cover.temp + cv;
|
|
var nc = config.uploads.torrent.cover.dest + cv;
|
|
copy(oc, nc, function (err) {
|
|
if (err) {
|
|
mtDebug.debugRed(err);
|
|
}
|
|
|
|
if (req.body._uImage.indexOf(cv) < 0) {
|
|
fs.unlinkSync(oc);
|
|
}
|
|
});
|
|
|
|
//move temp torrent image file to dest directory
|
|
req.body._uImage.forEach(function (f) {
|
|
var oi = config.uploads.torrent.image.temp + f;
|
|
var ni = config.uploads.torrent.image.dest + f;
|
|
move(oi, ni, function (err) {
|
|
if (err) {
|
|
mtDebug.debugRed(err);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
torrent.save(function (err) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
res.json(torrent);
|
|
|
|
scoreUpdate(req, req.user, scoreConfig.action.uploadTorrent);
|
|
|
|
//update user uptotal fields
|
|
req.user.update({
|
|
$inc: {uptotal: 1}
|
|
}).exec();
|
|
//update maker torrent count
|
|
if (torrent.maker) {
|
|
Maker.update({_id: torrent.maker}, {
|
|
$inc: {torrent_count: 1}
|
|
}).exec();
|
|
|
|
//set status to reviewed when maker upload access is pass
|
|
Maker.findOne({
|
|
_id: torrent.maker,
|
|
upload_access: 'pass'
|
|
}, function (err, m) {
|
|
if (!err && m) {
|
|
torrent.update({torrent_status: 'reviewed'}).exec();
|
|
announceTorrentToIRC(torrent, req);
|
|
}
|
|
});
|
|
} else {
|
|
//set status to reviewed when user upload access is pass
|
|
if (req.user.upload_access === 'pass') {
|
|
torrent.update({torrent_status: 'reviewed'}).exec();
|
|
announceTorrentToIRC(torrent, req);
|
|
}
|
|
}
|
|
|
|
//scrape torrent status info in public cms mode
|
|
if (!config.meanTorrentConfig.announce.privateTorrentCmsMode && config.meanTorrentConfig.scrapeTorrentStatus.onTorrentUpload) {
|
|
scrape.doScrape(torrent, function (err, result) {
|
|
if (err) {
|
|
mtDebug.debugRed(err);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
function copy(oldPath, newPath, callback) {
|
|
var readStream = fs.createReadStream(oldPath);
|
|
var writeStream = fs.createWriteStream(newPath);
|
|
|
|
readStream.on('error', callback);
|
|
writeStream.on('error', callback);
|
|
|
|
readStream.on('close', function () {
|
|
callback();
|
|
});
|
|
readStream.pipe(writeStream);
|
|
}
|
|
|
|
function move(oldPath, newPath, callback) {
|
|
fs.rename(oldPath, newPath, function (err) {
|
|
if (err) {
|
|
if (err.code === 'EXDEV') {
|
|
copy();
|
|
} else {
|
|
callback(err);
|
|
}
|
|
return;
|
|
}
|
|
callback();
|
|
});
|
|
|
|
function copy() {
|
|
var readStream = fs.createReadStream(oldPath);
|
|
var writeStream = fs.createWriteStream(newPath);
|
|
|
|
readStream.on('error', callback);
|
|
writeStream.on('error', callback);
|
|
|
|
readStream.on('close', function () {
|
|
fs.unlink(oldPath, callback);
|
|
});
|
|
readStream.pipe(writeStream);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* read a torrent
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.read = function (req, res) {
|
|
if (req.torrent.torrent_vip && !req.user.isVip && !req.user.isOper) {
|
|
return res.status(403).send({
|
|
message: 'SERVER.ONLY_VIP_CAN_DOWNLOAD'
|
|
});
|
|
} else {
|
|
// 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.resource_detail_info = req.body.resource_detail_info;
|
|
|
|
torrent.save(function (err) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
res.json(torrent);
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* scrape
|
|
* scrape torrent status info in public cms mode
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.scrape = function (req, res) {
|
|
if (!config.meanTorrentConfig.announce.privateTorrentCmsMode) {
|
|
scrape.doScrape(req.torrent, function (err, result) {
|
|
if (err) {
|
|
mtDebug.debugRed(err);
|
|
return res.status(422).send({
|
|
message: err
|
|
});
|
|
}
|
|
if (result && result.length === 1) {
|
|
res.json(result[0]);
|
|
}
|
|
});
|
|
} else {
|
|
return res.status(422).send({
|
|
message: 'privateTorrentCmsMode do not support scrape method'
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* toggleHnRStatus
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.toggleHnRStatus = function (req, res) {
|
|
var torrent = req.torrent;
|
|
|
|
torrent.torrent_hnr = !torrent.torrent_hnr;
|
|
|
|
torrent.save(function (err) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
res.json(torrent);
|
|
|
|
//remove the complete data and update user`s warning number when the H&R prop to false
|
|
if (!torrent.torrent_hnr)
|
|
removeTorrentHnRWarning(torrent._id);
|
|
|
|
//add server message
|
|
if (serverNoticeConfig.action.torrentHnRChanged.enable) {
|
|
serverMessage.addMessage(torrent.user._id, serverNoticeConfig.action.torrentHnRChanged.title, serverNoticeConfig.action.torrentHnRChanged.content, {
|
|
torrent_file_name: torrent.torrent_filename,
|
|
torrent_id: torrent._id,
|
|
by_name: req.user.displayName,
|
|
by_id: req.user._id,
|
|
hnr_status: torrent.torrent_hnr ? 'ON' : 'OFF'
|
|
});
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* toggleVIPStatus
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.toggleVIPStatus = function (req, res) {
|
|
var torrent = req.torrent;
|
|
|
|
torrent.torrent_vip = !torrent.torrent_vip;
|
|
|
|
torrent.save(function (err) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
res.json(torrent);
|
|
|
|
//add server message
|
|
if (serverNoticeConfig.action.torrentVipChanged.enable) {
|
|
serverMessage.addMessage(torrent.user._id, serverNoticeConfig.action.torrentVipChanged.title, serverNoticeConfig.action.torrentVipChanged.content, {
|
|
torrent_file_name: torrent.torrent_filename,
|
|
torrent_id: torrent._id,
|
|
by_name: req.user.displayName,
|
|
by_id: req.user._id,
|
|
vip_status: torrent.torrent_vip ? 'ON' : 'OFF'
|
|
});
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* removeTorrentHnRWarning
|
|
* @param torrent
|
|
*/
|
|
function removeTorrentHnRWarning(tid) {
|
|
Complete.find({
|
|
torrent: tid
|
|
})
|
|
.populate('user')
|
|
.exec(function (err, cs) {
|
|
if (!err && cs) {
|
|
cs.forEach(function (c) {
|
|
if (c.hnr_warning) {
|
|
c.removeHnRWarning(c.user);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* thumbsUp
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.thumbsUp = function (req, res) {
|
|
var user = req.user;
|
|
var exist = false;
|
|
var torrent = req.torrent;
|
|
var thumb = new Thumb();
|
|
thumb.user = req.user;
|
|
thumb.score = thumbsUpScore.torrent;
|
|
|
|
//check if already exist
|
|
exist = false;
|
|
torrent._thumbs.forEach(function (sr) {
|
|
if (sr.user._id.equals(req.user._id)) {
|
|
exist = true;
|
|
}
|
|
});
|
|
if (exist) {
|
|
return res.status(422).send({
|
|
message: 'SERVER.ALREADY_THUMBS_UP'
|
|
});
|
|
} else {
|
|
if (req.user.score >= thumbsUpScore.torrent) {
|
|
torrent._thumbs.push(thumb);
|
|
torrent.user.update({
|
|
$inc: {score: thumbsUpScore.torrent}
|
|
}).exec();
|
|
save();
|
|
|
|
//add server message
|
|
if (serverNoticeConfig.action.torrentThumbsUp.enable) {
|
|
serverMessage.addMessage(torrent.user._id, serverNoticeConfig.action.torrentThumbsUp.title, serverNoticeConfig.action.torrentThumbsUp.content, {
|
|
torrent_file_name: torrent.torrent_filename,
|
|
torrent_id: torrent._id,
|
|
by_name: user.displayName,
|
|
by_id: user._id
|
|
});
|
|
}
|
|
} else {
|
|
return res.status(422).send({
|
|
message: 'SERVER.SCORE_NOT_ENOUGH'
|
|
});
|
|
}
|
|
}
|
|
|
|
function save() {
|
|
torrent.save(function (err) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
res.json(torrent);
|
|
}
|
|
});
|
|
|
|
user.update({
|
|
$inc: {score: -thumbsUpScore.torrent}
|
|
}).exec();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* rating
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.rating = function (req, res) {
|
|
var user = req.user;
|
|
var exist = false;
|
|
var torrent = req.torrent;
|
|
var rat = new Rating();
|
|
rat.user = req.user;
|
|
rat.vote = req.query.vote;
|
|
|
|
mtDebug.debugGreen(rat);
|
|
//check if already exist
|
|
exist = false;
|
|
torrent._ratings.forEach(function (r) {
|
|
if (r.user._id.equals(user._id)) {
|
|
exist = true;
|
|
}
|
|
});
|
|
if (exist) {
|
|
return res.status(422).send({
|
|
message: 'ALREADY_RATING'
|
|
});
|
|
} else {
|
|
torrent._ratings.push(rat);
|
|
|
|
mtDebug.debugGreen(torrent.resource_detail_info);
|
|
torrent.resource_detail_info.vote_count = parseInt(torrent.resource_detail_info.vote_count, 10) + 1;
|
|
torrent.resource_detail_info.vote_total = parseInt(torrent.resource_detail_info.vote_total, 10) + rat.vote;
|
|
torrent.resource_detail_info.vote_average = Math.floor((torrent.resource_detail_info.vote_total / torrent.resource_detail_info.vote_count) * 10) / 10;
|
|
mtDebug.debugGreen(torrent.resource_detail_info);
|
|
|
|
torrent.markModified('resource_detail_info');
|
|
|
|
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);
|
|
|
|
//add server message
|
|
if (serverNoticeConfig.action.torrentSaleChanged.enable) {
|
|
serverMessage.addMessage(torrent.user._id, serverNoticeConfig.action.torrentSaleChanged.title, serverNoticeConfig.action.torrentSaleChanged.content, {
|
|
torrent_file_name: torrent.torrent_filename,
|
|
torrent_id: torrent._id,
|
|
by_name: req.user.displayName,
|
|
by_id: req.user._id,
|
|
sale_status: torrent.torrent_sale_status
|
|
});
|
|
}
|
|
|
|
//create trace log
|
|
traceLogCreate(req, traceConfig.action.AdminTorrentSetSaleType, {
|
|
torrent: torrent._id,
|
|
sale_status: req.params.saleType
|
|
});
|
|
}
|
|
});
|
|
} else {
|
|
return res.status(422).send({
|
|
message: 'params saleType error'
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* setRecommendLevel
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.setRecommendLevel = function (req, res) {
|
|
var torrent = req.torrent;
|
|
|
|
if (req.params.rlevel) {
|
|
torrent.torrent_recommended = req.params.rlevel;
|
|
torrent.orderedat = Date.now();
|
|
|
|
torrent.save(function (err) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
res.json(torrent);
|
|
|
|
scoreUpdate(req, torrent.user, scoreConfig.action.uploadTorrentBeRecommend);
|
|
//create trace log
|
|
traceLogCreate(req, traceConfig.action.AdminTorrentSetRecommendLevel, {
|
|
torrent: torrent._id,
|
|
recommended: req.params.rlevel
|
|
});
|
|
}
|
|
});
|
|
} else {
|
|
return res.status(422).send({
|
|
message: 'params rlevel error'
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* setTorrentTags
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.setTorrentTags = function (req, res) {
|
|
var torrent = req.torrent;
|
|
|
|
if (req.body.tags) {
|
|
torrent.torrent_tags = req.body.tags;
|
|
|
|
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 tags 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);
|
|
|
|
announceTorrentToIRC(torrent, req);
|
|
|
|
//add server message
|
|
if (serverNoticeConfig.action.torrentReviewed.enable) {
|
|
serverMessage.addMessage(torrent.user._id, serverNoticeConfig.action.torrentReviewed.title, serverNoticeConfig.action.torrentReviewed.content, {
|
|
torrent_file_name: torrent.torrent_filename,
|
|
torrent_id: torrent._id,
|
|
by_name: req.user.displayName,
|
|
by_id: req.user._id
|
|
});
|
|
}
|
|
|
|
//create trace log
|
|
traceLogCreate(req, traceConfig.action.AdminTorrentSetReviewedStatus, {
|
|
torrent: torrent._id,
|
|
status: 'reviewed'
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
function announceTorrentToIRC(torrent, req) {
|
|
//irc announce
|
|
if (ircConfig.enable) {
|
|
var msg = '';
|
|
var client = req.app.get('ircClient');
|
|
|
|
if (torrent.torrent_type === 'tvserial') {
|
|
msg = vsprintf(ircConfig.tvserialMsgFormat, [
|
|
torrent.user.displayName,
|
|
torrent.torrent_filename,
|
|
torrent.torrent_type,
|
|
torrent.torrent_size,
|
|
torrent.torrent_seasons,
|
|
torrent.torrent_episodes,
|
|
torrent.torrent_sale_status,
|
|
moment().format('YYYY-MM-DD HH:mm:ss')
|
|
]);
|
|
} else {
|
|
msg = vsprintf(ircConfig.defaultMsgFormat, [
|
|
torrent.user.displayName,
|
|
torrent.torrent_filename,
|
|
torrent.torrent_type,
|
|
torrent.torrent_size,
|
|
torrent.torrent_sale_status,
|
|
moment().format('YYYY-MM-DD HH:mm:ss')
|
|
]);
|
|
}
|
|
client.notice(ircConfig.channel, msg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* delete a torrent
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.delete = function (req, res) {
|
|
var torrent = req.torrent;
|
|
|
|
//DELETE the torrent file
|
|
var tfile = config.uploads.torrent.file.dest + req.torrent.torrent_filename;
|
|
fs.exists(tfile, function (exists) {
|
|
if (exists) {
|
|
fs.unlinkSync(tfile);
|
|
}
|
|
});
|
|
|
|
//update users seed/leech number
|
|
Peer.find({
|
|
torrent: torrent._id
|
|
})
|
|
.populate('user')
|
|
.exec(function (err, ps) {
|
|
ps.forEach(function (p) {
|
|
if (p.user && p.peer_status === PEERSTATE_SEEDER) {
|
|
p.user.update({
|
|
$inc: {seeded: -1}
|
|
}).exec();
|
|
}
|
|
if (p.user && p.peer_status === PEERSTATE_LEECHER) {
|
|
p.user.update({
|
|
$inc: {leeched: -1}
|
|
}).exec();
|
|
}
|
|
});
|
|
});
|
|
|
|
//remove all peers of the torrent
|
|
Peer.remove({
|
|
torrent: torrent._id
|
|
});
|
|
//remove all subtitle of the torrent
|
|
Subtitle.remove({
|
|
torrent: torrent._id
|
|
});
|
|
//update maker torrent count
|
|
if (torrent.maker) {
|
|
torrent.maker.update({
|
|
$inc: {torrent_count: -1}
|
|
}).exec();
|
|
}
|
|
|
|
//update user uptotal fields
|
|
torrent.user.update({
|
|
$inc: {uptotal: -1}
|
|
}).exec();
|
|
|
|
//remove the complete data and update user`s warning number if the torrent has H&R prop
|
|
removeTorrentHnRWarning(torrent._id);
|
|
Complete.remove({
|
|
torrent: torrent._id
|
|
});
|
|
|
|
torrent.remove(function (err) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
res.json(torrent);
|
|
|
|
scoreUpdate(req, torrent.user, scoreConfig.action.uploadTorrentBeDeleted);
|
|
//create trace log
|
|
traceLogCreate(req, traceConfig.action.AdminTorrentDelete, {
|
|
torrent: torrent._id
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* getTorrentsHomeList
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.getTorrentsHomeList = function (req, res) {
|
|
var getOrderList = function (callback) {
|
|
var query = Torrent.aggregate([
|
|
{'$match': {torrent_status: 'reviewed', torrent_vip: false}},
|
|
{'$sort': {torrent_recommended: 1, orderedat: -1, createdat: -1}},
|
|
{
|
|
'$lookup': {
|
|
from: 'peers',
|
|
localField: '_id',
|
|
foreignField: 'torrent',
|
|
as: 't_peer'
|
|
}
|
|
},
|
|
{
|
|
'$addFields': {
|
|
'my_peers': {
|
|
'$filter': {
|
|
'input': '$t_peer',
|
|
'as': 'p',
|
|
'cond': {'$eq': ['$$p.user', req.user._id]}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
'$project': {
|
|
't_peer': 0
|
|
}
|
|
},
|
|
{'$group': {_id: '$torrent_type', typeTorrents: {$push: '$$ROOT'}}},
|
|
{'$project': {'typeTorrents': {'$slice': ['$typeTorrents', itemsPerPageConfig.homeOrderTorrentListPerType]}}}
|
|
]);
|
|
|
|
query.exec(function (err, orderList) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
Torrent.populate(orderList,
|
|
[
|
|
{path: 'typeTorrents.user', select: 'username displayName isVip', model: 'User'},
|
|
{path: 'typeTorrents.maker', select: 'name', model: 'Maker'}
|
|
], function (err, items) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
callback(null, items);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
var getNewestList = function (callback) {
|
|
var query = Torrent.aggregate([
|
|
{'$match': {torrent_status: 'reviewed', torrent_vip: false}},
|
|
{'$sort': {createdat: -1}},
|
|
{
|
|
'$lookup': {
|
|
from: 'peers',
|
|
localField: '_id',
|
|
foreignField: 'torrent',
|
|
as: 't_peer'
|
|
}
|
|
},
|
|
{
|
|
'$addFields': {
|
|
'my_peers': {
|
|
'$filter': {
|
|
'input': '$t_peer',
|
|
'as': 'p',
|
|
'cond': {'$eq': ['$$p.user', req.user._id]}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
'$project': {
|
|
't_peer': 0
|
|
}
|
|
},
|
|
{'$group': {_id: '$torrent_type', typeTorrents: {$push: '$$ROOT'}}},
|
|
{'$project': {'typeTorrents': {'$slice': ['$typeTorrents', itemsPerPageConfig.homeNewestTorrentListPerType]}}}
|
|
]);
|
|
|
|
query.exec(function (err, newestList) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
Torrent.populate(newestList,
|
|
[
|
|
{path: 'typeTorrents.user', select: 'username displayName isVip', model: 'User'},
|
|
{path: 'typeTorrents.maker', select: 'name', model: 'Maker'}
|
|
], function (err, items) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
callback(null, items);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
async.parallel([getOrderList, getNewestList], function (err, results) {
|
|
if (err) {
|
|
return res.status(422).send(err);
|
|
} else {
|
|
res.json({orderList: results[0], newestList: results[1]});
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* list all torrents
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.list = function (req, res) {
|
|
var skip = 0;
|
|
var limit = 0;
|
|
var status = 'reviewed';
|
|
var rlevel = 'none';
|
|
var stype = 'movie';
|
|
var newest = false;
|
|
var hnr = false;
|
|
var sale = false;
|
|
var vip = undefined;
|
|
var release = undefined;
|
|
var userid = undefined;
|
|
var maker = undefined;
|
|
var tagsA = [];
|
|
var keysA = [];
|
|
|
|
//var sort = 'torrent_recommended -orderedat -createdat';
|
|
var sort = {torrent_recommended: 1, orderedat: -1, createdat: -1};
|
|
|
|
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.sort !== undefined) {
|
|
sort = JSON.parse(req.query.sort);
|
|
}
|
|
if (req.query.torrent_status !== undefined) {
|
|
status = req.query.torrent_status;
|
|
}
|
|
if (req.query.torrent_rlevel !== undefined) {
|
|
rlevel = req.query.torrent_rlevel;
|
|
}
|
|
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_hnr !== undefined) {
|
|
hnr = (req.query.torrent_hnr === 'true');
|
|
}
|
|
if (req.query.torrent_sale !== undefined) {
|
|
sale = (req.query.torrent_sale === 'true');
|
|
}
|
|
if (req.query.torrent_vip !== undefined) {
|
|
vip = (req.query.torrent_vip === 'true');
|
|
}
|
|
if (req.query.newest !== undefined) {
|
|
newest = (req.query.newest === 'true');
|
|
}
|
|
if (req.query.userid !== undefined) {
|
|
userid = objectId(req.query.userid);
|
|
}
|
|
if (req.query.maker !== undefined) {
|
|
maker = objectId(req.query.maker);
|
|
}
|
|
|
|
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 (rlevel !== 'none') {
|
|
condition.torrent_recommended = rlevel;
|
|
}
|
|
if (stype !== 'all') {
|
|
condition.torrent_type = stype;
|
|
}
|
|
if (hnr === true) {
|
|
condition.torrent_hnr = true;
|
|
}
|
|
if (sale === true) {
|
|
condition.torrent_sale_status = {
|
|
$ne: 'U1/D1'
|
|
};
|
|
}
|
|
if (vip !== undefined) {
|
|
if (vip === true) {
|
|
condition.torrent_vip = true;
|
|
} else {
|
|
condition.torrent_vip = false;
|
|
}
|
|
}
|
|
|
|
if (tagsA.length > 0) {
|
|
condition.torrent_tags = {$all: tagsA};
|
|
}
|
|
if (release !== undefined) {
|
|
condition['resource_detail_info.release_date'] = release;
|
|
}
|
|
if (keysA.length > 0) {
|
|
condition.$or = [
|
|
{torrent_filename: {'$all': keysA}},
|
|
{'resource_detail_info.title': {'$all': keysA}},
|
|
{'resource_detail_info.subtitle': {'$all': keysA}},
|
|
{'resource_detail_info.name': {'$all': keysA}},
|
|
{'resource_detail_info.original_title': {'$all': keysA}},
|
|
{'resource_detail_info.original_name': {'$all': keysA}}
|
|
];
|
|
}
|
|
if (userid !== undefined) {
|
|
condition.user = userid;
|
|
}
|
|
if (maker !== undefined) {
|
|
condition.maker = maker;
|
|
}
|
|
|
|
mtDebug.debugGreen(JSON.stringify(condition));
|
|
mtDebug.debugGreen(sort);
|
|
|
|
if (newest) {
|
|
//sort = '-createdat';
|
|
sort = {createdat: -1};
|
|
}
|
|
|
|
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(sort)
|
|
// .populate('user', 'username displayName isVip')
|
|
// .populate('maker', 'name')
|
|
// .skip(skip)
|
|
// .limit(limit)
|
|
// .exec(function (err, torrents) {
|
|
// if (err) {
|
|
// callback(err, null);
|
|
// } else {
|
|
// callback(null, torrents);
|
|
// }
|
|
// });
|
|
|
|
var query = Torrent.aggregate([
|
|
{'$match': condition},
|
|
{'$sort': sort},
|
|
{'$skip': skip},
|
|
{'$limit': limit},
|
|
{
|
|
'$lookup': {
|
|
from: 'peers',
|
|
localField: '_id',
|
|
foreignField: 'torrent',
|
|
as: 't_peer'
|
|
}
|
|
},
|
|
{
|
|
'$addFields': {
|
|
'my_peers': {
|
|
'$filter': {
|
|
'input': '$t_peer',
|
|
'as': 'p',
|
|
'cond': {'$eq': ['$$p.user', req.user._id]}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
'$project': {
|
|
't_peer': 0
|
|
}
|
|
}
|
|
]);
|
|
|
|
if (limit === 0) {
|
|
let i = query._pipeline.length;
|
|
while (i--) {
|
|
if (Object.keys(query._pipeline[i])[0] === '$limit') {
|
|
query._pipeline.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
query.exec(function (err, torrents) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
globalUpdateTorrent(torrents, function (ntorrents) {
|
|
|
|
Torrent.populate(ntorrents,
|
|
[
|
|
{path: 'user', select: 'username displayName isVip'},
|
|
{path: 'maker', select: 'name'}
|
|
], function (err, ts) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
callback(null, ts);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
async.parallel([countQuery, findQuery], function (err, results) {
|
|
if (err) {
|
|
return res.status(422).send(err);
|
|
} else {
|
|
res.json({rows: results[1], total: results[0]});
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* globalUpdateTorrent
|
|
* @param torrents
|
|
*/
|
|
function globalUpdateTorrent(torrents, cb) {
|
|
function updateFunc(ts, t, i) {
|
|
return function (callback) {
|
|
Torrent.findById(t._id).exec(function (err, ft) {
|
|
if (err)
|
|
return callback(ts);
|
|
ft.globalUpdateMethod(function (sft) {
|
|
ts[i] = sft;
|
|
callback(null, ts);
|
|
});
|
|
});
|
|
};
|
|
}
|
|
|
|
var funcs = [];
|
|
torrents.forEach(function (t, i) {
|
|
if (t.isSaling) {
|
|
funcs.push(updateFunc(torrents, t, i));
|
|
}
|
|
});
|
|
|
|
if (funcs.length <= 0) {
|
|
cb(torrents);
|
|
} else {
|
|
async.parallel(funcs, function (err, result) {
|
|
cb(result[result.length - 1]);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* siteInfo - get site torrent info, seeders/leechers/torrents count/users etc.
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.siteInfo = function (req, res) {
|
|
var countUsers = function (callback) {
|
|
User.count(function (err, count) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
callback(null, count);
|
|
}
|
|
});
|
|
};
|
|
|
|
var countVipUsers = function (callback) {
|
|
User.count({isVip: true}, function (err, count) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
callback(null, count);
|
|
}
|
|
});
|
|
};
|
|
|
|
var countTorrents = function (callback) {
|
|
Torrent.count(function (err, count) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
callback(null, count);
|
|
}
|
|
});
|
|
};
|
|
|
|
var totalUpDown = function (callback) {
|
|
User.aggregate({
|
|
$group: {
|
|
_id: null,
|
|
uploaded: {$sum: '$uploaded'},
|
|
downloaded: {$sum: '$downloaded'}
|
|
}
|
|
}).exec(function (err, total) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
callback(null, total);
|
|
}
|
|
});
|
|
};
|
|
|
|
var totalTorrentsSize = function (callback) {
|
|
Torrent.aggregate({
|
|
$group: {
|
|
_id: null,
|
|
size: {$sum: '$torrent_size'},
|
|
seeders: {$sum: '$torrent_seeds'},
|
|
leechers: {$sum: '$torrent_leechers'}
|
|
}
|
|
}).exec(function (err, total) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
callback(null, total);
|
|
}
|
|
});
|
|
};
|
|
|
|
var countForumTopics = function (callback) {
|
|
Topic.count(function (err, count) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
callback(null, count);
|
|
}
|
|
});
|
|
};
|
|
|
|
var totalForumReplies = function (callback) {
|
|
Topic.aggregate({
|
|
$group: {
|
|
_id: null,
|
|
replies: {$sum: '$replyCount'}
|
|
}
|
|
}).exec(function (err, total) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
callback(null, total);
|
|
}
|
|
});
|
|
};
|
|
|
|
async.parallel([countUsers, countTorrents, totalTorrentsSize, totalUpDown, countForumTopics, totalForumReplies, countVipUsers], function (err, results) {
|
|
if (err) {
|
|
return res.status(422).send(err);
|
|
} else {
|
|
res.json({
|
|
totalUsers: results[0],
|
|
totalTorrents: results[1],
|
|
totalTorrentsSize: results[2][0] ? results[2][0].size : 0,
|
|
totalSeeders: results[2][0] ? results[2][0].seeders : 0,
|
|
totalLeechers: results[2][0] ? results[2][0].leechers : 0,
|
|
totalUploaded: results[3][0] ? results[3][0].uploaded : 0,
|
|
totalDownloaded: results[3][0] ? results[3][0].downloaded : 0,
|
|
totalForumTopics: results[4],
|
|
totalForumReplies: results[5][0] ? results[5][0].replies : 0,
|
|
totalVipUsers: results[6]
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* getSeederUsers
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.getSeederUsers = function (req, res) {
|
|
var skip = 0;
|
|
var limit = 0;
|
|
|
|
if (req.query.skip !== undefined) {
|
|
skip = parseInt(req.query.skip, 10);
|
|
}
|
|
if (req.query.limit !== undefined) {
|
|
limit = parseInt(req.query.limit, 10);
|
|
}
|
|
|
|
var countSeederUsers = function (callback) {
|
|
Peer.count({
|
|
torrent: req.torrent._id,
|
|
peer_status: PEERSTATE_SEEDER
|
|
}, function (err, count) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
callback(null, count);
|
|
}
|
|
});
|
|
|
|
};
|
|
|
|
var findSeederUsers = function (callback) {
|
|
Peer.find({
|
|
torrent: req.torrent._id,
|
|
peer_status: PEERSTATE_SEEDER
|
|
})
|
|
.sort('-peer_uploaded')
|
|
.populate('user', 'username displayName profileImageURL isVip')
|
|
.skip(skip)
|
|
.limit(limit)
|
|
.exec(function (err, peers) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
callback(null, peers);
|
|
}
|
|
});
|
|
};
|
|
|
|
async.parallel([countSeederUsers, findSeederUsers], function (err, results) {
|
|
if (err) {
|
|
return res.status(422).send(err);
|
|
} else {
|
|
res.json({rows: results[1], total: results[0]});
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* getLeecherUsers
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
exports.getLeecherUsers = function (req, res) {
|
|
var skip = 0;
|
|
var limit = 0;
|
|
|
|
if (req.query.skip !== undefined) {
|
|
skip = parseInt(req.query.skip, 10);
|
|
}
|
|
if (req.query.limit !== undefined) {
|
|
limit = parseInt(req.query.limit, 10);
|
|
}
|
|
|
|
var countLeecherUsers = function (callback) {
|
|
Peer.count({
|
|
torrent: req.torrent._id,
|
|
peer_status: PEERSTATE_LEECHER
|
|
}, function (err, count) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
callback(null, count);
|
|
}
|
|
});
|
|
|
|
};
|
|
|
|
var findLeecherUsers = function (callback) {
|
|
Peer.find({
|
|
torrent: req.torrent._id,
|
|
peer_status: PEERSTATE_LEECHER
|
|
})
|
|
.sort('-peer_uploaded')
|
|
.populate('user', 'username displayName profileImageURL isVip')
|
|
.skip(skip)
|
|
.limit(limit)
|
|
.exec(function (err, peers) {
|
|
if (err) {
|
|
return res.status(422).send({
|
|
message: errorHandler.getErrorMessage(err)
|
|
});
|
|
} else {
|
|
callback(null, peers);
|
|
}
|
|
});
|
|
};
|
|
|
|
async.parallel([countLeecherUsers, findLeecherUsers], 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.find({_id: id}, {'_peers': 0})
|
|
.populate('user', 'username displayName profileImageURL isVip')
|
|
.populate('maker', 'name')
|
|
.populate('_thumbs.user', 'username displayName profileImageURL isVip uploaded downloaded')
|
|
.populate('_ratings.user', 'username displayName profileImageURL isVip uploaded downloaded')
|
|
.populate({
|
|
path: '_replies.user',
|
|
select: 'username displayName profileImageURL isVip uploaded downloaded',
|
|
model: 'User'
|
|
})
|
|
.populate({
|
|
path: '_replies._replies.user',
|
|
select: 'username displayName profileImageURL isVip uploaded downloaded',
|
|
model: 'User'
|
|
})
|
|
.populate({
|
|
path: '_subtitles',
|
|
populate: {
|
|
path: 'user',
|
|
select: 'username displayName profileImageURL isVip'
|
|
}
|
|
})
|
|
.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[0]);
|
|
});
|
|
};
|
|
|
|
var findOtherTorrents = function (torrent, callback) {
|
|
if (torrent.resource_detail_info.id) {
|
|
var condition = {
|
|
torrent_status: 'reviewed',
|
|
'resource_detail_info.id': torrent.resource_detail_info.id
|
|
};
|
|
|
|
mtDebug.debugGreen(condition);
|
|
|
|
var fields = 'user maker torrent_filename torrent_tags torrent_seeds torrent_leechers torrent_finished torrent_seasons torrent_episodes torrent_size torrent_sale_status torrent_type torrent_hnr isSaling torrent_vip torrent_sale_expires createdat';
|
|
|
|
Torrent.find(condition, fields)
|
|
.sort('-createdat')
|
|
.populate('user', 'username displayName isVip')
|
|
.populate('maker', 'name')
|
|
.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);
|
|
}
|
|
});
|
|
} else {
|
|
callback(null, torrent);
|
|
}
|
|
};
|
|
|
|
var writeAllFiles = function (torrent, callback) {
|
|
var filePath = config.uploads.torrent.file.dest + torrent.torrent_filename;
|
|
nt.read(filePath, function (err, torrent_data) {
|
|
if (err) {
|
|
callback(err);
|
|
} else {
|
|
var mdata = torrent_data.metadata;
|
|
torrent._all_files = [];
|
|
|
|
if (mdata.info.files) {
|
|
mdata.info.files.forEach(function (f) {
|
|
torrent._all_files.push(f.path.join('/') + ', ' + common.fileSizeFormat(f.length, 2));
|
|
});
|
|
} else {
|
|
torrent._all_files.push(mdata.info.name + ', ' + common.fileSizeFormat(mdata.info.length, 2));
|
|
}
|
|
|
|
callback(null, torrent);
|
|
}
|
|
});
|
|
|
|
};
|
|
|
|
async.waterfall([findTorrents, findOtherTorrents, writeAllFiles], function (err, torrent) {
|
|
if (err) {
|
|
next(err);
|
|
} else {
|
|
req.torrent = torrent;
|
|
next();
|
|
}
|
|
});
|
|
};
|