// ==UserScript== // @name Linux.do Credit Display // @namespace http://tampermonkey.net/ // @version 2.1 // @description 显示 linux.do 基础积分,支持手动计算差值 // @author You // @match https://linux.do/* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @connect credit.linux.do // @downloadURL none // ==/UserScript== (function() { 'use strict'; const TRANSACTIONS_API = 'https://credit.linux.do/api/v1/order/transactions'; const LEADERBOARD_URL = 'https://linux.do/leaderboard'; const STORAGE_KEY = 'linux_do_credit_cache'; // 获取今天的时间范围 function getTodayRange() { const now = new Date(); const y = now.getFullYear(); const m = String(now.getMonth() + 1).padStart(2, '0'); const d = String(now.getDate()).padStart(2, '0'); return { startTime: `${y}-${m}-${d}T00:00:00+08:00`, endTime: `${y}-${m}-${d}T23:59:59+08:00` }; } // 从 remark 解析积分: "社区积分从 1877 更新到 1938,变化 61" -> 1938 function parseScore(remark) { const match = remark.match(/更新到\s*(\d+)/); return match ? parseInt(match[1], 10) : null; } // 获取今日基础积分 function fetchBaseScore() { return new Promise((resolve, reject) => { const { startTime, endTime } = getTodayRange(); GM_xmlhttpRequest({ method: 'POST', url: TRANSACTIONS_API, headers: { 'Content-Type': 'application/json' }, data: JSON.stringify({ page: 1, page_size: 20, startTime, endTime }), onload: (res) => { try { const data = JSON.parse(res.responseText); const orders = data.data?.orders || []; for (const item of orders) { if (item.remark?.includes('社区积分')) { const score = parseScore(item.remark); if (score !== null) { resolve(score); return; } } } reject(new Error('未找到积分记录')); } catch (e) { reject(e); } }, onerror: reject }); }); } // 检查缓存是否有效(当天有效) function getCachedScore() { const cache = GM_getValue(STORAGE_KEY, null); if (cache && cache.date === new Date().toDateString()) { return cache.score; } return null; } // 保存缓存 function setCachedScore(score) { GM_setValue(STORAGE_KEY, { score, date: new Date().toDateString() }); } // 创建 UI function createUI(baseScore) { const container = document.createElement('div'); container.id = 'linux-do-credit'; container.style.cssText = ` position: fixed; bottom: 20px; right: 20px; background: #fff; color: #333; padding: 10px 14px; border-radius: 8px; font-size: 14px; z-index: 9999; box-shadow: 0 2px 12px rgba(0,0,0,0.15); display: flex; flex-direction: column; gap: 8px; `; container.innerHTML = `
📊 历史积分: ${baseScore}
--
`; document.body.appendChild(container); // 点击跳转排行榜(当前 tab) document.getElementById('credit-base').onclick = () => { window.location.href = LEADERBOARD_URL; }; // 输入计算差值 const input = document.getElementById('current-input'); const diffResult = document.getElementById('diff-result'); input.addEventListener('input', () => { const current = parseInt(input.value, 10); if (!isNaN(current)) { const diff = current - baseScore; const sign = diff >= 0 ? '+' : ''; diffResult.textContent = `${sign}${diff}`; diffResult.style.color = diff >= 0 ? '#22c55e' : '#ef4444'; } else { diffResult.textContent = '--'; diffResult.style.color = '#999'; } }); } // 显示错误状态 function showError() { const container = document.createElement('div'); container.style.cssText = ` position: fixed; bottom: 20px; right: 20px; background: #ef4444; color: white; padding: 10px 14px; border-radius: 8px; font-size: 14px; z-index: 9999; `; container.textContent = '📊 获取积分失败'; document.body.appendChild(container); } // 初始化 async function init() { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); return; } // 尝试使用缓存 const cached = getCachedScore(); if (cached !== null) { createUI(cached); return; } // 请求新数据 try { const score = await fetchBaseScore(); setCachedScore(score); createUI(score); } catch (e) { console.error('获取积分失败:', e); showError(); } } init(); })();