feat(pugongying): 支持小红书短链接输入

通过 GM_xmlhttpRequest HEAD 请求跟踪短链接重定向,
从 finalUrl 中提取达人 ID。支持 xhslink.com 域名。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
wxs 2026-03-13 23:46:06 +08:00
parent 465e1f7746
commit 99d16f1f70

View File

@ -6,6 +6,7 @@
// @match https://pgy.xiaohongshu.com/*
// @grant GM_xmlhttpRequest
// @connect api.internal.intelligrow.cn
// @connect xhslink.com
// @require https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js
// ==/UserScript==
@ -235,27 +236,28 @@
return baseTarget;
}
function extractBloggerId(value) {
const raw = normalizeScalar(value);
if (!raw) {
return "";
}
function resolveShortUrl(url) {
return new Promise((resolve) => {
if (typeof GM_xmlhttpRequest !== "function") {
resolve(url);
return;
}
GM_xmlhttpRequest({
method: "HEAD",
url,
onload(res) {
resolve(res.finalUrl || url);
},
onerror() {
resolve(url);
},
});
});
}
if (/^[0-9a-f]{24}$/i.test(raw)) {
return raw;
}
if (!/^https?:\/\//i.test(raw)) {
return "";
}
let parsedUrl;
try {
parsedUrl = new URL(raw);
} catch (error) {
return "";
}
const SHORT_LINK_HOSTS = ["xhslink.com"];
function extractIdFromUrl(parsedUrl) {
const queryCandidates = ["id", "user_id", "userId", "bloggerId", "creatorId"];
for (const key of queryCandidates) {
const queryValue = parsedUrl.searchParams.get(key);
@ -279,7 +281,45 @@
return "";
}
function parseCreatorInputs(rawInput) {
async function extractBloggerId(value) {
const raw = normalizeScalar(value);
if (!raw) {
return "";
}
if (/^[0-9a-f]{24}$/i.test(raw)) {
return raw;
}
if (!/^https?:\/\//i.test(raw)) {
return "";
}
let parsedUrl;
try {
parsedUrl = new URL(raw);
} catch (error) {
return "";
}
const directId = extractIdFromUrl(parsedUrl);
if (directId) {
return directId;
}
if (SHORT_LINK_HOSTS.some((h) => parsedUrl.hostname.endsWith(h))) {
const realUrl = await resolveShortUrl(raw);
try {
return extractIdFromUrl(new URL(realUrl));
} catch (error) {
return "";
}
}
return "";
}
async function parseCreatorInputs(rawInput) {
const values = normalizeScalar(rawInput)
.split(/[\n,\s]+/)
.map((item) => item.trim())
@ -288,8 +328,8 @@
const ids = [];
const seen = new Set();
for (const value of values) {
const id = extractBloggerId(value);
const resolved = await Promise.all(values.map((v) => extractBloggerId(v)));
for (const id of resolved) {
if (!id || seen.has(id)) {
continue;
}
@ -508,7 +548,7 @@
return {
async preview(rawInput, onProgress) {
const ids = parseCreatorInputs(rawInput);
const ids = await parseCreatorInputs(rawInput);
if (!ids.length) {
throw new Error("请输入至少一个有效的达人主页链接或达人 ID。");
}