From 9dafd8c8c8c46ac373c24cd00e8b12628748e4ed Mon Sep 17 00:00:00 2001 From: KwiatekMiki Date: Sat, 12 Jul 2025 15:10:08 +0200 Subject: [PATCH] api/xiaohongshu: add support for new share links --- api/src/processing/match.js | 1 + api/src/processing/service-config.js | 3 ++- api/src/processing/services/xiaohongshu.js | 20 +++++++++++++++++--- api/src/processing/url.js | 2 +- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/api/src/processing/match.js b/api/src/processing/match.js index 1265297c..508ccdd9 100644 --- a/api/src/processing/match.js +++ b/api/src/processing/match.js @@ -263,6 +263,7 @@ export default async function({ host, patternMatch, params, authType }) { case "xiaohongshu": r = await xiaohongshu({ ...patternMatch, + shareType: url.pathname.split("/")[1], h265: params.allowH265, isAudioOnly, dispatcher, diff --git a/api/src/processing/service-config.js b/api/src/processing/service-config.js index 906c23da..1bf5e020 100644 --- a/api/src/processing/service-config.js +++ b/api/src/processing/service-config.js @@ -207,7 +207,8 @@ export const services = { patterns: [ "explore/:id?xsec_token=:token", "discovery/item/:id?xsec_token=:token", - "a/:shareId" + "a/:shareId", + "m/:shareId" ], altDomains: ["xhslink.com"], }, diff --git a/api/src/processing/services/xiaohongshu.js b/api/src/processing/services/xiaohongshu.js index 06de21aa..a4f5cb0f 100644 --- a/api/src/processing/services/xiaohongshu.js +++ b/api/src/processing/services/xiaohongshu.js @@ -1,21 +1,35 @@ -import { resolveRedirectingURL } from "../url.js"; +import { resolveRedirectingURL, extract, normalizeURL } from "../url.js"; import { genericUserAgent } from "../../config.js"; import { createStream } from "../../stream/manage.js"; +import { request } from "undici"; const https = (url) => { return url.replace(/^http:/i, 'https:'); } -export default async function ({ id, token, shareId, h265, isAudioOnly, dispatcher }) { +export default async function ({ id, token, shareType, shareId, h265, isAudioOnly, dispatcher }) { let noteId = id; let xsecToken = token; - if (!noteId) { + if (!noteId && shareType === "a") { const patternMatch = await resolveRedirectingURL( `https://xhslink.com/a/${shareId}`, dispatcher ); + noteId = patternMatch?.id; + xsecToken = patternMatch?.token; + } else if (!noteId && shareType === "m") { + const location = await request(`https://xhslink.com/m/${shareId}`, { + dispatcher, + redirect: 'manual' + }).then(r => { + if (r.statusCode === 302 && r.headers['location']) { + return r.headers['location']; + } + }).catch(() => null); + + const { patternMatch } = extract(normalizeURL(location)); noteId = patternMatch?.id; xsecToken = patternMatch?.token; } diff --git a/api/src/processing/url.js b/api/src/processing/url.js index dbbda1cd..5f93f1d0 100644 --- a/api/src/processing/url.js +++ b/api/src/processing/url.js @@ -99,7 +99,7 @@ function aliasURL(url) { case "xhslink": if (url.hostname === 'xhslink.com' && parts.length === 3) { - url = new URL(`https://www.xiaohongshu.com/a/${parts[2]}`); + url = new URL(`https://www.xiaohongshu.com/${parts[1]}/${parts[2]}`); } break;