Skip to content

feat(xiaohongshu): lives — list live rooms with directly playable FLV stream URLs - #2471

Open
yisiliu wants to merge 1 commit into
jackwener:mainfrom
yisiliu:feat/xiaohongshu-lives
Open

yisiliu wants to merge 1 commit into
jackwener:mainfrom
yisiliu:feat/xiaohongshu-lives

Conversation

@yisiliu

@yisiliu yisiliu commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Standalone — based directly on main, merge-order independent of #2461. The only shared logic is a ~15-line navigateFresh helper that #2461 also introduces in shared.js; this PR carries a deliberate private copy (no file overlap, so no merge conflict either way) and will switch to the shared import once #2461 lands.

What

xiaohongshu lives lists currently-live rooms with, per room: id, title, host, viewer count, room URL — and a directly playable FLV stream_url. mpv <stream_url> plays the room; no room-page visit needed.

How

The web /livelist page server-renders __INITIAL_STATE__.liveList with everything already in it; the stream URL sits inside the double-nested JSON string roomExtraInfo.live_stream_info (streams[].master_url, default-stream preferred), and the CDN serves it without cookies — verified live: HTTP 200, video/x-flv, 1.6MB delivered in an 8-second probe. extractLiveStreamUrl parses the nested JSON node-side and falls back to the flvUrl param of the xhsdiscover:// deeplink for malformed payloads. The command follows the feed pattern from #2461: persistent session + always-fresh navigation (live listings churn constantly) + one hydration retry.

Verification

TDD: 9 unit tests (nested-JSON parsing, deeplink fallback, row mapping, --limit, warm-tab forced reload, hydration retry, EMPTY_RESULT) written first; boundary convention test includes lives in the persistent list; doc table row added; manifest regenerated (1367 entries). Live: returned 4 real rooms with titles/hosts/viewer counts and working stream URLs.

Known v1 limits (stated intentionally): SSR first screen only (~26 rooms, no scroll pagination), no category filter yet (liveList.categories exists in the store — a --channel arg is a natural follow-up), no in-room interaction.

Part of the xiaohongshu arc: #2470.

🤖 Generated with Claude Code

… stream URLs

The web /livelist page server-renders __INITIAL_STATE__.liveList with
everything a viewer needs per room: id/title/viewer count (tRoomInfo),
host identity (tLiveHostInfo), and - inside the double-nested JSON
string roomExtraInfo.live_stream_info - the FLV master URL, which the
CDN serves without cookies (verified live: HTTP 200, video/x-flv, 1.6MB
delivered in an 8s probe). No room-page visit is needed for discovery
or playback; `mpv <stream_url>` plays the room.

extractLiveStreamUrl parses the nested JSON node-side and falls back to
the flvUrl param of the xhsdiscover:// deeplink for malformed payloads.
The command declares a persistent site session and forces a real reload
when the warm tab already shows the live list (listings churn
constantly); the tiny navigateFresh helper is a deliberate private copy
of the one jackwener#2461 adds to shared.js, keeping this PR merge-order
independent - switch to the shared import once that lands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant