全站通知:
Widget:EditYear2024
刷
历
编
跳到导航
跳到搜索
<script> try{ (function (global) {
'use strict';
class BYearCacheDB {
constructor(dbName = 'YeatEditDB', storeName = 'YeatEditData', version = 1) {
this.dbName = dbName;
this.storeName = storeName;
this.version = version;
this.db = null;
}
async init() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(this.dbName, this.version);
request.onupgradeneeded = (event) => {
this.db = event.target.result;
if (!this.db.objectStoreNames.contains(this.storeName)) {
this.db.createObjectStore(this.storeName, {keyPath: 'key'});
}
};
request.onsuccess = (event) => {
this.db = event.target.result;
resolve();
};
request.onerror = (event) => {
console.error('IndexedDB 初始化失败:', event.target.error);
reject(event.target.error);
};
});
}
async setCache(key, data) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([this.storeName], 'readwrite');
const store = transaction.objectStore(this.storeName);
const cacheItem = {
key: key,
timestamp: Date.now(),
data: data
};
const request = store.put(cacheItem);
request.onsuccess = () => {
resolve();
};
request.onerror = (event) => {
console.error('设置缓存失败:', event.target.error);
reject(event.target.error);
};
});
}
async getCache(key) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([this.storeName], 'readonly');
const store = transaction.objectStore(this.storeName);
const request = store.get(key);
request.onsuccess = (event) => {
const result = event.target.result;
if (result) {
resolve(result);
} else {
resolve(null);
}
};
request.onerror = (event) => {
console.error('获取缓存失败:', event.target.error);
reject(event.target.error);
};
});
}
// 删除缓存
async deleteCache(key) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([this.storeName], 'readwrite');
const store = transaction.objectStore(this.storeName);
const request = store.delete(key);
request.onsuccess = () => {
resolve();
};
request.onerror = (event) => {
console.error('删除缓存失败:', event.target.error);
reject(event.target.error);
};
});
}
// 清空所有缓存
async clearCache() {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([this.storeName], 'readwrite');
const store = transaction.objectStore(this.storeName);
const request = store.clear();
request.onsuccess = () => {
resolve();
};
request.onerror = (event) => {
console.error('清空缓存失败:', event.target.error);
reject(event.target.error);
};
});
}
}
// 成就管理模块
var AchievementManager = {
processAchievements: function (data) {
var achievements = [];
var config = EditYearCount.config.achievements;
for (var i = 0; i < config.length; i++) {
var achievement = config[i];
try {
if (achievement.condition(data)) {
achievements.push(achievement);
}
} catch (e) {
console.error('处理成就时出错:', achievement.name, e);
}
}
return achievements; } };
// 编辑成就模块
var EditYearCount = {
// 配置对象
config: {
cacheKey: 'editYearCache2024',
cacheDuration: 24 * 60 * 60 * 1000, // 缓存持续时间 24小时
},
// 初始化函数
init: function (useCache = true) {
Utils.onApiReady(async function () {
var textarea = document.getElementById('editOverviewJsonBox');
if (textarea) {
console.log("exist textarea",textarea.value)
} else {
HTMLLogger.log("
");
textarea = document.createElement('textarea');
textarea.id = 'editOverviewJsonBox';
textarea.rows = 10;
textarea.name = 'editOverviewJsonBox233';
textarea.placeholder = "粘贴编辑概览API返回的JSON数据";
textarea.value = "";
HTMLLogger.log("
");
document.querySelector('#year-backup-inputs').innerHTML += '刷新缓存
你还可以在下方手动给出 这里 返回的JSON数据来查看编辑报告,粘贴内容后点击刷新缓存。';
document.querySelector('#year-backup-inputs').appendChild(textarea);
}
var refreshButton = document.querySelector('#refresh-achievement2');
if(refreshButton){
refreshButton.addEventListener('click', async function () {
refreshButton.disabled = true;
refreshButton.textContent = '刷新中...';
await EditYearCount.refresh();
refreshButton.disabled = false;
refreshButton.textContent = '刷新缓存';
});
}
var data = await EditYearCount.loadData(useCache);
if (data){
for (let i = 0; i < data.wiki.length; i++) {
data.wiki[i] = EditYearCount.stat(data.wiki[i]);
}
// data = EditYearCount.stat(data);
console.log("loadData end", data)
window.data = data;
console.log("可以在控制台访问 data 变量查看数据");
// return
Renderer.display(data);
}
});
},
stat:function (d) {
var eidt_ns = (data, ns) => data.contributions.filter(t => t.ns === ns).length
var edit_type = (data, type = ".css") => data.contributions.filter(t => t.title.endsWith(type)).length
d.stat = {
editcount: d.user.editcount,
editcount_year: d.contributions.length,
eidt_ns: {
0: eidt_ns(d, 0),
2: eidt_ns(d, 2),
4: eidt_ns(d, 4),
6: eidt_ns(d, 6),
8: eidt_ns(d, 8),
10: eidt_ns(d, 10),
12: eidt_ns(d, 12),
14: eidt_ns(d, 14),
274: eidt_ns(d, 274),
828: eidt_ns(d, 828),
},
edit_type:{
"css": edit_type(d, ".css"),
"js": edit_type(d, ".js"),
},
groups: d.user.groups,
registration: d.user.registration,
}
return d;
},
// 加载数据(包括缓存处理)
loadData: async function (useCache = true) {
var cached = await Utils.getCache(EditYearCount.config.cacheKey);
if (useCache && cached && !Utils.isCacheExpired(cached.timestamp, EditYearCount.config.cacheDuration)) {
console.log("从缓存加载数据");
return cached.data;
} else {
console.log("从API加载数据");
var data = await DataFetcher.fetchAllData();
if (data){
Utils.setCache(EditYearCount.config.cacheKey, data).then(() => {});
}
return data;
}
},
// 手动刷新数据接口
refresh: async function () {
console.log("手动刷新数据开始");
EditYearCount.init(false);
}
};
// 数据获取模块
var DataFetcher = {
fetchAllData: async function () {
var textarea = document.getElementById('editOverviewJsonBox');
console.log("textareatextarea", textarea)
console.log("textareatextarea", textarea.value)
var editOverview = {}
if (textarea && textarea.value && textarea.value.length > 1){
editOverview = JSON.parse(textarea.value).data;
console.log("手动输入的数据", editOverview)
}else{
editOverview = await DataFetcher.getEditOverview();
if (!editOverview || !editOverview.game_list) {
console.error('获取编辑概览数据失败:', editOverview);
HTMLLogger.log("获取编辑概览数据失败,推荐用电脑浏览器查看,掉登录也可能导致无法请求游戏中心API。")
return null;
}
}
var wikiList = [];
// 使用 for 循环遍历数组
for (let i = 0; i < editOverview.game_list.length; i++) {
const obj = editOverview.game_list[i];
wikiList.push({
name: obj.game_name,
path: obj.wiki_url.replace("https://wiki.biligame.com/","")// 只保留.com后边的部分
});
}
var allData = {
editOverview:{
username: editOverview.mid,
game_list: wikiList,
game_count: editOverview.game_count,
total_edit_count: editOverview.total_edit_count,
},
wiki:[]
};
HTMLLogger.log("开始获取数据!这可能需要一点时间,请耐心等待。数据会缓存在浏览器IndexDB中。
")
// 查看有哪些wiki,挨个遍历
for (let i = 0; i < wikiList.length; i++) {
let wiki_name = wikiList[i].name;
let wiki_path = wikiList[i].path;
var wiki_api_url = 'https://wiki.biligame.com/' + wiki_path + '/api.php'; console.log("get wiki data", wiki_name, wiki_path, wiki_api_url) HTMLLogger.log("获取数据:" + wiki_name + " " + wiki_path + "
") const response = await fetch(wiki_api_url, { method: 'HEAD', redirect: 'follow' }); if (response.redirected) { // wiki 不在了 continue; } allData.wiki.push({ name: wiki_name, path: wiki_path, contributions: await DataFetcher.getUserContributions(wiki_path, allData.editOverview.username), user: await DataFetcher.getUserInfoNew(wiki_path, allData.editOverview.username), }) } return allData; },
getEditOverview: async function () {
var url = 'https://le3-api.game.bilibili.com/pc/game/wiki/edit_overview';
var response = await fetch(url, {credentials: "include"});
var data = await response.json();
if (data && data.data){
return data.data;
}
HTMLLogger.log("游戏中心API(跨域请求)出错,目前已知APP无法请求此API。");
console.warn("edit_overview API 请求出错,数据可能不完整。", data);
return {};
},
getUserContributions: async function (wikiName, username) {
var allContributions = [];
var api = new mw.Api();
api.defaults.ajax.url = '/' + wikiName + '/api.php';
var params = {
action: 'query',
list: 'usercontribs',
ucuser: username, // 获取当前用户名
ucstart: "2024-12-31T16:00:00Z", // 2025.1.1 -8小时 因为处于+8时区
ucend: "2023-12-31T16:00:00Z", // 2024.1.1 -8小时 因为处于+8时区
uclimit: 'max',
ucprop: 'title|timestamp',
format: 'json',
};
try {
do {
var response = await api.get(params);
if (response && response.query && response.query.usercontribs) {
allContributions = allContributions.concat(response.query.usercontribs);
}
params.uccontinue = response.continue?.uccontinue || null;
} while (response.continue);
} catch (e) {
console.warn('API 请求出错,数据可能不完整。错误:', e);
}
return allContributions;
},
getUserInfoNew: async function (wikiName, username) {
var params = {
action: 'query',
list: 'users',
ususers: username,
usprop: 'groups|editcount|registration',
};
var api = new mw.Api();
api.defaults.ajax.url = '/' + wikiName + '/api.php';
try{
var response = await api.get(params);
if (response.query && response.query.users && response.query.users[0]) {
return response.query.users[0];
} else {
return {};
}
}catch (e) {
HTMLLogger.log("获取用户信息失败,可能是因为API请求失败。",e.toString());
return {};
}
},
getUserInfo: async function (wikiName) {
var params = {
action: 'query',
meta: 'userinfo',
uiprop: 'groups|editcount|registrationdate',
};
var api = new mw.Api();
api.defaults.ajax.url = '/' + wikiName + '/api.php';
var response = await api.get(params);
if (response.query && response.query.userinfo) {
return response.query.userinfo;
} else {
return {};
}
}
};
var HTMLLogger = {
log: function (message) {
var containerId = 'year-edit-log';
var container = document.getElementById(containerId);
if (!container) {
container = document.createElement('div');
container.id = containerId;
document.querySelector('.mw-parser-output').appendChild(container);
}
container.innerHTML += message;
},
clear: function () {
var containerId = 'year-edit-log';
var container = document.getElementById(containerId);
if (!container) {
container = document.createElement('div');
container.id = containerId;
document.querySelector('.mw-parser-output').appendChild(container);
}
container.innerHTML = "";
}
}
// 展示模块
var Renderer = {
display: async function (allData) {
// 插入容器
var containerId = 'year-edit-container';
var container = document.getElementById(containerId) || (() => {
var newDiv = document.createElement('div');
newDiv.id = containerId;
document.querySelector('.mw-parser-output').appendChild(newDiv);
return newDiv;
})();
// 插入按钮
var containerBtnsId = 'year-edit-reload-btns';
var containerBtns = document.getElementById(containerBtnsId) || (() => {
var newDiv = document.createElement('div');
newDiv.id = containerBtnsId;
newDiv.style.clear = 'both';
document.querySelector('.mw-parser-output').appendChild(newDiv);
return newDiv;
})();
containerBtns.innerHTML = '刷新缓存';
// 添加刷新按钮事件
var refreshButton = document.querySelector('#refresh-achievement');
refreshButton.addEventListener('click', async function () {
refreshButton.disabled = true;
refreshButton.textContent = '刷新中...';
await EditYearCount.refresh();
// 模拟同步刷新完成
refreshButton.disabled = false;
refreshButton.textContent = '刷新缓存';
});
var innerHTML = ;
// 拼接 wikitext
var wikitext = "";
wikitext += `BWiki 2024年度编辑报告,文字版(一早上写的能看就行了)
\n\n\n\n`;
wikitext += `从你加入BWiki至今,已经参与了${allData.editOverview.game_count}个wiki的建设,累计编辑${allData.editOverview.total_edit_count}次。
\n\n`
if(allData.editOverview.total_edit_count < 100){
wikitext += `Wiki需要所有人参与,感谢你的加入!\n\n
`
}else if (allData.editOverview.total_edit_count < 1000){
wikitext += `你是BWiki的中坚力量。\n\n
`
}else if(allData.editOverview.total_edit_count < 5000){
wikitext += `你是BWiki的核心编辑。\n\n
`
}else if(allData.editOverview.total_edit_count < 10000){
wikitext += `你是BWiki的大佬,所有读者都受益于你的编辑。\n\n
`
}else{
wikitext += `你是BWiki的传奇!\n\n
`
}
wikitext += `
编辑统计
`
var year_edit = 0;
var autoconfirmed = 0;
var sysop = 0;
var interfaceadmin = 0;
var bureaucrat = 0;
var editcss = 0;
var editjs = 0;
var editmodule = 0;
var editwidget = 0;
var editmw = 0;
var edit_wiki_year = 0
for (const wiki of allData.wiki) {
year_edit += wiki.stat.editcount_year;
if (wiki.stat.editcount_year > 0) {
edit_wiki_year+=1;
}
autoconfirmed += wiki.stat.groups.includes("autoconfirmed") ? 1 : 0;
sysop += wiki.stat.groups.includes("sysop") ? 1 : 0;
interfaceadmin += wiki.stat.groups.includes("interface-admin") ? 1 : 0;
bureaucrat += wiki.stat.groups.includes("bureaucrat") ? 1 : 0;
editcss += wiki.stat.edit_type.css;
editjs += wiki.stat.edit_type.js;
editmodule += wiki.stat.eidt_ns[828];
editwidget += wiki.stat.eidt_ns[274];
editmw += wiki.stat.eidt_ns[8];
}
wikitext += `2024年度编辑次数:${year_edit}次。参与了 ${edit_wiki_year} 个wiki的编辑。\n\n
`
if (bureaucrat > 0) {
wikitext += `你是 ` + bureaucrat.toString() + ` 个wiki的行政员。`
if (bureaucrat > 5) {
wikitext += `对wiki的管理权限数量仅次于托奇(雾)。`
}
wikitext += `
\n\n`
}
if (sysop > 0) {
wikitext += `你是 ` + sysop + ` 个wiki的管理员。`
if (sysop > 5) {
wikitext += `多个Wiki在你的管理下蓬勃发展。`
}
wikitext += `
\n\n`
}
if (interfaceadmin > 0) {
wikitext += `你是 ` + interfaceadmin.toString() + ` 个wiki的界面管理员。`
if (interfaceadmin > 5) {
wikitext += `BWiki需要更多的前端!`
}
wikitext += `
\n\n`
}
if (autoconfirmed > 0) {
wikitext += `你拥有 ` + autoconfirmed.toString() + `个wiki的免审权限。`
if (autoconfirmed > 5) {
wikitext += `你在各个Wiki的编辑质量被社区普遍认可。`
}
wikitext += `
\n\n`
}
wikitext += `
累计编辑不包括被删除的页面等情况,因此数量可能低于年度编辑(按照所有编辑列表计数)。
` // wikitext += `{| class="wikitable sortable" \n|-\n!首次访问!!wiki!!累计编辑!!年度编辑!!页面!!MediaWiki空间!!模板!!帮助!!Widget!!模块\n\n`
wikitext += '
<thead>\n' + '</thead><tbody>' allData.wiki.sort((a, b) => b.stat.editcount_year - a.stat.editcount_year);
for (const wiki of allData.wiki) {
if (wiki.stat.editcount < 1) {
continue
}
wikitext += ``
// wikitext += `|-\n|${wiki.stat.registration.toString().split("T")[0]}||${wiki.name}||${wiki.stat.editcount}||${wiki.stat.editcount_year}||${wiki.stat.eidt_ns[0]}||${wiki.stat.eidt_ns[8]}||${wiki.stat.eidt_ns[10]}||${wiki.stat.eidt_ns[12]}||${wiki.stat.eidt_ns[274]}||${wiki.stat.eidt_ns[828]}\n\n`
}
// wikitext += `|}\n`
wikitext += `| 首次访问 | wiki | 累计编辑 | 年度编辑 | 页面 | MediaWiki空间 | 模板 | 帮助 | Widget | 模块 |
|---|---|---|---|---|---|---|---|---|---|
| ${wiki.stat.registration.toString().split("T")[0]} | ${wiki.name} | ${wiki.stat.editcount} | ${wiki.stat.editcount_year} | ${wiki.stat.eidt_ns[0]} | ${wiki.stat.eidt_ns[8]} | ${wiki.stat.eidt_ns[10]} | ${wiki.stat.eidt_ns[12]} | ${wiki.stat.eidt_ns[274]} | ${wiki.stat.eidt_ns[828]} |
\n\n`
// datawiki
let data_wiki = allData.wiki.find(obj => obj.path === "data");
if (data_wiki) {
wikitext += `(你今年在 BWIKI数据库 编辑了 ${data_wiki.stat.editcount_year} 次。这些编辑是由社区插件自动执行的,为了更新缓存数据。)\n\n`
}
wikitext += `\n\n`
// // wikitext to html
// var params = {
// action: 'parse',
// contentmodel: 'wikitext',
// text: wikitext,
// prop: 'text|headhtml',
// format: 'json'
// };
// var api = new mw.Api();
// var res = await api.get(params);
// console.log("wikitext2html",res)
// if (res.parse && res.parse.text) {
// innerHTML = res.parse.text["*"];
// }
innerHTML = wikitext;
container.innerHTML = innerHTML; // 插入渲染结果
HTMLLogger.clear();
document.querySelector('#year-backup-inputs').innerHTML = ""; // 清空手动输入框
try{
$(".sortable").tablesorter();
(window.RLQ = window.RLQ || []).push(['jquery','jquery.tablesorter',()=>{$(function() {
$(".sortable").tablesorter();
});}]);
} catch (e) {/* nothing can do*/}
}
};
// 工具模块
var Utils = {
// 缓存数据到 localStorage
setCache: async function (key, data) {
try {
var db = new BYearCacheDB();
await db.init();
await db.setCache(key, data);
} catch (e) {
console.error('设置缓存失败:', e);
}
},
// 获取缓存数据
getCache: async function (key) {
try {
var db = new BYearCacheDB();
await db.init();
var cache = await db.getCache(key);
if (cache) {
return cache;
}
return null;
} catch (e) {
console.error('获取缓存失败:', e);
return null;
}
},
getUserID: function () {
var username = (document.cookie.match(/DedeUserID=([^;]+)/) || [])[1] || "";
if (!username) {
console.warn('Cookie中未找到用户名');
return ;
}
return username;
},
// 文档就绪回调
onDocumentReady: function (callback) {
if (document.readyState === 'complete' || document.readyState === 'interactive') {
callback();
} else {
document.addEventListener('DOMContentLoaded', callback);
}
},
// 检查缓存是否过期
isCacheExpired: function (timestamp, duration) {
var now = new Date().getTime();
console.log("isCacheExpired", timestamp, now, duration, (now - timestamp) > duration)
if (1735628493429 > timestamp){
return true;
}
return (now - timestamp) > duration;
},
// 等待 mw.Api 加载完成
onApiReady: function (callback) {
var maxRetry = 32; // 最大重试次数
var retryTimeout = 81; // 每次重试间隔时间 81ms * 32 ≈ 2600ms
var retryCount = 0;
function waitApi() {
if (window.mw && typeof mw.Api === 'function') {
setTimeout(callback, retryTimeout); // 81ms 后才开始执行, 以确保相关功能已加载且可用
} else {
retryCount++;
if (retryCount < maxRetry) {
setTimeout(waitApi, retryTimeout); // 等待 retryTimeout 毫秒
} else {
var errorLogText = "等待mw.Api加载超时。已经等待 " + maxRetry.toString() + " 次";
errorLogText += "累计时间:" + (maxRetry * retryTimeout).toString() + " 毫秒。";
console.error(errorLogText);
// 触发错误处理
ErrorHandler.handleError(new Error(errorLogText));
}
}
}
waitApi(); } };
// 将命名空间暴露到全局(可选) window.EditAchievement = EditYearCount;
// 启动初始化 EditYearCount.init();
})(this);
} catch (e) {
var log_div = (() => {
var newDiv = document.createElement('div');
newDiv.style.clear = 'both';
document.querySelector('body').appendChild(newDiv);
return newDiv;
})();
log_div.innerHTML = "报错信息:" + e.toString();
} </script>

沪公网安备 31011002002714 号