bgli100 / U2 Reward UC Calculator (Mods)

// ==UserScript==
// @name         U2 Reward UC Calculator (Mods)
// @version      0.22
// @description  Calc Calc Calc.
// @author       葛平改
// @license      MIT
// @match        https://u2.dmhy.org/forums.php?*action=viewtopic*
// @require      http://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.0.0.min.js
// @updateURL    https://openuserjs.org/meta/bgli100/U2_Reward_UC_Calculator_(Mods).meta.js
// @downloadURL  https://openuserjs.org/install/bgli100/U2_Reward_UC_Calculator_(Mods).user.js
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    const THREAD_TITLE_PATTEN = /^Get the UCoin Bonus \| 自购发布奖励申请帖$/i; //匹配帖子标题的正则表达式. 该脚本只在符合条件的帖子里运行
    const POST_PATTEN = /(Reward request|奖励申请)/i; //只在匹配左侧正则表达式的回复内运行
    const CATEGORY_PATTEN = /^(Category|分类)$/i; //匹配左侧正则表达式的行是分类行, 以下同理
    const BD_COUNTRY_CODE_PATTEN = /^(Country code|国家代码)$/i; //BD分类 国家代码
    const BD_MAIN_BD_PATTEN = /^(# of main BDs|正片BD数)$/i; //BD分类 正片BD数
    const BD_ACCUMULATED_PATTEN = /^(Accumulated volumes|累积卷数)$/i; //BD分类 累积卷数
    const BD_SCAN_PATTEN = /^(# of images scanned|扫图数)$/i; //BD分类 扫图数
    const BD_TOKUTEN_PATTEN = /^(# of tokuten discs\(CD, BD, DVD, etc\.\)|特典碟数\(包括CD, BD, DVD等\))$/i; //BD分类 特典碟数(包括CD, BD, DVD等)
    const BD_BASE_CREDIT = 60000;
    const BD_EXTRA_DISK_CREDIT = 15000;
    const BD_TOKUTEN_FACTOR = 0.15;
    const BD_ACCUMULATED_FACTOR = 0.1;
    const BD_COUNTRY_JPN_FACTOR = 1;
    const BD_COUNTRY_OTHER_FACTOR = 0.1;
    const BD_COMPLETE_CREDIT = 60000;
    const BD_SCAN_LIMITS = [20, 60, 200, 400];
    const BD_SCAN_FACTORS = [0.005, 0.002, 0.001, 0.0005, 0.0002];

    const DVD_COUNTRY_CODE_PATTEN = BD_COUNTRY_CODE_PATTEN; //DVD分类 国家代码
    const DVD_MAIN_DVD_PATTEN = /^(# of main DVDs|正片DVD数)$/i; //DVD分类 正片DVD数
    const DVD_ACCUMULATED_PATTEN = BD_ACCUMULATED_PATTEN; //DVD分类 累积卷数
    const DVD_SCAN_PATTEN = BD_SCAN_PATTEN; //DVD分类 扫图数
    const DVD_TOKUTEN_PATTEN = BD_TOKUTEN_PATTEN; //DVD分类 特典碟数(包括CD, BD, DVD等)
    const DVD_BASE_CREDIT = 25000;
    const DVD_EXTRA_DISK_CREDIT = 6000;
    const DVD_TOKUTEN_FACTOR = BD_TOKUTEN_FACTOR;
    const DVD_ACCUMULATED_FACTOR = BD_ACCUMULATED_FACTOR;
    const DVD_COUNTRY_JPN_FACTOR = BD_COUNTRY_JPN_FACTOR;
    const DVD_COUNTRY_OTHER_FACTOR = BD_COUNTRY_OTHER_FACTOR;
    const DVD_SCAN_LIMITS = BD_SCAN_LIMITS;
    const DVD_SCAN_FACTORS = BD_SCAN_FACTORS;

    const CD_SCAN_PATTEN = BD_SCAN_PATTEN; //CD分类 扫图数
    const CD_TOKUTEN_PATTEN = BD_TOKUTEN_PATTEN; //CD分类 特典碟数(包括CD, BD, DVD等)
    const CD_TYPE_PATTEN = /^(Type|类型)$/i; //CD分类 类型
    const CD_SINGLE_BASE_CREDIT = 25000;
    const CD_DRAMA_BASE_CREDIT = 35000;
    const CD_ALBUM_OST_BASE_CREDIT = 45000;
    const CD_TOKUTEN_FACTOR = 0.20;
    const CD_SCAN_LIMITS = [20, 60, 200];
    const CD_SCAN_FACTORS = [0.015, 0.006, 0.003, 0.001];

    const EXTRA_SCAN_PATTEN = BD_SCAN_PATTEN; //周边分类 扫图数
    const EXTRA_TOKUTEN_PATTEN = BD_TOKUTEN_PATTEN; //周边分类 特典碟数(包括CD, BD, DVD等)
    const EXTRA_BASE_CREDIT = 55000;
    const EXTRA_TOKUTEN_FACTOR = 0.2;
    const EXTRA_SCAN_LIMITS = CD_SCAN_LIMITS;
    const EXTRA_SCAN_FACTORS = CD_SCAN_FACTORS;

    //除非你非常清楚你在干啥否则不要修改下面的部分
    const TO_BE_REPLACED = '[to_be_replaced]';
    const THREAD_TITLE_SELECTOR = '.main>tbody>tr>td>h1>span';
    const POST_SELECTOR = '.post-body';
    const POST_TO_CONTENT_SELECTOR = 'span';
    const CHECK_AREA_HTML = "<br><input type='checkbox' class='UCRewardDupe'>DUPE" +
                            "<input type='checkbox' class='UCRewardComplete'>完结奖励" +
                            "<input class='UCRewardCalc' type='button' value='通过申请, 计算数额' data='" + TO_BE_REPLACED + "'>";
    const POST_ID_PATTEN = /^pid(\d+)body$/;
    const TORRENT_ID_PATTEN = /https:\/\/u2\.dmhy\.org\/details\.php\?id\=(\d+)/;

    if(!THREAD_TITLE_PATTEN.test($(THREAD_TITLE_SELECTOR).html())) {
        console.log("Thread title didn't match.");
        return;
    }
    var D;
    var scanFactor = function(value, limits, factors) {
        var ret = 0;
        limits.push(Number.POSITIVE_INFINITY);
        for(var i = 0; i < limits.length; i++){
            if(value >= limits[i])
                ret += (limits[i] - (i === 0 ? 0 : limits[i - 1])) * factors[i];
            else {
                ret += (value - (i === 0 ? 0 : limits[i - 1])) * factors[i];
                break;
            }
        }
        return ret;
    };
    var findValue = function(arr, patten, type = 'int') {
        var ret = false, tmp;
        arr.forEach(function (curr) {
            if(patten.test(curr[0])) {
                switch(type){
                    case 'str':
                        ret = curr[1].trim().replace('&nbsp;', '');
                        break;
                    case 'int':
                        tmp = parseInt(curr[1].trim().replace('&nbsp;', ''), 10);
                        if(tmp >= 0)
                            ret = tmp;
                        break;
                    default: break;
                }
            }
        });
        console.log(ret);
        return ret;
    };
    var doCalc = function(content, complete, dupe, time) {
        var ret = false;
        content = content.split("<br>").map(function(curr) {
            return curr.split(':');
        });
        var countryCode, main, scan, historyVolume, tokuten, type, cat = findValue(content, CATEGORY_PATTEN, 'str');
        cat = cat ? cat.toUpperCase() : false;
        switch (cat) {
            case 'BD':
                if(!([countryCode = findValue(content, BD_COUNTRY_CODE_PATTEN, 'str'),
                      main = findValue(content, BD_MAIN_BD_PATTEN),
                      scan = findValue(content, BD_SCAN_PATTEN),
                      historyVolume = findValue(content, BD_ACCUMULATED_PATTEN),
                      tokuten = findValue(content, BD_TOKUTEN_PATTEN)].every(elem => elem !== false)))
                    return false;
                if(historyVolume < 1 || main < 1)
                    return false;
                countryCode = countryCode === 'JPN' ? BD_COUNTRY_JPN_FACTOR : BD_COUNTRY_OTHER_FACTOR;
                scan = scanFactor(scan, BD_SCAN_LIMITS, BD_SCAN_FACTORS);
                complete = complete ? BD_COMPLETE_CREDIT : 0;
                ret = BD_BASE_CREDIT + BD_EXTRA_DISK_CREDIT * (main - 1);
                if(!dupe) {
                    ret *= 1 + scan + tokuten * BD_TOKUTEN_FACTOR + (historyVolume - 1) * BD_ACCUMULATED_FACTOR;
                    ret += complete;
                } else
                    ret *= scan + tokuten * BD_TOKUTEN_FACTOR;
                ret *= countryCode;
                break;
            case 'DVD':
                if(!([countryCode = findValue(content, DVD_COUNTRY_CODE_PATTEN, 'str'),
                      main = findValue(content, DVD_MAIN_DVD_PATTEN),
                      scan = findValue(content, DVD_SCAN_PATTEN),
                      historyVolume = findValue(content, DVD_ACCUMULATED_PATTEN),
                      tokuten = findValue(content, DVD_TOKUTEN_PATTEN)].every(elem => elem !== false)))
                    return false;
                if(historyVolume < 1 || main < 1)
                    return false;
                countryCode = countryCode === 'JPN' ? DVD_COUNTRY_JPN_FACTOR : DVD_COUNTRY_OTHER_FACTOR;
                scan = scanFactor(scan, DVD_SCAN_LIMITS, DVD_SCAN_FACTORS);
                ret = DVD_BASE_CREDIT + DVD_EXTRA_DISK_CREDIT * (main - 1);
                if(!dupe)
                    ret *= 1 + scan + tokuten * DVD_TOKUTEN_FACTOR + (historyVolume - 1) * DVD_ACCUMULATED_FACTOR;
                else
                    ret *= scan + tokuten * DVD_TOKUTEN_FACTOR;
                ret *= countryCode;
                break;
            case 'CD':
            case 'HI-RES':
                if(!([scan = findValue(content, CD_SCAN_PATTEN),
                      tokuten = findValue(content, CD_TOKUTEN_PATTEN),
                      type = findValue(content, CD_TYPE_PATTEN, 'str')].every(elem => elem !== false)))
                    return false;
                switch (type.toUpperCase()){
                    case 'SINGLE': ret = CD_SINGLE_BASE_CREDIT; break;
                    case 'DRAMA': ret = CD_DRAMA_BASE_CREDIT; break;
                    case 'OST':
                    case 'ALBUM': ret = CD_ALBUM_OST_BASE_CREDIT; break;
                    default:
                        return false;
                }
                ret *=  1 + scanFactor(scan, CD_SCAN_LIMITS, CD_SCAN_FACTORS) + tokuten * CD_TOKUTEN_FACTOR;
                break;
            case '周边':
            case 'EXTRA':
                if(!([scan = findValue(content, EXTRA_SCAN_PATTEN),
                      tokuten = findValue(content, EXTRA_TOKUTEN_PATTEN)].every(elem => elem !== false)))
                    return false;
                scan = scanFactor(scan, EXTRA_SCAN_LIMITS, EXTRA_SCAN_FACTORS);
                ret = EXTRA_BASE_CREDIT * (1 + scan + EXTRA_TOKUTEN_FACTOR * tokuten);
                break;
            default : return false;
        }
        return ret * D * (time > 0.5 ? 2 / (1 + Math.exp(time - 0.5)) : 1);
    };
    $.get('httpapi_globalconstant.php?constant=D', function(obj) {
        D = parseFloat(obj.data);
    }).fail(function() {
        alert('Failed to get D.');
    }).done(function() {
        $(POST_SELECTOR).each(function(index, elem) {
            var tid, content = $(elem).children(POST_TO_CONTENT_SELECTOR).html();
            if(!POST_PATTEN.test(content))
                return;
            else if($(elem).prevAll("div").length !== 0)
                return;
            else if(!(tid = content.match(TORRENT_ID_PATTEN)))
                return;
            var pid = $(elem).attr('id').match(POST_ID_PATTEN)[1];
            $(elem).append(CHECK_AREA_HTML.replace(TO_BE_REPLACED, pid));
            $(".UCRewardCalc[data='" + pid + "']").click(function() {
                $(this).attr('disabled', true);
                var myThis = $(this), dt, complete = $(this).prevAll('.UCRewardComplete').is(':checked'), dupe = $(this).prevAll('.UCRewardDupe').is(':checked');
                $.get('httpapi_torrentinfo.php?tid=' + tid[1], function(obj) {
                    dt = ((Date.now() / 1000 - obj.data.added) / (86400 * 365)).toFixed(3); //year
                }).done(function (){
                    var msg, amount = doCalc(content, complete, dupe, dt);
                    if(!amount) {
                        myThis.attr('value', '非法格式');
                        return;
                    }
                    amount = Math.floor(amount);
                    myThis.attr('value', '奖励' + amount + 'UCoin').attr('disabled', false);
                    msg = 'tid: ' + tid[1] + ', D = ' + D.toFixed(3) + ', ' + dt + ' years' + (complete ? ', complete' : '') + (dupe ? ', dupe' : '');
                    myThis.unbind('click').click(function() {
                        $(this).attr('disabled', true);
                        $.ajax({
                            url: 'forumpostadmin.php',
                            method: 'post',
                            tPid: pid,
                            data: 'markdes=add&mark=' + amount + '&reason=' + msg + '&admintype=mark&pid=' + pid
                        }).fail(function() {
                            alert('Failed on post#' + this.tPid);
                        }).done(function() {
                            location.reload();
                        });
                    });
                });
            });
        });
    });
})();