import { XhsClient as XhsClientBase } from '@kevisual/xhs-core'; import { Mention, CommonentInfo } from './xhs-type/mention.ts'; export type Result = { code: number; // 0: success msg?: string; data?: T; success?: boolean; }; type SignInfo = { uri: string; data: any; a1: string; web_session?: string; }; type SignOptions = { signUrl?: string; }; export const getSign = async (signInfo: SignInfo, options?: SignOptions) => { const { uri, data, a1, web_session } = signInfo; // console.log('getSign', uri, data, a1, web_session); // let signUri = new URL(uri, 'http://light.xiongxiao.me:5006').pathname; // signUri = '/api/sns/web/v2/user/me'; try { let signUrl = options?.signUrl || 'http://light.xiongxiao.me:5006/sign'; // signUrl = 'http://localhost:5005/sign' const signs = await fetch(signUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ uri: uri, data: data, a1, web_session: web_session, }), }).then((res) => res.json()); return signs; } catch (error) { return null; } }; type XhsOptions = { cookie?: string; }; type XhsSign = { signUrl?: string; }; export class XhsClient extends XhsClientBase { signConfig?: XhsSign; constructor(opts: XhsOptions) { super(opts as any); } printResult(msg: string, response: any) { if (msg === 'response') { console.log('url', response.url); if (response.response) { console.log('status', response.response.status); console.log('data', response.response.data); } } else if (msg === 'request') { // console.log('request', response); } else if (msg === 'html') { // console.log('html', response); } } /** * 获取未读消息 * @returns */ async getUnread(): Promise> { const url = '/api/sns/web/unread_count'; const response = await this.get(url); return response; } async postRead(type: 'unread_count' | 'likes' | 'mentions' | 'unread_count' = 'mentions') { const uri = '/api/sns/web/v1/message/read'; const data = { type, }; type RetrunData = { code: number; msg: string; success: boolean; }; const response = await this.post(uri, data, { sign: this.sign.bind(this), }); return response as Result; } async getUserInfoFromHtml(userId: string) { type ReturnData = { ip_location: string; desc: string; imageb: string; nickname: string; images: string; red_id: string; gender: number; }; const response = await super.getUserInfoFromHtml(userId); return response as ReturnData; } async getFollowNotifications(num = 10, cursor = '') { const url = '/api/sns/web/v1/you/connections'; type Connection = { type: 'fllow/you'; title: string; id: string; track_type: string; user: { fstatus: 'both' | 'follows' | 'fans'; red_official_verify_type: number; xsec_token: string; userid: string; nickname: string; images: string }; time: number; score: number; }; type ReturnData = { message_list: Connection[]; has_more: boolean; cursor: number; strCursor: string; }; const response = await this.get(url, { num, cursor }, { sign: this.sign.bind(this) }); return response as Result; } async getComment(noteId: string, xsecToken?: string) {} /** * * @uri /api/sns/web/v1/you/mentions * @returns */ async getMention(num = 10): Promise> { const url = '/api/sns/web/v1/you/mentions'; const response = await this.get( url, { num }, { sign: this.sign.bind(this), // headers: { // 'x-s': // 'XYW_eyJzaWduU3ZuIjoiNTYiLCJzaWduVHlwZSI6IngyIiwiYXBwSWQiOiJsb2dpbiIsInNpZ25WZXJzaW9uIjoiMSIsInBheWxvYWQiOiJiNGJmMGI2MDVkZTlkOWMyY2RlNTI2YmVjNjM2ZmIxMjkxYzUxMTIyYWQyOTk5MzIyMzNjMmU0OTEzMWFmYzgzY2FmOGQzZDIzMTA0Y2RlNWUzZDZlZDczMDg0MmUzYzAxOTNkY2FjZjEyZjk1NTMzZGQzY2ZkMGFmOTg5MGZmMDIwNWI0MmQwOTNiYmJjMGNkZWU3MzdmOGE2MmRkYWVlYjZhMjcxZDViNjZkNGRjYjA1NDg2MGZhNTllN2M5MjE0ZDE2OTJjYWQyZjZmNzE1NThmYWQ3YjQxZjlhZTNiYjA1ZDExN2YzYWI2ZjRjYzY5MzcyMzRhOTY1OTkxYzMwMWY2YjI1MzY4MTZiNzM1YzhmMWEzOTk2ODhkMWU0NDFiODljYTNlNzQ3YWNlN2M2MGIzZDlhZWQwZDVlZDZlNGFhMDE5MmQ5YzZjNDE1M2IxM2RjODAwYjUzZTQxYWEzOTU4MjJhMzYyMmJjODEwYmY4MzA3MjkwMjY2ZDUzNmQwMjdkMTJlOWEwMzhlZmY1YWU4OTM5NDVlNDhmYmY2MCJ9', // 'x-t': '1746097556685', // }, }, ); return response; } async sign(uri: string, data: any, config: any) { let headers = config?.headers || {}; const cookieDist = this.getCookieMap(); const web_session = cookieDist['web_session']; const a1 = cookieDist['a1']; const res = await getSign({ uri, data, a1, web_session }, this.signConfig); if (res) { headers['x-s'] = res?.['x-s']; headers['x-t'] = res?.['x-t']; config.headers = headers; } else { console.log('get sign error'); throw new Error('get sign error'); } return config; } async getNoteById(noteId: string, xsecToken?: string) { const data = { source_note_id: noteId, image_scenes: ['CRD_WM_WEBP'], }; const uri = '/api/sns/web/v1/feed'; try { const response = await this.post(uri, data, { sign: this.sign.bind(this) }); return response['items'][0]['node_card']; } catch (error) { console.log(error); } } /** * 发送评论,content最多为300个字符,如果多余300个字符,发送两次 * @param comment * @returns */ async postComment(comment: { note_id: string; comment_id: string; content: string }) { const uri = '/api/sns/web/v1/comment/post'; try { const data = { note_id: comment.note_id, content: comment.content, target_comment_id: comment.comment_id, at_users: [], // }; type PostCommentResponse = { comment: CommonentInfo; time: number; toast: string; }; const response = await this.post(uri, data, { sign: this.sign.bind(this) }); return response as Result; } catch (error) { console.log(error); } } } type UnreadCount = { unread_count: number; likes: number; connections: number; mentions: number; };