From efa37bad48a7cdece8b1aec849074d6e1aa7bcf1 Mon Sep 17 00:00:00 2001 From: PXLZJ <1083861403@qq.com> Date: Sun, 29 Mar 2026 12:07:50 +0800 Subject: [PATCH 1/3] feat(xiaohongshu): add cover image URL to user notes output Extract cover image URL from noteCard.cover.urlDefault in __INITIAL_STATE__ and include it in the user command output columns. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/clis/xiaohongshu/user-helpers.ts | 4 ++++ src/clis/xiaohongshu/user.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/clis/xiaohongshu/user-helpers.ts b/src/clis/xiaohongshu/user-helpers.ts index b5ddb9c0..9bf1ac5c 100644 --- a/src/clis/xiaohongshu/user-helpers.ts +++ b/src/clis/xiaohongshu/user-helpers.ts @@ -8,6 +8,7 @@ export interface XhsUserNoteRow { title: string; type: string; likes: string; + cover: string; url: string; } @@ -72,11 +73,14 @@ export function extractXhsUserNotes(snapshot: XhsUserPageSnapshot, fallbackUserI const xsecToken = toCleanString(entry?.xsecToken ?? entry?.xsec_token ?? noteCard.xsecToken ?? noteCard.xsec_token); const likes = toCleanString(noteCard.interactInfo?.likedCount ?? noteCard.interact_info?.liked_count ?? 0) || '0'; + const cover = toCleanString(noteCard.cover?.urlDefault ?? noteCard.cover?.urlPre ?? noteCard.cover?.url ?? ''); + rows.push({ id: noteId, title: toCleanString(noteCard.displayTitle ?? noteCard.display_title ?? noteCard.title), type: toCleanString(noteCard.type), likes, + cover, url: buildXhsNoteUrl(userId || fallbackUserId, noteId, xsecToken), }); } diff --git a/src/clis/xiaohongshu/user.ts b/src/clis/xiaohongshu/user.ts index 44fa9cf0..40622be1 100644 --- a/src/clis/xiaohongshu/user.ts +++ b/src/clis/xiaohongshu/user.ts @@ -32,7 +32,7 @@ cli({ { name: 'id', type: 'string', required: true, positional: true, help: 'User id or profile URL' }, { name: 'limit', type: 'int', default: 15, help: 'Number of notes to return' }, ], - columns: ['id', 'title', 'type', 'likes', 'url'], + columns: ['id', 'title', 'type', 'likes', 'cover', 'url'], func: async (page, kwargs) => { const userId = normalizeXhsUserId(String(kwargs.id)); const limit = Math.max(1, Number(kwargs.limit ?? 15)); From 6d22f7aa8003e5abd09b44e13139a6f661cad5e3 Mon Sep 17 00:00:00 2001 From: jackwener Date: Sun, 29 Mar 2026 17:34:55 +0800 Subject: [PATCH 2/3] test(xiaohongshu): cover user note rows --- src/clis/xiaohongshu/user-helpers.test.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/clis/xiaohongshu/user-helpers.test.ts b/src/clis/xiaohongshu/user-helpers.test.ts index f990110d..7050d4fe 100644 --- a/src/clis/xiaohongshu/user-helpers.test.ts +++ b/src/clis/xiaohongshu/user-helpers.test.ts @@ -75,6 +75,7 @@ describe('extractXhsUserNotes', () => { title: 'First note', type: 'video', likes: '4.6δΈ‡', + cover: '', url: 'https://www.xiaohongshu.com/user/profile/user-1/note-1?xsec_token=abc&xsec_source=pc_user', }, { @@ -82,11 +83,33 @@ describe('extractXhsUserNotes', () => { title: 'Second note', type: 'normal', likes: '42', + cover: '', url: 'https://www.xiaohongshu.com/user/profile/fallback-user/note-2', }, ]); }); + it('extracts cover urls with fallback priority urlDefault -> urlPre -> url', () => { + const rows = extractXhsUserNotes( + { + noteGroups: [ + [ + { noteCard: { noteId: 'cover-1', cover: { urlDefault: 'https://img.example/default.jpg', urlPre: 'https://img.example/pre.jpg', url: 'https://img.example/raw.jpg' } } }, + { noteCard: { noteId: 'cover-2', cover: { urlPre: 'https://img.example/pre-only.jpg', url: 'https://img.example/raw-only.jpg' } } }, + { noteCard: { noteId: 'cover-3', cover: { url: 'https://img.example/raw-fallback.jpg' } } }, + ], + ], + }, + 'fallback-user' + ); + + expect(rows.map(row => row.cover)).toEqual([ + 'https://img.example/default.jpg', + 'https://img.example/pre-only.jpg', + 'https://img.example/raw-fallback.jpg', + ]); + }); + it('deduplicates repeated notes by note id', () => { const rows = extractXhsUserNotes( { From fca62444f8952c3ae55ec419fb2bcbbea164d8e5 Mon Sep 17 00:00:00 2001 From: jackwener Date: Sun, 29 Mar 2026 17:38:29 +0800 Subject: [PATCH 3/3] refactor(xiaohongshu): keep cover out of default columns --- src/clis/xiaohongshu/user.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clis/xiaohongshu/user.ts b/src/clis/xiaohongshu/user.ts index 40622be1..44fa9cf0 100644 --- a/src/clis/xiaohongshu/user.ts +++ b/src/clis/xiaohongshu/user.ts @@ -32,7 +32,7 @@ cli({ { name: 'id', type: 'string', required: true, positional: true, help: 'User id or profile URL' }, { name: 'limit', type: 'int', default: 15, help: 'Number of notes to return' }, ], - columns: ['id', 'title', 'type', 'likes', 'cover', 'url'], + columns: ['id', 'title', 'type', 'likes', 'url'], func: async (page, kwargs) => { const userId = normalizeXhsUserId(String(kwargs.id)); const limit = Math.max(1, Number(kwargs.limit ?? 15));