Files
social-router/packages/xhs/src/libs/xhs.ts
2025-05-02 15:39:44 +08:00

211 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { XhsClient as XhsClientBase } from '@kevisual/xhs-core';
import { Mention, CommonentInfo } from './xhs-type/mention.ts';
export type Result<T> = {
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<Result<UnreadCount>> {
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<RetrunData>;
}
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<ReturnData>;
}
async getComment(noteId: string, xsecToken?: string) {}
/**
*
* @uri /api/sns/web/v1/you/mentions
* @returns
*/
async getMention(num = 10): Promise<Result<Mention>> {
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<PostCommentResponse>;
} catch (error) {
console.log(error);
}
}
}
type UnreadCount = {
unread_count: number;
likes: number;
connections: number;
mentions: number;
};