// ==UserScript==
// @name PT Level Helper
// @namespace https://xsky123.com/
// @version 0.2
// @description A simple way to help you know when you will level up
// @author XSky123
// @match *://u2.dmhy.org/userdetails*
// @match *://totheglory.im/userdetails*
// @match *://hdcmct.org/userdetails*
// @match *://tp.m-team.cc/userdetails*
// @grant none
// @require https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js
// ==/UserScript==
(function () {
'use strict';
function show_next_upgrade() {
let site = get_site_name();
let register_time = get_register_time();
let level = get_current_level(site);
let next_level = load_next_level(site, level);
let next_level_info = load_level_data(site, next_level);
let next_download = next_level_info['down'];
let next_upload = get_next_upload(next_level_info);
let upgrade_time = add_weeks(register_time, next_level_info['weeks']);
let current_upload = get_upload(site);
let current_download = get_download(site);
write_upgrade_time(site, next_level, upgrade_time);
write_traffic(site, current_upload, next_upload, next_level);
write_traffic(site, current_download, next_download, next_level, "download");
write_ratio(site, next_level_info['ratio'], next_level);
}
function write_upgrade_time(site, next_level, upgrade_time) {
let now = new Date();
let ksr = document.querySelectorAll('td.rowhead');
let ksp;
let target;
ksr.forEach(function (ksp) {
if (ksp.innerText.match('日期')) {
target = ksp;
}
});
let upgrade_info = document.createElement("span");
let upgrade_info_html;
if (upgrade_time > now) {
let rest_time = get_time_diff(now, upgrade_time, "day");
let rest_time_str = get_next_upgrade_txt(rest_time);
upgrade_info_html = ` 升级至<strong>${next_level}</strong>还需要<strong>${rest_time_str}</strong>`;
} else {
upgrade_info_html = ` 已满足升级至<strong>${next_level}</strong>的时间要求`;
}
upgrade_info.innerHTML = upgrade_info_html;
target.nextSibling.appendChild(upgrade_info);
}
function write_traffic(site, current_value, next_value, next_level, type = "upload") {
switch (site) {
case "ttg":
write_traffic_for_ttg(current_value, next_value, next_level, type);
break;
default:
write_traffic_for_normal_nexusphp(current_value, next_value, next_level, type);
}
}
function write_traffic_for_ttg(current_value, next_value, next_level, type = "upload") {
let target;
let origin_html;
if (type === "upload") {
target = $("td.rowhead:contains('上传'):first").next();
} else {
target = $("td.rowhead:contains('下载'):first").next();
}
origin_html = target.html();
if (next_value > current_value) {
origin_html += ` 距离下一等级<strong>${next_level}</strong>还有<strong>${number_format(next_value - current_value, 2)} GB</strong>`;
} else {
origin_html += ` 已满足升级至<strong>${next_level}</strong>的流量要求`;
}
target.html(origin_html);
}
function write_traffic_for_normal_nexusphp(current_value, next_value, next_level, type = "upload") {
/* This part of code was inspired by popcorner@DUTPT.
* Thanks to his advice, code here has been greatly simplified and normalized.
*/
let ksr = document.querySelectorAll('td.embedded>strong');
let ksp;
let ksl;
if (type === "upload") {
ksr.forEach(function (ksp) {
if (ksp.innerText === '上传量' || ksp.innerHTML === '上傳量') {
ksl = ksp
}
});
} else {
ksr.forEach(function (ksp) {
if (ksp.innerText === '下载量' || ksp.innerHTML === '下載量') {
ksl = ksp
}
});
}
let upgrade_info;
if (next_value > current_value) {
upgrade_info = ` 距离下一等级<strong>${next_level}</strong>还有<strong>${number_format(next_value - current_value, 2)} GB</strong> `;
} else {
upgrade_info = ` 已满足升级至<strong>${next_level}</strong>的流量要求 `;
}
ksl.parentElement.insertAdjacentHTML('beforeend', upgrade_info);
}
function write_ratio(site, next_ratio, next_level) {
let current_ratio;
switch (site){
case "ttg":
let target = $("td.rowhead:contains('分享率'):first").next();
let origin_html = target.html();
current_ratio = Number(target.text());
if (next_level > current_ratio) {
origin_html += ` 下一等级<strong>${next_level}</strong>需要达到分享率<strong>${next_ratio}</strong>`;
} else {
origin_html += ` 已满足升级至<strong>${next_level}</strong>的分享率要求`;
}
target.html(origin_html);
break;
default:
let ksr = document.querySelectorAll('td.embedded>strong');
let ksp;
let ksl;
ksr.forEach(function (ksp) {
if (ksp.innerText === '分享率') {
ksl = ksp
}
});
current_ratio = Number(ksl.nextElementSibling.innerText);
let ratio_text;
if (current_ratio < next_ratio) {
ratio_text = ` 下一等级<strong>${next_level}</strong>需要达到分享率<strong>${next_ratio}</strong> `;
}else{
ratio_text = ` 已满足升级至<strong>${next_level}</strong>的分享率要求 `;
}
ksl.nextElementSibling.insertAdjacentHTML('beforeend', ratio_text);
}
}
function get_current_user_personal_page_url(site){
let ksr;
let user_url;
switch (site){
case "ttg":
ksr = document.querySelector('span.smallfont');
break;
default:
ksr = document.querySelector('span.medium');
}
user_url = ksr.firstElementChild.firstElementChild.href;
return user_url;
}
function get_site_name() {
let domain = window.location.host;
let site_name = "";
switch (domain) {
case "u2.dmhy.org":
site_name = "u2";
break;
case "totheglory.im":
site_name = "ttg";
break;
case "hdcmct.org":
site_name = "cmct";
break;
case "tp.m-team.cc":
site_name = "mt";
break;
}
console.log(`Sitename: ${site_name}`);
return site_name;
}
function get_register_time() {
let html = document.body.innerHTML;
let reg_time_pattern = /日期.*?(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/;
let reg_time = html.match(reg_time_pattern);
let reg_time_value = reg_time[1];
console.log(`Register at: ${reg_time_value}`);
return new Date(reg_time_value);
}
function get_current_level(site) {
let level_value;
let html;
let level_pattern;
let level;
switch (site) {
case "ttg":
html = document.body.innerHTML;
level_pattern = /等级.*?\">(.*?)</;
level = html.match(level_pattern);
level_value = level[1];
break;
case "mt":
html = document.body.innerHTML;
level_pattern = /等級.*?\<img alt=\"(.*?)\//;
level = html.match(level_pattern);
level_value = level[1];
break;
default:
html = document.body.innerHTML;
level_pattern = /等级.*?\<img alt=\"(.*?)\"/;
level = html.match(level_pattern);
level_value = level[1];
}
console.log(`Level: ${level_value}`);
return level_value;
}
function get_upload(site){
return get_traffic(site);
}
function get_download(site){
return get_traffic(site, "download");
}
function get_traffic(site, type="upload"){
let traffic_data;
switch (site){
case "ttg":
traffic_data = get_traffic_from_ttg(type);
break;
default:
traffic_data = get_traffic_form_normal_nexusphp(type);
}
return all_tani_to_GB(traffic_data[0], traffic_data[1]);
}
function get_traffic_from_ttg(type){
let ksr = document.querySelectorAll('td.rowhead');
let ksp;
let ksl;
let raw_traffic_text;
let parsed_traffic;
let traffic_value;
let traffic_tani;
let traffic_pattern = /(\d+\.\d+) (\w{2,3})/;
ksr.forEach(function (ksp) {
if (type === 'download') {
if (ksp.innerText === '下载量') {
ksl = ksp;
}
} else{
if (ksp.innerText === '上传量') {
ksl = ksp;
}
}
});
raw_traffic_text = ksl.nextElementSibling.firstChild.textContent;
parsed_traffic = raw_traffic_text.match(traffic_pattern);
traffic_value = parsed_traffic[1];
traffic_tani = parsed_traffic[2];
return [traffic_value, traffic_tani];
}
function get_traffic_form_normal_nexusphp(type){
let ksr = document.querySelectorAll('td.embedded>strong');
let ksp;
let ksl;
let raw_traffic_text;
let parsed_traffic;
let traffic_value;
let traffic_tani;
let traffic_pattern = /(\d+\.\d+) (\w{2,3})/;
ksr.forEach(function (ksp) {
if (type === 'download'){
if (ksp.innerText === '下载量' || ksp.innerHTML === '下載量') {
ksl = ksp;
}
}else {
if (ksp.innerText === '上传量' || ksp.innerHTML === '上傳量') {
ksl = ksp;
}
}
});
raw_traffic_text = ksl.nextSibling.textContent;
parsed_traffic = raw_traffic_text.match(traffic_pattern);
traffic_value = parsed_traffic[1];
traffic_tani = parsed_traffic[2];
return [traffic_value, traffic_tani];
}
function get_next_upload(next_level_info) {
let next_upload = 0;
let next_upload_by_ratio = next_level_info['down'] * next_level_info['ratio'];
if (next_level_info.hasOwnProperty('up')) {
next_upload = ((next_upload > next_upload_by_ratio) ? next_upload : next_upload_by_ratio);
} else {
next_upload = next_upload_by_ratio;
}
console.log(`Next Upload Value: ${next_upload}`);
return next_upload;
}
function get_next_upgrade_txt(rest_time_by_day) {
let days = Math.floor(rest_time_by_day);
let origin_hours = (rest_time_by_day - days) * 24;
let hours = Math.floor(origin_hours);
let minutes = Math.floor((rest_time_by_day - days) * 60 * 24 - hours * 60);
return `${days}天${hours}小时${minutes}分`;
}
function get_time_diff(time_before, time_after, tani) {
let diff = time_after.getTime() - time_before.getTime();
let MICROSECONDS_PER_DAY = 86400000;
let MICROSECONDS_PER_HOUR = 3600000;
switch (tani) {
case "day":
return diff / MICROSECONDS_PER_DAY;
case "hour":
return diff / MICROSECONDS_PER_HOUR;
}
}
function add_weeks(time_obj, n) {
let new_date = new Date(time_obj);
new_date.setDate(time_obj.getDate() + n * 7);
return new_date;
}
function all_tani_to_GB(value, tani) {// 「tani」 は 「たんい」(単位)である。
switch (tani) {
case "TB":
return Number(value) * 1000;
case "TiB":
return Number(value) * 1024;
case "GB":
case "GiB":
return Number(value);
case "MB":
return Number(value) / 1000;
case "MiB":
return Number(value) / 1024;
case "PB":
return Number(value) * 1000 * 1000;
case "PiB":
return Number(value) * 1024 * 1024;
case "KB":
return Number(value) / 1000 / 1000;
case "KiB":
return Number(value) / 1024 / 1024;
}
return null;
}
function number_format(number, decimals, dec_point, thousands_sep, roundtag) {
/*
* code from: http://www.css88.com/archives/7324
* 参数说明:
* number:要格式化的数字
* decimals:保留几位小数
* dec_point:小数点符号
* thousands_sep:千分位符号
* roundtag:舍入参数,默认 "ceil" 向上取,"floor"向下取,"round" 四舍五入
* */
number = (number + '').replace(/[^0-9+-Ee.]/g, '');
roundtag = roundtag || "ceil"; //"ceil","floor","round"
var n = !isFinite(+number) ? 0 : +number,
prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
s = '',
toFixedFix = function (n, prec) {
var k = Math.pow(10, prec);
console.log();
return '' + parseFloat(Math[roundtag](parseFloat((n * k).toFixed(prec * 2))).toFixed(prec * 2)) / k;
};
s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
var re = /(-?\d+)(\d{3})/;
while (re.test(s[0])) {
s[0] = s[0].replace(re, "$1" + sep + "$2");
}
if ((s[1] || '').length < prec) {
s[1] = s[1] || '';
s[1] += new Array(prec - s[1].length + 1).join('0');
}
return s.join(dec);
}
function load_next_level(site, current_level) {
let data = {};
switch (site) {
case "u2":
data = {
"路人": "御宅族",
"御宅族": "宅修士",
"宅修士": "宅教士",
"宅教士": "宅传教士",
"宅传教士": "宅护法",
"宅护法": "宅贤者",
"宅贤者": "宅圣",
"宅圣": "宅神"
};
break;
case "ttg":
data = {
"Byte": "KiloByte",
"KiloByte": "MegaByte",
"MegaByte": "GigaByte",
"GigaByte": "TeraByte",
"TeraByte": "PetaByte",
"PetaByte": "ExaByte",
"ExaByte": "ZettaByte",
"ZettaByte": "YottaByte",
"YottaByte": "BrontoByte",
"BrontoByte": "NonaByte",
"NonaByte": "DoggaByte"
};
break;
case "cmct":
data = {
"新手": "入门",
"入门": "发烧",
"发烧": "着迷",
"着迷": "狂热",
"狂热": "资深",
"资深": "大师",
"大师": "宗师",
"宗师": "骨灰",
"骨灰": "神仙"
};
break;
case "mt":
data = {
"小卒": "捕頭",
"捕頭": "知縣",
"知縣": "通判",
"通判": "知州",
"知州": "府丞",
"府丞": "府尹",
"府尹": "總督",
"總督": "大臣"
};
break;
}
if (data.hasOwnProperty(current_level)) {
console.log(`Next level: ${data[current_level]}`);
return data[current_level];
}
console.warn(`Can not find next level of ${current_level}.`);
return null;
}
function load_level_data(site, level) {
let data = {};
switch (site) {
case "u2":
data = {
"御宅族": {
"title_en": "Power User",
"weeks": 4,
"down": 50,
"ratio": 1.05
},
"宅修士": {
"title_en": "Elite User",
"weeks": 8,
"down": 120,
"ratio": 1.55
},
"宅教士": {
"title_en": "Crazy User",
"weeks": 15,
"down": 300,
"ratio": 2.05
},
"宅传教士": {
"title_en": "Insane User",
"weeks": 25,
"down": 500,
"ratio": 2.55
},
"宅护法": {
"title_en": "Veteran User",
"weeks": 40,
"down": 750,
"ratio": 3.05
},
"宅贤者": {
"title_en": "Extreme User",
"weeks": 60,
"down": 1024,
"ratio": 3.55
},
"宅圣": {
"title_en": "Ultimate User",
"weeks": 80,
"down": 1536,
"ratio": 4.05
},
"宅神": {
"title_en": "Nexus Master",
"weeks": 100,
"down": 3072,
"ratio": 4.55
}
};
break;
case "ttg":
data = {
"KiloByte": {
"title_en": "KiloByte",
"weeks": 5,
"down": 60,
"ratio": 1.1
},
"MegaByte": {
"title_en": "MegaByte",
"weeks": 8,
"down": 150,
"ratio": 2
},
"GigaByte": {
"title_en": "GigaByte",
"weeks": 8,
"down": 250,
"ratio": 2
},
"TeraByte": {
"title_en": "TeraByte",
"weeks": 8,
"down": 500,
"ratio": 2.5
},
"PetaByte": {
"title_en": "PetaByte",
"weeks": 16,
"down": 750,
"ratio": 2.5
},
"ExaByte": {
"title_en": "ExaByte",
"weeks": 24,
"down": 1000,
"ratio": 3
},
"ZettaByte": {
"title_en": "ZettaByte",
"weeks": 24,
"down": 1500,
"ratio": 3.5
},
"YottaByte": {
"title_en": "YottaByte",
"weeks": 24,
"down": 2500,
"ratio": 4
},
"BrontoByte": {
"title_en": "BrontoByte",
"weeks": 32,
"down": 3500,
"ratio": 5
},
"NonaByte": {
"title_en": "NonaByte",
"weeks": 48,
"down": 5000,
"up": 50000,
"ratio": 6
},
"DoggaByte": {
"title_en": "DoggaByte",
"weeks": 48,
"down": 10000,
"up": 100000,
"ratio": 6
}
};
break;
case "cmct":
data = {
"入门": {
"title_en": "Power User",
"weeks": 5,
"down": 20,
"up": 50,
"ratio": 1.1
},
"发烧": {
"title_en": "Elite User",
"weeks": 10,
"down": 50,
"up": 100,
"ratio": 1.2
},
"着迷": {
"title_en": "Crazy User",
"weeks": 15,
"down": 100,
"up": 300,
"ratio": 1.2
},
"狂热": {
"title_en": "Insane User",
"weeks": 20,
"down": 200,
"up": 800,
"ratio": 1.2
},
"资深": {
"title_en": "Veteran User",
"weeks": 25,
"down": 500,
"up": 2000,
"ratio": 1.2
},
"大师": {
"title_en": "Extreme User",
"weeks": 25,
"down": 1000,
"up": 5000,
"ratio": 1.5
},
"宗师": {
"title_en": "Ultimate User",
"weeks": 30,
"down": 2000,
"up": 10000,
"ratio": 1.5
},
"骨灰": {
"title_en": "Nexus Master",
"weeks": 30,
"down": 4000,
"up": 20000,
"ratio": 1.5
},
"神仙": {
"title_en": "Nexus God",
"weeks": 50,
"down": 10000,
"up": 100000,
"ratio": 2
}
};
break;
case "mt":
data = {
"捕頭": {
"title_en": "Power User",
"weeks": 4,
"down": 200,
"ratio": 2
},
"知縣": {
"title_en": "Elite User",
"weeks": 8,
"down": 400,
"ratio": 3
},
"通判": {
"title_en": "Crazy User",
"weeks": 12,
"down": 500,
"ratio": 4
},
"知州": {
"title_en": "Insane User",
"weeks": 16,
"down": 800,
"ratio": 5
},
"府丞": {
"title_en": "Veteran User",
"weeks": 20,
"down": 1000,
"ratio": 6
},
"府尹": {
"title_en": "Extreme User",
"weeks": 24,
"down": 2000,
"ratio": 7
},
"總督": {
"title_en": "Ultimate User",
"weeks": 28,
"down": 2500,
"ratio": 8
},
"大臣": {
"title_en": "Nexus Master",
"weeks": 32,
"down": 3000,
"ratio": 9
}
};
break;
}
if (data.hasOwnProperty(level)) {
return data[level];
}
return null;
}
show_next_upgrade();
})();