diff --git a/README.md b/README.md index fe9c2263..dfeda443 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,7 @@ and [AngularJS](http://angularjs.org/) based applications. 56. An examination tasks system to check user`s incremental uploaded, download and score value within a specified period of time, if the value failed to reach the standard, admin can banned them. 57. Add email white list, user can not to receive invite mail and active mail if the email domain not in the list. 58. Add [angular-cache](https://github.com/jmdobry/angular-cache) support, to cache all data from $resource GET method, and update these data when $resource POST|PUT|DELETE method. +59. Daily check in function, continuous check-in to get more points. #### Chat room feature: 1. Users name list diff --git a/config/env/torrents.js b/config/env/torrents.js index 14f919ab..72b71236 100644 --- a/config/env/torrents.js +++ b/config/env/torrents.js @@ -81,12 +81,12 @@ module.exports = { * @index: list index in menu * @class: flag icon class, can find flag icon at '/public/lib/flag-icon-css/flags' * @title: language title show in menu item - * + * @enable: setting whether to enable or disable this language support, if false, user can not select it */ language: [ - {name: 'zh', index: 0, class: 'flag-icon-cn', title: '中文'}, - {name: 'en', index: 1, class: 'flag-icon-gb', title: 'English'}, - {name: 'zh-tw', index: 2, class: 'flag-icon-tw', title: '繁體中文'} + {name: 'en', index: 0, class: 'flag-icon-gb', title: 'English', enable: true}, + {name: 'zh', index: 1, class: 'flag-icon-cn', title: '中文', enable: true}, + {name: 'zh-tw', index: 2, class: 'flag-icon-tw', title: '繁體中文', enable: true} ], /** @@ -159,7 +159,8 @@ module.exports = { debugAnnounceUser: { debugAll: false, ids: [ - '59227f9095602327ea1d96ba' + '59227f9095602327ea1d96ba', + '592280c464be9e281a1ec56e' ] } }, @@ -191,6 +192,7 @@ module.exports = { * @webMaster: setting webMaster info of rss document * @generator: setting generator info of rss document * @ttl: setting ttl info of rss document, unit of seconds + * @pageItemsNumber: setting the items number of rss per page * @image_url: setting image_url info of rss document */ rss: { @@ -201,6 +203,7 @@ module.exports = { webMaster: 'webmaster@mean.im (%s Webmaster)', generator: '{MEAN.im} RSS Generator by meanTorrent', ttl: 60, + pageItemsNumber: 30, image_url: '/modules/core/client/img/rss.jpeg' }, @@ -435,8 +438,6 @@ module.exports = { action: { defaultAction: {name: 'defaultAction', value: 0, enable: true}, - checkInEveryDay: {name: 'checkInEveryDay', value: 10, enable: true}, - checkInConsDay: {name: 'checkInConsDay', value: 2, enable: true}, uploadTorrent: {name: 'uploadTorrent', value: 50, enable: true}, uploadTorrentBeDeleted: {name: 'uploadTorrentBeDeleted', value: -50, enable: true}, uploadTorrentBeRecommend: {name: 'uploadTorrentBeRecommend', value: 10, enable: true}, @@ -453,6 +454,14 @@ module.exports = { scoreToRemoveWarning: {name: 'scoreToRemoveWarning', value: 0, enable: true}, //value used hitAndRun.scoreToRemoveWarning activeIdleAccount: {name: 'activeIdleAccount', value: 0, enable: true}, //value used sign.idle.activeIdleAccountBasicScore + dailyCheckIn: { + enable: true, + name: 'dailyCheckIn', + dailyBasicScore: 10, + dailyStepScore: 1, + dailyMaxScore: 100 + }, + seedUpDownload: { name: 'seedUpDownload', additionSize: 1024 * 1024 * 1024 * 10, //10G @@ -504,7 +513,8 @@ module.exports = { * @value: type value * @checkUnreadInterval: set check unread message interval, default 2 minutes * @checkUnreadInterval_str: string desc of @checkUnreadInterval - * @serverMessageLimitCount: limit server notice message count in messagebox + * @serverMessageExpires: setting server message expire time, old message will be delete automatic + * @serverMessageExpires_str: setting desc of @serverMessageExpires * * NOTE: the first value 'user' cannot be deleted */ @@ -515,34 +525,39 @@ module.exports = { {name: 'USER', value: 'user', role: 'user'}, {name: 'SERVER', value: 'server', role: 'server'}, {name: 'SYSTEM', value: 'system', role: 'admin'}, - {name: 'ADVERT', value: 'advert', role: 'admin'}, - {name: 'NOTICE', value: 'notice', role: 'admin'} + {name: 'ADVERT', value: 'advert', role: 'admin'} ] }, checkUnreadInterval: 60 * 1000 * 2, checkUnreadInterval_str: '2m', - serverMessageLimitCount: 100 + serverMessageExpires: 60 * 60 * 1000 * 24 * 10, + serverMessageExpires_str: '10d' }, /** - * @inputLength + * @inputLength * - * input string length limit settings + * input string length limit settings * - * @userSignatureLength: user signature of forum string length limit - * @chatMessageMaxLength: chat room send message string length limit - * @messageTitleLength: user message send title length limit - * @messageBoxContentLength: user message send content length limit - * @messageBoxReplyLength: user message send reply content length limit - * @ticketContentLength: ticket content length limit - * @torrentCommentLength: torrent comment send content length limit - * @forumTopicTitleLength: forum topic title length limit - * @forumTopicContentLength: forum topic content length limit - * @forumReplyContentLength: forum reply content length limit - * @makerGroupDescLength: resources group desc content length limit - * @collectionsOverviewLength: movie collections overview content length limit + * @uploadTorrentTitleLength: torrent title length on upload page + * @uploadTorrentSubTitleLength: torrent sub title length on upload page + * @userSignatureLength: user signature of forum string length limit + * @chatMessageMaxLength: chat room send message string length limit + * @messageTitleLength: user message send title length limit + * @messageBoxContentLength: user message send content length limit + * @messageBoxReplyLength: user message send reply content length limit + * @ticketContentLength: ticket content length limit + * @torrentCommentLength: torrent comment send content length limit + * @forumTopicTitleLength: forum topic title length limit + * @forumTopicContentLength: forum topic content length limit + * @forumReplyContentLength: forum reply content length limit + * @makerGroupDescLength: resources group desc content length limit + * @collectionsOverviewLength: movie collections overview content length limit */ inputLength: { + uploadTorrentTitleLength: 128, + uploadTorrentSubTitleLength: 128, + userSignatureLength: 512, chatMessageMaxLength: 512, @@ -602,6 +617,7 @@ module.exports = { torrentReviewed: {title: 'TITLE_TORRENT_REVIEWED', content: 'CONTENT_TORRENT_REVIEWED', enable: true}, torrentVipChanged: {title: 'TITLE_TORRENT_VIP_CHANGED', content: 'CONTENT_TORRENT_VIP_CHANGED', enable: true}, torrentTopChanged: {title: 'TITLE_TORRENT_TOP_CHANGED', content: 'CONTENT_TORRENT_TOP_CHANGED', enable: true}, + torrentUniqueChanged: {title: 'TITLE_TORRENT_UNIQUE_CHANGED', content: 'CONTENT_TORRENT_UNIQUE_CHANGED', enable: true}, torrentHnRChanged: {title: 'TITLE_TORRENT_HNR_CHANGED', content: 'CONTENT_TORRENT_HNR_CHANGED', enable: true}, torrentSaleChanged: {title: 'TITLE_TORRENT_SALE_CHANGED', content: 'CONTENT_TORRENT_SALE_CHANGED', enable: true}, torrentDeleted: {title: 'TITLE_TORRENT_DELETED', content: 'CONTENT_TORRENT_DELETED', enable: true}, @@ -692,6 +708,7 @@ module.exports = { * @pageTitle: the page title string, used by translate at PAGETITLE * @uploadTemplateID: view templateID in upload torrent page, when selected type is changed, then include the template by this id, * all the template html is in file: modules/torrents/client/views/uploads-torrents.client.view.html + * @showSubtitleTabInDetailPage: setting whether show subtitle tab in torrent detail page * @showTopListInHome: setting whether show the TOP list in site home page, if false, don`t show * the 'other' type torrent always not show in home page * @@ -711,12 +728,13 @@ module.exports = { role: 'user', faIcon: 'fa-film', faClass: 'text-mt', - divider: true, + divider: false, position: 1, state: 'torrents.movie', url: '/movie', pageTitle: 'MOVIE_LIST', uploadTemplateID: 'movie', + showSubtitleTabInDetailPage: true, showTopListInHome: true }, { @@ -733,6 +751,7 @@ module.exports = { url: '/tv', pageTitle: 'TV_LIST', uploadTemplateID: 'tvserial', + showSubtitleTabInDetailPage: true, showTopListInHome: true }, { @@ -749,6 +768,7 @@ module.exports = { url: '/documentary', pageTitle: 'DOCUMENTARY_LIST', uploadTemplateID: 'default', + showSubtitleTabInDetailPage: true, showTopListInHome: true }, { @@ -765,6 +785,7 @@ module.exports = { url: '/music', pageTitle: 'MUSIC_LIST', uploadTemplateID: 'music', + showSubtitleTabInDetailPage: false, showTopListInHome: true }, { @@ -781,6 +802,7 @@ module.exports = { url: '/sports', pageTitle: 'SPORTS_LIST', uploadTemplateID: 'default', + showSubtitleTabInDetailPage: false, showTopListInHome: false }, { @@ -797,6 +819,7 @@ module.exports = { url: '/variety', pageTitle: 'VARIETY_LIST', uploadTemplateID: 'default', + showSubtitleTabInDetailPage: false, showTopListInHome: false }, { @@ -813,6 +836,7 @@ module.exports = { url: '/picture', pageTitle: 'PICTURE_LIST', uploadTemplateID: 'default', + showSubtitleTabInDetailPage: false, showTopListInHome: false }, { @@ -829,6 +853,7 @@ module.exports = { url: '/game', pageTitle: 'GAME_LIST', uploadTemplateID: 'default', + showSubtitleTabInDetailPage: false, showTopListInHome: false }, { @@ -845,6 +870,7 @@ module.exports = { url: '/software', pageTitle: 'SOFTWARE_LIST', uploadTemplateID: 'default', + showSubtitleTabInDetailPage: false, showTopListInHome: false }, { @@ -861,6 +887,7 @@ module.exports = { url: '/ebook', pageTitle: 'EBOOK_LIST', uploadTemplateID: 'default', + showSubtitleTabInDetailPage: false, showTopListInHome: false }, { @@ -877,6 +904,7 @@ module.exports = { url: '/other', pageTitle: 'OTHER_LIST', uploadTemplateID: 'default', + showSubtitleTabInDetailPage: false, showTopListInHome: false }, { @@ -893,6 +921,7 @@ module.exports = { url: '/adult', pageTitle: 'ADULT_LIST', uploadTemplateID: 'default', + showSubtitleTabInDetailPage: false, showTopListInHome: false } ] @@ -949,6 +978,7 @@ module.exports = { * when admin/oper to delete a h&r torrent, system will auto remove all warning and number of user * NOTE: you can change these value at anytime if you understand it * + * @enable: setting whether enable the H&R function * @condition: the condition of HnR warning, user must meet one of them before you receive the warning * @seedTime: torrent seed time, unit of day, default to 7 days * @seedTime_str: string desc of @seedTime @@ -960,6 +990,7 @@ module.exports = { * @checkWaringInterval_str: string desc of @checkWaringInterval */ hitAndRun: { + enable: true, condition: { seedTime: 60 * 60 * 1000 * 24 * 7, seedTime_str: '7d', @@ -1270,6 +1301,7 @@ module.exports = { * @collectionsListPerPage: movie collections list page settings * @backupFilesListPerPage: system backup files list page settings * @torrentPeersListPerPage: torrent detail seeder & leecher users list page settings + * @invitationsListPerPage: official invitations list page settings * * @uploaderUserListPerPage: admin management uploader access list page settings * @messageBoxListPerPage: message box list page settings @@ -1303,6 +1335,7 @@ module.exports = { collectionsListPerPage: 9, backupFilesListPerPage: 20, torrentPeersListPerPage: 20, + invitationsListPerPage: 20, uploaderUserListPerPage: 20, messageBoxListPerPage: 10, @@ -1342,6 +1375,23 @@ module.exports = { {command: './restart.sh', eid: 'restart', desc: 'COMMAND.RESTART'} ], + /** + * @mediaInfo + * + * mediaInfo settings + * + * @flag: flag icon class, can find flag icon at '/public/lib/flag-icon-css/flags' + */ + mediaInfo: { + flag: { + chs: {class: 'flag-icon-cn'}, + chinese: {class: 'flag-icon-cn'}, + cht: {class: 'flag-icon-tw'}, + korean: {class: 'flag-icon-kr'}, + eng: {class: 'flag-icon-gb'} + } + }, + /** * @resourcesTags * @@ -1371,8 +1421,8 @@ module.exports = { value: [ {name: 'BLU_RAY', icon: ''}, {name: 'REMUX', icon: ''}, - {name: 'WEB', icon: ''}, {name: 'ENCODE', icon: ''}, + {name: 'WEB', icon: ''}, {name: 'HDTV', icon: ''} ] }, @@ -1396,6 +1446,17 @@ module.exports = { {name: 'X265', icon: ''} ] }, + { + name: 'VISION', + cats: ['movie', 'tvserial', 'documentary', 'music', 'sports', 'variety', 'adult'], + value: [ + {name: 'DOLBY', icon: ''}, + {name: 'HDR10PLUS', icon: ''}, + {name: 'HDR10', icon: ''}, + {name: 'HDR', icon: ''}, + {name: 'SDR', icon: ''} + ] + }, { name: 'AUDIO', cats: ['movie', 'tvserial', 'documentary', 'music', 'sports', 'variety', 'adult'], diff --git a/config/lib/cron-job.js b/config/lib/cron-job.js index c6849034..695c7b4f 100644 --- a/config/lib/cron-job.js +++ b/config/lib/cron-job.js @@ -13,6 +13,7 @@ var path = require('path'), User = mongoose.model('User'), Peer = mongoose.model('Peer'), Complete = mongoose.model('Complete'), + Message = mongoose.model('Message'), MailTicket = mongoose.model('MailTicket'), backup = require('mongodb-backup'); @@ -22,6 +23,9 @@ var supportConfig = config.meanTorrentConfig.support; var backupConfig = config.meanTorrentConfig.backup; var announceConfig = config.meanTorrentConfig.announce; var signConfig = config.meanTorrentConfig.sign; +var hnrConfig = config.meanTorrentConfig.hitAndRun; +var messageConfig = config.meanTorrentConfig.messages; + var inbox = require('inbox'); var simpleParser = require('mailparser').simpleParser; @@ -70,8 +74,12 @@ module.exports = function (app) { } cronJobs.push(removeGhostPeers()); + cronJobs.push(removeOldServerMessages()); cronJobs.push(checkUserAccountIdleStatus()); - cronJobs.push(countUsersHnrWarning()); + + if (hnrConfig.enable) { + cronJobs.push(countUsersHnrWarning()); + } if (supportConfig.mailTicketSupportService) { cronJobs.push(listenServiceEmail()); @@ -133,7 +141,6 @@ function cronJobBackupMongoDB() { */ function removeGhostPeers() { var cronJob = new CronJob({ - //cronTime: '00 05 1 * * *', //cronTime: '*/5 * * * * *', cronTime: '00 30 */2 * * *', onTick: function () { @@ -172,6 +179,29 @@ function removeGhostPeers() { return cronJob; } +/** + * removeOldServerMessages + */ +function removeOldServerMessages() { + var cronJob = new CronJob({ + cronTime: '00 05 1 * * *', + onTick: function () { + logger.info(chalk.green('removeOldServerMessages: process!')); + + Message.remove({ + type: 'server', + createdat: {$lt: Date.now() - messageConfig.serverMessageExpires} + }).exec(); + }, + start: false, + timeZone: appConfig.cronTimeZone + }); + + cronJob.start(); + + return cronJob; +} + /** * checkUserAccountIdleStatus */ diff --git a/config/lib/debug.js b/config/lib/debug.js index eb454eb7..114be7a2 100644 --- a/config/lib/debug.js +++ b/config/lib/debug.js @@ -3,8 +3,10 @@ var path = require('path'), chalk = require('chalk'), logger = require('./logger'), + mongoose = require('mongoose'), loggerAnnounce = require('./loggerAnnounce'), moment = require('moment'), + objectId = require('mongodb').ObjectId, config = require(path.resolve('./config/config')); var appConfig = config.meanTorrentConfig.app; @@ -30,10 +32,12 @@ module.exports.info = function (obj, section = undefined, colorFunction = undefi var userPrefix = ''; if (isAnnounce && !announceConfig.debugAnnounceUser.debugAll) { if (user) { - if (!announceConfig.debugAnnounceUser.ids.includes(user._id.toString())) { + var id = (('_id' in user) ? user._id.toString() : user.toString()); + + if (!announceConfig.debugAnnounceUser.ids.includes(id)) { return; } else { - userPrefix = ' - ' + user.displayName + ' - ' + user._id.toString(); + userPrefix = ' - ' + (user.displayName || '-') + ' - ' + id; } } } diff --git a/config/lib/mediaInfo.js b/config/lib/mediaInfo.js new file mode 100644 index 00000000..8cf8ddaa --- /dev/null +++ b/config/lib/mediaInfo.js @@ -0,0 +1,601 @@ +'use strict'; + +var logger = require('./logger'); + +/** + * getMediaInfo + * @param nfo + * @returns {{}} + */ +module.exports.getMediaInfo = function (nfo) { + var minfo = {}; + + /** + * general + */ + var gInfo = getGeneralInfoContent(); + if (gInfo) { + minfo = getGeneralFileSize(gInfo, minfo); + minfo = getGeneralDuration(gInfo, minfo); + minfo = getGeneralOverallBitRate(gInfo, minfo); + } + + /** + * video + */ + var vInfo = getVideoInfoContent(); + if (vInfo) { + minfo = getVideoFormat(vInfo, minfo); + minfo = getVideoDuration(vInfo, minfo); + minfo = getVideoBitRate(vInfo, minfo); + minfo = getVideoWidth(vInfo, minfo); + minfo = getVideoHeight(vInfo, minfo); + minfo = getVideoFrameRateMode(vInfo, minfo); + minfo = getVideoFrameRate(vInfo, minfo); + minfo = getVideoBitDepth(vInfo, minfo); + minfo = getVideoStreamSize(vInfo, minfo); + minfo = getVideoWritingLibrary(vInfo, minfo); + } + + /** + * audio + */ + var aInfo = getAudioInfoContent(); + if (aInfo) { + minfo = getAudioFormat(aInfo, minfo); + minfo = getAudioBitRateMode(aInfo, minfo); + minfo = getAudioBitRate(aInfo, minfo); + minfo = getAudioChannel(aInfo, minfo); + minfo = getAudioLanguage(aInfo, minfo); + } + + /** + * text + */ + var tInfo = getTextInfoContent(); + if (tInfo) { + minfo = getTextLanguage(tInfo, minfo); + } + + /** + * get simple format media info + */ + if (!gInfo && !vInfo && !aInfo && !tInfo) { + minfo = getSimpleGeneralFileSize(nfo, minfo); + minfo = getSimpleGeneralReleaseSize(nfo, minfo); + minfo = getSimpleGeneralDuration(nfo, minfo); + minfo = getSimpleGeneralRuntime(nfo, minfo); + minfo = getSimpleVideoBitRate(nfo, minfo); + minfo = getSimpleVideoFrameRate(nfo, minfo); + minfo = getSimpleVideoResolution(nfo, minfo); + minfo = getSimpleVideoCodec(nfo, minfo); + minfo = getSimpleAudioInfo(nfo, minfo); + minfo = getSimpleAudioCodec(nfo, minfo); + minfo = getSimpleTextInfo(nfo, minfo); + + } + + return minfo; + + + /********************************************************************************** + * get general value + **********************************************************************************/ + function getGeneralInfoContent() { + var reg = /general[\r\n][\s\S]*?[\r\n][\r\n]|general[\r\n][\s\S]*/gi; + var res = nfo.match(reg); + return res || undefined; + } + + function getGeneralFileSize(gInfo, minfo) { + var reg = /file\s*size\s*:[^\r\n]+/gi; + var res = gInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('general')) { + minfo.general = {}; + } + minfo.general.fileSize = str.trim(); + } + return minfo; + } + + function getGeneralDuration(gInfo, minfo) { + var reg = /duration\s*:[^\r\n]+/gi; + var res = gInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('general')) { + minfo.general = {}; + } + minfo.general.duration = str.trim(); + } + return minfo; + } + + function getGeneralOverallBitRate(gInfo, minfo) { + var reg = /overall\s*bit\s*rate\s*:[^\r\n]+/gi; + var res = gInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('general')) { + minfo.general = {}; + } + minfo.general.overallBitRate = str.trim(); + } + return minfo; + } + + /********************************************************************************** + * get video value + **********************************************************************************/ + function getVideoInfoContent() { + var reg = /video[\s*\#\d]*[\r\n][\s\S]*?[\r\n][\r\n]|video[\s*\#\d]*[\r\n][\s\S]*/gi; + var res = nfo.match(reg); + return res || undefined; + } + + function getVideoFormat(vInfo, minfo) { + var reg = /format\s*:[^\r\n]+/gi; + var res = vInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('video')) { + minfo.video = {}; + } + minfo.video.format = str.trim(); + } + return minfo; + } + + function getVideoDuration(vInfo, minfo) { + var reg = /duration\s*:[^\r\n]+/gi; + var res = vInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('video')) { + minfo.video = {}; + } + minfo.video.duration = str.trim(); + } + return minfo; + } + + function getVideoBitRate(vInfo, minfo) { + var reg = /bit\s*rate\s*:[^\r\n]+/gi; + var res = vInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('video')) { + minfo.video = {}; + } + minfo.video.bitRate = str.trim(); + } + return minfo; + } + + function getVideoWidth(vInfo, minfo) { + var reg = /width\s*:[^\r\n]+/gi; + var res = vInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('video')) { + minfo.video = {}; + } + minfo.video.width = str.trim(); + } + return minfo; + } + + function getVideoHeight(vInfo, minfo) { + var reg = /height\s*:[^\r\n]+/gi; + var res = vInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('video')) { + minfo.video = {}; + } + minfo.video.height = str.trim(); + } + return minfo; + } + + function getVideoFrameRateMode(vInfo, minfo) { + var reg = /frame\s*rate\s*mode\s*:[^\r\n]+/gi; + var res = vInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('video')) { + minfo.video = {}; + } + minfo.video.frameRateMode = str.trim(); + } + return minfo; + } + + function getVideoFrameRate(vInfo, minfo) { + var reg = /frame\s*rate\s*:[^\r\n]+/gi; + var res = vInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('video')) { + minfo.video = {}; + } + minfo.video.frameRate = str.trim(); + } + return minfo; + } + + function getVideoBitDepth(vInfo, minfo) { + var reg = /bit\s*depth\s*:[^\r\n]+/gi; + var res = vInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('video')) { + minfo.video = {}; + } + minfo.video.bitDepth = str.trim(); + } + return minfo; + } + + function getVideoStreamSize(vInfo, minfo) { + var reg = /stream\s*size\s*:[^\r\n]+/gi; + var res = vInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('video')) { + minfo.video = {}; + } + minfo.video.streamSize = str.trim(); + } + return minfo; + } + + function getVideoWritingLibrary(vInfo, minfo) { + var reg = /writing\s*library\s*:[^\r\n]+/gi; + var res = vInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('video')) { + minfo.video = {}; + } + minfo.video.writingLibrary = str.trim(); + } + return minfo; + } + + /********************************************************************************** + * get audio value + **********************************************************************************/ + function getAudioInfoContent() { + var reg = /audio[\s*\#\d]*[\r\n][\s\S]*?[\r\n][\r\n]|audio[\s*\#\d]*[\r\n][\s\S]*/gi; + var res = nfo.match(reg); + return res || undefined; + } + + function getAudioFormat(aInfo, minfo) { + var reg = /format\s*:[^\r\n]+/gi; + var res = aInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('audio')) { + minfo.audio = {}; + } + minfo.audio.format = str.trim(); + } + return minfo; + } + + function getAudioBitRateMode(aInfo, minfo) { + var reg = /bit\s*rate\s*mode\s*:[^\r\n]+/gi; + var res = aInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('audio')) { + minfo.audio = {}; + } + minfo.audio.bitRateMode = str.trim(); + } + return minfo; + } + + function getAudioBitRate(aInfo, minfo) { + var reg = /bit\s*rate\s*:[^\r\n]+/gi; + var res = aInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('audio')) { + minfo.audio = {}; + } + minfo.audio.bitRate = str.trim(); + } + return minfo; + } + + function getAudioChannel(aInfo, minfo) { + var reg = /channel\(s\)\s*:[^\r\n]+/gi; + var res = aInfo[0].match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('audio')) { + minfo.audio = {}; + } + minfo.audio.channel = str.trim(); + } else { + reg = /channel\s*count\s*:[^\r\n]+/gi; + res = aInfo[0].match(reg); + str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('audio')) { + minfo.audio = {}; + } + minfo.audio.channel = str.trim(); + } + } + return minfo; + } + + function getAudioLanguage(aInfo, minfo) { + aInfo.forEach(function (vi) { + var reg = /language\s*:[^\r\n]+/gi; + var res = vi.match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('audio')) { + minfo.audio = {}; + } + if (!minfo.audio.hasOwnProperty('language')) { + minfo.audio.language = []; + } + if (!minfo.audio.language.includes(str)) { + minfo.audio.language.push(str.trim()); + } + } + }); + return minfo; + } + + /********************************************************************************** + * get text value + **********************************************************************************/ + function getTextInfoContent() { + var reg = /text[\s*\#\d]*[\r\n][\s\S]*?[\r\n][\r\n]|text[\s*\#\d]*[\r\n][\s\S]*/gi; + var res = nfo.match(reg); + return res || undefined; + } + + function getTextLanguage(tInfo, minfo) { + tInfo.forEach(function (vi) { + var reg = /language\s*:[^\r\n]+/gi; + var res = vi.match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('text')) { + minfo.text = {}; + } + if (!minfo.text.hasOwnProperty('language')) { + minfo.text.language = []; + } + if (!minfo.text.language.includes(str)) { + minfo.text.language.push(str.trim()); + } + } + }); + return minfo; + } + + /********************************************************************************** + * get simple value + **********************************************************************************/ + function getSimpleGeneralFileSize(gInfo, minfo) { + var reg = /file[\s|\.]*size[\s|\.]*:[^\r\n]+/gi; + var res = gInfo.match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('general')) { + minfo.general = {}; + } + minfo.general.fileSize = str.trim(); + } + return minfo; + } + + function getSimpleGeneralDuration(gInfo, minfo) { + var reg = /duration[\s|\.]*:[^\r\n]+/gi; + var res = gInfo.match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('general')) { + minfo.general = {}; + } + minfo.general.duration = str.trim(); + } + return minfo; + } + + function getSimpleGeneralRuntime(gInfo, minfo) { + var reg = /run[\s|\.]*time[\s|\.]*:[^\r\n]+/gi; + var res = gInfo.match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('general')) { + minfo.general = {}; + } + minfo.general.runtime = str.trim(); + } + return minfo; + } + + function getSimpleVideoBitRate(gInfo, minfo) { + var reg = /(video)*[\s|\.]*bit[\s|\.]*rate[\s|\.]*:[^\r\n]+/gi; + var res = gInfo.match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('video')) { + minfo.video = {}; + } + minfo.video.bitRate = str.trim(); + } + return minfo; + } + + function getSimpleVideoFrameRate(gInfo, minfo) { + var reg = /frame[\s|\.]*rate[\s|\.]*:[^\r\n]+/gi; + var res = gInfo.match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('video')) { + minfo.video = {}; + } + minfo.video.frameRate = str.trim(); + } + return minfo; + } + + function getSimpleVideoResolution(gInfo, minfo) { + var reg = /resolution[\s|\.]*:[^\r\n]+/gi; + var res = gInfo.match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('video')) { + minfo.video = {}; + } + minfo.video.resolution = str.trim(); + } + return minfo; + } + + function getSimpleAudioInfo(gInfo, minfo) { + var reg = /audio\s*\#*\d*[\s|\.]*:[^\r\n]+/gi; + var res = gInfo.match(reg); + if (res) { + res.forEach(function (ai) { + var str = ai.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('audio')) { + minfo.audio = {}; + } + if (!minfo.audio.hasOwnProperty('info')) { + minfo.audio.info = []; + } + minfo.audio.info.push(str.trim()); + }); + } + return minfo; + } + + function getSimpleTextInfo(gInfo, minfo) { + var reg = /subtitles*[\s|\.]*:[^\r\n]+/gi; + var res = gInfo.match(reg); + var str = res ? res[0] : undefined; + if (str) { + if (!minfo.hasOwnProperty('text')) { + minfo.text = {}; + } + if (!minfo.text.hasOwnProperty('language')) { + minfo.text.language = []; + } + + str = str.replace(/^[^\:]+.\s*/, ''); + if (!str.match(/\(|\)/)) { + var stlist = str.split(/\/|\,/); + stlist.forEach(function (st) { + minfo.text.language.push(st.trim()); + }); + } else { + // some value is "S_TEXT/ASS(chs/cht)", then do not split + minfo.text.language.push(str.trim()); + } + } else { + reg = /subtitles\d[\s|\.]*:[^\r\n]+/gi; + res = gInfo.match(reg); + if (res) { + res.forEach(function (st) { + st = st.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('text')) { + minfo.text = {}; + } + if (!minfo.text.hasOwnProperty('language')) { + minfo.text.language = []; + } + minfo.text.language.push(st.trim()); + }); + } + } + return minfo; + } + + //format start of .plot + function getSimpleGeneralReleaseSize(gInfo, minfo) { + var reg = /release[\s|\.]*size[\s|\.]*:[^\r\n]+/gi; + var res = gInfo.match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('general')) { + minfo.general = {}; + } + minfo.general.fileSize = str.trim(); + } + return minfo; + } + + function getSimpleVideoCodec(gInfo, minfo) { + var reg = /video[\s|\.]*codec[\s|\.]*:[^\r\n]+/gi; + var res = gInfo.match(reg); + var str = res ? res[0] : undefined; + if (str) { + str = str.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('video')) { + minfo.video = {}; + } + minfo.video.codec = str.trim(); + } + return minfo; + } + + function getSimpleAudioCodec(gInfo, minfo) { + var reg = /audio[\s|\.]*codec[\s|\.]*:[^\r\n]+/gi; + var res = gInfo.match(reg); + if (res) { + res.forEach(function (ac) { + var str = ac.replace(/^[^\:]+.\s*/, ''); + if (!minfo.hasOwnProperty('audio')) { + minfo.audio = {}; + } + if (!minfo.audio.hasOwnProperty('codec')) { + minfo.audio.codec = []; + } + minfo.audio.codec.push(str.trim()); + }); + } + return minfo; + } + +}; diff --git a/config/lib/multer.js b/config/lib/multer.js index 6f539bd7..5358f37e 100644 --- a/config/lib/multer.js +++ b/config/lib/multer.js @@ -59,11 +59,13 @@ module.exports.createUploadFilename = function (req, file, cb) { } //replace other pt site prefix - filename = filename.replace(/^\{([^}]+)\}[\.\s]|^\{([^}]+)\}/, ''); + var reg = /\{([a-zA-Z0-9\_\-\.\s]){2,10}\}[\.|\s]*/gi; + filename = filename.replace(reg, ''); if (fs.existsSync(config.uploads.torrent.file.dest + filename)) { var err = new Error(); err.code = 'FILE_ALREADY_EXISTS'; + err.filename = config.uploads.torrent.file.dest + filename; cb(err, null); } else { cb(null, filename); @@ -98,7 +100,9 @@ module.exports.createUploadAttachFilename = function (req, file, cb) { } //replace other pt site prefix - filename = filename.replace(/^\{([^}]+)\}[\.\s]|^\{([^}]+)\}/, ''); + var reg = /\{([a-zA-Z0-9\_\-\.\s]){2,10}\}[\.|\s]*/gi; + filename = filename.replace(reg, ''); + if (fs.existsSync(config.uploads.attach.file.dest + filename)) { var ext = file.originalname.replace(/^.+\./, ''); diff --git a/config/lib/score.js b/config/lib/score.js index 5b9c17f8..da59a94d 100644 --- a/config/lib/score.js +++ b/config/lib/score.js @@ -28,25 +28,28 @@ module.exports.update = function (req, user, action, value, writeLog = true) { if (action.enable && v !== 0) { if (user) { + var up = { + score: v + }; + if (common.examinationIsValid(user)) { - user.examinationData.score = user.examinationData.score || 0; - user.examinationData.score += v; - - var uploadFinished = user.examinationData.uploaded >= examinationConfig.incrementData.upload; - var downloadFinished = user.examinationData.downloaded >= examinationConfig.incrementData.download; - var scoreFinished = user.examinationData.score >= examinationConfig.incrementData.score; - user.examinationData.isFinished = uploadFinished && downloadFinished && scoreFinished; - user.examinationData.finishedTime = user.examinationData.isFinished ? Date.now() : null; - - user.markModified('examinationData'); + up['examinationData.score'] = v; + mtDebug.debugGreen('---------------WRITE EXAMINATION SCORE----------------', 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugRed('examinationData.score: ' + v, 'ANNOUNCE', true, req.passkeyuser); } - user.score += v; - user.save(function () { - traceLogCreate(req, traceConfig.action.userScoreChange, { - user: user._id, - score: v, - scoreActionName: action.name - }); + + User.update({_id: user._id}, { + $inc: up + }, function (err, num) { + if (err) { + logger.error(err); + } else { + traceLogCreate(req, traceConfig.action.userScoreChange, { + user: user._id, + score: v, + scoreActionName: action.name + }); + } }); //write score log diff --git a/modules/about/client/controllers/about.client.controller.js b/modules/about/client/controllers/about.client.controller.js index ba035bef..8ac7ca33 100644 --- a/modules/about/client/controllers/about.client.controller.js +++ b/modules/about/client/controllers/about.client.controller.js @@ -24,7 +24,7 @@ vm.scoreConfig = MeanTorrentConfig.meanTorrentConfig.score; vm.announce = MeanTorrentConfig.meanTorrentConfig.announce; vm.itemsPerPageConfig = MeanTorrentConfig.meanTorrentConfig.itemsPerPage; - vm.torrentType = MeanTorrentConfig.meanTorrentConfig.torrentType; + vm.torrentTypeConfig = MeanTorrentConfig.meanTorrentConfig.torrentType; vm.inputLengthConfig = MeanTorrentConfig.meanTorrentConfig.inputLength; vm.rssConfig = MeanTorrentConfig.meanTorrentConfig.rss; vm.ircConfig = MeanTorrentConfig.meanTorrentConfig.ircAnnounce; @@ -40,18 +40,38 @@ vm.examinationConfig = MeanTorrentConfig.meanTorrentConfig.examination; vm.chatConfig = MeanTorrentConfig.meanTorrentConfig.chat; vm.accessConfig = MeanTorrentConfig.meanTorrentConfig.access; + vm.resourcesTags = MeanTorrentConfig.meanTorrentConfig.resourcesTags; - vm.groupTorrentType = localStorageService.get('maker_last_selected_type') || 'movie'; vm.searchTags = []; + vm.searchKey = ''; + vm.releaseYear = undefined; + vm.filterType = undefined; + vm.filterHnR = false; + vm.filterTop = false; + vm.filterUnique = false; + vm.filterSale = false; + vm.torrentRLevel = 'level0'; uibButtonConfig.activeClass = 'btn-success'; + vm.torrentType = 'aggregate'; + vm.filterType = localStorageService.get('maker_last_selected_type') || 'aggregate'; + vm.addMemberPopover = { title: 'ABOUT.ADD_MEMBER_TITLE', templateUrl: 'add-member.html', isOpen: false }; + /** + * scope watch vm.filterType + */ + $scope.$watch('vm.filterType', function (newValue, oldValue) { + if (newValue) { + localStorageService.set('maker_last_selected_type', newValue); + } + }); + /** * getTemplateFileContent * @param file @@ -126,10 +146,32 @@ }; /** - * onTypeBtnClick + * onTorrentTypeChanged */ - vm.onTypeBtnClick = function () { - localStorageService.set('maker_last_selected_type', vm.groupTorrentType); + vm.onTorrentTypeChanged = function () { + vm.buildPager(); + localStorageService.set('maker_last_selected_type', vm.filterType); + }; + + /** + * tagsFilter + * @param item + * @returns {boolean} + */ + vm.tagsFilter = function (item) { + var res = false; + + if (vm.filterType === 'aggregate') { + angular.forEach(vm.torrentTypeConfig.value, function (t) { + if (t.enable && item.cats.includes(t.value)) + res = true; + }); + } else { + if (item.cats.includes(vm.filterType)) + res = true; + } + + return res; }; /** @@ -271,11 +313,18 @@ skip: (p - 1) * vm.itemsPerPage, limit: vm.itemsPerPage, sort: vm.sort, - torrent_type: vm.groupTorrentType, + torrent_type: (vm.filterType && vm.filterType !== 'aggregate') ? vm.filterType : (vm.torrentType === 'aggregate' ? 'all' : vm.torrentType), torrent_status: 'reviewed', maker: vm.maker._id, + keys: vm.searchKey, torrent_vip: false, - keys: vm.search + torrent_rlevel: vm.torrentRLevel, + torrent_release: vm.releaseYear, + torrent_tags: vm.searchTags, + torrent_hnr: vm.filterHnR, + torrent_sale: vm.filterSale, + isTop: vm.filterTop, + isUnique: vm.filterUnique }, function (data) { mtDebug.info(data); callback(data); @@ -594,5 +643,124 @@ var e = $('#cog_' + id); e.removeClass('fa-spin'); }; + + /** + * onMoreTagsClicked + */ + vm.onMoreTagsClicked = function () { + var e = $('.more-tags'); + var i = $('#more-tags-icon'); + + if (!e.hasClass('panel-collapsed')) { + e.slideUp(); + e.addClass('panel-collapsed'); + i.removeClass('glyphicon-chevron-up').addClass('glyphicon-chevron-down'); + } else { + e.slideDown(); + e.removeClass('panel-collapsed'); + i.removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up'); + } + }; + + /** + * clearAllCondition + */ + vm.clearAllCondition = function () { + vm.searchKey = ''; + vm.searchTags = []; + $('.btn-tag').removeClass('btn-success').addClass('btn-default'); + vm.releaseYear = undefined; + vm.filterHnR = false; + vm.filterTop = false; + vm.filterUnique = false; + vm.filterSale = false; + vm.torrentRLevel = 'level0'; + vm.filterType = 'aggregate'; + + vm.buildPager(); + }; + + /** + * onTorrentTypeClicked + * @param t + */ + vm.onTorrentTypeClicked = function (t) { + if (vm.filterType === t) { + vm.filterType = vm.torrentType; + } else { + vm.filterType = t; + } + vm.buildPager(); + }; + + /** + * onRLevelClicked + * @param y + */ + vm.onRLevelClicked = function (l) { + if (vm.torrentRLevel === l) { + vm.torrentRLevel = 'level0'; + } else { + vm.torrentRLevel = l; + } + vm.buildPager(); + }; + + /** + * onReleaseClicked + * @param y + */ + vm.onReleaseClicked = function (y) { + if (vm.releaseYear === y) { + vm.releaseYear = undefined; + } else { + vm.releaseYear = y; + } + vm.buildPager(); + }; + + /** + * onHnRClicked + */ + vm.onHnRClicked = function () { + vm.filterHnR = !vm.filterHnR; + vm.buildPager(); + }; + vm.onHnRChanged = function () { + vm.buildPager(); + }; + + /** + * onTopClicked, onTopChanged + */ + vm.onTopClicked = function () { + vm.filterTop = !vm.filterTop; + vm.buildPager(); + }; + vm.onTopChanged = function () { + vm.buildPager(); + }; + + /** + * onUniqueClicked, onUniqueChanged + */ + vm.onUniqueClicked = function () { + vm.filterUnique = !vm.filterUnique; + vm.buildPager(); + }; + vm.onUniqueChanged = function () { + vm.buildPager(); + }; + + /** + * onSaleChanged + */ + vm.onSaleClicked = function () { + vm.filterSale = !vm.filterSale; + vm.buildPager(); + }; + vm.onSaleChanged = function () { + vm.buildPager(); + }; } }()); diff --git a/modules/about/client/templates/score-rules-en.md b/modules/about/client/templates/score-rules-en.md index 1b770419..6bbe1009 100644 --- a/modules/about/client/templates/score-rules-en.md +++ b/modules/about/client/templates/score-rules-en.md @@ -5,7 +5,7 @@   #### :white_small_square: Score increase rules -* Check-in every day to get `%(scoreConfig.action.checkInEveryDay.value)d` scores, continuous check-in to get additional `%(scoreConfig.action.checkInConsDay.value)d` scores per day. +* Check-in every day to get `%(scoreConfig.action.dailyCheckIn.dailyBasicScore)d` scores, continuous check-in to get additional `%(scoreConfig.action.dailyCheckIn.dailyStepScore)d` scores per day, and the max value is `%(scoreConfig.action.dailyCheckIn.dailyMaxScore)d`. * Upload a torrent resource to get `%(scoreConfig.action.uploadTorrent.value)d` scores. * The uploaded torrent resource is set as a recommendation by the administrator to get `%(scoreConfig.action.uploadTorrentBeRecommend.value)d` scores. * Upload a resource subtitle to get `%(scoreConfig.action.uploadSubtitle.value)d` scores. diff --git a/modules/about/client/templates/score-rules-zh-tw.md b/modules/about/client/templates/score-rules-zh-tw.md index af26a106..5f7ab5b9 100644 --- a/modules/about/client/templates/score-rules-zh-tw.md +++ b/modules/about/client/templates/score-rules-zh-tw.md @@ -5,7 +5,7 @@   #### :white_small_square: 積分增加規則 -* 每日簽到獲得 `%(scoreConfig.action.checkInEveryDay.value)d` 積分,連續登記,每天額外增加 `%(scoreConfig.action.checkInConsDay.value)d` 累計積分。 +* 每日簽到獲得 `%(scoreConfig.action.dailyCheckIn.dailyBasicScore)d` 積分,連續簽到,每天額外增加 `%(scoreConfig.action.dailyCheckIn.dailyStepScore)d` 累計積分,`%(scoreConfig.action.dailyCheckIn.dailyMaxScore)d` 積分封頂。 * 每釋出一條種子資源可獲得 `%(scoreConfig.action.uploadTorrent.value)d` 積分。 * 釋出的種子資源被管理員設定為推薦可獲得 `%(scoreConfig.action.uploadTorrentBeRecommend.value)d` 積分。 * 每上傳一條資源字幕可獲得 `%(scoreConfig.action.uploadSubtitle.value)d` 積分。 diff --git a/modules/about/client/templates/score-rules-zh.md b/modules/about/client/templates/score-rules-zh.md index 8490c3b0..cd097653 100644 --- a/modules/about/client/templates/score-rules-zh.md +++ b/modules/about/client/templates/score-rules-zh.md @@ -5,7 +5,7 @@   #### :white_small_square: 积分增加规则 -* 每日签到获得 `%(scoreConfig.action.checkInEveryDay.value)d` 积分,连续登记,每天额外增加 `%(scoreConfig.action.checkInConsDay.value)d` 累计积分。 +* 每日签到获得 `%(scoreConfig.action.dailyCheckIn.dailyBasicScore)d` 积分,连续签到,每天额外增加 `%(scoreConfig.action.dailyCheckIn.dailyStepScore)d` 累计积分,`%(scoreConfig.action.dailyCheckIn.dailyMaxScore)d` 积分封顶。 * 每发布一条种子资源可获得 `%(scoreConfig.action.uploadTorrent.value)d` 积分。 * 发布的种子资源被管理员设置为推荐可获得 `%(scoreConfig.action.uploadTorrentBeRecommend.value)d` 积分。 * 每上传一条资源字幕可获得 `%(scoreConfig.action.uploadSubtitle.value)d` 积分。 diff --git a/modules/about/client/views/maker-view.client.view.html b/modules/about/client/views/maker-view.client.view.html index a153ab4f..a6a1e212 100644 --- a/modules/about/client/views/maker-view.client.view.html +++ b/modules/about/client/views/maker-view.client.view.html @@ -111,22 +111,157 @@
-
+
-
-
- +
+
+

-={{vm.maker.name}}=-    {{'TAGS_SEARCH' | translate}}

+
+
+
+
+ {{'TORRENT_TYPE_LABEL.' + vm.filterType.toUpperCase() | translate}} + + + + {{vm.releaseYear}} + + + + {{ 'TORRENT_RECOMMEND_LEVEL_ITEM.' + vm.torrentRLevel.toUpperCase() | translate}} + + + + {{ 'CA_TORRENT_SALE_NOW' | translate}} + + + + H&R + + + + {{'STATUS_TOP_KEY' | translate}} + + + + {{'STATUS_UNIQUE_KEY' | translate}} + + + + + {{ 'RESOURCESTAGS.' + vm.RTS.getTagTitle(t) + '.' + t.toUpperCase() | translate}} + + + + +
+
+
+
+
{{ 'CA_KEYWORD' | translate}}:
+
+
+
+ +
+
+ + {{ 'MORE_TAGS' | translate}} + + + {{ 'CA_RESET' | translate}} + +
+
+
+ + +
+
-
+
-
- -
@@ -174,120 +305,16 @@ {{ 'TABLE_FIELDS.PUBLISHER' | translate}} - - + +
-

{{vm.tooltipMsg | translate}}

+

{{vm.tooltipMsg | translate}}

- - - -
-
- {{vm.TGI.getTorrentTitle(item)}} - -
- -
-
-
-
- {{vm.TGI.getTorrentDoubleTitle(item)}} - -
- -
{{item.torrent_filename | filename}}
-
{{item.resource_detail_info.subtitle}}
- -
- {{t.name}} -
- -
- - {{ item.resource_detail_info.release_date}} - - {{'STATUS_TOP_KEY' | translate}} - - {{ 'TORRENT_RECOMMEND_LEVEL_ITEM.' + item.torrent_recommended.toUpperCase() | translate}} - - - {{item.torrent_sale_status}} {{item.torrent_sale_expires | unlife}} - - S{{item.torrent_seasons}}E{{item.torrent_episodes}} - - H&R - - VIP - - - - {{ 'RESOURCESTAGS.' + vm.RTS.getTagTitle(t) + '.' + t.toUpperCase() | translate}} - - -
-
-
- - - {{vm.TGI.getVoteTitle(item)}} {{item.resource_detail_info.vote_average | number : 1}} - - {{item.createdat | life}} - {{item.torrent_size | bytes:2}} - -

- - {{item.torrent_seeds}} -

- -

- - {{item.torrent_leechers}} -

- -

- - {{item.torrent_finished}} -

- - - - {{ 'ANONYMOUS' | translate }} - -
- - - - - - -
- - +
diff --git a/modules/about/client/views/maker.client.view.html b/modules/about/client/views/maker.client.view.html index f44e3b7c..2e24c922 100644 --- a/modules/about/client/views/maker.client.view.html +++ b/modules/about/client/views/maker.client.view.html @@ -1,6 +1,6 @@
-
+

{{'ABOUT.MAKER_GROUP' | translate}} @@ -14,7 +14,7 @@

-
+
diff --git a/modules/about/server/controllers/makers.server.controller.js b/modules/about/server/controllers/makers.server.controller.js index e267bc51..c23a03e8 100644 --- a/modules/about/server/controllers/makers.server.controller.js +++ b/modules/about/server/controllers/makers.server.controller.js @@ -153,8 +153,8 @@ exports.delete = function (req, res) { exports.list = function (req, res) { Maker.find() .sort('-torrent_count') - .populate('user', 'username displayName profileImageURL isVip') - .populate('members', 'username displayName profileImageURL isVip') + .populate('user', 'username displayName profileImageURL isVip score uploaded downloaded') + .populate('members', 'username displayName profileImageURL isVip score uploaded downloaded') .exec(function (err, makers) { if (err) { return res.status(422).send({ @@ -323,9 +323,9 @@ exports.makerByID = function (req, res, next, id) { } Maker.findById(id) - .populate('user', 'username displayName profileImageURL isVip') - .populate('members', 'username displayName profileImageURL isVip') - .populate('_ratings.user', 'username displayName profileImageURL isVip uploaded downloaded') + .populate('user', 'username displayName profileImageURL isVip score uploaded downloaded') + .populate('members', 'username displayName profileImageURL isVip score uploaded downloaded') + .populate('_ratings.user', 'username displayName profileImageURL isVip score uploaded downloaded') .exec(function (err, maker) { if (err) { return next(err); diff --git a/modules/announce/server/controllers/announces.server.controller.js b/modules/announce/server/controllers/announces.server.controller.js index 2d4de6c2..f3495bcd 100644 --- a/modules/announce/server/controllers/announces.server.controller.js +++ b/modules/announce/server/controllers/announces.server.controller.js @@ -22,10 +22,8 @@ var path = require('path'), var traceConfig = config.meanTorrentConfig.trace; var scoreConfig = config.meanTorrentConfig.score; var hnrConfig = config.meanTorrentConfig.hitAndRun; -var signConfig = config.meanTorrentConfig.sign; var announceConfig = config.meanTorrentConfig.announce; var globalSalesConfig = config.meanTorrentConfig.torrentGlobalSales; -var examinationConfig = config.meanTorrentConfig.examination; var appConfig = config.meanTorrentConfig.app; @@ -166,8 +164,10 @@ exports.announce = function (req, res) { req.selfpeer = []; req.seeder = false; - mtDebug.debugGreen('', 'ANNOUNCE', true, req.passkeyuser); - mtDebug.debugGreen('============= Announce request =============', 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugGreen('\n\n', 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugGreen('================================================================================', 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugGreen(' ANNOUNCE REQUEST ', 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugGreen('================================================================================', 'ANNOUNCE', true, req.passkeyuser); mtDebug.debugBlue(req.url, 'ANNOUNCE', true, req.passkeyuser); var s = req.url.split('?'); @@ -277,6 +277,8 @@ exports.announce = function (req, res) { torrent data include peers ---------------------------------------------------------------*/ function (done) { + mtDebug.debugRed('req.passkeyuser._id = ' + req.passkeyuser._id.toString(), 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugRed('req.torrent.info_hash = ' + query.info_hash, 'ANNOUNCE', true, req.passkeyuser); Torrent.findOne({ info_hash: query.info_hash }) @@ -334,7 +336,7 @@ exports.announce = function (req, res) { ---------------------------------------------------------------*/ function (done) { mtDebug.debugGreen('---------------' + eventString(query.event) + '----------------', 'ANNOUNCE', true, req.passkeyuser); - if (req.seeder && event(query.event) !== EVENT_COMPLETED) { + if (req.seeder && event(query.event) !== EVENT_COMPLETED && event(query.event) !== EVENT_STOPPED) { if (announceConfig.seedingInFinishedCheck) { if (!req.passkeyuser._id.equals(req.torrent.user._id)) { Finished.findOne({ @@ -363,7 +365,7 @@ exports.announce = function (req, res) { if not find and torrent is h&r and user isn`t vip, then create complete record ---------------------------------------------------------------*/ function (done) { - if (req.torrent.torrent_hnr && !req.passkeyuser.isVip) { + if (hnrConfig.enable && req.torrent.torrent_hnr && !req.passkeyuser.isVip) { Complete.findOne({ torrent: req.torrent._id, user: req.passkeyuser._id @@ -405,8 +407,6 @@ exports.announce = function (req, res) { ----------------------------------------------------------------*/ function (done) { if (event(query.event) === EVENT_STARTED) { - mtDebug.debugGreen('---------------EVENT_STARTED----------------', 'ANNOUNCE', true, req.passkeyuser); - Peer.remove({ torrent: req.torrent._id, _id: {$nin: req.torrent._peers} @@ -429,19 +429,23 @@ exports.announce = function (req, res) { ---------------------------------------------------------------*/ function (done) { if (!req.seeder && !req.passkeyuser.isVip && event(query.event) === EVENT_STARTED) { - if (req.passkeyuser.hnr_warning >= hnrConfig.forbiddenDownloadMinWarningNumber) { - if (!req.torrent.torrent_hnr) { - done(190); - } else { - if (!req.completeTorrent) { - done(191); + if (hnrConfig.enable) { + if (req.passkeyuser.hnr_warning >= hnrConfig.forbiddenDownloadMinWarningNumber) { + if (!req.torrent.torrent_hnr) { + done(190); } else { - if (!req.completeTorrent.hnr_warning) { - done(190); + if (!req.completeTorrent) { + done(191); } else { - done(null); + if (!req.completeTorrent.hnr_warning) { + done(190); + } else { + done(null); + } } } + } else { + done(null); } } else { done(null); @@ -457,7 +461,7 @@ exports.announce = function (req, res) { vip user not checked ---------------------------------------------------------------*/ function (done) { - if (!req.seeder && !req.passkeyuser.isVip && event(query.event) === EVENT_STARTED) { + if (!req.seeder && !req.passkeyuser.isVip && !req.passkeyuser.isOper && event(query.event) === EVENT_STARTED) { if (req.passkeyuser.ratio !== -1 && req.passkeyuser.ratio < announceConfig.downloadCheck.ratio) { var checkTimeBegin = moment(req.passkeyuser.created).add(announceConfig.downloadCheck.checkAfterSignupDays, 'd'); if (checkTimeBegin < moment(Date.now())) { @@ -492,6 +496,9 @@ exports.announce = function (req, res) { } getCurrentPeer(function () { + mtDebug.debugRed('req.currentPeer.isNewCreated = ' + req.currentPeer.isNewCreated, 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugRed('req.currentPeer._id = ' + req.currentPeer._id.toString(), 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugRed('req.currentPeer.torrent._id = ' + req.currentPeer.torrent._id, 'ANNOUNCE', true, req.passkeyuser); done(null); }); }, @@ -503,15 +510,16 @@ exports.announce = function (req, res) { numbers is in setting announceConfig.announceCheck ---------------------------------------------------------------*/ function (done) { + mtDebug.debugGreen('---------------CHECK USER SEED/LEECH COUNT----------------', 'ANNOUNCE', true, req.passkeyuser); var lcount = getSelfLeecherCount(); var scount = getSelfSeederCount(); if (lcount > announceConfig.announceCheck.maxLeechNumberPerUserPerTorrent && !req.seeder) { - mtDebug.debugYellow('getSelfLeecherCount = ' + lcount, 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugRed('getSelfLeecherCount = ' + lcount, 'ANNOUNCE', true, req.passkeyuser); removeCurrPeer(); done(180); } else if (scount > announceConfig.announceCheck.maxSeedNumberPerUserPerTorrent && req.seeder) { - mtDebug.debugYellow('getSelfSeederCount = ' + scount, 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugRed('getSelfSeederCount = ' + scount, 'ANNOUNCE', true, req.passkeyuser); removeCurrPeer(); done(181); } else { @@ -555,25 +563,24 @@ exports.announce = function (req, res) { } //write user uploaded and downloaded - req.passkeyuser.uploaded += u; - req.passkeyuser.downloaded += d; - req.passkeyuser.true_uploaded += curru; - req.passkeyuser.true_downloaded += currd; - //write examination uploaded and downloaded - if (common.examinationIsValid(req.passkeyuser)) { - req.passkeyuser.examinationData.uploaded = req.passkeyuser.examinationData.uploaded || 0; - req.passkeyuser.examinationData.uploaded += u; - req.passkeyuser.examinationData.downloaded = req.passkeyuser.examinationData.downloaded || 0; - req.passkeyuser.examinationData.downloaded += d; + var up_d = { + uploaded: u, + downloaded: d, + true_uploaded: curru, + true_downloaded: currd + }; + mtDebug.debugRed(JSON.stringify(up_d), 'ANNOUNCE', true, req.passkeyuser); - var uploadFinished = req.passkeyuser.examinationData.uploaded >= examinationConfig.incrementData.upload; - var downloadFinished = req.passkeyuser.examinationData.downloaded >= examinationConfig.incrementData.download; - var scoreFinished = req.passkeyuser.examinationData.score >= examinationConfig.incrementData.score; - req.passkeyuser.examinationData.isFinished = uploadFinished && downloadFinished && scoreFinished; - req.passkeyuser.examinationData.finishedTime = req.passkeyuser.examinationData.isFinished ? Date.now() : null; - req.passkeyuser.markModified('examinationData'); + if (common.examinationIsValid(req.passkeyuser)) { + up_d['examinationData.uploaded'] = u; + up_d['examinationData.downloaded'] = d; + mtDebug.debugGreen('---------------WRITE EXAMINATION DATA----------------', 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugRed('examinationData.uploaded: ' + u + ', examinationData.downloaded: ' + d, 'ANNOUNCE', true, req.passkeyuser); } - req.passkeyuser.save(); + + req.passkeyuser.update({ + $inc: up_d + }).exec(); //write peer speed var sp = {}; @@ -642,6 +649,7 @@ exports.announce = function (req, res) { } totalScore = Math.round(totalScore * 100) / 100; scoreUpdate(req, req.passkeyuser, action, totalScore, false); + mtDebug.debugRed('announce score: ' + totalScore, 'ANNOUNCE', true, req.passkeyuser); } } @@ -691,10 +699,13 @@ exports.announce = function (req, res) { } //write peer data - req.currentPeer.peer_uploaded = query.uploaded; - req.currentPeer.peer_downloaded = query.downloaded; - req.currentPeer.peer_left = query.peer_left; - req.currentPeer.save(); + req.currentPeer.update({ + $set: { + peer_uploaded: query.uploaded, + peer_downloaded: query.downloaded, + peer_left: query.left + } + }).exec(); done(null, curru, currd); }, @@ -704,11 +715,14 @@ exports.announce = function (req, res) { ---------------------------------------------------------------*/ function (curru, currd, done) { if (curru > 0 || currd > 0) { - if (req.completeTorrent) { + if (hnrConfig.enable && req.completeTorrent) { mtDebug.debugGreen('---------------WRITE COMPLETE DATA----------------', 'ANNOUNCE', true, req.passkeyuser); - req.completeTorrent.total_uploaded += curru; - req.completeTorrent.total_downloaded += currd; - req.completeTorrent.save(function () { + req.completeTorrent.update({ + $inc: { + total_uploaded: curru, + total_downloaded: currd + } + }, function () { done(null); }); } else { @@ -725,10 +739,13 @@ exports.announce = function (req, res) { ---------------------------------------------------------------*/ function (done) { if (!req.currentPeer.isNewCreated) { - if (req.completeTorrent && req.completeTorrent.complete && event(query.event) !== EVENT_COMPLETED) { + if (hnrConfig.enable && req.completeTorrent && req.completeTorrent.complete && event(query.event) !== EVENT_COMPLETED) { mtDebug.debugGreen('---------------UPDATE H&R COMPLETE TOTAL_SEED_TIME----------------', 'ANNOUNCE', true, req.passkeyuser); - req.completeTorrent.total_seed_time += (Date.now() - req.currentPeer.last_announce_at); - req.completeTorrent.save(function () { + req.completeTorrent.update({ + $inc: { + total_seed_time: (Date.now() - req.currentPeer.last_announce_at) + } + }, function () { done(null); }); } else { @@ -745,7 +762,7 @@ exports.announce = function (req, res) { ---------------------------------------------------------------*/ function (done) { if (!req.currentPeer.isNewCreated) { - if (req.seeder && event(query.event) !== EVENT_COMPLETED) { + if (req.seeder && event(query.event) !== EVENT_COMPLETED && event(query.event) !== EVENT_STARTED) { mtDebug.debugGreen('---------------UPLOAD SCORE THROUGH SEED TIMED----------------', 'ANNOUNCE', true, req.passkeyuser); var action = scoreConfig.action.seedTimed; @@ -779,6 +796,7 @@ exports.announce = function (req, res) { } seedScore = Math.round(seedScore * 100) / 100; scoreUpdate(req, req.passkeyuser, action, seedScore); + mtDebug.debugRed('seed timed score: ' + seedScore, 'ANNOUNCE', true, req.passkeyuser); done(null); } else { @@ -803,12 +821,11 @@ exports.announce = function (req, res) { mtDebug.debugGreen('---------------UPDATE LAST_ANNOUNCE_AT----------------', 'ANNOUNCE', true, req.passkeyuser); if (!req.currentPeer.isNewCreated) { - req.currentPeer.last_announce_at = Date.now(); - req.currentPeer.save(); - } - - if (req.completeTorrent) { - req.completeTorrent.globalUpdateMethod(); + req.currentPeer.update({ + $set: { + last_announce_at: Date.now() + } + }).exec(); } done(null); @@ -820,22 +837,6 @@ exports.announce = function (req, res) { function (done) { if (event(query.event) === EVENT_COMPLETED) { mtDebug.debugGreen('---------------EVENT_COMPLETED----------------', 'ANNOUNCE', true, req.passkeyuser); - //write completed torrent data into finished - var finished = new Finished(); - finished.user = req.passkeyuser; - finished.torrent = req.torrent; - finished.user_ip = req.cf_ip; - finished.user_agent = req.get('User-Agent'); - finished.user_port = query.port; - finished.save(); - - traceLogCreate(req, traceConfig.action.userAnnounceFinished, { - user: req.passkeyuser._id, - torrent: req.torrent._id, - agent: req.get('User-Agent'), - ip: req.cf_ip, - port: query.port - }); doCompleteEvent(function () { done(null); @@ -850,7 +851,7 @@ exports.announce = function (req, res) { ---------------------------------------------------------------*/ function (done) { if (!req.currentPeer.isNewCreated) { - if (req.completeTorrent && event(query.event) !== EVENT_COMPLETED) { + if (hnrConfig.enable && req.completeTorrent && event(query.event) !== EVENT_COMPLETED) { mtDebug.debugGreen('---------------COUNT H&R WARNING FOR USER----------------', 'ANNOUNCE', true, req.passkeyuser); req.completeTorrent.countHnRWarning(false, true); } @@ -867,7 +868,7 @@ exports.announce = function (req, res) { if (event(query.event) === EVENT_STOPPED) { mtDebug.debugGreen('---------------EVENT_STOPPED----------------', 'ANNOUNCE', true, req.passkeyuser); - if (req.completeTorrent) { + if (hnrConfig.enable && req.completeTorrent) { req.completeTorrent.countHnRWarning(true, false); } removeCurrPeer(function () { @@ -908,8 +909,9 @@ exports.announce = function (req, res) { var len = writePeers(peerBuffer, want, req.torrent._peers); peerBuffer = peerBuffer.slice(0, len); + mtDebug.debugGreen('---------------SEND RESPONSE TO USER----------------', 'ANNOUNCE', true, req.passkeyuser); var resp = 'd8:intervali' + ANNOUNCE_INTERVAL + 'e8:completei' + req.torrent.torrent_seeds + 'e10:incompletei' + req.torrent.torrent_leechers + 'e10:downloadedi' + req.torrent.torrent_finished + 'e5:peers' + len + ':'; - mtDebug.debugGreen(resp, 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugRed(resp, 'ANNOUNCE', true, req.passkeyuser); res.writeHead(200, { 'Content-Length': resp.length + peerBuffer.length + 1, @@ -924,6 +926,25 @@ exports.announce = function (req, res) { mtDebug.debug(peerBuffer, 'ANNOUNCE', true, req.passkeyuser); } + done(null); + }, + + /** + * update user, torrent, peer, complete + * @param done + */ + function (done) { + req.passkeyuser.globalUpdateMethod(true); + req.torrent.globalUpdateMethod(true); + + if (req.currentPeer) { + req.currentPeer.globalUpdateMethod(true); + } + + if (hnrConfig.enable && req.completeTorrent) { + req.completeTorrent.globalUpdateMethod(true); + } + done(null, 'done'); } ], function (err, reason) { @@ -940,8 +961,22 @@ exports.announce = function (req, res) { req.selfpeer.every(function (p) { if (p.peer_id === query.peer_id) { req.currentPeer = p; + req.currentPeer.torrent = req.torrent; req.currentPeer.isNewCreated = false; + //if find peer_id, but some time some client (like qbittorrent 4.1.0) the ip or port is changed, update it + if ((req.currentPeer.peer_ip !== req.cf_ip || req.currentPeer.peer_port !== query.port) && query.port !== 0) { + req.currentPeer.peer_ip = req.cf_ip; + req.currentPeer.peer_port = query.port; + + req.currentPeer.update({ + $set: { + peer_ip: req.cf_ip, + peer_port: query.port + } + }).exec(); + } + if (req.seeder && req.currentPeer.peer_status !== PEERSTATE_SEEDER && event(query.event) !== EVENT_COMPLETED) { mtDebug.debugGreen('---------------PEER STATUS CHANGED: Seeder----------------', 'ANNOUNCE', true, req.passkeyuser); doCompleteEvent(function () { @@ -966,19 +1001,48 @@ exports.announce = function (req, res) { * doCompleteEvent */ function doCompleteEvent(callback) { - req.currentPeer.peer_status = PEERSTATE_SEEDER; - req.currentPeer.save(); + //write completed torrent data into finished + var finished = new Finished(); + finished.user = req.passkeyuser; + finished.torrent = req.torrent; + finished.user_ip = req.cf_ip; + finished.user_agent = req.get('User-Agent'); + finished.user_port = query.port; + finished.save(); - req.torrent.torrent_finished += 1; - req.torrent.save(); + traceLogCreate(req, traceConfig.action.userAnnounceFinished, { + user: req.passkeyuser._id, + torrent: req.torrent._id, + agent: req.get('User-Agent'), + ip: req.cf_ip, + port: query.port + }); - req.passkeyuser.finished += 1; - req.passkeyuser.save(); + req.currentPeer.update({ + $set: { + peer_status: PEERSTATE_SEEDER + } + }).exec(); + + req.torrent.update({ + $inc: { + torrent_finished: 1 + } + }).exec(); + + req.passkeyuser.update({ + $inc: { + finished: 1 + } + }).exec(); //update completeTorrent complete status - if (req.completeTorrent) { - req.completeTorrent.complete = true; - req.completeTorrent.save(function () { + if (hnrConfig.enable && req.completeTorrent) { + req.completeTorrent.update({ + $set: { + complete: true + } + }, function () { if (callback) callback(); }); } else { @@ -1017,12 +1081,10 @@ exports.announce = function (req, res) { req.passkeyuser.addLeechedIp(peer.peer_ip); req.passkeyuser.addClientAgent(peer.user_agent); - peer.save(function (err) { - if (!err) { - req.currentPeer = peer; - mtDebug.debugGreen('---------------createCurrentPeer()----------------', 'ANNOUNCE', true, req.passkeyuser); - if (callback) callback(); - } + peer.save(function () { + req.currentPeer = peer; + mtDebug.debugGreen('---------------createCurrentPeer()----------------', 'ANNOUNCE', true, req.passkeyuser); + if (callback) callback(); }); } @@ -1032,13 +1094,23 @@ exports.announce = function (req, res) { function removeCurrPeer(callback) { req.selfpeer.splice(req.selfpeer.indexOf(req.currentPeer), 1); - req.torrent.update({ - $pull: {_peers: req.currentPeer._id} - }).exec(); + req.torrent._peers.forEach(function (_p) { + if (_p._id.equals(req.currentPeer._id)) { + req.torrent._peers.pull(_p); + req.torrent.save(); + } + }); - req.currentPeer.remove(function () { - if (callback) callback(); - mtDebug.debugGreen('---------------removeCurrPeer()----------------', 'ANNOUNCE', true, req.passkeyuser); + Peer.findById(req.currentPeer._id, function (err, _p) { + _p.remove(function (err) { + if (err) { + mtDebug.debugGreen('---------------removeCurrPeer(): Error----------------', 'ANNOUNCE', true, req.passkeyuser); + } else { + mtDebug.debugGreen('---------------removeCurrPeer()----------------', 'ANNOUNCE', true, req.passkeyuser); + } + req.currentPeer = undefined; + if (callback) callback(); + }); }); } @@ -1090,13 +1162,15 @@ exports.announce = function (req, res) { var udr = {}; var sale = req.torrent.torrent_sale_status; - var start = moment(globalSalesConfig.global.startAt, globalSalesConfig.global.timeFormats).utc().valueOf(); + var start = moment(globalSalesConfig.global.startAt, globalSalesConfig.global.timeFormats).valueOf(); var end = start + globalSalesConfig.global.expires; var now = Date.now(); isGlobalSaleValid = (now > start && now < end && globalSalesConfig.global.value) ? true : false; if (isGlobalSaleValid && globalSalesConfig.global.value) { sale = globalSalesConfig.global.value; + mtDebug.debugRed('isGlobalSaleValid = ' + isGlobalSaleValid, 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugRed('global sale value = ' + sale, 'ANNOUNCE', true, req.passkeyuser); } switch (sale) { @@ -1185,6 +1259,10 @@ exports.announce = function (req, res) { var c = 0; if (!req.seeder && event(query.event) !== EVENT_STOPPED && event(query.event) !== EVENT_COMPLETED) { + mtDebug.debugGreen('---------------GET PEERS LIST----------------', 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugRed('want.count = ' + count, 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debugRed('peers.length = ' + peers.length, 'ANNOUNCE', true, req.passkeyuser); + var p; var bc; var m = Math.min(peers.length, count); @@ -1201,14 +1279,14 @@ exports.announce = function (req, res) { if (p.last_announce_at > (Date.now() - announceConfig.announceInterval - announceConfig.announceIdleTime)) { //do not send inactive peer if (p.user.equals(req.passkeyuser._id)) { if (announceConfig.peersCheck.peersSendListIncludeOwnSeed) { - mtDebug.debug(p._id.toString(), 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debug(p._id.toString() + ' IP:' + p.peer_ip + ' PORT:' + p.peer_port, 'ANNOUNCE', true, req.passkeyuser); bc = compact(p); if (bc) { bc.copy(buf, c++ * PEER_COMPACT_SIZE); } } } else { - mtDebug.debug(p._id.toString(), 'ANNOUNCE', true, req.passkeyuser); + mtDebug.debug(p._id.toString() + ' IP:' + p.peer_ip + ' PORT:' + p.peer_port, 'ANNOUNCE', true, req.passkeyuser); bc = compact(p); if (bc) { bc.copy(buf, c++ * PEER_COMPACT_SIZE); diff --git a/modules/check/client/check.client.module.js b/modules/check/client/check.client.module.js new file mode 100644 index 00000000..766781f8 --- /dev/null +++ b/modules/check/client/check.client.module.js @@ -0,0 +1,9 @@ +(function (app) { + 'use strict'; + + app.registerModule('check', ['core']);// The core module is required for special route handling; see /core/client/config/core.client.routes + app.registerModule('check.admin', ['core.admin']); + app.registerModule('check.admin.routes', ['core.admin.routes']); + app.registerModule('check.services'); + app.registerModule('check.routes', ['ui.router', 'core.routes', 'check.services']); +}(ApplicationConfiguration)); diff --git a/modules/check/client/services/check.client.service.js b/modules/check/client/services/check.client.service.js new file mode 100644 index 00000000..b4577736 --- /dev/null +++ b/modules/check/client/services/check.client.service.js @@ -0,0 +1,24 @@ +(function () { + 'use strict'; + + // Users service used for communicating with the users REST endpoint + angular + .module('check.services') + .factory('CheckService', CheckService); + + CheckService.$inject = ['$resource']; + + function CheckService($resource) { + var Check = $resource('/api/check', {}, { + get: { + method: 'GET' + }, + update: { + method: 'PUT' + } + }); + + return Check; + } + +}()); diff --git a/modules/check/server/config/check.server.config.js b/modules/check/server/config/check.server.config.js new file mode 100644 index 00000000..629c3606 --- /dev/null +++ b/modules/check/server/config/check.server.config.js @@ -0,0 +1,14 @@ +'use strict'; + +/** + * Module dependencies + */ +var path = require('path'), + config = require(path.resolve('./config/config')); + +/** + * Module init function. + */ +module.exports = function (app, db) { + +}; diff --git a/modules/check/server/controllers/check.server.controller.js b/modules/check/server/controllers/check.server.controller.js new file mode 100644 index 00000000..92d93843 --- /dev/null +++ b/modules/check/server/controllers/check.server.controller.js @@ -0,0 +1,114 @@ +'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')), + moment = require('moment'), + User = mongoose.model('User'), + Check = mongoose.model('Check'), + scoreUpdate = require(path.resolve('./config/lib/score')).update; + +var mtDebug = require(path.resolve('./config/lib/debug')); +var scoreConfig = config.meanTorrentConfig.score; +var appConfig = config.meanTorrentConfig.app; + +/** + * Show the current collection + */ +exports.get = function (req, res) { + if (!req.user) { + return res.status(403).json({ + message: 'SERVER.USER_IS_NOT_AUTHORIZED' + }); + } else { + Check.findOne({user: req.user._id}, function (err, ck) { + if (err) { + return res.status(422).send({ + message: errorHandler.getErrorMessage(err) + }); + } else { + if (!ck) { + return res.status(422).send({ + message: 'no check data founded' + }); + } else { + var oldCheckDate = moment(moment(ck.lastCheckedAt).utcOffset(appConfig.dbTimeZone).format('YYYY-MM-DD')); + var now = moment(moment().utcOffset(appConfig.dbTimeZone).format('YYYY-MM-DD')); + var diff = now.diff(oldCheckDate, 'days'); + + var nck = ck.toJSON(); + nck.todayIsDone = (diff === 0 ? true : false); + res.json(nck); + } + } + }); + } + +}; + +/** + * Update an collection + */ +exports.check = function (req, res) { + if (!req.user) { + return res.status(403).json({ + message: 'SERVER.USER_IS_NOT_AUTHORIZED' + }); + } else { + var score = 0; + Check.findOne({user: req.user._id}, function (err, ck) { + if (!ck) { + ck = new Check(); + ck.user = req.user._id; + ck.keepDays = 1; + ck.save(); + + score = scoreConfig.action.dailyCheckIn.dailyBasicScore + (ck.keepDays - 1) * scoreConfig.action.dailyCheckIn.dailyStepScore; + score = Math.min(score, scoreConfig.action.dailyCheckIn.dailyMaxScore); + scoreUpdate(req, req.user, scoreConfig.action.dailyCheckIn, score); + + ck = ck.toJSON(); + ck.todayIsDone = true; + res.json(ck); + } else { + var oldCheckDate = moment(moment(ck.lastCheckedAt).utcOffset(appConfig.dbTimeZone).format('YYYY-MM-DD')); + var now = moment(moment().utcOffset(appConfig.dbTimeZone).format('YYYY-MM-DD')); + var diff = now.diff(oldCheckDate, 'days'); + + if (diff === 0) { + return res.status(422).json({ + message: 'SERVER.YOU_ALREADY_CHECK_IN' + }); + } else if (diff === 1) { + ck.keepDays += 1; + ck.lastCheckedAt = Date.now(); + ck.save(); + + score = scoreConfig.action.dailyCheckIn.dailyBasicScore + (ck.keepDays - 1) * scoreConfig.action.dailyCheckIn.dailyStepScore; + score = Math.min(score, scoreConfig.action.dailyCheckIn.dailyMaxScore); + scoreUpdate(req, req.user, scoreConfig.action.dailyCheckIn, score); + + ck = ck.toJSON(); + ck.todayIsDone = true; + res.json(ck); + } else { + ck.keepDays = 1; + ck.lastCheckedAt = Date.now(); + ck.save(); + + score = scoreConfig.action.dailyCheckIn.dailyBasicScore + (ck.keepDays - 1) * scoreConfig.action.dailyCheckIn.dailyStepScore; + score = Math.min(score, scoreConfig.action.dailyCheckIn.dailyMaxScore); + scoreUpdate(req, req.user, scoreConfig.action.dailyCheckIn, score); + + ck = ck.toJSON(); + ck.todayIsDone = true; + res.json(ck); + } + } + }); + } +}; diff --git a/modules/check/server/models/check.server.model.js b/modules/check/server/models/check.server.model.js new file mode 100644 index 00000000..5db3e04f --- /dev/null +++ b/modules/check/server/models/check.server.model.js @@ -0,0 +1,30 @@ +'use strict'; + +/** + * Module dependencies + */ +var mongoose = require('mongoose'), + Schema = mongoose.Schema; + +/** + * Check in Schema + */ +var CheckSchema = new Schema({ + user: { + type: Schema.Types.ObjectId, + ref: 'User' + }, + keepDays: { + type: Number, + default: 0 + }, + lastCheckedAt: { + type: Date, + default: Date.now + } +}, {usePushEach: true}); + + +CheckSchema.index({user: 1, createdAt: -1}); + +mongoose.model('Check', CheckSchema); diff --git a/modules/check/server/routes/check.server.routes.js b/modules/check/server/routes/check.server.routes.js new file mode 100644 index 00000000..05691f65 --- /dev/null +++ b/modules/check/server/routes/check.server.routes.js @@ -0,0 +1,8 @@ +'use strict'; + +module.exports = function (app) { + var check = require('../controllers/check.server.controller'); + + app.route('/api/check').get(check.get); + app.route('/api/check').put(check.check); +}; diff --git a/modules/collections/client/views/collection-view.client.view.html b/modules/collections/client/views/collection-view.client.view.html index a48ce0ab..e331929f 100644 --- a/modules/collections/client/views/collection-view.client.view.html +++ b/modules/collections/client/views/collection-view.client.view.html @@ -95,121 +95,7 @@ {{ 'TABLE_FIELDS.PUBLISHER' | translate}} - - - - -
-
- {{vm.TGI.getTorrentTitle(item)}} - -
- -
-
-
-
- {{vm.TGI.getTorrentDoubleTitle(item)}} - -
- -
{{item.torrent_filename | filename}}
-
{{item.resource_detail_info.subtitle}}
- -
- {{t.name}} -
- -
- - {{ item.resource_detail_info.release_date}} - - {{'STATUS_TOP_KEY' | translate}} - - {{ 'TORRENT_RECOMMEND_LEVEL_ITEM.' + item.torrent_recommended.toUpperCase() | translate}} - - - {{item.torrent_sale_status}} {{item.torrent_sale_expires | unlife}} - - S{{item.torrent_seasons}}E{{item.torrent_episodes}} - - H&R - - VIP - - - - {{ 'RESOURCESTAGS.' + vm.RTS.getTagTitle(t) + '.' + t.toUpperCase() | translate}} - - -
-
-
- - - {{vm.TGI.getVoteTitle(item)}} {{item.resource_detail_info.vote_average | number : 1}} - - {{item.createdat | life}} - {{item.torrent_size | bytes:2}} - -

- - {{item.torrent_seeds}} -

- -

- - {{item.torrent_leechers}} -

- -

- - {{item.torrent_finished}} -

- - -
- - {{ 'ANONYMOUS' | translate }} - -
- - -
-
- -
- - - - -
- - - +
diff --git a/modules/collections/server/controllers/collections.server.controller.js b/modules/collections/server/controllers/collections.server.controller.js index f01de5a4..aee77af3 100644 --- a/modules/collections/server/controllers/collections.server.controller.js +++ b/modules/collections/server/controllers/collections.server.controller.js @@ -279,7 +279,7 @@ exports.list = function (req, res) { var findQuery = function (callback) { Collection.find(condition) .sort('-recommend_level -ordered_at -created_at') - .populate('user', 'username displayName profileImageURL isVip') + .populate('user', 'username displayName profileImageURL isVip score uploaded downloaded') .populate('torrents') .skip(skip) .limit(limit) @@ -312,12 +312,12 @@ exports.collectionByID = function (req, res, next, id) { } Collection.findById(id) - .populate('user', 'username displayName profileImageURL isVip') + .populate('user', 'username displayName profileImageURL isVip score uploaded downloaded') .populate({ path: 'torrents', populate: [{ path: 'user', - select: 'username displayName profileImageURL isVip' + select: 'username displayName profileImageURL isVip score uploaded downloaded' }, { path: 'maker', select: 'name' diff --git a/modules/core/client/app/trans-string-en.js b/modules/core/client/app/trans-string-en.js index 920a609d..3e359c98 100644 --- a/modules/core/client/app/trans-string-en.js +++ b/modules/core/client/app/trans-string-en.js @@ -23,6 +23,7 @@ VALUE_CUSTOM: 'CUSTOM', VALUE_SELECT_ALL: 'Select All', BTN_REMOVE: 'Remove', + BTN_CONTINUE: 'Continue', //Support SUPPORT_GROUP_NAME_DESC: 'Management group', @@ -131,6 +132,15 @@ } }, + CHECK: { + BTN_CHECK_IN: 'Check In', + CHECK_TOOLTIP: '#### `mine.pt` invites you to participate in the daily check in. Now check in to get `{{todayScore}}` scores and renew tomorrow to get `{{tomorrowScore}}` scores!', + CHECK_TODAY_NOT: '#### You have not checked in yet. Last check in at: `{{checkTime | date: "yyyy-MM-dd HH:mm"}}`. Now check in to get `{{todayScore}}` scores and renew tomorrow to get `{{tomorrowScore}}` scores!', + CHECK_TODAY_DONE: '#### You have checked in to `{{keepDays}}` days in a row, today check in at: `{{checkTime | date: "yyyy-MM-dd HH:mm"}}`, you have got `{{todayScore}}` scores and renew tomorrow to get `{{tomorrowScore}}` scores, please be careful not to interrupt!', + CHECK_SUCCESSFULLY: 'Check in successfully', + CHECK_ERROR: 'Check in failed' + }, + //element title/alt TITLE_ALT: { SEEDS: 'Seeds users', @@ -162,16 +172,12 @@ TITLE_LIFE: 'orderBy life', //status - UPLOADED_SPEED: 'U/S', - DOWNLOADED_RATIO: 'D/R', - DOWNLOADED_SPEED: 'D/S', - UPLOADED_RATIO_PERCENT: 'U/R/P', + UPLOADED_SPEED: 'U/S/R', + DOWNLOADED_SPEED: 'D/S/P', UP_DOWN_RATIO_TIME: 'U/D/R/T', - ABBR_UPLOADED_SPEED: 'uploaded/speed', - ABBR_DOWNLOADED_RATIO: 'downloaded/ratio', - ABBR_DOWNLOADED_SPEED: 'downloaded/speed', - ABBR_UPLOADED_RATIO_PERCENT: 'uploaded/ratio/percent', + ABBR_UPLOADED_SPEED: 'uploaded/speed/ratio', + ABBR_DOWNLOADED_SPEED: 'downloaded/speed/percent', ABBR_UP_DOWN_RATIO_TIME: 'uploaded/downloaded/ratio/seeding time', //peer @@ -336,17 +342,20 @@ TAGS_SEARCH_GLOBAL: 'Tags Search - Global', CA_KEYWORD: 'Keyword', CA_TORRENT_STATUS: 'Torrent status', + CA_TORRENT_ATTR: 'Torrent attribute', CA_TORRENT_HNR: 'Hit and Run', CA_TORRENT_SALE_STATUS: 'Sale Status', CA_TORRENT_SALE_NOW: 'Saling', CA_TORRENT_VIP: 'VIP resources', + CA_TORRENT_TOP: 'Top Status', + CA_TORRENT_UNIQUE: 'Unique Status', CA_RESOURCE_TYPE: 'Resource type', - CA_MAKE_RSS_URL: 'Rss Url', - DESC_MAKE_RSS_URL: 'This RSS url is make with above filter conditions, you can used it in the BT client (such as uTorrent) that supports the RSS subscription function to download torrent and resources automatic.', + DESC_MAKE_RSS_URL: 'Based on the RSS address generated by the current search conditions, click Copy to clipboard.', COPY_TO_CLIPBOARD: 'Copy to clipboard', COPY_LINK_TO_CLIPBOARD: 'Copy torrent file download link to clipboard', COPY_LINK_TEXT: 'Copy torrent file link', COPY_TO_CLIPBOARD_SUCCESSFULLY: 'Copy data to clipboard successfully!', + TORRENT_LABEL_LINK: 'Torrent Link', PH_KEYWORD: 'Search keyword', CLEAR_ALL_CONDITION: 'Clear All Condition', MORE_TAGS: 'More Tags', @@ -371,7 +380,13 @@ TORRENT_THUMBS_FAILED: 'Thumbs-up for torrent failed', TORRENT_RATING_SUCCESSFULLY: 'Rating torrent successfully', TORRENT_RATING_FAILED: 'Rating torrent failed', - EDIT_THIS_OVERVIEW: 'Edit this Overview', + EDIT_THIS_OVERVIEW: 'Edit this overview', + VIEW_ORIGINAL_MEDIA_INFO: 'View original media info', + VIEW_FORMATTED_MEDIA_INFO: 'View formatted media info', + EDIT_THIS_MEDIA_INFO: 'Edit media info', + SAVE_THIS_MEDIA_INFO: 'Save media info', + EDIT_TORRENT_NFO_SUCCESSFULLY: 'Torrent media info edited successfully', + EDIT_TORRENT_NFO_FAILED: 'Torrent media info edited failed', IMG_PAGE_INFO: 'Current: {{index}} / {{total}}', ANNOUNCE_URL: 'Announce Url', @@ -382,10 +397,12 @@ ALL_FILES_LIST: 'Files List', VIDEO_SIZE: 'Video Size', UPLOAD_TIME: 'Upload Time', - VIDEO_SALE_INFO: 'Video Sale Info', SALE_EXPIRES_TIME: 'expires', TORRENT_STATUS_TOP_TITLE: 'Top Level', + TORRENT_STATUS_UNIQUE: 'Unique resource', + TORRENT_STATUS_UNIQUE_TITLE: 'Unique resource, no transfer', STATUS_TOP_KEY: 'TOP', + STATUS_UNIQUE_KEY: 'UNIQUE', UPLOAD_SUBTITLE: 'Upload Subtitle file', SUBTITLE_LIST: 'Subtitle list', SUBTITLE_RULES: { @@ -422,6 +439,8 @@ ADMIN_BASIC_UNSET_VIP: 'UnsetVIP', ADMIN_BASIC_SET_TOP: 'SetTop', ADMIN_BASIC_UNSET_TOP: 'UnsetTop', + ADMIN_BASIC_SET_UNIQUE: 'SetUnique', + ADMIN_BASIC_UNSET_UNIQUE: 'UnsetUnique', ADMIN_BASIC_TYPE_SET: 'Sale Type', ADMIN_SALE_TYPE_SET: 'Sale Type Set', ADMIN_BASIC_RLEVEL_SET: 'Recommend Level', @@ -465,6 +484,8 @@ TORRENT_TOGGLE_VIP_FAILED: 'Torrent toggle VIP tag failed', TORRENT_TOGGLE_TOP_SUCCESSFULLY: 'Torrent toggle TOP tag successfully', TORRENT_TOGGLE_TOP_FAILED: 'Torrent toggle TOP tag failed', + TORRENT_TOGGLE_UNIQUE_SUCCESSFULLY: 'Torrent toggle Unique tag successfully', + TORRENT_TOGGLE_UNIQUE_FAILED: 'Torrent toggle Unique tag failed', TORRENT_SETTAGS_SUCCESSFULLY: 'Torrent tags set successfully', TORRENT_SETTAGS_ERROR: 'Torrent tags set failed', @@ -510,7 +531,7 @@ SELECT_TORRENT_FILE: '1. Please select the torrent file', SELECT_FILE: 'Select file', DO_UPLOAD: 'Upload', - ENTER_TMDB_ID: '3. Please enter theMovieDB id', + ENTER_TMDB_ID: '3 Please enter theMovieDB id', LOAD_TMDB_INFO: 'Load info', SEARCH_FROM_TMDB: 'Search From TMDB', TMDB_ID: 'TMDB ID', @@ -553,8 +574,8 @@ ERROR_ONLY_IMAGE: 'Only image files support(gif, png, bmp, jpg, jpeg)', FILE_TYPE_ERROR: 'File type that is not accepted', - ENTER_RESOURCE_TITLE: '3. Please enter the resource title and desc', - RESOURCE_TITLE: 'resource title', + ENTER_RESOURCE_TITLE: '4.1 Please enter the resource main title and sub title', + RESOURCE_TITLE: 'resource main title', RESOURCE_SUB_TITLE: 'resource sub title', SELECT_RESOURCE_IMAGE: '3.1 Please select resource cover image', ENTER_RESOURCE_DETAIL_INFO: '4. Please enter the resource detail info', @@ -848,9 +869,10 @@ COMMENT_REMOVE_ERROR: 'Comment removed failed!', DESC_LIST: '### NOTE: \n - The list contains only the last `{{days}}` days of the requests. \n - If your response is accepted, the requestor\'s reward score will be automatically transferred to your account. \n - Only the torrents reviewed by the administrator can be accepted by the requestor. \n - The requester can only accept one of the responses. \n - If your response is complains, your account may be punished, Please respond to the user\'s request carefully.', DESC_MY: '### NOTE: \n - If you accept a response, your reward score will be transferred to the respondent\'s account that you accept. \n - Only the torrents reviewed by the administrator can be accepted by you. \n - You can only accept one of the responses. \n - The request over `{{days}}` days has expired and cannot accept the response, you can only post the request again. \n - If your score is maliciously damaged, Please contact our {{sNameDesc | translate}} by **[Message](/messages/send?to={{sName}})** or **[Email](mailto:{{sMail}})** to complaints.', - DESC_ADD: '### NOTE: \n - Each request will be automatically deducted from `{{add_score}}` points, but your reward score will only be transferred to the responder\'s account that you eventually accept. \n - Only the torrents reviewed by the administrator can be accepted by you. \n - Each request is only valid for `{{days}}` days. After expiry, you can only post the request again. \n - Please give a clear resources description of your request when you post the request.', + DESC_ADD: '### NOTE: \n - Each request will be automatically deducted from `{{add_score}}` points, and your reward score will only be transferred to the responder\'s account that you eventually accept. \n - Only the torrents reviewed by the administrator can be accepted by you. \n - Each request is only valid for `{{days}}` days. After expiry, you can only post the request again. \n - Please give a clear resources description of your request when you post the request.', DESC_RES: '### NOTE: \n - If requestor accept your response, the reward score will be transferred to your account. \n - Only the torrents reviewed by the administrator can be accepted by requestor. \n - Requestor can only accept one of the responses.', - DESC_VIEW: '### NOTE: \n - If you want to response a request, please upload the torrent file and seed, Please respond to the user\'s request carefully. \n - If you are a requestor, you can choose a responder and accept it, and only the torrents reviewed by the administrator can be accepted. \n - If you accept a response, your reward score will be transferred to the respondent\'s account that you accept. \n - The request over `{{days}}` days has expired and cannot accept or response(upload).' + DESC_VIEW: '### NOTE: \n - If you want to response a request, please upload the torrent file and seed, Please respond to the user\'s request carefully. \n - If you are a requestor, you can choose a responder and accept it, and only the torrents reviewed by the administrator can be accepted. \n - If you accept a response, your reward score will be transferred to the respondent\'s account that you accept. \n - The request over `{{days}}` days has expired and cannot accept or response(upload).', + CAN_NTO_TO_ADD: 'Each request will be automatically deducted from `{{add_score}}` points,your scores are too small, please try again later ...' }, //user status @@ -1060,13 +1082,12 @@ MESSAGE_TYPE_USER: 'User message', MESSAGE_TYPE_SYSTEM: 'System message', MESSAGE_TYPE_ADVERT: 'Advert message', - MESSAGE_TYPE_NOTICE: 'Notice message', MESSAGE_TYPE_SERVER: 'Server notice', MESSAGE_SEND_SUCCESSFULLY: 'Message send successfully', MESSAGE_SEND_FAILED: 'Message send failed', MESSAGE_DELETED_SUCCESSFULLY: 'Message deleted successfully', MESSAGE_DELETED_ERROR: 'Message deleted failed', - MESSAGE_SERVER_TOOLTIP: '

Server message

Server message is send to you by server automatic when you do some operations or your account status make some change or some important things about you, There may be a lot of messages, so you need to check and delete them in time. The system only keeps the last {{count}} messages.', + MESSAGE_SERVER_TOOLTIP: '

Server message

Server message is send to you by server automatic when you do some operations or your account status make some change or some important things about you, There may be a lot of messages, so you need to check and delete them in time. The system keeps only the messages of the last {{days}} days.', MESSAGE_DELETE_CONFIRM_OK: 'Delete', MESSAGE_DELETE_CONFIRM_CANCEL: 'Cancel', @@ -1438,7 +1459,7 @@ TYPE: { SELF: 'Medium', BLU_RAY: 'Blu-ray', - WEB: 'Web', + WEB: 'WEB', REMUX: 'Remux', ENCODE: 'Encode', HDTV: 'HDTV' @@ -1460,14 +1481,23 @@ X265: 'x265' }, + VISION: { + SELF: 'Video Vision', + DOLBY: 'DolbyVision', + HDR10PLUS: 'HDR10+', + HDR10: 'HDR10', + HDR: 'HDR', + SDR: 'SDR' + }, + AUDIO: { SELF: 'Audio Codec', DTS_X: 'DTS:X', ATMOS: 'Atmos', DTS_HD: 'DTS-HD', - TRUE_HD: 'TRUE-HD', + TRUE_HD: 'True-HD', DTS: 'DTS', - AC3: 'AC3', + AC3: 'AC-3', AAC: 'AAC' }, @@ -1572,6 +1602,45 @@ } }, + MEDIAINFO: { + GENERAL: { + SELF: 'General Info', + FILESIZE: 'File Size', + RUNTIME: 'Runtime', + DURATION: 'Duration', + OVERALLBITRATE: 'Overall Bit Rate' + }, + VIDEO: { + SELF: 'Video Info', + FORMAT: 'Format', + DURATION: 'Duration', + BITRATE: 'Bit Rate', + WIDTH: 'Width', + HEIGHT: 'Height', + FRAMERATEMODE: 'Frame Rate Mode', + FRAMERATE: 'Frame Rate', + BITDEPTH: 'Bit Depth', + STREAMSIZE: 'Stream Size', + WRITINGLIBRARY: 'Writing Library', + RESOLUTION: 'Resolution', + CODEC: 'Video Codec' + }, + AUDIO: { + SELF: 'Audio Info', + FORMAT: 'Format', + BITRATEMODE: 'Bit Rate Mode', + BITRATE: 'Bit Rate', + CHANNEL: 'Channel', + LANGUAGE: 'Language', + INFO: 'Audio Info', + CODEC: 'Codec' + }, + TEXT: { + SELF: 'Subtitle Info', + LANGUAGE: 'Language' + } + }, + //server returned string SERVER: { USER_IS_NOT_AUTHORIZED: 'User is not authorized', @@ -1606,10 +1675,12 @@ INVITE_MAIL_SEND_FAILED: 'Invitation mail send failed (SERVER)', EMAIL_ADDRESS_IS_NOT_ALLOW: 'The domain of this email address is not allowable from server', INFO_HASH_IS_EMPTY: 'Info hash field of torrent file is empty', - INFO_HASH_ALREADY_EXISTS: 'This info hash value is already exists', + INFO_HASH_ALREADY_EXISTS: 'This info hash value is already exists, {{hash}}', + FILE_ALREADY_EXISTS: 'This torrent file name already exists, {{filename}}', UPLOAD_ACCESS_DENY: 'System only accepts resources group to upload torrents', READ_TORRENT_FILE_FAILD: 'The torrent file parsing error. Please check your torrent file to check if some of the necessary information is missing', - MOVE_TORRENT_FILE_ERROR: 'The torrent file was moved incorrectly. Please do not repeat the submit operation quickly or the uploaded torrent file is missing.' + MOVE_TORRENT_FILE_ERROR: 'The torrent file was moved incorrectly. Please do not repeat the submit operation quickly or the uploaded torrent file is missing.', + YOU_ALREADY_CHECK_IN: 'You already checked in today' }, //server message string, content string support markdown and emoji @@ -1682,6 +1753,9 @@ TITLE_TORRENT_TOP_CHANGED: 'Torrent TOP status changed', CONTENT_TORRENT_TOP_CHANGED: '### TOP status changed! \n You uploaded torrent [{{torrent_file_name}}](/torrents/{{torrent_id}}) TOP status was changed by user [{{by_name}}](/userinfo/{{by_id}}), current status is **{{top_status}}**.', + TITLE_TORRENT_UNIQUE_CHANGED: 'Torrent Unique status changed', + CONTENT_TORRENT_UNIQUE_CHANGED: '### Unique status changed! \n You uploaded torrent [{{torrent_file_name}}](/torrents/{{torrent_id}}) Unique status was changed by user [{{by_name}}](/userinfo/{{by_id}}), current status is **{{unique_status}}**.', + TITLE_TORRENT_SALE_CHANGED: 'Torrent sale status changed', CONTENT_TORRENT_SALE_CHANGED: '### Sale status changed! \n You uploaded torrent [{{torrent_file_name}}](/torrents/{{torrent_id}}) sale status was changed by user [{{by_name}}](/userinfo/{{by_id}}), current status is **{{sale_status}}**.', @@ -1710,7 +1784,7 @@ SITE_NOTICE: { GLOBAL_SALES_NOTICE: '### IMPORTANT NOTICE: \n :radio: **Happy new year 2018**, **{{site_name}}** global sale is coming, sales value is **{{sale_value}}**, sales start at **{{sale_start_at | date: "yyyy-MM-dd HH:mm"}}** and continued **{{sale_days}}** days and end at **{{sale_end_at | date: "yyyy-MM-dd HH:mm"}}**, Thank you for all the help and support you have been giving us all the time!', EXAMINATION_NOTICE: '### IMPORTANT NOTICE: \n :radio: **{{site_name}}** will take a new incremental examination from **{{examination_start_at | date: "yyyy-MM-dd HH:mm"}}** to **{{examination_end_at | date: "yyyy-MM-dd HH:mm"}}**, Incremental data requirements: upload **{{data_upload | bytes:2}}**, download **{{data_download | bytes:2}}**, score **{{data_score}}**, Please arrange your own time and hope to pass the exam smoothly. All **VIP** users and registered new users within **{{join_days}}** days are exempt, The unfinished user account will be banned. [Get more detail at here]({{detail_url}}).', - EXAMINATION_STATUS: '### EXAMINATION STATUS: \n
Examination time:
{{examination_start_at | date: "yyyy-MM-dd HH:mm"}} - {{examination_end_at | date: "yyyy-MM-dd HH:mm"}}
Incremental data of upload:
{{data_upload | bytes:2}}, finished {{finished_upload | bytes:2}}
Incremental data of download:
{{data_download | bytes:2}}, finished {{finished_download | bytes:2}}
Incremental data of score:
{{data_score | number: 2}}, finished {{finished_score | number: 2}}
Examination status:
{{data_status | translate}}
[more detail]({{detail_url}})
', + EXAMINATION_STATUS: '### EXAMINATION STATUS: \n
Examination time:
{{examination_start_at | date: "yyyy-MM-dd HH:mm"}} - {{examination_end_at | date: "yyyy-MM-dd HH:mm"}}
Incremental data of upload:
{{data_upload | bytes:2}}, finished {{finished_upload | bytes:2}}
Incremental data of download:
{{data_download | bytes:2}}, finished {{finished_download | bytes:2}}
Incremental data of score:
{{data_score | score: 2}}, finished {{finished_score | score: 2}}
Examination status:
{{data_status | translate}}
[more detail]({{detail_url}})
', EXAMINATION_FINISHED: 'Finished', EXAMINATION_UNFINISHED: 'Unfinished' } diff --git a/modules/core/client/app/trans-string-zh-tw.js b/modules/core/client/app/trans-string-zh-tw.js index dee65660..dbfe7cbf 100644 --- a/modules/core/client/app/trans-string-zh-tw.js +++ b/modules/core/client/app/trans-string-zh-tw.js @@ -1466,7 +1466,7 @@ }, RESOLUTION: { - SELF: '解析度', + SELF: '分辨率', S4K: '4K', S1080P: '1080p', S1080I: '1080i', @@ -1756,6 +1756,9 @@ TITLE_TORRENT_UNIQUE_CHANGED: '上傳的種子 禁轉 狀態改變', CONTENT_TORRENT_UNIQUE_CHANGED: '### 禁轉 狀態改變! \n 您上傳的種子 [{{torrent_file_name}}](/torrents/{{torrent_id}}) 禁轉 狀態已經由管理員用戶 [{{by_name}}](/userinfo/{{by_id}}) 修改, 當前狀態為: **{{unique_status}}**.', + TITLE_TORRENT_UNIQUE_CHANGED: '上傳的種子 禁轉 狀態改變', + CONTENT_TORRENT_UNIQUE_CHANGED: '### 禁轉狀態改變! \n 您上傳的種子[{{torrent_file_name}}](/torrents/{{torrent_id}}) 禁轉狀態已經由管理員用戶[{{by_name}}]( /userinfo/{{by_id}}) 修改, 當前狀態為: **{{unique_status}}**.', + TITLE_TORRENT_SALE_CHANGED: '上傳的種子促銷狀態改變', CONTENT_TORRENT_SALE_CHANGED: '### 促銷狀態改變! \n 您上傳的種子 [{{torrent_file_name}}](/torrents/{{torrent_id}}) 促銷狀態已經由管理員用戶 [{{by_name}}](/userinfo/{{by_id}}) 修改, 當前狀態為: **{{sale_status}}**.', diff --git a/modules/core/client/app/trans-string-zh.js b/modules/core/client/app/trans-string-zh.js index 1e73dee7..5caf3ecb 100644 --- a/modules/core/client/app/trans-string-zh.js +++ b/modules/core/client/app/trans-string-zh.js @@ -23,6 +23,7 @@ VALUE_CUSTOM: '自定义', VALUE_SELECT_ALL: '全选', BTN_REMOVE: '删除', + BTN_CONTINUE: '继续', //Support SUPPORT_GROUP_NAME_DESC: '管理组', @@ -131,6 +132,15 @@ } }, + CHECK: { + BTN_CHECK_IN: '我要签到', + CHECK_TOOLTIP: '#### `mine.pt` 邀请您参加每日签到,现在签到可获得 `{{todayScore}}` 积分,明日续签可获得 `{{tomorrowScore}}` 积分哦!', + CHECK_TODAY_NOT: '#### 您今日还未签到,上次签到:`{{checkTime | date: "yyyy-MM-dd HH:mm"}}`,现在签到可获得 `{{todayScore}}` 积分,明日续签到可获得 `{{tomorrowScore}}` 积分哦!', + CHECK_TODAY_DONE: '#### 您已连续签到 `{{keepDays}}` 天,今日签到时间:`{{checkTime | date: "yyyy-MM-dd HH:mm"}}`,已经获得 `{{todayScore}}` 积分,明日续签到可获得 `{{tomorrowScore}}` 积分,请注意不要中断哦!', + CHECK_SUCCESSFULLY: '签到成功', + CHECK_ERROR: '签到失败' + }, + //element title/alt TITLE_ALT: { SEEDS: '做种用户数', @@ -162,16 +172,12 @@ TITLE_LIFE: '按上传时间排序', //status - UPLOADED_SPEED: '上/速', - DOWNLOADED_RATIO: '下/比', - DOWNLOADED_SPEED: '下/速', - UPLOADED_RATIO_PERCENT: '上/比/进度', + UPLOADED_SPEED: '上/速/分享', + DOWNLOADED_SPEED: '下/速/进度', UP_DOWN_RATIO_TIME: '上/下/比/时', - ABBR_UPLOADED_SPEED: '上传量/速度', - ABBR_DOWNLOADED_RATIO: '下载量/分享率', - ABBR_DOWNLOADED_SPEED: '下载量/速度', - ABBR_UPLOADED_RATIO_PERCENT: '上传量/分享率/完成百分比', + ABBR_UPLOADED_SPEED: '上传量/速度/分享率', + ABBR_DOWNLOADED_SPEED: '下载量/速度/完成进度', ABBR_UP_DOWN_RATIO_TIME: '上传量/下载量/分享率/做种时间', //peer @@ -336,20 +342,23 @@ TAGS_SEARCH_GLOBAL: '种子搜索 - 全局', CA_KEYWORD: '关键字', CA_TORRENT_STATUS: '种子状态', + CA_TORRENT_ATTR: '种子属性', CA_TORRENT_HNR: 'H&R 黑种', CA_TORRENT_SALE_STATUS: '促销状态', CA_TORRENT_SALE_NOW: '正在促销', CA_TORRENT_VIP: 'VIP 资源', + CA_TORRENT_TOP: '置顶状态', + CA_TORRENT_UNIQUE: '禁转状态', CA_RESOURCE_TYPE: '资源类型', - CA_MAKE_RSS_URL: 'RSS连接', - DESC_MAKE_RSS_URL: '这个 RSS 地址是通过上面的过滤条件生成的,您可以使用支持 RSS 订阅功能的BT客户端(如uTorrent)来自动下载您想要的这些种子和资源文件.', + DESC_MAKE_RSS_URL: '根据当前检索条件生成的 RSS 地址, 点击复制到粘贴版.', COPY_TO_CLIPBOARD: '复制到剪切板', COPY_LINK_TO_CLIPBOARD: '复制种子文件下载连接到剪切板', COPY_LINK_TEXT: '复制种子文件地址', COPY_TO_CLIPBOARD_SUCCESSFULLY: '内容已复制到剪切板!', + TORRENT_LABEL_LINK: '种子连接', PH_KEYWORD: '搜索关键字', CLEAR_ALL_CONDITION: '清空所有条件', - MORE_TAGS: '显示更多标签', + MORE_TAGS: '更多标签', CA_RESET: '重置条件', TORRENT_DOWNLOAD_ERROR: '种子文件下载失败', TORRENTS_DOWNLOAD_SUCCESSFULLY: '种子文件下载成功', @@ -372,6 +381,12 @@ TORRENT_RATING_SUCCESSFULLY: '为种子投票成功', TORRENT_RATING_FAILED: '为种子投票失败', EDIT_THIS_OVERVIEW: '编辑详情介绍', + VIEW_ORIGINAL_MEDIA_INFO: '查看原始的媒体信息', + VIEW_FORMATTED_MEDIA_INFO: '查看格式化的媒体信息', + EDIT_THIS_MEDIA_INFO: '编辑媒体信息', + SAVE_THIS_MEDIA_INFO: '保存媒体信息', + EDIT_TORRENT_NFO_SUCCESSFULLY: '种子媒体信息编辑成功', + EDIT_TORRENT_NFO_FAILED: '种子媒体信息编辑失败', IMG_PAGE_INFO: '当前页: {{index}} / {{total}}', ANNOUNCE_URL: 'Tracker 地址', @@ -382,10 +397,12 @@ ALL_FILES_LIST: '文件清单', VIDEO_SIZE: '视频文件大小', UPLOAD_TIME: '上传时间', - VIDEO_SALE_INFO: '视频促销信息', SALE_EXPIRES_TIME: '过期', TORRENT_STATUS_TOP_TITLE: '置顶推荐', + TORRENT_STATUS_UNIQUE: '禁转资源', + TORRENT_STATUS_UNIQUE_TITLE: '禁转资源,禁止转发', STATUS_TOP_KEY: '置顶', + STATUS_UNIQUE_KEY: '禁转', UPLOAD_SUBTITLE: '上传字幕文件', SUBTITLE_LIST: '字幕列表', SUBTITLE_RULES: { @@ -422,6 +439,8 @@ ADMIN_BASIC_UNSET_VIP: '取消VIP', ADMIN_BASIC_SET_TOP: '设为置顶', ADMIN_BASIC_UNSET_TOP: '取消置顶', + ADMIN_BASIC_SET_UNIQUE: '设为禁转', + ADMIN_BASIC_UNSET_UNIQUE: '取消禁转', ADMIN_BASIC_TYPE_SET: '设置促销', ADMIN_SALE_TYPE_SET: '种子促销类型', ADMIN_BASIC_RLEVEL_SET: '推荐级别', @@ -465,6 +484,8 @@ TORRENT_TOGGLE_VIP_FAILED: '改变种子VIP标签失败', TORRENT_TOGGLE_TOP_SUCCESSFULLY: '改变种子置顶状态成功', TORRENT_TOGGLE_TOP_FAILED: '改变种子置顶状态失败', + TORRENT_TOGGLE_UNIQUE_SUCCESSFULLY: '改变种子禁转状态成功', + TORRENT_TOGGLE_UNIQUE_FAILED: '改变种子禁转状态失败', TORRENT_SETTAGS_SUCCESSFULLY: '种子属性标签设置成功', TORRENT_SETTAGS_ERROR: '种子属性标签设置失败', @@ -510,7 +531,7 @@ SELECT_TORRENT_FILE: '1. 请选择种子文件', SELECT_FILE: '选择文件', DO_UPLOAD: '上传', - ENTER_TMDB_ID: '3. 请输入TMDB_ID', + ENTER_TMDB_ID: '3 请输入TMDB_ID', LOAD_TMDB_INFO: '检索信息', TMDB_ID: 'TMDB ID', SEARCH_FROM_TMDB: '从 TMDB 搜索', @@ -553,8 +574,8 @@ ERROR_ONLY_IMAGE: '此处只支持图片文件上传(gif, png, bmp, jpg, jpeg)', FILE_TYPE_ERROR: '文件类型不被接受', - ENTER_RESOURCE_TITLE: '3. 请输入资源标题与描述', - RESOURCE_TITLE: '资源标题', + ENTER_RESOURCE_TITLE: '4.1 请输入资源主副标题', + RESOURCE_TITLE: '资源主标题', RESOURCE_SUB_TITLE: '资源副标题', SELECT_RESOURCE_IMAGE: '3.1 请选择资源封面图片', ENTER_RESOURCE_DETAIL_INFO: '4. 请输入资源详细信息', @@ -850,7 +871,8 @@ DESC_MY: '### 提示: \n - 如果您接受一个响应, 您的悬赏积分就会转入您接受的响应者的帐户. \n - 只有被管理员审核通过的种子才能被您接受. \n - 您只能接受多个响应中的一个. \n - 超过 `{{days}}` 天的请求已经过期且不能接受响应, 如果需要您只能再次发起请求. \n - 如果您的积分受到恶意损害, 请给{{sNameDesc | translate}}发送 **[消息](/messages/send?to={{sName}})** 或 **[邮件](mailto:{{sMail}})** 进行投诉.', DESC_ADD: '### 提示: \n - 每发布一个请求会被自动扣除 `{{add_score}}` 积分, 而您的悬赏积分会转入您最终接受的响应者的帐户. \n - 只有被管理员审核通过的种子才能被您接受. \n - 每一个发布的请求只有 `{{days}}` 天的有效期, 过期后您只能再次发起请求. \n - 请在发布请求时明确描述您对资源的要求.', DESC_RES: '### NOTE: \n - 如果请求者接受了您的响应, 悬赏积分将自动转入您的帐户. \n - 只有被管理员审核通过的种子才能被请求者接受. \n - 请求者只会接受多个响应中的一个.', - DESC_VIEW: '### NOTE: \n - 如果您是一个响应者, 请上传您的种子文件并开始做种, 请认真响应用户的请求. \n - 如果您是一个请求者, 您可以选择一个响应并接受它, 只有被管理员审核通过的种子才能被您接受. \n - 如果您接受一个响应, 您的悬赏积分就会转入您接受的响应者的帐户. \n - 超过 `{{days}}` 天的请求已经过期且不能接受响应或上传种子.' + DESC_VIEW: '### NOTE: \n - 如果您是一个响应者, 请上传您的种子文件并开始做种, 请认真响应用户的请求. \n - 如果您是一个请求者, 您可以选择一个响应并接受它, 只有被管理员审核通过的种子才能被您接受. \n - 如果您接受一个响应, 您的悬赏积分就会转入您接受的响应者的帐户. \n - 超过 `{{days}}` 天的请求已经过期且不能接受响应或上传种子.', + CAN_NTO_TO_ADD: '每发布一个请求会被自动扣除 `{{add_score}}` 积分,您的积分太少,请稍候再试 ...' }, //user status @@ -1058,15 +1080,14 @@ BUTTON_MESSAGE_REPLY: '回复', MESSAGE_TYPE_USER: '用户消息', - MESSAGE_TYPE_SYSTEM: '全局系统消息', - MESSAGE_TYPE_ADVERT: '全局广告推送', - MESSAGE_TYPE_NOTICE: '全局系统通知', + MESSAGE_TYPE_SYSTEM: '系统消息', + MESSAGE_TYPE_ADVERT: '广告推送', MESSAGE_TYPE_SERVER: '服务器事件通知', MESSAGE_SEND_SUCCESSFULLY: '消息发送成功', MESSAGE_SEND_FAILED: '消息发送失败', MESSAGE_DELETED_SUCCESSFULLY: '消息删除成功', MESSAGE_DELETED_ERROR: '消息删除失败', - MESSAGE_SERVER_TOOLTIP: '

服务器事件通知

当您做了一些重要的操作或者您的帐户状态发生变化以及某些重要事情与您有关时,服务器会自动发送消息给您,这种消息可能会很多,所以请及时查看及删除,服务器只保留最后的 {{count}} 条消息.', + MESSAGE_SERVER_TOOLTIP: '

服务器事件通知

当您做了一些重要的操作或者您的帐户状态发生变化以及某些重要事情与您有关时,服务器会自动发送消息给您,这种消息可能会很多,所以请及时查看及删除,系统只保留最近 {{days}} 天的消息。', MESSAGE_DELETE_CONFIRM_OK: '删除', MESSAGE_DELETE_CONFIRM_CANCEL: '取消', @@ -1438,7 +1459,7 @@ TYPE: { SELF: '媒介', BLU_RAY: 'Blu-ray', - WEB: 'Web', + WEB: 'WEB', REMUX: 'Remux', ENCODE: 'Encode', HDTV: 'HDTV' @@ -1460,14 +1481,23 @@ X265: 'x265' }, + VISION: { + SELF: '视频色彩', + DOLBY: 'DolbyVision', + HDR10PLUS: 'HDR10+', + HDR10: 'HDR10', + HDR: 'HDR', + SDR: 'SDR' + }, + AUDIO: { SELF: '音频编码', DTS_X: 'DTS:X', ATMOS: 'Atmos', DTS_HD: 'DTS-HD', - TRUE_HD: 'TRUE-HD', + TRUE_HD: 'True-HD', DTS: 'DTS', - AC3: 'AC3', + AC3: 'AC-3', AAC: 'AAC' }, @@ -1572,6 +1602,45 @@ } }, + MEDIAINFO: { + GENERAL: { + SELF: '资源通用信息', + FILESIZE: '总体积', + RUNTIME: '总时长', + DURATION: '总时长', + OVERALLBITRATE: '总码率' + }, + VIDEO: { + SELF: '视频信息', + FORMAT: '格式', + DURATION: '时长', + BITRATE: '码率', + WIDTH: '分辨率.宽', + HEIGHT: '分辨率.高', + FRAMERATEMODE: '帧率模式', + FRAMERATE: '帧率', + BITDEPTH: '位深', + STREAMSIZE: '体积', + WRITINGLIBRARY: '编码方式', + RESOLUTION: '分辨率', + CODEC: '编码' + }, + AUDIO: { + SELF: '音频信息', + FORMAT: '格式', + BITRATEMODE: '码率模式', + BITRATE: '码率', + CHANNEL: '声道', + LANGUAGE: '音轨', + INFO: '音轨信息', + CODEC: '编码' + }, + TEXT: { + SELF: '字幕信息', + LANGUAGE: '语言' + } + }, + //server returned string SERVER: { USER_IS_NOT_AUTHORIZED: '用户身份验证未通过', @@ -1606,10 +1675,12 @@ INVITE_MAIL_SEND_FAILED: '邀请邮件发送失败(SERVER)', EMAIL_ADDRESS_IS_NOT_ALLOW: '该邮件地址不允许被邀请或注册', INFO_HASH_IS_EMPTY: 'Info hash 字段值不能为空', - INFO_HASH_ALREADY_EXISTS: '该 info hash 值已经存在,不能重复提交', + INFO_HASH_ALREADY_EXISTS: '该 info hash 值已经存在,不能重复提交, {{hash}}', + FILE_ALREADY_EXISTS: '该种子文件名已经存在, {{filename}}', UPLOAD_ACCESS_DENY: '当前系统只接受资源制作小组上传种子', READ_TORRENT_FILE_FAILD: '种子文件解析错误,请检查您的种子文件,看是否缺少某些必要信息', - MOVE_TORRENT_FILE_ERROR: '种子文件移动错误,请不要快速重复进行提交操作或者上传的种子文件已丢失' + MOVE_TORRENT_FILE_ERROR: '种子文件移动错误,请不要快速重复进行提交操作或者上传的种子文件已丢失', + YOU_ALREADY_CHECK_IN: '您今天已经签过到了,不能重复签到' }, //server message string, content string support markdown and emoji @@ -1682,6 +1753,9 @@ TITLE_TORRENT_TOP_CHANGED: '上传的种子 置顶 状态改变', CONTENT_TORRENT_TOP_CHANGED: '### 置顶 状态改变! \n 您上传的种子 [{{torrent_file_name}}](/torrents/{{torrent_id}}) 置顶 状态已经由管理员用户 [{{by_name}}](/userinfo/{{by_id}}) 修改, 当前状态为: **{{top_status}}**.', + TITLE_TORRENT_UNIQUE_CHANGED: '上传的种子 禁转 状态改变', + CONTENT_TORRENT_UNIQUE_CHANGED: '### 禁转 状态改变! \n 您上传的种子 [{{torrent_file_name}}](/torrents/{{torrent_id}}) 禁转 状态已经由管理员用户 [{{by_name}}](/userinfo/{{by_id}}) 修改, 当前状态为: **{{unique_status}}**.', + TITLE_TORRENT_SALE_CHANGED: '上传的种子促销状态改变', CONTENT_TORRENT_SALE_CHANGED: '### 促销状态改变! \n 您上传的种子 [{{torrent_file_name}}](/torrents/{{torrent_id}}) 促销状态已经由管理员用户 [{{by_name}}](/userinfo/{{by_id}}) 修改, 当前状态为: **{{sale_status}}**.', @@ -1710,7 +1784,7 @@ SITE_NOTICE: { GLOBAL_SALES_NOTICE: '### 重要通知! \n :radio: **新年快乐 2018**, **{{site_name}}** 新年促销活动已准备就绪, 促销活动类型为 **{{sale_value}}** , 活动将开始于 **{{sale_start_at | date: "yyyy-MM-dd HH:mm"}}** 并持续 **{{sale_days}}** 天, 结束于 **{{sale_end_at | date: "yyyy-MM-dd HH:mm"}}**, 并感谢所有会员用户一直以来给予我们的帮助与支持!', EXAMINATION_NOTICE: '### 重要通知! \n :radio: **{{site_name}}** 将从 **{{examination_start_at | date: "yyyy-MM-dd HH:mm"}}** 到 **{{examination_end_at | date: "yyyy-MM-dd HH:mm"}}** 进行一次新的增量考核, 增量数据要求: 上传 **{{data_upload | bytes:2}}**, 下载 **{{data_download | bytes:2}}**, 积分 **{{data_score}}**, 请各位会员安排好自已的时间,并祝您顺利通过这次考核. 所有 **vip** 用户以及最近 **{{join_days}}** 天内注册的新用户免考, 考核未达标的用户帐号将会被禁止.[更多详情请看这里]({{detail_url}}).', - EXAMINATION_STATUS: '### 考核状态信息: \n
考核时间区间:
{{examination_start_at | date: "yyyy-MM-dd HH:mm"}} - {{examination_end_at | date: "yyyy-MM-dd HH:mm"}}
增量上传数据:
{{data_upload | bytes:2}}, 已完成 {{finished_upload | bytes:2}}
增量下载数据:
{{data_download | bytes:2}}, 已完成 {{finished_download | bytes:2}}
增量积分:
{{data_score | number: 2}}, 已完成 {{finished_score | number: 2}}
当前考核状态:
{{data_status | translate}}
[更多详情]({{detail_url}})
', + EXAMINATION_STATUS: '### 考核状态信息: \n
考核时间区间:
{{examination_start_at | date: "yyyy-MM-dd HH:mm"}} - {{examination_end_at | date: "yyyy-MM-dd HH:mm"}}
增量上传数据:
{{data_upload | bytes:2}}, 已完成 {{finished_upload | bytes:2}}
增量下载数据:
{{data_download | bytes:2}}, 已完成 {{finished_download | bytes:2}}
增量积分:
{{data_score | score: 2}}, 已完成 {{finished_score | score: 2}}
当前考核状态:
{{data_status | translate}}
[更多详情]({{detail_url}})
', EXAMINATION_FINISHED: '已通过', EXAMINATION_UNFINISHED: '未通过' } diff --git a/modules/core/client/controllers/header.client.controller.js b/modules/core/client/controllers/header.client.controller.js index f519a558..3647e687 100644 --- a/modules/core/client/controllers/header.client.controller.js +++ b/modules/core/client/controllers/header.client.controller.js @@ -6,13 +6,14 @@ .controller('HeaderController', HeaderController); HeaderController.$inject = ['$scope', '$state', '$timeout', '$translate', 'Authentication', 'menuService', 'MeanTorrentConfig', 'localStorageService', - 'ScoreLevelService', 'InvitationsService', '$interval', 'MessagesService', 'TorrentsService', 'UsersService', 'DebugConsoleService']; + 'ScoreLevelService', 'InvitationsService', '$interval', 'MessagesService', 'TorrentsService', 'UsersService', 'DebugConsoleService', 'getStorageLangService']; function HeaderController($scope, $state, $timeout, $translate, Authentication, menuService, MeanTorrentConfig, localStorageService, ScoreLevelService, - InvitationsService, $interval, MessagesService, TorrentsService, UsersService, mtDebug) { + InvitationsService, $interval, MessagesService, TorrentsService, UsersService, mtDebug, getStorageLangService) { $scope.$state = $state; var vm = this; vm.user = Authentication.user; + vm.langService = getStorageLangService; vm.language = MeanTorrentConfig.meanTorrentConfig.language; vm.announceConfig = MeanTorrentConfig.meanTorrentConfig.announce; vm.messageConfig = MeanTorrentConfig.meanTorrentConfig.messages; @@ -46,12 +47,50 @@ }); }); + /** + * bindHoverToMenuItem + */ + vm.bindHoverToMenuItem = function () { + //set menu bar opened when hover + $timeout(function () { + $('div.navbar-mt ul.nav li.dropdown').off('mouseenter mouseleave').hover(function (evt) { + if (!$(this).hasClass('open')) { + $(this).find('.dropdown-toggle', this).trigger('click'); + bindClick($(this)); + } else { + bindClick($(this)); + } + }, function (evt) { + $(this).off('click'); + if ($(this).hasClass('open')) { + $(this).find('.dropdown-toggle', this).trigger('click'); + } + }); + + $('div.navbar-mt ul.nav li.dropdown ul.dropdown-menu').off('mouseenter mouseleave').hover(function (evt) { + $(this).parent().off('click'); + }, function (evt) { + bindClick($(this).parent()); + }); + }, 0); + + function bindClick(ele) { + ele.off('click').on('click', function (e) { + var sta = ele.find('.dropdown-toggle', ele).attr('alt'); + if (sta) { + $state.go(sta); + } + }); + } + }; + /** * auth-user-changed */ $scope.$on('auth-user-changed', function (event, args) { vm.user = Authentication.user; vm.scoreLevelData = vm.user ? ScoreLevelService.getScoreLevelJson(vm.user.score) : undefined; + vm.bindHoverToMenuItem(); vm.getInvitationsCount(); vm.getWarning(); vm.getCountUnread(); @@ -149,12 +188,14 @@ * checkHnRWarning */ vm.checkHnRWarning = function () { - vm.getWarning(); - $interval(vm.getWarning, vm.hnrConfig.checkWaringInterval); + if (vm.hnrConfig.enable) { + vm.getWarning(); + $interval(vm.getWarning, vm.hnrConfig.checkWaringInterval); + } }; vm.getWarning = function () { - if (Authentication.user) { + if (Authentication.user && vm.hnrConfig.enable) { UsersService.getUserWarningNumber() .then(function (data) { vm.user.hnr_warning = Authentication.user.hnr_warning = data.hnr_warning; diff --git a/modules/core/client/controllers/home.client.controller.js b/modules/core/client/controllers/home.client.controller.js index 5981f1bf..4ec46805 100644 --- a/modules/core/client/controllers/home.client.controller.js +++ b/modules/core/client/controllers/home.client.controller.js @@ -5,13 +5,13 @@ .module('core') .controller('HomeController', HomeController); - HomeController.$inject = ['$scope', '$state', '$translate', 'Authentication', 'TorrentsService', 'Notification', 'MeanTorrentConfig', + HomeController.$inject = ['$scope', '$state', '$translate', 'Authentication', 'TorrentsService', 'NotifycationService', 'MeanTorrentConfig', 'getStorageLangService', 'ForumsService', '$timeout', 'localStorageService', 'TopicsService', 'TorrentGetInfoServices', 'DebugConsoleService', - 'marked']; + 'marked', 'CheckService']; - function HomeController($scope, $state, $translate, Authentication, TorrentsService, Notification, MeanTorrentConfig, getStorageLangService, + function HomeController($scope, $state, $translate, Authentication, TorrentsService, NotifycationService, MeanTorrentConfig, getStorageLangService, ForumsService, $timeout, localStorageService, TopicsService, TorrentGetInfoServices, mtDebug, - marked) { + marked, CheckService) { var vm = this; vm.user = Authentication.user; vm.appConfig = MeanTorrentConfig.meanTorrentConfig.app; @@ -23,8 +23,10 @@ vm.announceConfig = MeanTorrentConfig.meanTorrentConfig.announce; vm.homeConfig = MeanTorrentConfig.meanTorrentConfig.home; vm.supportConfig = MeanTorrentConfig.meanTorrentConfig.support; + vm.scoreConfig = MeanTorrentConfig.meanTorrentConfig.score; vm.searchType = 'torrents'; + vm.checkData = undefined; /** * initBodyBackground @@ -89,7 +91,7 @@ $state.go('forums.search', {forumId: fid, keys: vm.searchKeys}); } else { //search from torrents - $state.go('torrents.search', {keys: vm.searchKeys}); + $state.go('torrents.aggregate', {keys: vm.searchKeys}); } } }; @@ -146,9 +148,9 @@ var e = $('.sales_notice'); $timeout(function () { - e.slideDown(800); + e.slideDown(500); e.removeClass('panel-collapsed'); - }, 1000); + }, 300); }; /** @@ -195,9 +197,9 @@ var e = $('.examination_notice'); $timeout(function () { - e.slideDown(800); + e.slideDown(500); e.removeClass('panel-collapsed'); - }, 1000); + }, 300); }; /** @@ -247,9 +249,9 @@ var e = $('.examination_status'); $timeout(function () { - e.slideDown(800); + e.slideDown(500); e.removeClass('panel-collapsed'); - }, 1000); + }, 300); }; /** @@ -323,5 +325,86 @@ return marked(ts, {sanitize: true}); }; + /** + * getMyCheckData + */ + vm.getMyCheckData = function () { + CheckService.get(function (res) { + mtDebug.info(res); + vm.checkData = res; + vm.openCheckTooltip(); + }, function (err) { + vm.checkData = false; + vm.openCheckTooltip(); + }); + }; + + /** + * checkIn + */ + vm.checkIn = function () { + CheckService.update(function (res) { + mtDebug.info(res); + vm.checkData = res; + NotifycationService.showSuccessNotify('CHECK.CHECK_SUCCESSFULLY'); + }, function (err) { + NotifycationService.showErrorNotify(err.data.message, 'CHECK.CHECK_ERROR'); + }); + }; + + /** + * getCheckTodayDoneMessage + * @returns {*} + */ + vm.getCheckTodayDoneMessage = function () { + var ts = $translate.instant('CHECK.CHECK_TODAY_DONE', { + keepDays: vm.checkData.keepDays, + checkTime: vm.checkData.lastCheckedAt, + todayScore: vm.scoreConfig.action.dailyCheckIn.dailyBasicScore + (vm.checkData.keepDays - 1) * vm.scoreConfig.action.dailyCheckIn.dailyStepScore, + tomorrowScore: vm.scoreConfig.action.dailyCheckIn.dailyBasicScore + vm.checkData.keepDays * vm.scoreConfig.action.dailyCheckIn.dailyStepScore + }); + + return marked(ts, {sanitize: false}); + }; + + /** + * getCheckTodayNotMessage + * @returns {*} + */ + vm.getCheckTodayNotMessage = function () { + var ts = $translate.instant('CHECK.CHECK_TODAY_NOT', { + checkTime: vm.checkData.lastCheckedAt, + todayScore: vm.scoreConfig.action.dailyCheckIn.dailyBasicScore + vm.checkData.keepDays * vm.scoreConfig.action.dailyCheckIn.dailyStepScore, + tomorrowScore: vm.scoreConfig.action.dailyCheckIn.dailyBasicScore + (vm.checkData.keepDays + 1) * vm.scoreConfig.action.dailyCheckIn.dailyStepScore + }); + + return marked(ts, {sanitize: false}); + }; + + /** + * getCheckTooltipMessage + * @returns {*} + */ + vm.getCheckTooltipMessage = function () { + var ts = $translate.instant('CHECK.CHECK_TOOLTIP', { + todayScore: vm.scoreConfig.action.dailyCheckIn.dailyBasicScore, + tomorrowScore: vm.scoreConfig.action.dailyCheckIn.dailyBasicScore + vm.scoreConfig.action.dailyCheckIn.dailyStepScore + }); + + return marked(ts, {sanitize: false}); + }; + + /** + * openCheckTooltip + */ + vm.openCheckTooltip = function () { + var e = $('.home-check-in'); + + $timeout(function () { + e.slideDown(500); + e.removeClass('panel-collapsed'); + }, 300); + }; + } }()); diff --git a/modules/core/client/directives/editable-line.client.directive.js b/modules/core/client/directives/editable-line.client.directive.js index 22496fb8..37a80fce 100644 --- a/modules/core/client/directives/editable-line.client.directive.js +++ b/modules/core/client/directives/editable-line.client.directive.js @@ -27,11 +27,13 @@ $scope.input = jQuery($element).find('.editable-line-input'); $scope.originalDivBackground = $scope.div.css('background-color'); - $scope.div.awesomeCursor('wrench', { - color: '#ff6000', - flip: 'horizontal', - outline: '#ff3e00' - }); + if (!$scope.readonly) { + $scope.div.awesomeCursor('pencil', { + color: '#ff6000', + flip: 'vertical', + outline: '#ff3e00' + }); + } var originalValue; $scope.div.bind('click', function () { diff --git a/modules/core/client/directives/torrent-list-item.client.directive.js b/modules/core/client/directives/torrent-list-item.client.directive.js new file mode 100644 index 00000000..664c6fad --- /dev/null +++ b/modules/core/client/directives/torrent-list-item.client.directive.js @@ -0,0 +1,377 @@ +(function () { + 'use strict'; + + angular.module('core') + .directive('torrentListItem', torrentListItem); + + function torrentListItem() { + var TorrentsItemController = ['$scope', '$state', 'TorrentGetInfoServices', 'ResourcesTagsServices', '$timeout', 'DownloadService', 'MeanTorrentConfig', + 'TorrentsService', 'Authentication', 'NotifycationService', 'ModalConfirmService', '$translate', 'moment', + function ($scope, $state, TorrentGetInfoServices, ResourcesTagsServices, $timeout, DownloadService, MeanTorrentConfig, TorrentsService, Authentication, + NotifycationService, ModalConfirmService, $translate, moment) { + var vm = this; + + vm.user = Authentication.user; + vm.state = $state; + vm.TGI = TorrentGetInfoServices; + vm.RTS = ResourcesTagsServices; + vm.DLS = DownloadService; + vm.torrentSalesType = MeanTorrentConfig.meanTorrentConfig.torrentSalesType; + vm.torrentRLevels = MeanTorrentConfig.meanTorrentConfig.torrentRecommendLevel; + vm.salesGlobalConfig = MeanTorrentConfig.meanTorrentConfig.torrentGlobalSales; + vm.hnrConfig = MeanTorrentConfig.meanTorrentConfig.hitAndRun; + + /** + * buildPager + */ + function buildPager() { + if (typeof $scope.parent.torrentBuildPager === 'function') { + $scope.parent.torrentBuildPager(); + } else if (typeof $scope.parent.buildPager === 'function') { + $scope.parent.buildPager(); + } + } + + /** + * getTagUsedStatus + * @param t + * @returns {boolean} + */ + vm.getTagUsedStatus = function (t) { + return $scope.parent.searchTags.indexOf(t) !== -1; + }; + + /** + * onTagClicked + * @param tag: tag name + */ + vm.onTagClicked = function (tag) { + if ($('#tag_' + tag) && $('#tag_' + tag).val()) { + $timeout(function () { + angular.element('#tag_' + tag).trigger('click'); + }, 10); + } else { + if ($scope.parent.searchTags.includes(tag)) { + $scope.parent.searchTags.splice($scope.parent.searchTags.indexOf(tag), 1); + } else { + $scope.parent.searchTags.push(tag); + } + buildPager(); + } + }; + + /** + * onReleaseClicked + * @param y + */ + vm.onReleaseClicked = function (y) { + if ($scope.parent.releaseYear === y) { + $scope.parent.releaseYear = undefined; + } else { + $scope.parent.releaseYear = y; + } + + buildPager(); + }; + + /** + * onTorrentTypeClicked + * @param t + */ + vm.onTorrentTypeClicked = function (t) { + if ($state.current.name.startsWith('admin.torrents')) { + if ($scope.parent.torrentType === t) { + $scope.parent.torrentType = 'aggregate'; + } else { + $scope.parent.torrentType = t; + } + } else { + if ($scope.parent.filterType === t) { + $scope.parent.filterType = $scope.parent.torrentType; + } else { + $scope.parent.filterType = t; + } + } + + buildPager(); + }; + + /** + * onRLevelClicked + * @param y + */ + vm.onRLevelClicked = function (l) { + if ($scope.parent.torrentRLevel === l) { + $scope.parent.torrentRLevel = 'level0'; + } else { + $scope.parent.torrentRLevel = l; + } + + buildPager(); + }; + + /** + * onHnRClicked + */ + vm.onHnRClicked = function () { + $scope.parent.filterHnR = !$scope.parent.filterHnR; + + buildPager(); + }; + + /** + * onSaleChanged + */ + vm.onSaleClicked = function () { + $scope.parent.filterSale = !$scope.parent.filterSale; + + buildPager(); + }; + + /** + * onVIPClicked + */ + vm.onVIPClicked = function () { + $scope.parent.filterVIP = !$scope.parent.filterVIP; + + buildPager(); + }; + + /** + * onTopClicked + */ + vm.onTopClicked = function () { + $scope.parent.filterTop = !$scope.parent.filterTop; + buildPager(); + }; + + /** + * onUniqueClicked + */ + vm.onUniqueClicked = function () { + $scope.parent.filterUnique = !$scope.parent.filterUnique; + buildPager(); + }; + + /** + * toggleTop + */ + vm.toggleTop = function (item) { + var dt = new TorrentsService(item); + dt.$toggleTopStatus(function (res) { + $scope.list[$scope.list.indexOf(item)] = res; + NotifycationService.showSuccessNotify('TORRENT_TOGGLE_TOP_SUCCESSFULLY'); + }, function (res) { + NotifycationService.showErrorNotify(res.data.message, 'TORRENT_TOGGLE_TOP_FAILED'); + }); + }; + + /** + * toggleTop + */ + vm.toggleUnique = function (item) { + var dt = new TorrentsService(item); + dt.$toggleUniqueStatus(function (res) { + $scope.list[$scope.list.indexOf(item)] = res; + NotifycationService.showSuccessNotify('TORRENT_TOGGLE_UNIQUE_SUCCESSFULLY'); + }, function (res) { + NotifycationService.showErrorNotify(res.data.message, 'TORRENT_TOGGLE_UNIQUE_FAILED'); + }); + }; + + /** + * toggleHnR + */ + vm.toggleHnR = function (item) { + var dt = new TorrentsService(item); + dt.$toggleHnRStatus(function (res) { + $scope.list[$scope.list.indexOf(item)] = res; + NotifycationService.showSuccessNotify('TORRENT_TOGGLE_HNR_SUCCESSFULLY'); + }, function (res) { + NotifycationService.showErrorNotify(res.data.message, 'TORRENT_TOGGLE_HNR_FAILED'); + }); + }; + + /** + * toggleVIP + */ + vm.toggleVIP = function (item) { + var dt = new TorrentsService(item); + dt.$toggleVIPStatus(function (res) { + $scope.list[$scope.list.indexOf(item)] = res; + NotifycationService.showSuccessNotify('TORRENT_TOGGLE_VIP_SUCCESSFULLY'); + }, function (res) { + NotifycationService.showErrorNotify(res.data.message, 'TORRENT_TOGGLE_VIP_FAILED'); + }); + }; + + /** + * vm.setRecommendLevel + */ + vm.setRecommendLevel = function (item, rl) { + TorrentsService.setRecommendLevel({ + _torrentId: item._id, + _rlevel: rl.value + }, function (res) { + $scope.list[$scope.list.indexOf(item)] = res; + NotifycationService.showSuccessNotify('TORRENT_SETRLEVEL_SUCCESSFULLY'); + }, function (res) { + NotifycationService.showErrorNotify(res.data.message, 'TORRENT_SETRLEVEL_ERROR'); + }); + }; + + /** + * setSaleType + */ + vm.setSaleType = function (item, st) { + TorrentsService.setSaleType({ + _torrentId: item._id, + _saleType: st.name + }, function (res) { + $scope.list[$scope.list.indexOf(item)] = res; + NotifycationService.showSuccessNotify('TORRENT_SETSALETYPE_SUCCESSFULLY'); + }, function (res) { + NotifycationService.showErrorNotify(res.data.message, 'TORRENT_SETSALETYPE_ERROR'); + }); + }; + + /** + * deleteTorrent + */ + vm.deleteTorrent = function (item) { + var modalOptions = { + closeButtonText: $translate.instant('TORRENT_DELETE_CONFIRM_CANCEL'), + actionButtonText: $translate.instant('TORRENT_DELETE_CONFIRM_OK'), + headerText: $translate.instant('TORRENT_DELETE_CONFIRM_HEADER_TEXT'), + bodyText: $translate.instant('TORRENT_DELETE_CONFIRM_BODY_TEXT'), + bodyParams: item.torrent_filename, + + selectOptions: { + enable: true, + title: 'TORRENT_DELETE_REASON', + options: [ + 'TORRENT_DELETE_REASON_OVERVIEW', + 'TORRENT_DELETE_REASON_NFO', + 'TORRENT_DELETE_REASON_QUALITY', + 'TORRENT_DELETE_REASON_ILLEGAL' + ] + } + }; + + ModalConfirmService.showModal({}, modalOptions) + .then(function (result) { + var reason = result.reason; + if (reason === 'CUSTOM') reason = result.custom; + + var dt = new TorrentsService(item); + dt.$remove({ + reason: reason + }, function (response) { + successCallback(response); + }, function (errorResponse) { + errorCallback(errorResponse); + }); + + function successCallback(res) { + $scope.list.splice($scope.list.indexOf(item), 1); + NotifycationService.showSuccessNotify('TORRENT_DELETE_SUCCESSFULLY'); + } + + function errorCallback(res) { + NotifycationService.showErrorNotify(res.data.message, 'TORRENT_DELETE_ERROR'); + } + }); + }; + + /** + * reviewedTorrentStatus + * @param item + */ + vm.reviewedTorrentStatus = function (item) { + TorrentsService.setReviewedStatus({ + _torrentId: item._id + }, function (res) { + $scope.list[$scope.list.indexOf(item)] = res; + NotifycationService.showSuccessNotify('TORRENT_SETREVIEWED_SUCCESSFULLY'); + }, function (res) { + NotifycationService.showErrorNotify(res.data.message, 'TORRENT_SETREVIEWED_ERROR'); + }); + }; + + /** + * showByLabel + * @returns {boolean} + */ + vm.showByLabel = function () { + if (vm.state.current.name.startsWith('admin.torrents')) { + return true; + } else if (vm.state.current.name.indexOf('seeding') > 0) { + return true; + } else if (vm.state.current.name.indexOf('leeching') > 0) { + return true; + } else if (vm.state.current.name.indexOf('warning') > 0) { + return true; + } else if (vm.state.current.name.indexOf('downloading') > 0) { + return true; + } else { + return false; + } + }; + + /** + * showByUser + * @returns {boolean} + */ + vm.showByUser = function () { + if (vm.state.current.name.startsWith('admin.torrents')) { + return false; + } else if (vm.state.current.name.indexOf('seeding') > 0) { + return false; + } else if (vm.state.current.name.indexOf('leeching') > 0) { + return false; + } else if (vm.state.current.name.indexOf('warning') > 0) { + return false; + } else if (vm.state.current.name.indexOf('downloading') > 0) { + return false; + } else if (vm.state.current.name.startsWith('collections')) { + return false; + } else if (vm.state.current.name.startsWith('requests')) { + return false; + } else { + return true; + } + }; + + /** + * isGlobalSaleNow + * @returns {boolean} + */ + vm.isGlobalSaleNow = function () { + var start = moment(vm.salesGlobalConfig.global.startAt, vm.salesGlobalConfig.global.timeFormats).valueOf(); + var end = start + vm.salesGlobalConfig.global.expires; + var now = Date.now(); + + if (now > start && now < end && vm.salesGlobalConfig.global.value) { + return true; + } else { + return false; + } + }; + + }]; + + return { + restrict: 'AE', + templateUrl: '/modules/torrents/client/templates/torrent-item.client.view.html', + controller: TorrentsItemController, + controllerAs: 'vm', + scope: { + item: '=', + list: '=', + peer: '=', + warning: '=', + parent: '=' + } + }; + } +}()); diff --git a/modules/core/client/directives/torrent-progress.client.directive.js b/modules/core/client/directives/torrent-progress.client.directive.js index b542558e..b81c46e3 100644 --- a/modules/core/client/directives/torrent-progress.client.directive.js +++ b/modules/core/client/directives/torrent-progress.client.directive.js @@ -20,10 +20,8 @@ function link(scope, element, attrs) { scope.$watch(attrs.torrentProgress, function (p) { - if (p && p.length > 0) { - var pt = p[0]; - //mtDebug.info(pt); - + var pt = Array.isArray(p) ? (p.length > 0 ? p[0] : undefined) : p; + if (pt) { var t_progressbar = ngProgressFactory.createInstance(); t_progressbar.setParent(element[0]); t_progressbar.setAbsolute(); @@ -69,8 +67,6 @@ scope.$watch(attrs.cardProgress, function (p) { if (p && p.length > 0) { var pt = p[0]; - //mtDebug.info(pt); - var t_progressbar = ngProgressFactory.createInstance(); t_progressbar.setParent(element[0]); t_progressbar.setAbsolute(); diff --git a/modules/core/client/filter/bytes.client.filter.js b/modules/core/client/filter/bytes.client.filter.js index ea06792a..9986abf5 100644 --- a/modules/core/client/filter/bytes.client.filter.js +++ b/modules/core/client/filter/bytes.client.filter.js @@ -9,7 +9,7 @@ function bytes() { return function (bytes, precision) { - if (bytes === 0 || isNaN(parseFloat(bytes)) || !isFinite(bytes)) return '-'; + if (bytes === 0 || isNaN(parseFloat(bytes)) || !isFinite(bytes)) return '0'; if (typeof precision === 'undefined') precision = 1; //var units = ['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'], var units = ['b', 'K', 'M', 'G', 'T', 'P'], diff --git a/modules/core/client/filter/dollar.client.filter.js b/modules/core/client/filter/dollar.client.filter.js index 38e78fc8..223d9deb 100644 --- a/modules/core/client/filter/dollar.client.filter.js +++ b/modules/core/client/filter/dollar.client.filter.js @@ -11,7 +11,7 @@ function dollar($translate) { return function (number, precision) { - if (number === 0 || isNaN(parseFloat(number)) || !isFinite(number)) return '-'; + if (number === 0 || isNaN(parseFloat(number)) || !isFinite(number)) return '0'; if (typeof precision === 'undefined') precision = 1; return '$' + (number / 1000000).toFixed(precision) + ' ' + $translate.instant('UNIT_MILLION'); }; diff --git a/modules/core/client/filter/score.client.filter.js b/modules/core/client/filter/score.client.filter.js new file mode 100644 index 00000000..6280379d --- /dev/null +++ b/modules/core/client/filter/score.client.filter.js @@ -0,0 +1,18 @@ +(function () { + 'use strict'; + + // Focus the element on page load + // Unless the user is on a small device, because this could obscure the page with a keyboard + + angular.module('core') + .filter('score', score); + + score.$inject = ['$filter']; + + function score($filter) { + return function (input, decimals) { + if (input === 0 || isNaN(parseFloat(input)) || !isFinite(input)) return '0'; + return $filter('number')(input, decimals); + }; + } +}()); diff --git a/modules/core/client/less/btn-size.less b/modules/core/client/less/btn-size.less index 1de14495..d495eef3 100644 --- a/modules/core/client/less/btn-size.less +++ b/modules/core/client/less/btn-size.less @@ -108,6 +108,46 @@ min-width: 500px !important; } +.max-width-10 { + max-width: 10px !important; +} + +.max-width-20 { + max-width: 20px !important; +} + +.max-width-30 { + max-width: 30px !important; +} + +.max-width-40 { + max-width: 40px !important; +} + +.max-width-50 { + max-width: 50px !important; +} + +.max-width-60 { + max-width: 60px !important; +} + +.max-width-70 { + max-width: 70px !important; +} + +.max-width-80 { + max-width: 80px !important; +} + +.max-width-90 { + max-width: 90px !important; +} + +.max-width-100 { + max-width: 100px !important; +} + .max-width-300 { max-width: 300px !important; } @@ -134,9 +174,19 @@ } } +.btn-mt-o-default-dark { + color: #666; + border: solid 1px #666; + &:focus { + color: #666; + border-color: #666; + } +} + .btn-mt-o-success { color: @state-success-text; border: solid 1px @state-success-text; + &:hover, &:focus { color: @state-success-text; border-color: @state-success-text; diff --git a/modules/core/client/less/home.less b/modules/core/client/less/home.less index c9bf80cb..bdac4200 100644 --- a/modules/core/client/less/home.less +++ b/modules/core/client/less/home.less @@ -113,6 +113,30 @@ } } +.col-valign-middle { + @media (min-width: @screen-sm-min) { + display: table-cell; + vertical-align: middle; + float: none; + } +} + +.home-check-in { + padding: 10px 0; + h4, .h4 { + line-height: 1.8; + } + .check-in-btn { + margin-top: 10px; + @media(max-width: @screen-sm-max){ + margin-top: 20px; + } + @media(max-width: @screen-xs-max){ + margin-top: 15px; + } + } +} + .home-button-list { padding: 50px 0; @media (max-width: @screen-xs-max) { @@ -316,6 +340,18 @@ } } +.filter-check-in { + position: relative; + margin-top: 2px; + background-color: @mt-body-background-color; + background-color: rgba(255, 255, 255, .85); + transition: background-color .2s ease-in; + &:hover { + background-color: @mt-body-background-color; + background-color: rgba(255, 255, 255, .95); + } +} + .filter-copy { position: relative; line-height: 2; @@ -378,71 +414,73 @@ vertical-align: middle; } } - .search-panel { + .top-panel { min-height: 120px; padding: 20px 0; text-shadow: 0 0 0.1em #000,-0 -0 0.1em #000; - .search-title { - color: #fff; - font-size: 2em; - font-weight: 400; - margin-bottom: 0 !important; - } - .search-sub-title { - margin-top: 10px; - color: #aaa; - text-shadow: 0 0 0.1em #000, 0 0 0.1em #000; - } - .search-group { - max-width: 50em; - margin-right: auto; - margin-left: auto; - display: block; - input { - color: #eee; - background-color: #ccc; - background-color: rgba(255, 255, 255, 0.2); - border-radius: 17px; - position: inherit; - z-index: 2; - float: none; - width: 100%; - margin-bottom: 0; - padding-right: 105px; + .home-search { + .search-title { + color: #fff; + font-size: 2em; + font-weight: 400; + margin-bottom: 0 !important; } - .btn-search { - border-top-right-radius: 17px; - border-bottom-right-radius: 17px; - position: absolute; - right: 1px; - top: 1px; - bottom: 1px; - opacity: 0.6; - z-index: 3; - &:hover, - &:focus { - outline: none; - opacity: 1; + .search-sub-title { + margin-top: 10px; + color: #aaa; + text-shadow: 0 0 0.1em #000, 0 0 0.1em #000; + } + .search-group { + max-width: 50em; + margin-right: auto; + margin-left: auto; + display: block; + input { + color: #eee; + background-color: #ccc; + background-color: rgba(255, 255, 255, 0.2); + border-radius: 17px; + position: inherit; + z-index: 2; + float: none; + width: 100%; + margin-bottom: 0; + padding-right: 105px; + } + .btn-search { + border-top-right-radius: 17px; + border-bottom-right-radius: 17px; + position: absolute; + right: 1px; + top: 1px; + bottom: 1px; + opacity: 0.6; + z-index: 3; + &:hover, + &:focus { + outline: none; + opacity: 1; + } } } - } - .search-type { - color: #aaa; - text-shadow: 0 0 0.1em #000, 0 0 0.1em #000; - input { - opacity: 0.6; - &:hover, - &:checked, - &:focus { - opacity: 1; + .search-type { + color: #aaa; + text-shadow: 0 0 0.1em #000, 0 0 0.1em #000; + input { + opacity: 0.6; + &:hover, + &:checked, + &:focus { + opacity: 1; + } + } + .radio-inline + .radio-inline, + .checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 50px; // space out consecutive inline controls } - } - .radio-inline + .radio-inline, - .checkbox-inline + .checkbox-inline { - margin-top: 0; - margin-left: 50px; // space out consecutive inline controls - } + } } } } diff --git a/modules/core/client/less/media-margin.less b/modules/core/client/less/media-margin.less new file mode 100644 index 00000000..5ba962dc --- /dev/null +++ b/modules/core/client/less/media-margin.less @@ -0,0 +1,7 @@ +@import (reference) "../../../core/client/less/mt-var.less"; + +.xs-margin-top-10 { + @media (max-width: @screen-xs-max) { + margin-top: 10px; + } +} diff --git a/modules/core/client/less/mt.less b/modules/core/client/less/mt.less index 258b2f7a..800198f3 100644 --- a/modules/core/client/less/mt.less +++ b/modules/core/client/less/mt.less @@ -14,6 +14,10 @@ body { background-color: @mt-body-background-color; } +.ui-notification{ + width: 400px; +} + .social-list { img { border-radius: 12px; @@ -438,6 +442,7 @@ body { color: #FF6600; > kbd { background-color: #FF6600; + font-size: 12px; } } @@ -908,6 +913,12 @@ body { .coll-item-remove { display: block; } + .warning-btn { + display: block; + } + .warning-data { + display: none; + } } .media-left { position: relative; @@ -918,8 +929,8 @@ body { > .td-text-overflow { .text-long { @media (min-width: @screen-lg-min) { - max-width: 570px; - min-width: 560px; + max-width: 550px; + min-width: 540px; } @media (max-width: @screen-md-max) { max-width: 420px; @@ -1064,14 +1075,15 @@ body { position: relative; .torrent-filename { margin-top: 2px; - font-size: 12px; + font-size: 13px; color: @gray-light; } .list-all-tags { - position: absolute; - bottom: 1px; + min-height: 52px; + margin-top: 8px; + width: 100%; .label { - margin-top: 3px; + margin-top: 5px; } span { position: relative; @@ -1089,10 +1101,25 @@ body { border: solid 1px #fff; } } + .label-torrent-link { + color: #8a8a8a; + border: solid 1px #dedede; + background-color: #fafafa; + &:hover { + color: #f00; + } + } } .media-heading { + line-height: 1.2; margin-bottom: 5px; } + .list-all-genres { + font-size: 12px; + .genres-item { + color: @gray-light; + } + } } .td-imdb { min-width: 90px; @@ -1111,7 +1138,10 @@ body { } .td-admin-cmd { min-width: 143px; - padding: 0 !important; + padding: 5px !important; + } + .warning-btn { + display: none; } } @@ -1133,10 +1163,7 @@ body { } .list-all-genres { - font-size: 12px; .genres-item { - color: @gray-light; - font-size: 12px; &:not(:first-child) { &::before { content: " | "; @@ -1215,6 +1242,7 @@ body { .label-tag { color: #0366d6; background-color: #f1f8ff; + border: solid 1px #ddeeff; &:hover { cursor: pointer; color: #f00; @@ -1225,6 +1253,7 @@ body { } .label-rlevel { + border: solid 1px darken(@brand-info, 2%); &:hover { cursor: pointer; color: #f00; @@ -1234,6 +1263,7 @@ body { .label-hnr-info { color: #eee; background-color: #333; + border: solid 1px #000; &:hover { cursor: pointer; color: #f00; @@ -1242,9 +1272,9 @@ body { } .label-vip-info { - color: @mt-base-color; - font-weight: bold; - background-color: #f1f8ff; + color: #fff; + background-color: @mt-base-color; + border: solid 1px darken(@mt-base-color, 2%); &:hover { cursor: pointer; color: #f00; @@ -1254,9 +1284,29 @@ body { } } +.label-unique-info { + color: #fff; + background-color: @brand-danger; + border: solid 1px darken(@brand-danger, 2%); + &:hover { + cursor: pointer; + color: #f00; + } + &:active { + color: #0366d6; + } +} + +.upload-by { + color: #888; + background-color: #efefef; + border: solid 1px #dedede; +} + .label-se-info { color: @mt-base-color; background-color: #f1f8ff; + border: solid 1px #ddeeff; &:hover { cursor: pointer; color: #f00; @@ -1264,6 +1314,7 @@ body { } .label-ttype { + border: solid 1px darken(@brand-primary, 2%); &:hover { cursor: pointer; color: #f00; @@ -1278,6 +1329,7 @@ body { } .label-sale { + border: solid 1px darken(@brand-success, 2%); &:hover { cursor: pointer; color: #f00; @@ -1285,6 +1337,17 @@ body { } .label-release { + border: solid 1px darken(@brand-warning, 2%); + &:hover { + cursor: pointer; + color: #f00; + } +} + +.torrent-top { + color: @mt-base-color; + border: solid 1px darken(@mt-base-color, 2%); + background-color: #fafafa; &:hover { cursor: pointer; color: #f00; @@ -1305,6 +1368,15 @@ body { } } +.radio-type { + margin-top: 0; + margin-bottom: 0; + line-height: 1.6; + input[type="radio"] { + margin-top: 5px; + } +} + .checkbox-hnr { margin-top: 0; margin-bottom: 0; @@ -1658,6 +1730,9 @@ body { padding: 15px 8px; } } + + tbody { + border-top: none; + } } } } @@ -1724,16 +1799,38 @@ body { } .lang-list { - margin-left: 10px; + margin-top: 5px; + padding-left: 5px; line-height: 2; .flag-icon { font-size: 18px; margin-left: 10px; &, - &:hover, &:focus { cursor: pointer; } + &:hover { + &:after { + content: ''; + background-color: #c0c0c0; + position: absolute; + width: 100%; + height: 3px; + top: -5px; + right: 0; + } + } + &.curr-language { + &:after { + content: ''; + background-color: @brand-primary; + position: absolute; + width: 100%; + height: 3px; + top: -5px; + right: 0; + } + } } } @@ -1760,11 +1857,6 @@ body { padding-top: 5px; } -.upload-by { - color: #888; - font-size: 12px; -} - .status-avatar { border-radius: 3px; height: 44px; diff --git a/modules/core/client/services/menu.client.service.js b/modules/core/client/services/menu.client.service.js index 20f90d72..f0419915 100644 --- a/modules/core/client/services/menu.client.service.js +++ b/modules/core/client/services/menu.client.service.js @@ -61,7 +61,8 @@ target: options.target || undefined, divider: options.divider || false, faClass: options.faClass || null, - faIcon: options.faIcon || null + faIcon: options.faIcon || null, + linkState: options.linkState || undefined }); // Add submenu items @@ -96,7 +97,8 @@ target: options.target || undefined, divider: options.divider || false, faClass: options.faClass || null, - faIcon: options.faIcon || null + faIcon: options.faIcon || null, + linkState: options.linkState || undefined }); }); diff --git a/modules/core/client/views/footer.client.view.html b/modules/core/client/views/footer.client.view.html index fae498d4..e835ab8d 100644 --- a/modules/core/client/views/footer.client.view.html +++ b/modules/core/client/views/footer.client.view.html @@ -36,7 +36,7 @@
  • + ng-repeat="l in vm.language | filter: {enable: true}" ng-class="{'curr-language': vm.langService.getLang() == l.name}">
  • diff --git a/modules/core/client/views/header.client.view.html b/modules/core/client/views/header.client.view.html index 9cbed53e..7ff27125 100644 --- a/modules/core/client/views/header.client.view.html +++ b/modules/core/client/views/header.client.view.html @@ -1,4 +1,5 @@ - +
    +
    +
    +
    +
    + +