feat(rss): compete rss feed support.

#20
This commit is contained in:
OldHawk
2017-12-28 17:25:07 +08:00
parent e4923a53d6
commit e95ce29ca0
10 changed files with 248 additions and 47 deletions

View File

@@ -16,7 +16,7 @@ module.exports = {
*/
app: {
name: 'CHD.im',
domain: 'http://chd.im:3000',
domain: 'http://127.0.0.1:3000',
showDemoWarningPopup: true,
cronTimeZone: 'Asia/Shanghai',
showDebugLog: true
@@ -56,37 +56,36 @@ module.exports = {
* tracker server announce settings
* NOTE: you can change these value at anytime if you understand it
*
* @url: announce url, download client will request this url to report uploads and downloads data
* @comment: used in admin tools, auto replace torrent make group info with this setting
* @announceInterval: interval of twice announce request
* @announcePrefix: prefix of torrent file name, is will auto add when user download the torrent files
* @admin: site admin mail address
* @baseUrl: torrent announce url base url, system will check it when user upload torrent file
* @clientBlackListUrl: forbidden download client list url, user can view this list to check forbidden client software
* @privateTorrentCmsMode: meanTorrent default tracker server mode is private (value true), the tracker server only accept private mode.
* but, you can set this value to false to make a public torrent cms web site without tracker server and announce function.
* if this value is false(public mode), server can scrape all torrent status from owner tracker server
* @downloadCheck: announce download(leech) settings
* @ratio: if less than this value, can not download(leech)
* @checkAfterSignupDays: all users download check start {value} days after signup, so the newest register user has {value} days to upgrade his ratio value,
* after {value} days, if less then setting of here, can not download(leech) any things, but can continue seed, unit of day
* @announceCheck: announce seed/leech numbers settings
* @url: announce url, download client will request this url to report uploads and downloads data
* @comment: used in admin tools, auto replace torrent make group info with this setting
* @announceInterval: interval of twice announce request
* @announcePrefix: prefix of torrent file name, is will auto add when user download the torrent files
* @admin: site admin mail address
* @clientBlackListUrl: forbidden download client list url, user can view this list to check forbidden client software
* @privateTorrentCmsMode: meanTorrent default tracker server mode is private (value true), the tracker server only accept private mode.
* but, you can set this value to false to make a public torrent cms web site without tracker server and announce function.
* if this value is false(public mode), server can scrape all torrent status from owner tracker server
* @downloadCheck: announce download(leech) settings
* @ratio: if less than this value, can not download(leech)
* @checkAfterSignupDays: all users download check start {value} days after signup, so the newest register user has {value} days to upgrade his ratio value,
* after {value} days, if less then setting of here, can not download(leech) any things, but can continue seed, unit of day
* @announceCheck: announce seed/leech numbers settings
* @maxLeechNumberPerUserPerTorrent: settings the max leech numbers of same user on same torrent
* @maxSeedNumberPerUserPerTorrent: settings the max seed numbers of same user on same torrent
* @peersCheck: send peers list of downloading announce request settings
* @peersSendListIncludeOwnSeed: settings whether include own seed peer in download announce request
* NOTE: the best value is false, In order to prevent cheating, user can not download data from own seeding.
* @ghostCheck
* @ghostPeersIdleTime: setting idle time more than this value is a ghost peer(died), remove it
* @ghostCompletesIdleTime: setting check users H&R warning interval time, unit of hours, default to 2
* @maxSeedNumberPerUserPerTorrent: settings the max seed numbers of same user on same torrent
* @peersCheck: send peers list of downloading announce request settings
* @peersSendListIncludeOwnSeed: settings whether include own seed peer in download announce request
* NOTE: the best value is false, In order to prevent cheating, user can not download data from own seeding.
* @ghostCheck:
* @ghostPeersIdleTime: setting idle time more than this value is a ghost peer(died), remove it
* @warningCheck:
* @userHnrWarningCheckInterval: setting check users H&R warning interval time, unit of hours, default to 2
*/
announce: {
url: 'http://chd.im:3000/announce',
url: '/announce',
comment: 'meanTorrent group',
announceInterval: 60 * 1000 * 5,
announcePrefix: '{CHD.im}.',
admin: 'admin@chd.im',
baseUrl: 'http://chd.im:3000',
clientBlackListUrl: '/about/black',
privateTorrentCmsMode: true,
downloadCheck: {
@@ -108,6 +107,31 @@ module.exports = {
}
},
/**
* @rss
*
* rss field value settings
*
* @title: setting title info of rss document
* @description: setting description info of rss document
* @copyright: setting copyright info of rss document
* @managingEditor: setting managingEditor info of rss document
* @webMaster: setting webMaster info of rss document
* @generator: setting generator info of rss document
* @ttl: setting ttl info of rss document
* @image_url: setting image_url info of rss document
*/
rss: {
title: '[%s] - RSS torrents',
description: 'Latest torrents from [%s]',
copyright: 'Copyright (c) [%s] 2012-2017, all rights reserved',
managingEditor: 'admin@chd.im (%s Admin)',
webMaster: 'webmaster@chd.im (%s Webmaster)',
generator: 'meanTorrent RSS Generator',
ttl: 60,
image_url: '/modules/core/client/img/rss.jpeg'
},
/**
* @scrapeTorrentsStatus
*
@@ -163,8 +187,8 @@ module.exports = {
userName: 'meanTorrent',
realName: 'IRC announce client',
channel: '#chdAnnounce',
defaultMsgFormat: '%s upload - torrent: %s, type: %s, size: %d, sale: %s, at %s',
tvserialMsgFormat: '%s upload - torrent: %s, type: %s, size: %d, seasons: %d, episodes: %s, sale: %s, at %s',
defaultMsgFormat: '%s uploaded - torrent: %s, type: %s, size: %d, sale: %s, url: %s, at %s',
tvserialMsgFormat: '%s uploaded - torrent: %s, type: %s, size: %d, seasons: %d, episodes: %s, sale: %s, url: %s, at %s',
showErrors: true,
autoRejoin: true,
autoConnect: true,

View File

@@ -22,6 +22,7 @@ var scoreConfig = config.meanTorrentConfig.score;
var hnrConfig = config.meanTorrentConfig.hitAndRun;
var signConfig = config.meanTorrentConfig.sign;
var announceConfig = config.meanTorrentConfig.announce;
var appConfig = config.meanTorrentConfig.app;
var mtDebug = require(path.resolve('./config/lib/debug'));
@@ -36,14 +37,14 @@ const FAILURE_REASONS = {
151: 'Invalid peerid: peerid is not 20 bytes long',
152: 'Invalid numwant. Client requested more peers than allowed by tracker',
153: 'Passkey length error (length=32)',
154: 'Invalid passkey, if you changed you passkey, please redownload the torrent file from ' + announceConfig.baseUrl,
154: 'Invalid passkey, if you changed you passkey, please redownload the torrent file from ' + appConfig.domain,
160: 'Invalid torrent info_hash',
161: 'No torrent with that info_hash has been found',
170: 'your account status is banned',
171: 'your account status is inactive',
172: 'your client is not allowed, here is the blacklist: ' + announceConfig.baseUrl + announceConfig.clientBlackListUrl,
172: 'your client is not allowed, here is the blacklist: ' + appConfig.domain + announceConfig.clientBlackListUrl,
173: 'this torrent status is not reviewed by administrators, try again later',
174: 'this torrent is only for VIP members',
175: 'your account status is idle',

View File

@@ -5,16 +5,17 @@
.module('torrents')
.controller('TorrentsController', TorrentsController);
TorrentsController.$inject = ['$scope', '$state', '$translate', '$timeout', 'Authentication', 'Notification', 'TorrentsService',
TorrentsController.$inject = ['$scope', '$state', '$translate', '$timeout', 'Authentication', 'Notification', 'TorrentsService', 'getStorageLangService',
'MeanTorrentConfig', 'DownloadService', '$window', 'ScrapeService', 'DebugConsoleService', 'TorrentGetInfoServices', 'ResourcesTagsServices'];
function TorrentsController($scope, $state, $translate, $timeout, Authentication, Notification, TorrentsService, MeanTorrentConfig,
function TorrentsController($scope, $state, $translate, $timeout, Authentication, Notification, TorrentsService, getStorageLangService, MeanTorrentConfig,
DownloadService, $window, ScrapeService, mtDebug, TorrentGetInfoServices, ResourcesTagsServices) {
var vm = this;
vm.DLS = DownloadService;
vm.TGI = TorrentGetInfoServices;
vm.user = Authentication.user;
vm.RTS = ResourcesTagsServices;
vm.lang = getStorageLangService.getLang();
vm.announce = MeanTorrentConfig.meanTorrentConfig.announce;
vm.scrapeConfig = MeanTorrentConfig.meanTorrentConfig.scrapeTorrentStatus;
vm.resourcesTags = MeanTorrentConfig.meanTorrentConfig.resourcesTags;
@@ -323,7 +324,8 @@
//make rss url
vm.rssUrl = vm.appConfig.domain;
vm.rssUrl += '/api/rss';
vm.rssUrl += '?passkey=' + vm.user.passkey;
vm.rssUrl += '/' + vm.user.passkey;
vm.rssUrl += '?language=' + vm.lang;
vm.rssUrl += '&limit=' + vm.torrentItemsPerPage;
vm.rssUrl += vm.searchKey.trim() ? '&keys=' + vm.searchKey.trim() : '';
vm.rssUrl += '&torrent_type=' + vm.torrentType;

View File

@@ -147,7 +147,7 @@
<dt class="h-line">{{'CA_MAKE_RSS_URL' | translate}}:</dt>
<dd class="h-line rss-desc-line">{{'DESC_MAKE_RSS_URL' | translate}}
<div class="margin-top-5">
<a href="{{vm.rssUrl}}">{{vm.rssUrl}}</a>
<a href="{{vm.rssUrl}}" target="_blank">{{vm.rssUrl}}</a>
<span style="position: relative">
<i class="fa fa-clipboard color-mt-base" aria-hidden="true" title="{{'COPY_TO_CLIPBOARD' | translate}}"
mt-scale-by-click="{scale: 2, duration: '.3s'}"

View File

@@ -26,7 +26,6 @@ var path = require('path'),
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;
@@ -42,6 +41,8 @@ var mtDebug = require(path.resolve('./config/lib/debug'));
var serverMessage = require(path.resolve('./config/lib/server-message'));
var serverNoticeConfig = config.meanTorrentConfig.serverNotice;
var announceConfig = config.meanTorrentConfig.announce;
var appConfig = config.meanTorrentConfig.app;
var rssConfig = config.meanTorrentConfig.rss;
const PEERSTATE_SEEDER = 'seeder';
const PEERSTATE_LEECHER = 'leecher';
@@ -202,15 +203,8 @@ exports.upload = function (req, res) {
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;
var announce = appConfig.domain + config.meanTorrentConfig.announce.url;
torrent.metadata.announce = announce;
var cws = fs.createWriteStream(newfile);
@@ -483,7 +477,7 @@ exports.announceEdit = function (req, res) {
message = 'Read torrent file faild';
reject(message);
} else {
var announce = config.meanTorrentConfig.announce.url;
var announce = appConfig.domain + config.meanTorrentConfig.announce.url;
torrent.metadata.announce = announce;
torrent.metadata.comment = req.query.comment;
torrent_data = torrent.metadata;
@@ -557,7 +551,7 @@ exports.download = function (req, res) {
reject(message);
} else {
if (config.meanTorrentConfig.announce.privateTorrentCmsMode) {
var announce = config.meanTorrentConfig.announce.url + '/' + user.passkey;
var announce = appConfig.domain + config.meanTorrentConfig.announce.url + '/' + user.passkey;
torrent.metadata.announce = announce;
}
torrent_data = torrent.metadata;
@@ -1153,6 +1147,7 @@ function announceTorrentToIRC(torrent, req) {
torrent.torrent_seasons,
torrent.torrent_episodes,
torrent.torrent_sale_status,
appConfig.domain + '/api/torrents/download/' + torrent._id + '/' + torrent.user.passkey,
moment().format('YYYY-MM-DD HH:mm:ss')
]);
} else {
@@ -1162,6 +1157,7 @@ function announceTorrentToIRC(torrent, req) {
torrent.torrent_type,
torrent.torrent_size,
torrent.torrent_sale_status,
appConfig.domain + '/api/torrents/download/' + torrent._id + '/' + torrent.user.passkey,
moment().format('YYYY-MM-DD HH:mm:ss')
]);
}
@@ -1622,6 +1618,179 @@ exports.list = function (req, res) {
});
};
/**
* makeRss
* @param req
* @param res
*/
exports.makeRss = function (req, res) {
var limit = 0;
var status = 'reviewed';
var stype = 'movie';
var hnr = false;
var sale = false;
var vip = false;
var release = undefined;
var tagsA = [];
var keysA = [];
var language = 'en';
var sort = '-createdat';
if (req.query.torrent_vip !== undefined) {
vip = (req.query.torrent_vip === 'true');
}
if (!req.passkeyuser) {
res.end('user is not authorized');
} else {
if (vip && !req.passkeyuser.isVip && !req.passkeyuser.isOper) {
res.end('You are not vip user!');
} else {
if (req.query.limit !== undefined) {
limit = parseInt(req.query.limit, 10);
}
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.language !== undefined) {
language = req.query.language;
}
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 = {};
condition.torrent_status = status;
condition.torrent_type = stype;
if (hnr === true) {
condition.torrent_hnr = true;
}
if (sale === true) {
condition.torrent_sale_status = {
$ne: 'U1/D1'
};
}
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}}
];
}
mtDebug.debugGreen(JSON.stringify(condition));
mtDebug.debugGreen(sort);
Torrent.find(condition)
.sort(sort)
.populate('user', 'username displayName isVip')
.populate('maker', 'name')
.limit(limit)
.exec(function (err, torrents) {
if (err) {
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.writeHead(200, {
'Content-Type': 'text/xml'
});
res.write('<?xml version="1.0" encoding="utf-8" ?>');
res.write('<rss version="2.0">');
res.write('<channel>');
res.write('<title>' + vsprintf(rssConfig.title, [appConfig.name + ' - ' + stype]) + '</title>');
res.write('<link><![CDATA[' + appConfig.domain + ']]></link>');
res.write('<description><![CDATA[' + vsprintf(rssConfig.description, [appConfig.name]) + ']]></description>');
res.write('<language>' + language + '</language>');
res.write('<copyright>' + vsprintf(rssConfig.copyright, [appConfig.name]) + '</copyright>');
res.write('<managingEditor>' + vsprintf(rssConfig.managingEditor, [appConfig.name]) + '</managingEditor>');
res.write('<webMaster>' + vsprintf(rssConfig.webMaster, [appConfig.name]) + '</webMaster>');
res.write('<lastBuildDate>' + moment().format('YYYY-MM-DD HH:mm:ss') + '</lastBuildDate>');
res.write('<generator>' + rssConfig.generator + '</generator>');
res.write('<docs><![CDATA[http://www.rssboard.org/rss-specification]]></docs>');
res.write('<ttl>' + rssConfig.ttl + '</ttl>');
res.write('<image>');
res.write('<title>' + vsprintf(rssConfig.title, [appConfig.name]) + '</title>');
res.write('<link><![CDATA[' + appConfig.domain + ']]></link>');
res.write('<url><![CDATA[' + appConfig.domain + '/modules/core/client/img/rss.jpeg]]></url>');
res.write('<width>100</width>');
res.write('<height>100</height>');
res.write('<description>' + vsprintf(rssConfig.description, [appConfig.name]) + '</description>');
res.write('</image>');
torrents.forEach(function (t) {
res.write('<item>');
res.write('<title><![CDATA[' + t.torrent_filename + ']]></title>');
res.write('<link>' + appConfig.domain + '/torrents/' + t._id + '</link>');
res.write('<description><![CDATA[' + t.resource_detail_info.overview + ']]></description>');
res.write('<author>' + t.user.displayName + '</author>');
res.write('<category domain="' + appConfig.domain + '/torrents/' + stype + '">' + stype + '</category>');
res.write('<comments><![CDATA[' + appConfig.domain + '/torrents/' + t._id + ']]></comments>');
res.write('<enclosure url="' + appConfig.domain + '/api/torrents/download/' + t._id + '/' + req.passkeyuser.passkey + '" length="' + t.torrent_size + '" type="application/x-bittorrent" />');
res.write('<guid isPermaLink="false">' + t.info_hash + '</guid>');
res.write('<pubDate>' + moment(t.createdat).format('YYYY-MM-DD HH:mm:ss') + '</pubDate>');
res.write('</item>');
});
res.write('</channel>');
res.write('</rss>');
res.end();
}
});
}
}
};
/**
* globalUpdateTorrent
* @param torrents

View File

@@ -27,6 +27,7 @@ exports.invokeRolesPolicies = function () {
{resources: '/api/torrents/download/:torrentId', permissions: '*'},
{resources: '/api/torrents/download/:torrentId/:passkey', permissions: '*'},
{resources: '/api/torrents', permissions: '*'},
{resources: '/api/rss/:passkey', permissions: '*'},
{resources: '/api/torrents/homeList', permissions: '*'},
{resources: '/api/torrents/:torrentId', permissions: '*'},
{resources: '/api/torrents/:torrentId/thumbsUp', permissions: '*'},
@@ -68,6 +69,7 @@ exports.invokeRolesPolicies = function () {
{resources: '/api/torrents/download/:torrentId', permissions: ['get']},
{resources: '/api/torrents/download/:torrentId/:passkey', permissions: ['get']},
{resources: '/api/torrents', permissions: ['get', 'post']},
{resources: '/api/rss/:passkey', permissions: ['get']},
{resources: '/api/torrents/homeList', permissions: ['get']},
{resources: '/api/torrents/:torrentId', permissions: ['get', 'put']},
{resources: '/api/torrents/:torrentId/thumbsUp', permissions: ['put']},
@@ -98,6 +100,7 @@ exports.invokeRolesPolicies = function () {
{resources: '/api/tvinfo/:tmdbid/:language', permissions: ['get']},
{resources: '/api/search/movie/:language', permissions: ['get']},
{resources: '/api/torrents', permissions: ['get']},
{resources: '/api/rss/:passkey', permissions: ['get']},
{resources: '/api/torrents/homeList', permissions: ['get']},
{resources: '/api/torrents/:torrentId', permissions: ['get']},
{resources: '/api/torrents/:torrentId/seederUsers', permissions: ['get']},

View File

@@ -36,6 +36,8 @@ module.exports = function (app) {
app.route('/api/torrents').all(torrentsPolicy.isAllowed)
.get(torrents.list)
.post(torrents.create);
app.route('/api/rss/:passkey').all(torrentsPolicy.isAllowed)
.get(torrents.makeRss);
app.route('/api/torrents/siteInfo')
.get(torrents.siteInfo);

View File

@@ -224,7 +224,8 @@
//make rss url
vm.rssUrl = vm.appConfig.domain;
vm.rssUrl += '/api/rss';
vm.rssUrl += '?passkey=' + vm.user.passkey;
vm.rssUrl += '/' + vm.user.passkey;
vm.rssUrl += '?language=' + localStorageService.get('storage_user_lang');
vm.rssUrl += '&limit=' + vm.itemsPerPage;
vm.rssUrl += vm.searchKey.trim() ? '&keys=' + vm.searchKey.trim() : '';
vm.rssUrl += '&torrent_type=' + vm.vipTorrentType;

View File

@@ -133,7 +133,7 @@
<dt class="h-line">{{'CA_MAKE_RSS_URL' | translate}}:</dt>
<dd class="h-line rss-desc-line">{{'DESC_MAKE_RSS_URL' | translate}}
<div class="margin-top-5">
<a href="{{vm.rssUrl}}">{{vm.rssUrl}}</a>
<a href="{{vm.rssUrl}}" target="_blank">{{vm.rssUrl}}</a>
<span style="position: relative">
<i class="fa fa-clipboard color-mt-base" aria-hidden="true"
title="{{'COPY_TO_CLIPBOARD' | translate}}"

View File

@@ -57,7 +57,6 @@
"express": "^4.16.2",
"express-hbs": "~1.0.4",
"express-session": "^1.15.6",
"feed": "^1.1.1",
"generate-password": "~1.3.0",
"glob": "~7.1.1",
"gulp": "~3.9.1",