diff --git a/pugongying/xhs-pgy-export.user.js b/pugongying/xhs-pgy-export.user.js index 8eb29d8..58bdb36 100644 --- a/pugongying/xhs-pgy-export.user.js +++ b/pugongying/xhs-pgy-export.user.js @@ -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。"); }