182 lines
5.2 KiB
JavaScript
182 lines
5.2 KiB
JavaScript
const fs = require("node:fs");
|
||
const path = require("node:path");
|
||
const vm = require("node:vm");
|
||
|
||
const INPUT = "/Users/lanmu/Desktop/ai-chatbot-main/analysis/qiaodou-extract/extracted/assets/index-m-NWkaV-.js";
|
||
const OUTPUT_JSON = "/Users/lanmu/Desktop/ai-chatbot-main/analysis/qiaodou-extract/bundle-intel.json";
|
||
|
||
const source = fs.readFileSync(INPUT, "utf8");
|
||
|
||
function unique(values) {
|
||
return Array.from(new Set(values));
|
||
}
|
||
|
||
function safeEvalObjectLiteral(literal) {
|
||
return vm.runInNewContext(`(${literal})`, Object.create(null), {
|
||
timeout: 1000,
|
||
});
|
||
}
|
||
|
||
function extractBetween(startMarker, endMarker) {
|
||
const start = source.indexOf(startMarker);
|
||
if (start < 0) return null;
|
||
const from = start + startMarker.length;
|
||
const end = source.indexOf(endMarker, from);
|
||
if (end < 0) return null;
|
||
return source.slice(from, end);
|
||
}
|
||
|
||
function normalizeUrl(url) {
|
||
return String(url || "").replace(/[.,;]+$/, "").trim();
|
||
}
|
||
|
||
function isLikelyAppRelevantUrl(url) {
|
||
if (!url || url === "http://" || url === "https://") return false;
|
||
return !(
|
||
url.includes("w3.org/") ||
|
||
url.includes("apache.org/") ||
|
||
url.includes("reactjs.org/") ||
|
||
url.includes("github.com/") ||
|
||
url.includes("raw.github.com/") ||
|
||
url.includes("developer.mozilla.org/") ||
|
||
url.includes("feross.org") ||
|
||
url.includes("stuk.github.io/") ||
|
||
url.includes("stuartk.com/jszip")
|
||
);
|
||
}
|
||
|
||
const storageKeys = unique(
|
||
Array.from(source.matchAll(/qiaodoumayi_[A-Za-z0-9_]+/g)).map((match) => match[0])
|
||
).sort();
|
||
|
||
const tauriCommands = unique(
|
||
Array.from(source.matchAll(/yn\("([a-zA-Z0-9_:-]+)"/g)).map((match) => match[1])
|
||
).sort();
|
||
|
||
const requireHints = unique(
|
||
Array.from(source.matchAll(/\.\.\/[A-Za-z0-9_./-]+/g)).map((match) => match[0])
|
||
).sort();
|
||
|
||
const allUrls = unique(
|
||
Array.from(source.matchAll(/https?:\/\/[^\s"'`\\)<>,]+/g)).map((match) => normalizeUrl(match[0]))
|
||
).sort();
|
||
|
||
const appRelevantUrls = allUrls.filter(isLikelyAppRelevantUrl);
|
||
const domains = unique(
|
||
appRelevantUrls
|
||
.map((url) => {
|
||
try {
|
||
return new URL(url).host;
|
||
} catch {
|
||
return null;
|
||
}
|
||
})
|
||
.filter(Boolean)
|
||
).sort();
|
||
|
||
let quickConnectConfig = {};
|
||
const quickConnectLiteral = extractBetween("DV=", ";function npe");
|
||
if (quickConnectLiteral) {
|
||
quickConnectConfig = safeEvalObjectLiteral(quickConnectLiteral);
|
||
}
|
||
|
||
let nodeLabelMap = {};
|
||
const nodeLabelMatch = source.match(/function Rm\(e\)\{return(\{[\s\S]*?\})\[e\]\|\|"节点"\}/);
|
||
if (nodeLabelMatch) {
|
||
nodeLabelMap = safeEvalObjectLiteral(nodeLabelMatch[1]);
|
||
}
|
||
|
||
const nodeSizeMap = {};
|
||
const nodeSizeMatch = source.match(/function jO\(e\)\{switch\(e\)\{([\s\S]*?)default:return\{w:(\d+),h:(\d+)\}\}\}/);
|
||
if (nodeSizeMatch) {
|
||
const body = nodeSizeMatch[1];
|
||
const defaultSize = { w: Number(nodeSizeMatch[2]), h: Number(nodeSizeMatch[3]) };
|
||
nodeSizeMap.default = defaultSize;
|
||
const groupedCases = body.matchAll(/((?:case"[^"]+":)+)return\{w:(\d+),h:(\d+)\}/g);
|
||
for (const groupedCase of groupedCases) {
|
||
const labels = Array.from(groupedCase[1].matchAll(/case"([^"]+)":/g)).map((match) => match[1]);
|
||
const size = { w: Number(groupedCase[2]), h: Number(groupedCase[3]) };
|
||
for (const label of labels) {
|
||
nodeSizeMap[label] = size;
|
||
}
|
||
}
|
||
}
|
||
|
||
const quickConnectTypes = Object.keys(quickConnectConfig);
|
||
const nodeTypes = unique([
|
||
...Object.keys(nodeLabelMap),
|
||
...Object.keys(nodeSizeMap).filter((key) => key !== "default"),
|
||
...quickConnectTypes,
|
||
...quickConnectTypes.flatMap((type) =>
|
||
(quickConnectConfig[type]?.output || []).map((item) => item.type)
|
||
),
|
||
]).sort();
|
||
|
||
const nodeCatalog = nodeTypes.map((type) => ({
|
||
type,
|
||
label: nodeLabelMap[type] || null,
|
||
size: nodeSizeMap[type] || nodeSizeMap.default || null,
|
||
quickConnectOutputs: (quickConnectConfig[type]?.output || []).map((item) => ({
|
||
type: item.type,
|
||
label: item.label,
|
||
})),
|
||
}));
|
||
|
||
const indexedDb = {
|
||
databaseName: source.includes('"qiaodoumayi_projects"') ? "qiaodoumayi_projects" : null,
|
||
version: source.includes('qiaodoumayi_projects",Ioe=2') ? 2 : null,
|
||
stores: unique(
|
||
Array.from(source.matchAll(/"(project_meta|project_payload|project_assets)"/g)).map(
|
||
(match) => match[1]
|
||
)
|
||
),
|
||
};
|
||
|
||
const snippets = {};
|
||
for (const term of [
|
||
"qiaodoumayi_seedance_moderation_url",
|
||
"download_file_bypass_cors",
|
||
"start_local_server",
|
||
"qiaodoumayi_projects",
|
||
"qiaodoumayi_script_projects",
|
||
"qiaodoumayi_saved_skills",
|
||
"qiaodoumayi_characters",
|
||
"https://ai.comfly.chat/sora/v1/characters",
|
||
"https://www.runninghub.cn",
|
||
]) {
|
||
const index = source.indexOf(term);
|
||
snippets[term] =
|
||
index >= 0
|
||
? {
|
||
index,
|
||
preview: source.slice(Math.max(0, index - 180), Math.min(source.length, index + 260)),
|
||
}
|
||
: null;
|
||
}
|
||
|
||
const result = {
|
||
input: INPUT,
|
||
stats: {
|
||
bytes: Buffer.byteLength(source, "utf8"),
|
||
lines: source.split("\n").length,
|
||
hasSourceMap: /sourceMappingURL/.test(source),
|
||
},
|
||
storageKeys,
|
||
tauriCommands,
|
||
requireHints,
|
||
urls: {
|
||
appRelevant: appRelevantUrls,
|
||
all: allUrls,
|
||
domains,
|
||
},
|
||
indexedDb,
|
||
quickConnectConfig,
|
||
nodeLabelMap,
|
||
nodeSizeMap,
|
||
nodeCatalog,
|
||
snippets,
|
||
};
|
||
|
||
fs.writeFileSync(OUTPUT_JSON, `${JSON.stringify(result, null, 2)}\n`);
|
||
console.log(`Wrote ${OUTPUT_JSON}`);
|