整合小红书页面:内联扫码登录、用户主页、移除独立登录和内容浏览页

- 新增 XiaohongshuPage:顶部搜索栏、登录用户头像/ID、退出按钮
- 未登录时内联显示二维码,无需跳转独立登录页
- 点击笔记作者可打开用户主页 slide-over(复用 UserCard)
- 修复用户主页关注/粉丝/获赞数为零:选择器从 .data-area .data-item 改为 .user-interactions > div
- 修复用户头像选择器:img.user-image(img 本身带该 class)
- backend LoginStatus 新增 avatar/userId 字段,登录状态接口返回头像和用户 ID
- 删除 LoginPage、BrowserPage,侧边栏精简为小红书单入口
This commit is contained in:
2026-03-02 00:12:24 +08:00
parent ee154f990d
commit 9d0a9c93f4
11 changed files with 440 additions and 477 deletions
+14
View File
@@ -49,9 +49,23 @@ export async function checkLoginStatus(page: Page): Promise<LoginStatus> {
// Attempt to extract a username from the indicator area.
const username = await indicator.textContent().catch(() => null);
// Attempt to extract the logged-in user's avatar URL.
const avatar = await page
.$eval(XHS_SELECTORS.login.userAvatar, (el) => el.getAttribute('src') ?? '')
.catch(() => '');
// Attempt to extract the userId from the profile link href.
const userLinkHref = await page
.$eval(XHS_SELECTORS.login.userLink, (el) => el.getAttribute('href') ?? '')
.catch(() => '');
const userIdMatch = userLinkHref.match(/\/user\/profile\/([a-f0-9]+)/);
const userId = userIdMatch?.[1] ?? '';
return {
loggedIn: true,
...(username ? { username: username.trim() } : {}),
...(avatar ? { avatar } : {}),
...(userId ? { userId } : {}),
};
}
+7 -3
View File
@@ -10,6 +10,10 @@ export const XHS_SELECTORS = {
loggedInIndicator: '.user .link-wrapper .channel',
/** The "login" button that opens the QR code modal (if not already shown). */
loginButton: '.login-btn',
/** Logged-in user's avatar image in the sidebar. */
userAvatar: '.user .avatar img',
/** Logged-in user's profile link in the sidebar (href contains userId). */
userLink: '.user .link-wrapper a',
},
feed: {
@@ -108,8 +112,8 @@ export const XHS_SELECTORS = {
headerContainer: '.user-info',
/** User nickname. */
nickname: '.user-info .user-name',
/** User avatar image. */
avatar: '.user-info .user-image img',
/** User avatar image (the img itself carries class user-image). */
avatar: '.user-info img.user-image',
/** User bio / description text. */
description: '.user-info .user-desc',
/** User gender icon or text. */
@@ -117,7 +121,7 @@ export const XHS_SELECTORS = {
/** IP location. */
ipLocation: '.user-info .user-ip',
/** Follower / following / interaction count elements. */
followCount: '.user-info .data-area .data-item',
followCount: '.user-info .user-interactions > div',
/** Note count (displayed somewhere on the profile page). */
noteCountTab: '.reds-tab-item',
/** Individual feed items on the user profile. */
+2
View File
@@ -7,6 +7,8 @@
export interface LoginStatus {
loggedIn: boolean;
username?: string;
avatar?: string;
userId?: string;
}
export interface QRCodeResult {