拾荒小猫无限卡槽控制矩阵远端硬核核心库
Este script no debería instalarse directamente. Es una biblioteca que utilizan otros scripts mediante la meta-directiva de inclusión // @require https://update.greasyfork.org/scripts/579916/1835580/NitterCorpusCore.js
// ==UserScript==
// @name NitterCorpusCore
// @version 1.2.4
// @description 拾荒小猫无限卡槽控制矩阵远端硬核核心库 (1800px究极宽体+GM跨域修复版)
// @author Gemini Collaborator
// @grant GM_xmlhttpRequest
// @grant GM_setClipboard
// ==/UserScript==
(function(window) {
'use strict';
const NitterCorpusCore = {
init(options) {
this.version = options.version || '1.0.0';
this.currentUsername = options.username || 'unknown';
this.currentHost = options.host || location.hostname;
this.capturedTweets = options.tweets || [];
this.metaText = options.metaText || '';
this.DB_KEY = `rp_corpus_${this.currentHost}_${this.currentUsername}`;
this.HISTORY_KEY = 'rp_asset_history_pool';
this.SANDBOX_A_KEY = `${this.DB_KEY}_snap_a`;
this.SANDBOX_B_KEY = `${this.DB_KEY}_snap_b`;
this.initStorage();
this.injectStyles();
this.buildDOM();
this.bindEvents();
this.executeAutoRun();
},
initStorage() {
let rawStore = localStorage.getItem(this.DB_KEY);
this.defaultSlots = [
{ id: 'slot_1', name: '🎭 赛博拾荒者', content: '你是一个专业的推文分析师...' },
{ id: 'slot_2', name: '🎭 语料解构师', content: '提取并精炼以下推文的技术内核...' },
{ id: 'slot_3', name: '🎭 仿生复刻机', content: '克隆以下目标用户的发帖逻辑与语气...' }
];
if (!rawStore) {
this.localStore = {
currentPage: 1,
lastUrl: "",
tweets: [],
metaText: this.metaText,
activeSlotId: 'slot_1',
slots: JSON.parse(JSON.stringify(this.defaultSlots)),
config: { img: true, video: true, stamp: true, hot: true, level: 2, customPrompt: '你是一个专业的推文分析师...' }
};
} else {
this.localStore = JSON.parse(rawStore);
if (!this.localStore.slots || this.localStore.slots.length === 0) {
this.localStore.slots = JSON.parse(JSON.stringify(this.defaultSlots));
}
if (!this.localStore.config) {
this.localStore.config = { img: true, video: true, stamp: true, hot: true, level: 2, customPrompt: this.localStore.slots[0].content };
}
}
this.capturedTweets.forEach(t => {
let existIndex = this.localStore.tweets.findIndex(old => old.includes(`[BASETEXT]${t.baseText}[/BASETEXT]`) || old.includes(t.baseText));
if (existIndex !== -1) {
let oldBlock = this.localStore.tweets[existIndex];
if ((oldBlock.includes('💬评论: 0 | 🔄转推: 0') || !oldBlock.includes('[HOTMETRIC]')) && (t.replyCount !== "0" || t.retweetCount !== "0")) {
this.localStore.tweets[existIndex] = t.rawContentBlock;
}
} else {
this.localStore.tweets.push(t.rawContentBlock);
}
});
this.localStore.metaText = this.metaText || this.localStore.metaText;
localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore));
try {
this.assetHistory = JSON.parse(localStorage.getItem(this.HISTORY_KEY)) || [];
} catch(e) { this.assetHistory = []; }
this.snapshottedBackup = null;
},
injectStyles() {
if (document.getElementById('rp-core-styles')) return;
const style = document.createElement('style');
style.id = 'rp-core-styles';
style.innerHTML = `
#rp-toast-container { position: fixed; top: 20px; right: 20px; z-index: 100000; font-family: monospace; pointer-events: none; }
.rp-toast { background: #1e1e2e; color: #cdd6f4; border-left: 4px solid #a6e3a1; padding: 10px 14px; margin-bottom: 8px; border-radius: 4px; box-shadow: 0 4px 12px rgba(0,0,0,0.5); font-size: 11px; min-width: 200px; max-width: 350px; opacity: 0; transform: translateX(50px); transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); pointer-events: auto; }
.rp-toast.show { opacity: 1; transform: translateX(0); }
/* 究极宽体平铺抽屉:1800px 或占满屏幕,右侧对齐,绝不向左侵占你 200px 的常驻面板 */
#rp-mega-drawer { position: fixed; top: 0; right: 0; width: 1800px; max-width: 90vw; height: 100vh; background: rgba(17,17,27,0.85); backdrop-filter: blur(8px); z-index: 99998; font-family: monospace; display: flex; align-items: center; justify-content: flex-end; }
#rp-mega-drawer.hidden { display: none !important; }
/* 三块化超级网格布局:给足纵向高度 */
.mega-layout { width: 100%; height: 98vh; background: #1e1e2e; border: 1px solid #45475a; border-radius: 12px; display: grid; grid-template-rows: 1.2fr 1fr; overflow: hidden; box-shadow: 0 20px 50px rgba(0,0,0,0.8); margin-right: 10px; box-sizing: border-box; }
.mega-top-split { display: grid; grid-template-columns: 350px 1fr; border-bottom: 1px solid #45475a; height: 100%; overflow: hidden; }
/* 左上块:槽位控制及本地总线 */
.mega-sidebar-left { background: #181825; border-right: 1px solid #45475a; padding: 16px; display: flex; flex-direction: column; gap: 12px; overflow-y: auto; box-sizing: border-box; }
/* 右上块:控制面板集群 */
.mega-sidebar-right { background: #1e1e2e; padding: 16px; display: flex; grid-template-columns: 1fr; gap: 12px; overflow-y: auto; box-sizing: border-box; }
/* 下块:主作业区 */
.mega-main-bottom { padding: 16px; display: flex; flex-direction: column; gap: 8px; background: #11111b; box-sizing: border-box; }
.slot-header-area { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #313244; padding-bottom: 6px; }
.btn-create-slot { background: #b4befe; color: #11111b; border: none; padding: 4px 8px; font-size: 11px; font-weight: bold; border-radius: 4px; cursor: pointer; }
.slot-container { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 6px; padding-right: 2px; }
.mega-btn { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: 8px 12px; font-size: 12px; border-radius: 6px; cursor: pointer; text-align: left; transition: all 0.2s; }
.slot-active { background: #f5c2e7 !important; color: #11111b !important; font-weight: bold; }
/* 外部资产加载/大输入框长文本无敌设计 */
.api-flow-wrapper { background: #11111b; border: 1px solid #313244; border-radius: 8px; padding: 12px; display: flex; flex-direction: column; gap: 10px; }
/* 彻底拉大输入框:提供 380px 高度,可直接无压力粘贴全量单文本角色卡 */
.mega-api-textarea { width: 100%; height: 380px; background: #181825; color: #cca7ef; border: 1px solid #45475a; border-radius: 6px; resize: vertical; font-size: 12px; padding: 8px; box-sizing: border-box; line-height: 1.4; font-family: monospace; }
/* 按钮控制网格 */
.api-sub-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.api-sub-btn { border: none; color: #11111b; font-size: 11px; font-weight: bold; height: 28px; border-radius: 5px; cursor: pointer; text-align: center; line-height: 28px; }
.sandbox-row { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; margin-top: 2px; }
.micro-deck-btn { border: none; color: #11111b; font-size: 11px; font-weight: bold; height: 26px; border-radius: 4px; cursor: pointer; text-align: center; }
.btn-deck-grey { background: #313244 !important; color: #585b70 !important; cursor: not-allowed !important; }
/* 在线同步集群 */
.cloud-matrix-box { display: flex; flex-direction: column; gap: 6px; background: #181825; padding: 10px; border-radius: 6px; border: 1px dashed #45475a; }
.cloud-matrix-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.cloud-btn { border: none; color: #11111b; font-size: 11px; font-weight: bold; height: 26px; border-radius: 4px; cursor: pointer; display: flex; align-items: center; justify-content: center; }
/* 历史解析看板独立窗口 */
.history-panel-wrapper { background: #11111b; border: 1px solid #313244; border-radius: 6px; padding: 8px; display: flex; flex-direction: column; height: 110px; box-sizing: border-box; }
.history-list-scroll { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; }
.history-item-row { display: flex; justify-content: space-between; background: #181825; padding: 4px 8px; font-size: 11px; color: #a6e3a1; border-radius: 4px; cursor: pointer; white-space: nowrap; }
/* 本地数据管理组 */
.mega-matrix-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.matrix-btn { background: #313244; color: #cdd6f4; border: 1px solid #45475a; font-size: 11px; height: 26px; border-radius: 4px; cursor: pointer; font-weight: bold; }
/* 下层主作业区拉满 */
.mega-textarea { flex: 1; background: #181825; color: #a6e3a1; border: 1px solid #45475a; border-radius: 8px; padding: 12px; font-family: monospace; font-size: 13px; line-height: 1.5; resize: none; box-sizing: border-box; }
.rp-drawer-btn { width: 100%; margin-top: 4px; height: 24px; background: #b4befe; color: #11111b; border: none; font-size: 10px; font-weight: bold; border-radius: 4px; cursor: pointer; }
`;
document.head.appendChild(style);
const tContainer = document.createElement('div');
tContainer.id = 'rp-toast-container';
document.body.appendChild(tContainer);
},
showToast(title, desc, isErr = false) {
const container = document.getElementById('rp-toast-container');
const toast = document.createElement('div');
toast.className = 'rp-toast';
if (isErr) toast.style.borderLeftColor = '#f38ba8';
toast.innerHTML = `<div style="font-weight:bold;margin-bottom:2px;">${title}</div><div style="color:#a6adc8;font-size:10px;">${desc}</div>`;
container.appendChild(toast);
setTimeout(() => toast.classList.add('show'), 50);
setTimeout(() => { toast.classList.remove('show'); setTimeout(() => toast.remove(), 300); }, 3500);
},
buildDOM() {
const isVisible = localStorage.getItem('rp_panel_visible') !== 'false';
const isDrawerVisible = localStorage.getItem('rp_drawer_visible') === 'true';
// 主控制台浮窗
const panel = document.createElement('div');
panel.id = 'rp-heavy-panel';
panel.style = `position: fixed; bottom: 20px; left: 20px; z-index: 99999; background: #11111b; color: #cdd6f4; padding: 10px; border: 1px solid #45475a; border-radius: 6px; font-family: monospace; font-size: 11px; width: 135px; box-shadow: 0 4px 15px rgba(0,0,0,0.7); box-sizing: border-box; display: ${isVisible ? 'block' : 'none'};`;
panel.innerHTML = `
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:4px;"><span style="color:#f5c2e7; font-weight:bold; font-size:9.5px;">v${this.version}</span><span id="rp-close" style="cursor:pointer; font-weight:bold; color:#f38ba8; font-size:12px;">×</span></div>
<div style="overflow:hidden; text-overflow:ellipsis; white-space:nowrap; width:100%; font-size:9.5px; margin-bottom:3px;">👤:${this.currentUsername}</div>
<div style="font-size:9.5px; color:#a6adc8; margin-bottom:6px;">页:[${this.localStore.currentPage}] 语料:[${this.localStore.tweets.length}条]</div>
<div style="display:flex; justify-content:space-between; margin-bottom:6px; width:100%; gap:2px;">
<button id="btn-run" style="width:25px; height:20px; padding:0; background:#f9e2af; color:#11111b; border:none; cursor:pointer; font-size:10px; font-weight:bold; border-radius:3px;" title="开始挖掘语料">挖</button>
<button id="btn-copy" style="width:25px; height:20px; padding:0; background:#a6e3a1; color:#11111b; border:none; cursor:pointer; font-size:10px; font-weight:bold; border-radius:3px;" title="复制全量语料">拷</button>
<button id="btn-download" style="width:25px; height:20px; padding:0; background:#cca7ef; color:#11111b; border:none; cursor:pointer; font-size:10px; font-weight:bold; border-radius:3px;" title="导出Markdown">存</button>
<button id="btn-zip" style="width:25px; height:20px; padding:0; background:#89b4fa; color:#11111b; border:none; cursor:pointer; font-size:10px; font-weight:bold; border-radius:3px;" title="打包所有博主语料为Zip">包</button>
<button id="btn-clear" style="width:22px; height:20px; padding:0; background:#313244; color:#f38ba8; border:none; cursor:pointer; font-size:9px; font-weight:bold; border-radius:3px;" title="清空当前缓存">清</button>
</div>
<div style="border-top:1px dashed #45475a; padding-top:4px;">
<div style="display:flex; justify-content:space-between; margin-bottom:5px; gap:2px;">
<button id="state-img" style="flex:1; height:18px; border:none; cursor:pointer; font-size:9px; font-weight:bold; border-radius:3px;">图</button>
<button id="state-video" style="flex:1; height:18px; border:none; cursor:pointer; font-size:9px; font-weight:bold; border-radius:3px;">影</button>
<button id="state-stamp" style="flex:1; height:18px; border:none; cursor:pointer; font-size:9px; font-weight:bold; border-radius:3px;">戳</button>
<button id="state-hot" style="flex:1; height:18px; border:none; cursor:pointer; font-size:9px; font-weight:bold; border-radius:3px;">热</button>
</div>
<div style="font-size:9px; display:flex; justify-content:space-between;"><span>调速:</span><span id="speed-txt" style="color:#a6e3a1; font-weight:bold;">3.0s</span></div>
<input type="range" id="cfg-speed" min="1" max="3" step="1" value="${this.localStore.config.level}" style="width:100%; margin:0; cursor:pointer; accent-color:#f5c2e7; height:4px;">
</div>
<button id="btn-toggle-drawer" class="rp-drawer-btn">⚙️ 提示词配置中心</button>
`;
document.body.appendChild(panel);
// 全屏高级抽屉面板
const megaDrawer = document.createElement('div');
megaDrawer.id = 'rp-mega-drawer';
megaDrawer.className = isDrawerVisible ? '' : 'hidden';
megaDrawer.innerHTML = `
<div class="mega-layout">
<div class="mega-top-split">
<div class="mega-sidebar-left">
<div class="slot-header-area">
<span style="color:#f5c2e7; font-size:13px; font-weight:bold;">🎭 角色配置卡槽池</span>
<button id="btn-new-slot" class="btn-create-slot">➕ 新建</button>
</div>
<div id="slot-list-zone" class="slot-container"></div>
<div style="display:flex; flex-direction:column; gap:4px; margin-top:auto; border-top:1px solid #313244; padding-top:8px;">
<span style="color:#a6adc8; font-size:11px; font-weight:bold;">💾 本地数据总线</span>
<div class="mega-matrix-grid">
<button id="mega-btn-export-cfg" class="matrix-btn">导JSON</button>
<button id="mega-btn-import-cfg" class="matrix-btn">解JSON</button>
<button id="mega-btn-copy-raw" class="matrix-btn">拷全量</button>
</div>
<div class="mega-matrix-grid">
<button id="mega-btn-copy-gf" class="matrix-btn">拷GF源</button>
<button id="mega-btn-dl-gf" class="matrix-btn">生脚本</button>
<button id="mega-btn-paste-raw" class="matrix-btn">粘文本</button>
</div>
<input type="file" id="mega-file-handler" accept=".json" style="display:none;">
</div>
</div>
<div class="mega-sidebar-right">
<div class="api-flow-wrapper">
<span style="color:#bac2de; font-size:12px; font-weight:bold;">🌐 外部资产流抽离 & 快照对账 (支持直链与超长单文本角色卡直接粘贴)</span>
<textarea id="mega-api-url" class="mega-api-textarea" placeholder="在此贴入远程配置JSON直链、公共云直链、或者在这里直接砸入你要切片的超长原始单文本角色卡/提示词..."></textarea>
<div class="api-sub-grid">
<button id="sub-generic-flow" class="api-sub-btn" style="background:#a6e3a1;">远端 JSON 部署</button>
<button id="sub-url-extract" class="api-sub-btn" style="background:#cca7ef;">远程源码解包</button>
<button id="sub-local-slice" class="api-sub-btn" style="background:#f9e2af;">本地文本切片机</button>
<button id="deck-btn-default" class="api-sub-btn" style="background:#f2cdcd;">重置默认卡槽</button>
</div>
<div style="border-top:1px dashed #313244; margin:2px 0;"></div>
<div class="sandbox-row">
<button id="deck-btn-back" class="micro-deck-btn btn-deck-grey" style="grid-column: span 1;" title="撤销上一次导入" disabled>🔙 撤销导入</button>
<button id="deck-btn-save-a" class="micro-deck-btn" style="background:#fab387;">快照存A轨</button>
<button id="deck-btn-back-a" class="micro-deck-btn btn-deck-grey" disabled>恢复A轨</button>
<button id="deck-btn-save-b" class="micro-deck-btn" style="background:#fab387;">快照存B轨</button>
<button id="deck-btn-back-b" class="micro-deck-btn btn-deck-grey" disabled>恢复B轨</button>
</div>
</div>
<div class="cloud-matrix-box">
<span style="color:#a6adc8; font-size:11px; font-weight:bold;">☁️ TextDB 开放式分布式同步网络</span>
<div class="cloud-matrix-grid">
<button id="cloud-btn-share" class="cloud-btn" style="background:#b4befe;">🌐 托管分享</button>
<button id="cloud-btn-update" class="cloud-btn" style="background:#a6e3a1;">🔄 覆盖更新</button>
<button id="cloud-btn-delete" class="cloud-btn" style="background:#f38ba8;">🧹 彻底销毁</button>
</div>
</div>
<div class="history-panel-wrapper">
<div style="display:flex; justify-content:space-between; margin-bottom:4px;">
<span style="color:#bac2de; font-size:11px; font-weight:bold;">🕒 解析历史 (单选填回 / 双击拷贝)</span>
<button id="btn-clear-history" style="background:transparent; border:none; color:#f38ba8; font-size:11px; cursor:pointer;">[清空]</button>
</div>
<div id="history-scroll-zone" class="history-list-scroll"></div>
</div>
</div>
</div>
<div class="mega-main-bottom">
<div style="display:flex; justify-content:space-between; align-items:center;">
<span id="current-slot-title" style="font-size:13px; color:#f5e0dc; font-weight:bold;">📝 主作业区</span>
<button id="mega-close-btn" style="background:#f38ba8; color:#11111b; border:none; padding:4px 14px; font-family:monospace; font-size:12px; font-weight:bold; border-radius:4px; cursor:pointer;">关闭面板 (ESC)</button>
</div>
<textarea id="rp-prompt-box" class="mega-textarea" placeholder="在此选择或输入当前卡槽下的全局系统提示词方案..."></textarea>
</div>
</div>
`;
document.body.appendChild(megaDrawer);
this.renderSlotsList();
this.renderStateButtons();
this.renderAssetHistoryList();
this.updateSpeedDisplay(this.localStore.config.level);
document.getElementById('rp-prompt-box').value = this.localStore.config.customPrompt;
},
renderSlotsList() {
const container = document.getElementById('slot-list-zone');
if (!container) return;
container.innerHTML = '';
this.localStore.slots.forEach(slot => {
const btn = document.createElement('button');
btn.className = 'mega-btn';
btn.style = "background:#313244; color:#cdd6f4; border:1px solid transparent;";
if (slot.id === this.localStore.activeSlotId) {
btn.classList.add('slot-active');
document.getElementById('current-slot-title').innerText = `📝 当前活动槽位 ➔ ${slot.name}`;
}
btn.innerHTML = `<span style="overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:85%;">${slot.name}</span><span>➔</span>`;
btn.addEventListener('click', () => {
this.localStore.activeSlotId = slot.id;
this.localStore.config.customPrompt = slot.content;
localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore));
document.getElementById('rp-prompt-box').value = slot.content;
this.renderSlotsList();
this.triggerAutoStateModification();
});
container.appendChild(btn);
});
this.refreshManualSandboxesUI();
},
renderAssetHistoryList() {
const historyZone = document.getElementById('history-scroll-zone');
if (!historyZone) return;
historyZone.innerHTML = '';
if (this.assetHistory.length === 0) {
historyZone.innerHTML = `<div style="color:#585b70; font-size:11px; padding:4px; text-align:center;">暂无资产解包历史</div>`;
return;
}
this.assetHistory.forEach(item => {
const row = document.createElement('div');
row.className = 'history-item-row';
row.title = `单击载入文本区 | 双击刷入剪贴板\nURL: ${item.url}`;
row.innerHTML = `<span style="overflow:hidden; text-overflow:ellipsis; max-width:80%;">${item.type === '☁️云分' ? '☁️ 云:' : '[链]'} ${item.url.replace('https://', '')}</span><span style="color:#6c7086; font-size:10px;">${item.time}</span>`;
row.addEventListener('click', () => {
document.getElementById('mega-api-url').value = item.url;
this.showToast('📋 已调回历史链接', '选中的历史链接已重新置入外部配置区。');
});
row.addEventListener('dblclick', () => {
if (typeof GM_setClipboard !== 'undefined') {
GM_setClipboard(item.url);
this.showToast('📋 链接复制就绪', '资产链接已安全刷入全局剪贴板。');
}
});
historyZone.appendChild(row);
});
},
refreshManualSandboxesUI() {
const btnA = document.getElementById('deck-btn-back-a');
const btnB = document.getElementById('deck-btn-back-b');
if (localStorage.getItem(this.SANDBOX_A_KEY)) { btnA.classList.remove('btn-deck-grey'); btnA.style.background = '#fab387'; btnA.style.color = '#11111b'; btnA.removeAttribute('disabled'); }
else { btnA.classList.add('btn-deck-grey'); btnA.style.background = ''; btnA.style.color = ''; btnA.setAttribute('disabled', 'true'); }
if (localStorage.getItem(this.SANDBOX_B_KEY)) { btnB.classList.remove('btn-deck-grey'); btnB.style.background = '#fab387'; btnB.style.color = '#11111b'; btnB.removeAttribute('disabled'); }
else { btnB.classList.add('btn-deck-grey'); btnB.style.background = ''; btnB.style.color = ''; btnB.setAttribute('disabled', 'true'); }
},
triggerAutoStateModification() {
if (!this.snapshottedBackup) this.snapshottedBackup = JSON.parse(JSON.stringify(this.localStore));
const backBtn = document.getElementById('deck-btn-back');
backBtn.classList.remove('btn-deck-grey'); backBtn.style.background = '#f9e2af'; backBtn.style.color = '#11111b'; backBtn.removeAttribute('disabled');
},
renderStateButtons() {
const c = this.localStore.config;
document.getElementById('state-img').style = `flex:1; height:18px; border:none; cursor:pointer; font-size:9px; font-weight:bold; border-radius:3px; background:${c.img?'#a6e3a1':'#313244'}; color:${c.img?'#11111b':'#585b70'}`;
document.getElementById('state-video').style = `flex:1; height:18px; border:none; cursor:pointer; font-size:9px; font-weight:bold; border-radius:3px; background:${c.video?'#89b4fa':'#313244'}; color:${c.video?'#11111b':'#585b70'}`;
document.getElementById('state-stamp').style = `flex:1; height:18px; border:none; cursor:pointer; font-size:9px; font-weight:bold; border-radius:3px; background:${c.stamp?'#f2cdcd':'#313244'}; color:${c.stamp?'#11111b':'#585b70'}`;
document.getElementById('state-hot').style = `flex:1; height:18px; border:none; cursor:pointer; font-size:9px; font-weight:bold; border-radius:3px; background:${c.hot?'#f9e2af':'#313244'}; color:${c.hot?'#11111b':'#585b70'}`;
},
updateSpeedDisplay(l) {
const speedTxt = document.getElementById('speed-txt');
speedTxt.innerText = l==1?"1.5s 冲":l==3?"5.0s 养":"3.0s 衡";
speedTxt.style.color = l==1?"#f38ba8":l==3?"#89b4fa":"#a6e3a1";
},
buildPromptText(data, username, host, runtimeConfig = null) {
const cfg = runtimeConfig || data.config || { img: true, video: true, stamp: true, hot: true, customPrompt: this.localStore.config.customPrompt };
const processed = data.tweets.map(rawBlock => {
let prefix = rawBlock.match(/\[METAPREFIX\]([\s\S]*?)\[\/METAPREFIX\]/)?.[1] || '';
let hot = rawBlock.match(/\[HOTMETRIC\]([\s\S]*?)\[\/HOTMETRIC\]/)?.[1] || '';
let base = rawBlock.match(/\[BASETEXT\]([\s\S]*?)\[\/BASETEXT\]/)?.[1] || '';
let mediaLines = [];
rawBlock.split('\n').forEach(line => {
if (line.startsWith('__IMG__') && cfg.img) mediaLines.push(line.replace('__IMG__', ''));
if (line.startsWith('__VID__') && cfg.video) mediaLines.push(line.replace('__VID__', ''));
});
let finalPrefix = cfg.stamp ? prefix : (prefix.includes('[🔄 转推自:') ? (prefix.match(/\[🔄 转推自:.*?\]/)?.[0] || '') : '');
let blockParts = [];
if (finalPrefix.trim()) blockParts.push(finalPrefix.trim());
if (cfg.hot && hot.trim()) blockParts.push(hot.trim());
if (base.trim()) blockParts.push(base.trim());
if (mediaLines.length > 0) blockParts.push(mediaLines.join('\n'));
return blockParts.join('\n').trim();
}).filter(t => t && t.trim().length > 0);
return `${cfg.customPrompt || this.localStore.config.customPrompt}\n\n以下是目标用户的真实账号元数据与推文语料库(共 ${processed.length} 条):\n--------------------------------------------------\n【原始主页元数据纯文本】\n${data.metaText || '未抓取到描述'}\n\n【清洗过滤后的大批量推文语料库】\n${processed.join('\n---\n')}\n--------------------------------------------------`;
},
generateGfCode() {
let lines = [ "// ==UserScript==", "// @name 拾荒小猫_云端扩展组件", `// @version ${Date.now()}`, "// ==/UserScript==", "", "window.CloudPrompts = {" ];
this.localStore.slots.forEach((s, idx) => {
const key = s.name.replace(/[^\w\u4e00-\u9fa5]/g, '') || `slot_${idx}`;
const formatter = s.content.split('\n').map(line => ` ${JSON.stringify(line)}`).join(',\n');
lines.push(` ${JSON.stringify(key)}: [\n${formatter}\n ].join('\\n')${idx === this.localStore.slots.length - 1 ? '' : ','}`);
});
lines.push("};"); return lines.join('\n');
},
executeRawTextSequenceImport(rawText, isCloudSource = false) {
if (!rawText || !rawText.trim()) return;
const blocks = rawText.split(/={10,}/);
let parsedSlots = [];
let currentName = "";
blocks.forEach(block => {
let lines = block.split('\n').map(l => l.trim()).filter(l => l.length > 0);
if (lines.length === 0) return;
if (lines.length === 1 && lines[0].length < 30) { currentName = lines[0]; }
else {
let name = currentName || lines[0].substring(0, 15);
let content = (currentName ? lines : lines.slice(1)).join('\n');
parsedSlots.push({
id: `slot_gen_${Date.now()}_${Math.random().toString(36).substr(2, 4)}`,
name: `${isCloudSource ? '☁️' : '🎭'} ${name}`,
content: content
});
currentName = "";
}
});
if (parsedSlots.length === 0) {
parsedSlots.push({ id: `slot_gen_${Date.now()}`, name: isCloudSource ? '☁️ 外部文本槽' : '🎭 快捷切片槽', content: rawText.trim() });
}
this.localStore.slots = parsedSlots;
this.localStore.activeSlotId = parsedSlots[0].id;
this.localStore.config.customPrompt = parsedSlots[0].content;
localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore));
document.getElementById('rp-prompt-box').value = parsedSlots[0].content;
this.renderSlotsList();
this.triggerAutoStateModification();
this.showToast('📥 序列切片成功', `本地切片机提取并部署了 ${parsedSlots.length} 个独立卡槽。`);
},
// 使用 GM_xmlhttpRequest 彻底修复 CORS 跨域限制
async executeCloudShareFlow(actionType) {
const cloudKey = `cat_db_${this.currentHost}_${this.currentUsername}`.replace(/[^\w-]/g, '');
const targetUrl = `https://textdb.online/update/`;
const payloadData = JSON.stringify({ config: this.localStore.config, slots: this.localStore.slots });
if (actionType === 'delete') {
if (!confirm("⚠️ 确定要在公开存储空间中注销并彻底销毁该备份矩阵吗?")) return;
this.showToast('🧹 正在连接销毁轴...', '正在请求抹除公网开放式数据链...');
GM_xmlhttpRequest({
method: 'POST',
url: `${targetUrl}?key=${cloudKey}&value=`,
onload: (response) => {
try {
let json = JSON.parse(response.responseText);
if (json.status === 1) this.showToast('🧹 云端数据销毁成功', '公网备份矩阵已抹除。');
else this.showToast('❌ 抹除失败', '服务器拒绝了请求。', true);
} catch (e) { this.showToast('❌ 响应结构异常', e.message, true); }
},
onerror: (err) => { this.showToast('❌ 销毁网络受阻', '高级特权管道泵入遭遇异常中断。', true); }
});
return;
}
this.showToast('🌐 正在通过高级流道同步...', '正在由 GM 特权总线透传 textdb.online 集群...');
GM_xmlhttpRequest({
method: 'POST',
url: targetUrl,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: `key=${encodeURIComponent(cloudKey)}&value=${encodeURIComponent(payloadData)}`,
onload: (response) => {
try {
let json = JSON.parse(response.responseText);
if (json.status === 1) {
const fetchUrl = `https://textdb.online/${cloudKey}`;
document.getElementById('mega-api-url').value = fetchUrl;
if (typeof GM_setClipboard !== 'undefined') GM_setClipboard(fetchUrl);
const timestamp = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
this.assetHistory.unshift({ type: '☁️云分', url: fetchUrl, time: timestamp });
if (this.assetHistory.length > 25) this.assetHistory.pop();
localStorage.setItem(this.HISTORY_KEY, JSON.stringify(this.assetHistory));
this.renderAssetHistoryList();
this.showToast('🚀 云端同步就绪', `同步成功!读取直链已写入系统剪贴板。`);
} else {
this.showToast('❌ 矩阵部署失败', '已触发现流控制上限或参数残缺。', true);
}
} catch (e) {
this.showToast('❌ 解包逆向异常', `回执处理分裂: ${e.message}`, true);
}
},
onerror: (err) => {
this.showToast('❌ 矩阵泵入故障', 'GM_xmlhttpRequest 核心阻断,请确认网络对准状态。', true);
}
});
},
// 针对远端获取配置也进行 GM 扩展修复
async executeRemoteFetchDeploy() {
const inputVal = document.getElementById('mega-api-url').value.trim();
if (!inputVal.startsWith('http')) {
this.showToast('⚠️ 解析被终止', '输入区内未发现有效的网络直链协议头。', true);
return;
}
this.showToast('🌐 正在透传远端资产...', '通过独立流道绕过跨域锁...');
GM_xmlhttpRequest({
method: 'GET',
url: inputVal,
onload: (response) => {
this.processImportData(response.responseText);
const timestamp = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
this.assetHistory.unshift({ type: '🔗链接', url: inputVal, time: timestamp });
if (this.assetHistory.length > 25) this.assetHistory.pop();
localStorage.setItem(this.HISTORY_KEY, JSON.stringify(this.assetHistory));
this.renderAssetHistoryList();
},
onerror: (err) => { this.showToast('❌ 远程流同步死锁', '未能在目标地址建立安全通道。', true); }
});
},
processImportData(text) {
if (!text || !text.trim()) { this.showToast('❌ 导入失败', '没有探测到任何有效数据。', true); return; }
try {
const cloud = JSON.parse(text.trim());
if (cloud && cloud.slots && Array.isArray(cloud.slots)) {
this.triggerAutoStateModification();
this.localStore.slots = cloud.slots;
this.localStore.activeSlotId = cloud.slots[0].id;
this.localStore.config.customPrompt = cloud.slots[0].content;
if (cloud.config) this.localStore.config = Object.assign({}, this.localStore.config, cloud.config);
localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore));
document.getElementById('rp-prompt-box').value = this.localStore.config.customPrompt;
this.renderSlotsList();
this.renderStateButtons();
this.showToast('📋 热泵入成功', `解包同步完毕,载入 ${cloud.slots.length} 个配置卡槽!`);
} else { this.showToast('❌ 结构破坏', 'JSON 格式解析成功但未包含 slots 数组。', true); }
} catch(e) { this.showToast('❌ 逆向故障', `JSON 解析致命断裂,请检查数据格式。`, true); }
},
executeAutoRun() {
const autoRun = localStorage.getItem('rp_global_autorun') === 'true';
if (autoRun && localStorage.getItem('rp_active_key') === this.DB_KEY) {
const currentUrl = location.href;
if (this.localStore.lastUrl && (currentUrl === this.localStore.lastUrl || !currentUrl.includes('cursor='))) {
localStorage.setItem('rp_global_autorun', 'false'); localStorage.removeItem('rp_active_key');
this.showToast('⚠️ 自动化中断', `未能成功拉取新翻页。当前锚定在第 ${this.localStore.currentPage} 页。`, true);
} else if (this.localStore.currentPage < 10) {
const findMoreBtn = () => Array.from(document.querySelectorAll('.show-more a')).find(el => el.textContent && el.textContent.includes('Load more'));
const moreBtn = findMoreBtn();
if (moreBtn) {
this.localStore.currentPage++; this.localStore.lastUrl = currentUrl; localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore));
let delay = this.localStore.config.level == 1 ? 1500 : this.localStore.config.level == 3 ? 5000 : 3000;
setTimeout(() => { window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }); setTimeout(() => { const b = findMoreBtn(); if(b) b.click(); }, 500); }, delay - 500);
} else { localStorage.setItem('rp_global_autorun', 'false'); localStorage.removeItem('rp_active_key'); this.showToast('🏁 挖掘完成', '全站开放式语料已捕获完毕!'); }
}
}
},
bindEvents() {
const promptBox = document.getElementById('rp-prompt-box');
const megaDrawer = document.getElementById('rp-mega-drawer');
const fileHandler = document.getElementById('mega-file-handler');
const speedInput = document.getElementById('cfg-speed');
document.getElementById('rp-close').addEventListener('click', () => { document.getElementById('rp-heavy-panel').style.display = 'none'; localStorage.setItem('rp_panel_visible', 'false'); });
document.getElementById('state-img').addEventListener('click', () => { this.localStore.config.img = !this.localStore.config.img; localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore)); this.renderStateButtons(); });
document.getElementById('state-video').addEventListener('click', () => { this.localStore.config.video = !this.localStore.config.video; localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore)); this.renderStateButtons(); });
document.getElementById('state-stamp').addEventListener('click', () => { this.localStore.config.stamp = !this.localStore.config.stamp; localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore)); this.renderStateButtons(); });
document.getElementById('state-hot').addEventListener('click', () => { this.localStore.config.hot = !this.localStore.config.hot; localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore)); this.renderStateButtons(); });
speedInput.addEventListener('input', (e) => { let val = parseInt(e.target.value); this.updateSpeedDisplay(val); this.localStore.config.level = val; localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore)); });
const toggleMegaDrawer = () => {
const isHidden = megaDrawer.classList.contains('hidden');
if (isHidden) { megaDrawer.classList.remove('hidden'); localStorage.setItem('rp_drawer_visible', 'true'); }
else { megaDrawer.classList.add('hidden'); localStorage.setItem('rp_drawer_visible', 'false'); }
};
document.getElementById('btn-toggle-drawer').addEventListener('click', toggleMegaDrawer);
document.getElementById('mega-close-btn').addEventListener('click', toggleMegaDrawer);
window.addEventListener('keydown', (e) => { if (e.key === 'Escape' && !megaDrawer.classList.contains('hidden')) toggleMegaDrawer(); });
promptBox.addEventListener('input', (e) => {
this.localStore.config.customPrompt = e.target.value;
let actSlot = this.localStore.slots.find(s => s.id === this.localStore.activeSlotId);
if (actSlot) actSlot.content = e.target.value;
localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore));
this.triggerAutoStateModification();
});
document.getElementById('btn-new-slot').addEventListener('click', () => {
const cardName = prompt("请输入新角色卡的标题:", "🆕 自定义提示词卡槽");
if (cardName === null) return;
const finalName = cardName.trim() || "未命名卡槽";
this.triggerAutoStateModification();
const newId = `slot_custom_${Date.now()}`;
const newSlot = { id: newId, name: `🎭 ${finalName}`, content: "在此输入全新的系统提示词指令..." };
this.localStore.slots.push(newSlot);
this.localStore.activeSlotId = newId;
this.localStore.config.customPrompt = newSlot.content;
localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore));
this.renderSlotsList();
promptBox.value = newSlot.content;
promptBox.focus();
this.showToast('➕ 角色卡创建成功', `全新控制卡槽 [${finalName}] 已部署到位!`);
});
document.getElementById('btn-clear-history').addEventListener('click', () => {
if (confirm("确定要清空所有外部资产解析历史记录吗?")) {
this.assetHistory = []; localStorage.setItem(this.HISTORY_KEY, JSON.stringify(this.assetHistory));
this.renderAssetHistoryList(); this.showToast('🧹 历史已重置', '外部历史看板已清空。');
}
});
document.getElementById('deck-btn-default').addEventListener('click', () => {
this.triggerAutoStateModification(); this.localStore.slots = JSON.parse(JSON.stringify(this.defaultSlots)); this.localStore.activeSlotId = this.defaultSlots[0].id; this.localStore.config.customPrompt = this.defaultSlots[0].content;
localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore)); promptBox.value = this.defaultSlots[0].content; this.renderSlotsList(); this.showToast('🔄 已恢复系统状态', '默认配置卡槽已重设。');
});
document.getElementById('deck-btn-save-a').addEventListener('click', () => { localStorage.setItem(this.SANDBOX_A_KEY, JSON.stringify(this.localStore)); this.refreshManualSandboxesUI(); this.showToast('💾 快照同步成功', '当前卡槽资产已备份至 A 轨。'); });
document.getElementById('deck-btn-save-b').addEventListener('click', () => { localStorage.setItem(this.SANDBOX_B_KEY, JSON.stringify(this.localStore)); this.refreshManualSandboxesUI(); this.showToast('💾 快照同步成功', '当前卡槽资产已备份至 B 轨。'); });
document.getElementById('deck-btn-back-a').addEventListener('click', () => { const d = localStorage.getItem(this.SANDBOX_A_KEY); if (!d) return; this.triggerAutoStateModification(); this.localStore = JSON.parse(d); localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore)); promptBox.value = this.localStore.config.customPrompt; this.renderSlotsList(); this.renderStateButtons(); this.showToast('🔙 快照还原成功', 'A 轨归档资产已无感知重组。'); });
document.getElementById('deck-btn-back-b').addEventListener('click', () => { const d = localStorage.getItem(this.SANDBOX_B_KEY); if (!d) return; this.triggerAutoStateModification(); this.localStore = JSON.parse(d); localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore)); promptBox.value = this.localStore.config.customPrompt; this.renderSlotsList(); this.renderStateButtons(); this.showToast('🔙 快照还原成功', 'B 轨归档资产已无感知重组。'); });
document.getElementById('mega-btn-export-cfg').addEventListener('click', () => {
const blob = new Blob([JSON.stringify({ version: this.version, config: this.localStore.config, slots: this.localStore.slots }, null, 2)], { type: 'application/json' });
const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = `拾荒小猫_无限卡槽备份.json`; a.click();
});
document.getElementById('mega-btn-import-cfg').addEventListener('click', () => fileHandler.click());
fileHandler.addEventListener('change', (e) => {
const file = e.target.files[0]; if (!file) return;
const reader = new FileReader();
reader.onload = (ev) => {
try {
const cloud = JSON.parse(ev.target.result);
if (cloud && cloud.slots) {
this.localStore.slots = cloud.slots; this.localStore.activeSlotId = cloud.slots[0].id; this.localStore.config.customPrompt = cloud.slots[0].content;
if(cloud.config) this.localStore.config = Object.assign(this.localStore.config, cloud.config);
promptBox.value = this.localStore.config.customPrompt; localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore)); this.renderSlotsList(); this.renderStateButtons(); this.showToast('📥 导入配置文件成功', '本地 JSON 资产已就绪。');
}
} catch(err) { this.showToast('❌ 导入错误', '非合规配置格式。', true); }
};
reader.readAsText(file);
});
if (typeof GM_setClipboard !== 'undefined') {
document.getElementById('mega-btn-copy-gf').addEventListener('click', () => { GM_setClipboard(this.generateGfCode()); this.showToast('📋 源码已拷贝', '可直接在 GF 粘贴发布!'); });
document.getElementById('mega-btn-copy-raw').addEventListener('click', () => { GM_setClipboard(JSON.stringify({ config: this.localStore.config, slots: this.localStore.slots }, null, 2)); this.showToast('📋 复制卡槽数据成功', '数据已完整泵入全局剪贴板!'); });
document.getElementById('btn-copy').addEventListener('click', () => { if (this.localStore.tweets.length === 0) return; GM_setClipboard(this.buildPromptText(this.localStore, this.currentUsername, this.currentHost, this.localStore.config)); this.showToast('📋 复制成功', '全量语料已装载!'); });
}
document.getElementById('mega-btn-dl-gf').addEventListener('click', () => {
const blob = new Blob([this.generateGfCode()], { type: 'application/javascript;charset=utf-8;' });
const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = `拾荒小猫_GF组件.js`; a.click();
});
document.getElementById('btn-download').addEventListener('click', () => { if (this.localStore.tweets.length === 0) return; const blob = new Blob([this.buildPromptText(this.localStore, this.currentUsername, this.currentHost, this.localStore.config)], { type: 'text/markdown;charset=utf-8;' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = `${this.currentHost}_${this.currentUsername}_语料.md`; a.click(); });
document.getElementById('btn-zip').addEventListener('click', () => {
if (typeof JSZip === 'undefined') { this.showToast('❌ 依赖缺失', '未检测到全局 JSZip 支持库。', true); return; }
const zip = new JSZip(); let count = 0;
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key.startsWith('rp_corpus_')) {
const parts = key.replace('rp_corpus_', '').split('_');
try {
const data = JSON.parse(localStorage.getItem(key));
if (data && data.tweets && data.tweets.length > 0) { zip.file(`${parts[0]}_${parts.slice(1).join('_')}_语料.md`, this.buildPromptText(data, parts.slice(1).join('_'), parts[0], Object.assign({}, this.localStore.config, data.config||{}))); count++; }
} catch(e) {}
}
}
if (count === 0) return;
zip.generateAsync({type: "blob"}).then(c => { const a = document.createElement('a'); a.href = URL.createObjectURL(c); a.download = `Nitter_聚合语料库_共${count}位博主.zip`; a.click(); });
});
document.getElementById('btn-run').addEventListener('click', () => { this.localStore.currentPage = 1; this.localStore.lastUrl = ""; localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore)); localStorage.setItem('rp_global_autorun', 'true'); localStorage.setItem('rp_active_key', this.DB_KEY); location.reload(); });
document.getElementById('btn-clear').addEventListener('click', () => {
const totalCount = this.localStore.tweets ? this.localStore.tweets.length : 0;
if (confirm(`⚠️ 警告:您正准备清空当前博主 [👤:${this.currentUsername}] 的所有语料缓存。\n\n当前已捕获: ${totalCount} 条语料。\n清空后将无法恢复,确定要执行清除并刷新页面吗?`)) {
localStorage.removeItem(this.DB_KEY); this.showToast('🧹 缓存已清空', '语料库已安全重置,页面即将刷新...'); setTimeout(() => location.reload(), 1000);
}
});
document.getElementById('mega-btn-paste-raw').addEventListener('click', async () => {
if (navigator.clipboard && navigator.clipboard.readText) {
try { const text = await navigator.clipboard.readText(); this.processImportData(text); return; } catch (err) { console.warn("Fallback to GM..."); }
}
if (typeof GM_getClipboard !== 'undefined') { GM_getClipboard((text) => this.processImportData(text)); }
else { this.showToast('❌ 导入中断', '不支持任何剪贴板读取接口。', true); }
});
// 绑定跨域修复版远端部署
document.getElementById('sub-generic-flow').addEventListener('click', () => this.executeRemoteFetchDeploy());
document.getElementById('sub-url-extract').addEventListener('click', () => this.executeRemoteFetchDeploy());
document.getElementById('sub-local-slice').addEventListener('click', () => this.executeRawTextSequenceImport(document.getElementById('mega-api-url').value, false));
document.getElementById('deck-btn-back').addEventListener('click', () => {
if (!this.snapshottedBackup) return; this.localStore = JSON.parse(JSON.stringify(this.snapshottedBackup)); localStorage.setItem(this.DB_KEY, JSON.stringify(this.localStore));
promptBox.value = this.localStore.config.customPrompt; this.renderSlotsList(); this.renderStateButtons(); this.snapshottedBackup = null;
document.getElementById('deck-btn-back').classList.add('btn-deck-grey'); document.getElementById('deck-btn-back').setAttribute('disabled', 'true'); this.showToast('🔙 安全对账已回滚', '配置资产已还原。');
});
document.getElementById('cloud-btn-share').addEventListener('click', () => this.executeCloudShareFlow('share'));
document.getElementById('cloud-btn-update').addEventListener('click', () => this.executeCloudShareFlow('update'));
document.getElementById('cloud-btn-delete').addEventListener('click', () => this.executeCloudShareFlow('delete'));
}
};
window.NitterCorpusCore = NitterCorpusCore;
})(window);