# 【神人】一个极其无聊的油猴自证篇

80hou 2026-08-29 10:46 1

前言:


对事件的回复引用,懒得更新了,随便瞅瞅吧

按照你这个逻辑,是不是被我送过鸡腿的都要封号?


星辰是公开可追溯的,刷这玩意有啥用,难道看帖给人送鸡腿点赞的也有问题?


我是拿鸡腿和星辰换了兑换码还是啥?







在酒神帖子下公然刷星辰,你脑子确定出门时候没被夹了下?



爱恨情仇篇:引子,因为我举报这神人

经济回暖了吗有人恶意抬高抽奖金额扰乱抽奖秩序


造谣玷污清白篇:开端

星辰兑换邀请码要严防刷星辰的


疑神疑鬼脑补篇:谜语人系列

如果不是你心虚,你为什么要扶


栽赃嫁祸篇:脑补好歹请你装个Pro插件看看对方3个星辰后在污蔑我哈

用脚本复读机刷回复也行?






自证篇:对看板中的各项数据与收支流水进行逐步核算


1. 流水总笔数核对



  • 收到点赞笔数:1261 笔

  • 送出转账笔数:42 笔

  • 收到转账笔数:143 笔

  • 总笔数计算:1261 + 42 + 143 = 1446 条(与看板显示的「真实总流水:1446 条」一致)




2. 累计收入构成核对



  • 收到点赞获赠收益:+1261 星辰(每次获赠点赞增加 1 个星辰)

  • 收到转账入账收益:+2076 星辰

  • 总收入计算:1261 + 2076 = +3337 星辰(与看板显示的「累计收入:+3337」一致)




3. 累计支出构成核对



  • 送出转账支出:-1527 星辰(对应 42 笔主动转出,如之前流水中的 -520 等)

  • 送出点赞支出:0 星辰(在 NodeSeek 中,给他人点赞属于免费互动,不扣除自身星辰资产)

  • 总支出计算:-1527 星辰(与看板显示的「累计支出:-1527」一致)




4. 账户净变动与最终余额核对



  • 历史累计净收益:累计收入 3337 - 累计支出 1527 = 1810星辰

  • 当前钱包余额:1810 星辰




经过对笔数、收入、支出及净额的独立四步验算,看板中的加减逻辑与底层数值完全吻合,计算方式准确无误。



全部流水

账本总览汇总



  • 当前星辰余额: 1810

  • 真实总流水: 1446 条

  • 累计收入: +3337

  • 累计支出: -1527

  • 收到点赞: 1261 次 (+1261)

  • 送出转账: 42 笔 (-1527)

  • 收到转账: 143 笔 (+2076)



其他闲言碎语:


自加入Ns时候就开始了收集星辰的玩法,刷星辰兑换邀请码这种脑回路我是万万没想到的.



油猴插件:NodeSeek 全量星辰账本分析器 (完整校准版)
// ==UserScript==
// @name NodeSeek 全量星辰账本分析器 (完整校准版)
// @namespace https://www.nodeseek.com/
// @version 4.6.0
// @description 全量精准核算星辰账本:校准下一页按钮、数学核算真实余额(1810)、导出MD前自动并发补齐100%全量用户真实昵称、秒级时间戳、转账收支(+388/-520)、获赠点赞(+1),支持包含贡献者统计小计的 tabs Markdown 导出
// @author Sherlock
// @match https://www.nodeseek.com/*
// @grant GM_addStyle
// @grant GM_registerMenuCommand
// @grant GM_setClipboard
// @run-at document-idle
// ==/UserScript==

(function () {
'use strict';

const CONFIG = {
COUNT_PER_REQ: 1000,
PAGE_SIZE: 50,
DELAY_MS: 300,
USER_FETCH_DELAY_MS: 100,
BATCH_CONCURRENCY: 5
};

GM_addStyle(`
#ns-stardust-btn {
position: fixed;
bottom: 85px;
right: 20px;
z-index: 9999;
background: #2563eb;
color: #fff;
padding: 9px 14px;
border-radius: 20px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
box-shadow: 0 4px 12px rgba(37,99,235,0.35);
transition: all 0.2s ease;
border: 1px solid rgba(255,255,255,0.2);
user-select: none;
}
#ns-stardust-btn:hover {
background: #1d4ed8;
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(37,99,235,0.45);
}
#ns-modal-mask {
display: none;
position: fixed;
top: 0; left: 0; width: 100vw; height: 100vh;
background: rgba(0,0,0,0.65);
z-index: 10000;
backdrop-filter: blur(4px);
justify-content: center;
align-items: center;
}
#ns-stardust-modal {
background: #1e222d;
color: #e2e8f0;
width: 92%;
max-width: 1260px;
height: 85vh;
border-radius: 12px;
box-shadow: 0 20px 40px rgba(0,0,0,0.6);
display: flex;
flex-direction: column;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
border: 1px solid #334155;
}
.ns-modal-header {
padding: 14px 20px;
border-bottom: 1px solid #334155;
display: flex;
justify-content: space-between;
align-items: center;
background: #181b24;
}
.ns-modal-title { font-size: 16px; font-weight: bold; color: #60a5fa; }
.ns-close-btn { cursor: pointer; font-size: 20px; color: #94a3b8; line-height: 1; }
.ns-close-btn:hover { color: #fff; }

.ns-stats-bar {
padding: 10px 20px;
background: #14171f;
display: flex;
gap: 10px;
flex-wrap: wrap;
border-bottom: 1px solid #334155;
font-size: 13px;
}
.ns-stat-item { background: #1e293b; padding: 5px 10px; border-radius: 6px; }
.ns-stat-val { font-weight: bold; margin-left: 4px; }
.val-balance { color: #38bdf8; font-size: 14px; font-weight: 800; }
.val-plus { color: #4ade80; }
.val-minus { color: #f87171; }

.ns-controls {
padding: 10px 20px;
display: flex;
gap: 8px;
align-items: center;
flex-wrap: wrap;
background: #181b24;
border-bottom: 1px solid #334155;
}
.ns-tab-btn {
background: #334155;
color: #cbd5e1;
border: none;
padding: 6px 12px;
border-radius: 6px;
cursor: pointer;
font-size: 12px;
transition: all 0.2s;
}
.ns-tab-btn.active { background: #2563eb; color: #fff; font-weight: bold; }
.ns-search-input {
background: #0f172a;
border: 1px solid #334155;
color: #fff;
padding: 6px 10px;
border-radius: 6px;
font-size: 12px;
margin-left: auto;
outline: none;
width: 200px;
}

.ns-table-container {
flex: 1;
overflow-y: auto;
padding: 0;
}
.ns-table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
text-align: left;
}
.ns-table th {
position: sticky;
top: 0;
background: #1e293b;
color: #94a3b8;
padding: 10px 14px;
border-bottom: 1px solid #334155;
z-index: 1;
}
.ns-table td {
padding: 9px 14px;
border-bottom: 1px solid #242b38;
color: #cbd5e1;
vertical-align: middle;
}
.ns-table tr:hover { background: rgba(255,255,255,0.04); }
.badge {
display: inline-block;
padding: 2px 6px;
border-radius: 4px;
font-size: 11px;
font-weight: 500;
}
.badge-upvote-in { background: rgba(34, 197, 94, 0.2); color: #86efac; border: 1px solid rgba(34, 197, 94, 0.4); }
.badge-transfer-out { background: rgba(239, 68, 68, 0.2); color: #fca5a5; border: 1px solid rgba(239, 68, 68, 0.4); }
.badge-transfer-in { background: rgba(59, 130, 246, 0.2); color: #93c5fd; border: 1px solid rgba(59, 130, 246, 0.4); }

.ns-time-cell {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
color: #94a3b8;
font-size: 11.5px;
white-space: nowrap;
}
.ns-uid-link {
color: #60a5fa;
text-decoration: none;
font-family: monospace;
font-size: 12px;
}
.ns-uid-link:hover {
color: #93c5fd;
text-decoration: underline;
}

.ns-user-tag {
color: #38bdf8;
font-weight: 600;
text-decoration: none;
background: rgba(56, 189, 248, 0.12);
padding: 2px 6px;
border-radius: 4px;
border: 1px solid rgba(56, 189, 248, 0.25);
display: inline-block;
margin-right: 8px;
}
.ns-user-tag:hover {
color: #7dd3fc;
background: rgba(56, 189, 248, 0.2);
text-decoration: none;
}

.ns-balance-tag {
color: #94a3b8;
font-size: 11px;
background: #0f172a;
padding: 2px 6px;
border-radius: 4px;
border: 1px solid #334155;
margin-right: 6px;
font-family: monospace;
}
.ns-memo-tag {
color: #f1f5f9;
margin-left: 4px;
}

.ns-pagination-bar {
padding: 8px 20px;
background: #181b24;
border-top: 1px solid #334155;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 12px;
color: #94a3b8;
}
.ns-page-controls { display: flex; gap: 8px; }
.ns-page-btn {
background: #334155;
color: #fff;
border: none;
padding: 4px 10px;
border-radius: 4px;
cursor: pointer;
}
.ns-page-btn:disabled { opacity: 0.4; cursor: not-allowed; }

.ns-progress { padding: 40px; text-align: center; color: #94a3b8; font-size: 14px; }
`);

let cachedRecords = [];
let currentFilter = 'all';
let currentPage = 1;
let myUid = null;
let currentWalletBalance = 0;
const userCache = new Map();
let isFetchingUsers = false;

function getBalanceFromSidebar() {
try {
const sidebar = document.querySelector('.sidebar, #sidebar, .user-card, .menu-list, .dashboard-container');
const targetText = sidebar ? sidebar.innerText : '';
const match = targetText.match(/星辰\s*[::]?\s*([0-9]+)/);
if (match && match[1]) {
const num = parseInt(match[1], 10);
if (!isNaN(num) && num > 0) return num;
}
} catch (e) {}
return 0;
}

async function fetchSingleUser(uid) {
try {
const res = await fetch(`https://www.nodeseek.com/api/account/getInfo/${uid}`);
const data = await res.json();
if (data && data.success && data.detail && data.detail.member_name) {
userCache.set(uid, data.detail.member_name);
} else {
userCache.set(uid, `UID:${uid}`);
}
} catch (e) {
userCache.set(uid, `UID:${uid}`);
}
}

async function resolveVisibleUserNames(uids) {
if (isFetchingUsers) return;
const missingUids = [...new Set(uids)].filter(id => id && !userCache.has(id));
if (missingUids.length === 0) return;

isFetchingUsers = true;
for (const uid of missingUids) {
await fetchSingleUser(uid);

document.querySelectorAll(`.ns-user-tag[data-uid="${uid}"]`).forEach(el => {
const name = userCache.get(uid);
el.innerText = (name && !name.startsWith('UID:')) ? `@${name}` : `@UID:${uid}`;
});

await new Promise(r => setTimeout(r, CONFIG.USER_FETCH_DELAY_MS));
}
isFetchingUsers = false;
}

function formatExactTime(val) {
if (!val) return '-';
let d;
if (typeof val === 'number') {
d = new Date(val > 1e11 ? val : val * 1000);
} else {
d = new Date(val);
}
if (isNaN(d.getTime())) return String(val);

const pad = (n) => String(n).padStart(2, '0');
const Y = d.getFullYear();
const M = pad(d.getMonth() + 1);
const D = pad(d.getDate());
const h = pad(d.getHours());
const m = pad(d.getMinutes());
const s = pad(d.getSeconds());
return `${Y}/${M}/${D} ${h}:${m}:${s}`;
}

function extractAmount(r) {
const priorityKeys = [
'amount', 'stardust', 'stardusts', 'count', 'delta', 'value', 'points',
'num', 'quantity', 'change', 'trade_stardust', 'credit', 'score', 'gain'
];
for (const k of priorityKeys) {
if (r[k] !== undefined && r[k] !== null && r[k] !== '') {
const num = parseFloat(String(r[k]).replace(/[^\d.-]/g, ''));
if (!isNaN(num) && num !== 0) return num;
}
}

const ignoreKeys = new Set([
'id', '_id', 'member_id', 'peer_id', 'ref_id', 'post_id', 'comment_id',
'created_at', 'updated_at', 'timestamp', 'time', 'status', 'code',
'floor', 'balance', 'remain', 'type'
]);
for (const [k, v] of Object.entries(r)) {
if (!ignoreKeys.has(k)) {
if (typeof v === 'number' && v !== 0) return v;
if (typeof v === 'string' && /^-?\d+(\.\d+)?$/.test(v.trim())) {
const parsed = parseFloat(v.trim());
if (!isNaN(parsed) && parsed !== 0) return parsed;
}
}
}
return 0;
}

function extractBalance(r) {
const keys = [
'balance', 'current_balance', 'remain', 'remain_stardust', 'after_balance',
'user_balance', 'stardust_balance', 'current_stardust', 'after', 'current',
'user_stardust', 'total', 'cur_balance', 'post_balance', 'remained', 'available',
'total_stardust'
];
for (const k of keys) {
if (r[k] !== undefined && r[k] !== null && r[k] !== '') {
const num = parseFloat(String(r[k]).replace(/[^\d.-]/g, ''));
if (!isNaN(num) && num >= 0) return num;
}
}
return null;
}

function formatDetailHtml(item) {
const parts = [];

if (item.targetUid) {
const cachedName = userCache.get(item.targetUid);
const showName = (cachedName && !cachedName.startsWith('UID:')) ? `@${cachedName}` : `@UID:${item.targetUid}`;
parts.push(`<a class="ns-user-tag" data-uid="${item.targetUid}" href="https://www.nodeseek.com/space/${item.targetUid}#/general" target="_blank" title="点击访问对方空间">${showName}</a>`);
}

if (item.balance !== null && item.balance !== undefined) {
parts.push(`<span class="ns-balance-tag">💰 变动后余额: ${item.balance}</span>`);
}

if (item.memo) {
parts.push(`<span class="ns-memo-tag">📝 留言: ${item.memo}</span>`);
}

return parts.length > 0 ? parts.join(' ') : '-';
}

function buildMarkdownTable(list) {
if (!list || list.length === 0) {
return `*(暂无相关记录)*\n\n`;
}

let md = `| 时间 | 类型 | 数额 | 对方 UID | 明细信息 (@对方用户名 / 变动后余额 / 留言) |\n`;
md += `| :--- | :--- | :--- | :--- | :--- |\n`;

list.forEach(item => {
let typeLabel = '';
if (item.category === 'upvote_in') typeLabel = '💖 收到点赞';
else if (item.category === 'transfer_out') typeLabel = '💸 送出转账';
else if (item.category === 'transfer_in') typeLabel = '💰 收到转账';
else typeLabel = '星辰流水';

const amountLabel = item.amount > 0 ? `+${item.amount}` : `${item.amount}`;
const uidLabel = item.targetUid ? `[UID: ${item.targetUid}](https://www.nodeseek.com/space/${item.targetUid}#/general)` : '-';

const detailParts = [];
if (item.targetUid) {
const name = userCache.get(item.targetUid);
const showName = (name && !name.startsWith('UID:')) ? `@${name}` : `@UID:${item.targetUid}`;
detailParts.push(`[${showName}](https://www.nodeseek.com/space/${item.targetUid}#/general)`);
}
if (item.balance !== null && item.balance !== undefined) {
detailParts.push(`余额: ${item.balance}`);
}
if (item.memo) {
detailParts.push(`留言: ${item.memo.replace(/\|/g, '/')}`);
}

const detailLabel = detailParts.length > 0 ? detailParts.join(' · ') : '-';
md += `| ${item.time} | ${typeLabel} | ${amountLabel} | ${uidLabel} | ${detailLabel} |\n`;
});
md += `\n`;
return md;
}

function buildUserSummaryTable(list, actionText) {
if (!list || list.length === 0) return '';

const userMap = new Map();
list.forEach(item => {
if (!item.targetUid) return;
if (!userMap.has(item.targetUid)) {
const rawName = userCache.get(item.targetUid);
const showName = (rawName && !rawName.startsWith('UID:')) ? `@${rawName}` : `@UID:${item.targetUid}`;
userMap.set(item.targetUid, {
uid: item.targetUid,
name: showName,
count: 0,
totalAmount: 0
});
}
const stat = userMap.get(item.targetUid);
stat.count += 1;
stat.totalAmount += Math.abs(item.amount);
});

const sortedUsers = Array.from(userMap.values()).sort((a, b) => b.count - a.count || b.totalAmount - a.totalAmount);
if (sortedUsers.length === 0) return '';

let md = `### 👑 贡献者统计排行 (小计共 ${sortedUsers.length} 位用户)\n\n`;
md += `| 排名 | 用户 (@昵称) | 对方 UID | ${actionText}次数 | 累计星辰 |\n`;
md += `| :--- | :--- | :--- | :--- | :--- |\n`;

sortedUsers.forEach((u, index) => {
const rank = index + 1;
const rankIcon = rank === 1 ? '🥇 1' : rank === 2 ? '🥈 2' : rank === 3 ? '🥉 3' : String(rank);
md += `| ${rankIcon} | [${u.name}](https://www.nodeseek.com/space/${u.uid}#/general) | [UID: ${u.uid}](https://www.nodeseek.com/space/${u.uid}#/general) | **${u.count} 次** | **${u.totalAmount}** |\n`;
});
md += `\n`;
return md;
}

async function copyMarkdownTabs() {
if (cachedRecords.length === 0) {
alert("暂无流水数据可导出,请先抓取数据!");
return;
}

const copyBtn = document.getElementById('ns-btn-copy-md');
const originText = copyBtn ? copyBtn.innerText : '📋 复制 Markdown (含小计)';

const allDistinctUids = [...new Set(cachedRecords.map(r => r.targetUid).filter(Boolean))];
const unparsedUids = allDistinctUids.filter(uid => !userCache.has(uid) || userCache.get(uid).startsWith('UID:'));

if (unparsedUids.length > 0) {
if (copyBtn) copyBtn.disabled = true;
let finishedCount = 0;
const totalToFetch = unparsedUids.length;

for (let i = 0; i < totalToFetch; i += CONFIG.BATCH_CONCURRENCY) {
const batch = unparsedUids.slice(i, i + CONFIG.BATCH_CONCURRENCY);
await Promise.all(batch.map(fetchSingleUser));
finishedCount += batch.length;

if (copyBtn) {
copyBtn.innerText = `⏳ 正在解析全量昵称 (${finishedCount}/${totalToFetch})...`;
}
await new Promise(r => setTimeout(r, 60));
}

if (copyBtn) copyBtn.disabled = false;
renderTable();
}

const upvoteInList = cachedRecords.filter(r => r.category === 'upvote_in');
const transferOutList = cachedRecords.filter(r => r.category === 'transfer_out');
const transferInList = cachedRecords.filter(r => r.category === 'transfer_in');

let totalIncome = 0;
let totalExpense = 0;
let upvoteInStardust = 0;
let transferOutStardust = 0;
let transferInStardust = 0;

cachedRecords.forEach(item => {
if (item.category === 'upvote_in') {
upvoteInStardust += item.amount;
totalIncome += item.amount;
} else if (item.category === 'transfer_in') {
transferInStardust += item.amount;
totalIncome += item.amount;
} else if (item.category === 'transfer_out') {
const absVal = Math.abs(item.amount);
transferOutStardust += absVal;
totalExpense += absVal;
}
});

const calculatedBal = totalIncome - totalExpense;
const displayBal = (calculatedBal > 0) ? calculatedBal : currentWalletBalance;

let fullMd = `:::: tabs\n`;

fullMd += `::: tab-item 💖 收到的点赞\n`;
fullMd += buildUserSummaryTable(upvoteInList, '获赠点赞');
fullMd += `### 📜 点赞明细记录\n\n`;
fullMd += buildMarkdownTable(upvoteInList);
fullMd += `:::\n`;

fullMd += `::: tab-item 💸 送出的转账\n`;
fullMd += buildUserSummaryTable(transferOutList, '转出');
fullMd += `### 📜 送出转账明细\n\n`;
fullMd += buildMarkdownTable(transferOutList);
fullMd += `:::\n`;

fullMd += `::: tab-item 💰 收到的转账\n`;
fullMd += buildUserSummaryTable(transferInList, '转入');
fullMd += `### 📜 收到转账明细\n\n`;
fullMd += buildMarkdownTable(transferInList);
fullMd += `:::\n`;

fullMd += `::: tab-item 🎁 全部流水\n`;
fullMd += `### 📊 账本总览汇总\n\n`;
fullMd += `- **当前星辰余额**: ${displayBal}\n`;
fullMd += `- **真实总流水**: ${cachedRecords.length} 条\n`;
fullMd += `- **累计收入**: +${totalIncome}\n`;
fullMd += `- **累计支出**: -${totalExpense}\n`;
fullMd += `- **收到点赞**: ${upvoteInList.length} 次 (+${upvoteInStardust})\n`;
fullMd += `- **送出转账**: ${transferOutList.length} 笔 (-${transferOutStardust})\n`;
fullMd += `- **收到转账**: ${transferInList.length} 笔 (+${transferInStardust})\n\n`;
fullMd += `### 📜 全部流水明细\n\n`;
fullMd += buildMarkdownTable(cachedRecords);
fullMd += `:::\n`;

fullMd += `::::\n`;

if (typeof GM_setClipboard === 'function') {
GM_setClipboard(fullMd, 'text');
} else if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(fullMd);
}

if (copyBtn) {
copyBtn.innerText = "✅ 全量用户名 MD 已复制到剪贴板!";
copyBtn.style.background = "#059669";
setTimeout(() => {
copyBtn.innerText = originText;
copyBtn.style.background = "#7c3aed";
}, 2500);
}
}

function initUI() {
if (document.getElementById('ns-stardust-btn')) return;

const btn = document.createElement('div');
btn.id = 'ns-stardust-btn';
btn.innerHTML = `🌟 星辰账本`;
btn.onclick = openModal;
document.body.appendChild(btn);

const modalMask = document.createElement('div');
modalMask.id = 'ns-modal-mask';
modalMask.innerHTML = `
<div id="ns-stardust-modal">
<div class="ns-modal-header">
<div class="ns-modal-title">🌌 NodeSeek 全量星辰账本分析器</div>
<div class="ns-close-btn" id="ns-modal-close">&times;</div>
</div>
<div class="ns-stats-bar">
<div class="ns-stat-item">当前星辰余额: <span id="ns-stat-balance" class="ns-stat-val val-balance">0</span></div>
<div class="ns-stat-item">真实总流水: <span id="ns-stat-total" class="ns-stat-val">0 条</span></div>
<div class="ns-stat-item">累计收入: <span id="ns-stat-income" class="ns-stat-val val-plus">+0</span></div>
<div class="ns-stat-item">累计支出: <span id="ns-stat-expense" class="ns-stat-val val-minus">-0</span></div>
<div class="ns-stat-item">收到点赞: <span id="ns-stat-upvote" class="ns-stat-val val-plus">0 次 (+0)</span></div>
<div class="ns-stat-item">送出转账: <span id="ns-stat-transfer-out" class="ns-stat-val val-minus">0 笔 (-0)</span></div>
<div class="ns-stat-item">收到转账: <span id="ns-stat-transfer-in" class="ns-stat-val val-plus">0 笔 (+0)</span></div>
<div class="ns-stat-item">状态: <span id="ns-status-text" style="color:#60a5fa;font-weight:bold;">待加载</span></div>
</div>
<div class="ns-controls">
<button class="ns-tab-btn active" data-filter="all">全部流水</button>
<button class="ns-tab-btn" data-filter="upvote_in">💖 收到点赞 (+1)</button>
<button class="ns-tab-btn" data-filter="transfer_out">💸 送出的转账 (支出)</button>
<button class="ns-tab-btn" data-filter="transfer_in">💰 收到转账 (收入)</button>
<button class="ns-tab-btn" id="ns-btn-reload" style="background:#059669;color:#fff;">🔄 重新抓取</button>
<button class="ns-tab-btn" id="ns-btn-copy-md" style="background:#7c3aed;color:#fff;font-weight:bold;">📋 复制 Markdown (含小计)</button>
<input type="text" id="ns-search" class="ns-search-input" placeholder="搜索 用户名 / UID / 留言..." />
</div>
<div class="ns-table-container" id="ns-table-box">
<div class="ns-progress">点击开始抓取...</div>
</div>
<div class="ns-pagination-bar" id="ns-pagination-bar">
<span id="ns-page-info">第 1 / 1 页 (共 0 条)</span>
<div class="ns-page-controls">
<button class="ns-page-btn" id="ns-prev-page">上一页</button>
<button class="ns-page-btn" id="ns-next-page">下一页</button>
</div>
</div>
</div>
`;
document.body.appendChild(modalMask);

document.getElementById('ns-modal-close').onclick = closeModal;
modalMask.onclick = (e) => { if (e.target === modalMask) closeModal(); };

document.querySelectorAll('.ns-tab-btn[data-filter]').forEach(b => {
b.onclick = () => {
document.querySelectorAll('.ns-tab-btn[data-filter]').forEach(btn => btn.classList.remove('active'));
b.classList.add('active');
currentFilter = b.getAttribute('data-filter');
currentPage = 1;
renderTable();
};
});

document.getElementById('ns-btn-reload').onclick = () => loadAllData(true);
document.getElementById('ns-btn-copy-md').onclick = copyMarkdownTabs;

document.getElementById('ns-search').oninput = () => {
currentPage = 1;
renderTable();
};

document.getElementById('ns-prev-page').onclick = () => {
if (currentPage > 1) {
currentPage--;
renderTable();
}
};

document.getElementById('ns-next-page').onclick = () => {
currentPage++;
renderTable();
};
}

function openModal() {
document.getElementById('ns-modal-mask').style.display = 'flex';
const sidebarBal = getBalanceFromSidebar();
if (sidebarBal > 0) {
currentWalletBalance = sidebarBal;
renderStats();
}
if (cachedRecords.length === 0) {
loadAllData();
}
}

function closeModal() {
document.getElementById('ns-modal-mask').style.display = 'none';
}

async function getMyUid() {
if (myUid) return myUid;

try {
const res = await fetch("https://www.nodeseek.com/api/account/getInfo");
const data = await res.json();
if (data && data.success && data.detail) {
myUid = parseInt(data.detail.member_id || data.detail.id || data.detail.uid, 10);
if (data.detail.member_name) {
userCache.set(myUid, data.detail.member_name);
}
if (data.detail.stardust !== undefined && data.detail.stardust !== null) {
const parsed = Number(data.detail.stardust);
if (!isNaN(parsed) && parsed > 0) currentWalletBalance = parsed;
}
}
} catch (e) {}

if (!myUid) {
const manual = prompt("未能自动识别当前登录 UID,请输入您的 UID:");
myUid = parseInt(manual, 10);
}
return myUid;
}

async function loadAllData(force = false) {
if (cachedRecords.length > 0 && !force) return;

const tableBox = document.getElementById('ns-table-box');
const statusText = document.getElementById('ns-status-text');
if (tableBox) tableBox.innerHTML = `<div class="ns-progress">⏳ 正在精准拉取个人真实全量流水账本...</div>`;
if (statusText) statusText.innerText = `正在初始化...`;

const uid = await getMyUid();
if (!uid) {
if (tableBox) tableBox.innerHTML = `<div class="ns-progress">❌ 未能获取到当前 UID</div>`;
if (statusText) statusText.innerText = `UID 异常`;
return;
}

let rawList = [];
let cursor = null;
let hasMore = true;
let batch = 0;

try {
while (hasMore) {
batch++;
const url = new URL("https://www.nodeseek.com/api/stardust/list");
url.searchParams.set("count", String(CONFIG.COUNT_PER_REQ));
url.searchParams.set("member_id", String(uid));
if (cursor) url.searchParams.set("before_id", String(cursor));

if (statusText) statusText.innerText = `第 ${batch} 批(已获取 ${rawList.length} 条)...`;

const res = await fetch(url);
const data = await res.json();

if (!data.success || !data.records || data.records.length === 0) break;

rawList = rawList.concat(data.records);
cursor = data.cursor;
hasMore = data.exist_more;

if (!hasMore) break;
await new Promise(r => setTimeout(r, CONFIG.DELAY_MS));
}

const uniqueMap = new Map();
rawList.forEach(r => {
const rawCreatedAt = typeof r.created_at === 'number' ? (r.created_at > 1e11 ? r.created_at : r.created_at * 1000) : new Date(r.created_at).getTime();
const id = r.id || `${rawCreatedAt}_${r.peer_id}_${r.member_id}`;
if (!uniqueMap.has(id)) {
uniqueMap.set(id, {
raw: r,
id: id,
rawCreatedAt: rawCreatedAt || 0
});
}
});

const sortedList = Array.from(uniqueMap.values()).sort((a, b) => b.rawCreatedAt - a.rawCreatedAt);

const processed = [];
sortedList.forEach(item => {
const r = item.raw;
const mId = r.member_id ? parseInt(r.member_id, 10) : 0;
const pId = r.peer_id ? parseInt(r.peer_id, 10) : 0;
const rawType = (r.type || '').toLowerCase();
const refId = parseInt(r.ref_id || r.refId || 0, 10);

const extractedNum = extractAmount(r);
const isUpvote = (refId === 10) || rawType.includes('upvote') || rawType.includes('like') || Boolean(r.comment_id);

let category = 'transfer_out';
let finalAmount = 0;

if (isUpvote) {
category = 'upvote_in';
finalAmount = extractedNum > 0 ? extractedNum : 1;
} else {
if (extractedNum > 0 || rawType.includes('in') || rawType.includes('receive') || (mId !== uid && mId > 0)) {
category = 'transfer_in';
finalAmount = Math.abs(extractedNum || 1);
} else if (extractedNum < 0 || rawType.includes('out') || rawType.includes('send') || rawType.includes('pay')) {
category = 'transfer_out';
finalAmount = -Math.abs(extractedNum || 1);
} else {
category = (mId === uid && pId) ? 'transfer_out' : 'transfer_in';
finalAmount = (category === 'transfer_out') ? -1 : 1;
}
}

const targetUid = (pId && pId !== uid) ? pId : ((mId && mId !== uid) ? mId : (pId || mId || null));

processed.push({
id: item.id,
rawCreatedAt: item.rawCreatedAt,
amount: finalAmount,
targetUid: targetUid,
memo: r.memo || r.reason || r.description || r.note || null,
balance: extractBalance(r),
category: category,
time: formatExactTime(r.created_at)
});
});

cachedRecords = processed;

currentPage = 1;
if (statusText) statusText.innerText = `已就绪`;

renderStats();
renderTable();
} catch (e) {
if (tableBox) tableBox.innerHTML = `<div class="ns-progress">❌ 获取中断: ${e.message}</div>`;
if (statusText) statusText.innerText = `获取失败`;
}
}

function renderStats() {
let totalIncome = 0;
let totalExpense = 0;
let upvoteInCount = 0;
let upvoteInStardust = 0;
let transferOutCount = 0;
let transferOutStardust = 0;
let transferInCount = 0;
let transferInStardust = 0;

cachedRecords.forEach(item => {
if (item.category === 'upvote_in') {
upvoteInCount++;
upvoteInStardust += item.amount;
totalIncome += item.amount;
} else if (item.category === 'transfer_in') {
transferInCount++;
transferInStardust += item.amount;
totalIncome += item.amount;
} else if (item.category === 'transfer_out') {
const absVal = Math.abs(item.amount);
transferOutCount++;
transferOutStardust += absVal;
totalExpense += absVal;
}
});

const netCalculated = totalIncome - totalExpense;
if (netCalculated > 0) {
currentWalletBalance = netCalculated;
} else {
const sidebarBal = getBalanceFromSidebar();
if (sidebarBal > 0) currentWalletBalance = sidebarBal;
}

const elBalance = document.getElementById('ns-stat-balance');
const elTotal = document.getElementById('ns-stat-total');
const elIncome = document.getElementById('ns-stat-income');
const elExpense = document.getElementById('ns-stat-expense');
const elUpvote = document.getElementById('ns-stat-upvote');
const elTransferOut = document.getElementById('ns-stat-transfer-out');
const elTransferIn = document.getElementById('ns-stat-transfer-in');

if (elBalance) elBalance.innerText = String(currentWalletBalance);
if (elTotal) elTotal.innerText = `${cachedRecords.length} 条`;
if (elIncome) elIncome.innerText = `+${totalIncome}`;
if (elExpense) elExpense.innerText = `-${totalExpense}`;
if (elUpvote) elUpvote.innerText = `${upvoteInCount} 次 (+${upvoteInStardust})`;
if (elTransferOut) elTransferOut.innerText = `${transferOutCount} 笔 (-${transferOutStardust})`;
if (elTransferIn) elTransferIn.innerText = `${transferInCount} 笔 (+${transferInStardust})`;
}

function renderTable() {
const tableBox = document.getElementById('ns-table-box');
const searchKeyword = document.getElementById('ns-search').value.trim().toLowerCase();

const filtered = cachedRecords.filter(item => {
if (currentFilter !== 'all' && item.category !== currentFilter) {
return false;
}

if (searchKeyword) {
const uidStr = String(item.targetUid || '');
const nameStr = (userCache.get(item.targetUid) || '').toLowerCase();
const memoStr = String(item.memo || '').toLowerCase();
const timeStr = String(item.time || '');
return uidStr.includes(searchKeyword) || nameStr.includes(searchKeyword) || memoStr.includes(searchKeyword) || timeStr.includes(searchKeyword);
}
return true;
});

const totalItems = filtered.length;
const totalPages = Math.ceil(totalItems / CONFIG.PAGE_SIZE) || 1;
if (currentPage > totalPages) currentPage = totalPages;
if (currentPage < 1) currentPage = 1;

const startIndex = (currentPage - 1) * CONFIG.PAGE_SIZE;
const pageRecords = filtered.slice(startIndex, startIndex + CONFIG.PAGE_SIZE);

const pageInfo = document.getElementById('ns-page-info');
const prevBtn = document.getElementById('ns-prev-page');
const nextBtn = document.getElementById('ns-next-page');

if (pageInfo) pageInfo.innerText = `第 ${currentPage} / ${totalPages} 页 (共 ${totalItems} 条)`;
if (prevBtn) prevBtn.disabled = currentPage <= 1;
if (nextBtn) nextBtn.disabled = currentPage >= totalPages;

if (pageRecords.length === 0) {
if (tableBox) tableBox.innerHTML = `<div class="ns-progress">未找到符合条件的记录</div>`;
return;
}

const visibleUids = [];

const rowsHtml = pageRecords.map(item => {
let badgeHtml = '';
let amountHtml = '';

if (item.amount > 0) {
amountHtml = `<span class="val-plus">+${item.amount}</span>`;
} else if (item.amount < 0) {
amountHtml = `<span class="val-minus">${item.amount}</span>`;
} else {
amountHtml = `<span>0</span>`;
}

switch (item.category) {
case 'upvote_in':
badgeHtml = `<span class="badge badge-upvote-in">💖 收到点赞</span>`;
break;
case 'transfer_out':
badgeHtml = `<span class="badge badge-transfer-out">💸 送出转账</span>`;
break;
case 'transfer_in':
badgeHtml = `<span class="badge badge-transfer-in">💰 收到转账</span>`;
break;
default:
badgeHtml = `<span class="badge badge-transfer-out">💸 送出转账</span>`;
break;
}

let uidCellHtml = '-';
if (item.targetUid) {
visibleUids.push(item.targetUid);
uidCellHtml = `<a class="ns-uid-link" href="https://www.nodeseek.com/space/${item.targetUid}#/general" target="_blank">UID: ${item.targetUid}</a>`;
}

const detailHtml = formatDetailHtml(item);

return `
<tr>
<td class="ns-time-cell">${item.time}</td>
<td>${badgeHtml}</td>
<td><b>${amountHtml}</b></td>
<td>${uidCellHtml}</td>
<td>${detailHtml}</td>
</tr>
`;
}).join('');

if (tableBox) {
tableBox.innerHTML = `
<table class="ns-table">
<thead>
<tr>
<th style="width: 170px;">时间 (精确秒级)</th>
<th style="width: 120px;">类型</th>
<th style="width: 90px;">数额</th>
<th style="width: 110px;">对方 UID</th>
<th>明细信息 (@对方用户名 / 变动后余额 / 转账留言)</th>
</tr>
</thead>
<tbody>${rowsHtml}</tbody>
</table>
`;
}

resolveVisibleUserNames(visibleUids);
}

GM_registerMenuCommand("🌟 打开星辰账本分析器", openModal);
initUI();
})();


代码来来自 @小号 刷星辰检测脚本(更新版)基础上迭代,仅进行代码无错校验,并未进行任何性能优化与冲突审计。


nsapp://stardust-receive?member_id=39375&ref_id=78504510&description=人生若只如初见,何须以猜忌量真心;愿你卸下满怀疑云,还彼此最初的坦荡与笃定。&diff=1&onetime=false

最新回复 (51)
  • Alloon 08-29 10:48
    1

    没事 如果论坛不管 你也刷就完了 ^-^

  • solaireh3 08-29 10:49
    2

    ^-^ 没必要理睬

  • chenhaoyujj 08-29 10:49
    3

    吃瓜

  • 1x 08-29 10:51
    4

    你好👋我是骗星辰的


    nsapp://stardust-receive?member_id=58464&ref_id=94798566&description=愿者上钩&diff=1&onetime=false


    nsapp://stardust-receive?member_id=58464&ref_id=6142145&description=不愿者也上钩&diff=2&onetime=false


    nsapp://stardust-receive?member_id=58464&ref_id=901205&description=统统上钩&diff=3&onetime=false


    好奇怪,三个 ref id 不一样长

  • 80hou 楼主 08-29 10:52
    5

    @Alloon #1


    这谜语人造谣真的就靠一张图加一张嘴了. ^-^ 玷污我清白之身.


    昨夜睡眼惺忪无缘无故被人怀疑刷星辰.真的是,星辰公开可追溯的.造谣诽谤也不上证据. ^-^

  • juvenile1024 08-29 10:53
    6

    支持脑婆捏

    ^-^ ^-^ ^-^

  • 昶- 08-29 10:54
    7

    ^-^ 这瓜不甜

  • 我也要打十个 08-29 10:56
    8

    看不懂这里面的弯弯绕

    楼主这个人平时很有意思 是个活宝

    带给大家很多快乐

    ^-^

  • 80hou 楼主 08-29 11:00
    9

    @昶- #7 发布于2026/8/29 10:54:15

    ^-^ 这瓜不甜


    nsapp://stardust-receive?member_id=39375&ref_id=21645602&description=V我4个星辰%2C我去华强那边买个保熟的瓜.嘻嘻%2C来NS这么久都没从你这薅一个星辰过%2C必须打破魔咒.&diff=4&onetime=false

  • tafei 08-29 11:02
    10

    80hou 关注的人挺多,基本都有回应,赠人玫瑰,手留余香

    想要星辰 ^-^


    nsapp://stardust-receive?member_id=50489&ref_id=23141323&description=赛博乞讨中&diff=8&onetime=true




    底下的小字怎么没有了

    你未付款 , 共计 0 用户付款, 共收到 0 🌌

  • ZaiLin 08-29 11:03
    11

    支持楼主 ^-^

  • clawoo 08-29 11:05
    12

    啊?还有我的事? ^-^

    还有截图为什么不截全,这说明有8个人认可我的说法 ^-^


  • 80hou 楼主 08-29 11:10
    13

    @clawoo #12 发布于2026/8/29 11:05:40

    啊?还有我的事? ^-^


    坏人总喜欢引用好人的话题..嘻嘻.不要在意啦. ^-^


    只是懒得打码 ^-^

  • 80hou 楼主 08-29 11:13
    14

    @clawoo #12




  • clawoo 08-29 11:17
    15

    @80hou #14

    不用理他,是不是互刷管理后台一看就知道了 ^-^

  • 80hou 楼主 08-29 11:17
    16

    @tafei #10 发布于2026/8/29 11:02:35,编辑于2026/8/29 11:06:56

    80hou 关注的人挺多,基本都有回应,赠人玫瑰,手留余香

    想要星辰 ^-^


    nsapp://stardust-receive?member_id=50489&ref_id=23141323&description=赛博乞讨中&diff=8&onetime=true




    底下的小字怎么没有了

    你未付款 , 共计 0 用户付款, 共收到 0 🌌




    不知道哈,最近好像有时候会这样不显示的.不知道什么原因,有时候又显示的.

  • juvenile1024 08-29 11:18
    17

    到底谁是你老公?

  • tafei 08-29 11:18
    18

    @80hou #16 ^-^ 第一次遇到

  • 80hou 楼主 08-29 11:19
    19

    @clawoo #15 发布于2026/8/29 11:17:08

    @80hou #14

    不用理他,是不是互刷管理后台一看就知道了 ^-^


    所以闲的啊,把星辰追溯这个脚本完善了下统计.

    nsapp://stardust-receive?member_id=39375&ref_id=91284457&description=毕竟更直观的数据才是对事件真相的还原.毕竟人都是先入为主的.透过事务方能看透本质.&diff=1&onetime=false

  • clawoo 08-29 11:20
    20

    @80hou #19

    接着送接着点,气死他 ^-^

  • sdo888 08-29 11:21
    21


    试试 ^-^

  • juvenile1024 08-29 11:21
    22

    @juvenile1024 #17 发布于2026/8/29 11:18:31

    到底谁是你老公?


    回答我!look in my eyes!

  • 80hou 楼主 08-29 11:27
    23

    @clawoo #20 发布于2026/8/29 11:20:27

    @80hou #19

    接着送接着点,气死他 ^-^




    昨天被诽谤时候还是1706星辰,今天直接1822开头了..这神人妙不可言. ^-^

  • 80hou 楼主 08-29 11:28
    24

    @sdo888 #21 发布于2026/8/29 11:21:14

    nsapp://stardust-receive?member_id=20663&ref_id=16475381&description=Pay with Stardust&diff=1&onetime=true


    试试 ^-^




    是勾选了一次性收款么..平时倒是没注意这个区别. ^-^

  • juvenile1024 08-29 11:32
    25

    @80hou #24 回答我!

  • 80hou 楼主 08-29 11:36
    26

    @juvenile1024 #25 发布于2026/8/29 11:32:54

    @80hou #24 回答我!


    nsapp://stardust-receive?member_id=39375&ref_id=15827215&description=婆娘被污蔑的时候%2C竟然没有挺身而出..老伤心了%2C我现在去打胎的路上.车胎都气炸咯.赶紧打钱补胎&diff=45&onetime=false

  • juvenile1024 08-29 11:37
    27

    @80hou #26 奶奶的,你艾特我了?我上哪里挺身而出去?

  • 神秘买鸡人 08-29 11:38
    28

    nsapp://stardust-receive?member_id=60154&ref_id=63471715&description=Pay with Stardust&diff=1&onetime=false

    试一试

  • 80hou 楼主 08-29 11:42
    29

    @juvenile1024 #27 发布于2026/8/29 11:37:57

    @80hou #26 奶奶的,你艾特我了?我上哪里挺身而出去?


    ^-^ 那你半夜At我,是让我自证清白么,都被玷污糟蹋成什么样子了.. ^-^


    nsapp://stardust-receive?member_id=39375&ref_id=67148760&description= look in my eyes!我到现在还以泪洗面呢 &diff=5&onetime=false

  • juvenile1024 08-29 11:43
    30

    @80hou #29 我哪里半夜艾特你了?

  • juvenile1024 08-29 11:50
    31

    @80hou #29 看看,喜欢看被操哭的样子

  • 80hou 楼主 08-29 11:52
    32

    @juvenile1024 #30 发布于2026/8/29 11:43:33

    @80hou #29 我哪里半夜艾特你了?




    这不是半夜是啥,昨天在听孙子兵法说书的,睡得迷迷糊糊,就说TG啥情况,一直震动个不停..


    原来是老公一直At提醒我. ^-^ 是我看错了时间..嘻嘻 ^-^

  • 梦影 08-29 11:53
    33

  • WZ-Software 08-29 11:53
    34

    nsapp://stardust-receive?member_id=4398&ref_id=15965495&description=老大饿饿&diff=99&onetime=false


    老大这样真的会有人给星辰吗 ^-^

  • 梦影 08-29 11:54
    35

    @WZ-Software #34 贪了兄弟,攻略度还不够阿

  • juvenile1024 08-29 11:54
    36

    @80hou #32

    罚你给我剪指甲,下不为例

    ^-^ ^-^

  • 80hou 楼主 08-29 11:55
    37

    @梦影 #35 发布于2026/8/29 11:54:12

    @WZ-Software #34 贪了兄弟,攻略度还不够阿


    ^-^ 要细水长流,天天跟着薅才是长久之道. ^-^

  • 80hou 楼主 08-29 11:57
    38

    @juvenile1024 #36 发布于2026/8/29 11:54:53

    @80hou #32

    罚你给我剪指甲,下不为例

    ^-^ ^-^




    感觉要把你名字也加入进去....还有那个张小泉 ^-^

  • juvenile1024 08-29 12:02
    39

    @80hou #38 你老公正乐此不疲的吃瓜呢,别闹

  • 80hou 楼主 08-29 12:06
    40

    @juvenile1024 #39 发布于2026/8/29 12:02:32

    @80hou #38 你老公正乐此不疲的吃瓜呢,别闹


    吃饭去啦,提桶跑路了.. ^-^


  • juvenile1024 08-29 12:07
    41

    @80hou #40 嗯,记得好好吃饭哦

  • cn1831 08-29 13:01
    42

    扰乱抽奖秩序真让人绷不住 ^-^

  • sss1231 08-29 18:42
    43

    @juvenile1024 #41 你们真的是夫妻嘛

  • 233bit 08-29 18:59
    44

    看了一下确实没有互刷,只不过是有个账号送得多点罢了

  • juvenile1024 08-29 19:53
    45

    @sss1231 #43

    我很难跟你解释啊,@80hou 你出来让哈基米解释一下吧

  • JohnLeo 08-29 19:56
    46

    @juvenile1024 #45 太变态了,趁我修复落地的机的这几天,你们的感情又精进了吗 ^-^

  • juvenile1024 08-29 19:57
    47

    @JohnLeo #46 哈哈哈哈哈,现在半夜叫醒 @80hou 的已经不是TG消息了捏

    ^-^ ^-^ ^-^

  • 陌生人 08-29 20:04
    48

    无视别人闲话了,自己开心就好


  • 80hou 楼主 08-29 20:59
    49

    @sss1231 #43 发布于2026/8/29 18:42:19

    @juvenile1024 #41 你们真的是夫妻嘛


    那肯定不是的啦,顶多算星辰夫妻 ^-^

  • 80hou 楼主 08-29 21:04
    50

    @233bit #44 发布于2026/8/29 18:59:30

    看了一下确实没有互刷,只不过是有个账号送得多点罢了


    ^-^ 哈哈哈,那个是痴情种。来Ns一直聊到现在。


    Ns临时夫妻 ^-^

  • juvenile1024 08-29 21:26
    51

    @80hou #50 什么?你我 怎么两清 怎么忍心~ 怎么做回 甲乙~ 丙丁

* 帖子来源NodeSeek
返回