This commit is contained in:
2025-05-05 00:01:36 +08:00
parent d6014b3c40
commit a412c09da0
20 changed files with 2911 additions and 102 deletions

View File

@@ -128,6 +128,23 @@ class XhsClient {
}
return {};
}
/**
*
* @param {*} data
*/
setCookieMap(data = {}) {
const cookieDict = this.getCookieMap();
const newCookieDict = { ...cookieDict, ...data };
const cookieStr = Object.entries(newCookieDict)
.map(([key, value]) => {
const trimmedKey = key.trim();
const trimmedValue = value ? value.trim() : '';
return `${trimmedKey}=${trimmedValue}`;
})
.join('; ');
this.axiosInstance.defaults.headers.Cookie = cookieStr;
this.cookie = cookieStr;
}
/**
* Get X-S and X-T
* @param {*} url

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,7 @@
import { XhsClient } from '../src/index.js';
// import { XhsClient } from '../dist/app.mjs';
import { cookie } from './common.ts';
const client = new XhsClient({ cookie } as any);
client.setCookieMap({ a1: 'thisistest' })
console.log(client.getCookieMap());
console.log(client.cookie);

View File

@@ -0,0 +1,4 @@
import qs from 'querystring';
const r = qs.stringify({ a: 1, b: 2, c: 3 });
console.log(r); // a=1&b=2&c=3

View File

@@ -4,7 +4,7 @@ import { XhsServices } from '@kevisual/xhs/services/xhs-services.ts';
export const app = new QueryRouterServer();
export const xhsServices = new XhsServices();
const cookie =
'a1=1969088bf22oidhober22hsb74h3qoavpucdvmrbb30000712484;abRequestId=e1b9d999-8838-528a-9933-5f3ac9134d8c;gid=yjKj8YYdSSUqyjKj8YYDi76FJJl3fxlDdFJJSDDxMDW4xfq8qAl0hh888WyJ4Y48ySjjfKfd;loadts=1746193349304;sec_poison_id=74e35006-555a-47a5-a11b-7d4a2482b933;unread={%22ub%22:%2268077ca2000000001b03bff6%22%2C%22ue%22:%22680e491b000000000b015506%22%2C%22uc%22:30};web_session=040069b2e9c511ca302098d5213a4b8556ed1d;webBuild=4.62.3;webId=bffbeec4c301c7b3dc284ee35dd742fb;websectiga=cffd9dcea65962b05ab048ac76962acee933d26157113bb213105a116241fa6c;xsecappid=xhs-pc-web;acw_tc=0a00d5b517461933472156520e55fc213ae73b04699cd042b86f1525ccab06;';
'a1=1969a2df762vy6p46vet3jjpwfvnoce52hge24v0430000640615;abRequestId=48bccb63-a540-5533-8215-546916a6386f;gid=yjKj0JdyjKJ4yjKj0JfiWx4hKJhvKU4Khd9qk84VVUEihdq8IlSd2J888K48Ky28SSqJKYSK;loadts=1746343425888;sec_poison_id=32d8febc-7543-41e7-8a1f-c652d32a1e1a;unread={%22ub%22:%2267f73e21000000001b0384ea%22%2C%22ue%22:%226812f08300000000090166d7%22%2C%22uc%22:32};web_session=040069b6528dbc23c355705e223a4b27b6660a;webBuild=4.62.3;webId=05b45ad626037308d58668196c6af47d;websectiga=8886be45f388a1ee7bf611a69f3e174cae48f1ea02c0f8ec3256031b8be9c7ee;xsecappid=xhs-pc-web;acw_tc=0a00d14717463434250061733e8b2fcd3804e9b06020e1f339ebd8b7e80fc4;';
xhsServices.createRoot({
cookie,

View File

@@ -0,0 +1,6 @@
import { XhsClient } from '../xhs.ts';
export const addNote = async function(){
const that = this as XhsClient;
//
}

View File

@@ -12,7 +12,8 @@ const parseComment = (comment: CommonentInfo) => {
};
export class Parse {
static getComment(mention: Mention) {
if (mention.type === 'mention/comment') {
const typeList = ['comment/item', 'mention/comment', 'comment/comment'];
if (typeList.includes(mention.type)) {
const comment_info = mention.comment_info;
const comment = parseComment(comment_info);
const target_comment = parseComment(comment_info.target_comment);

View File

@@ -21,17 +21,21 @@ export type CommonentInfo = {
content: string;
target_comment: CommonentInfo;
user_info?: UserInfo;
image_list?: string[];
};
export type MentionItem = {
id: string;
type: 'mention/item';
track_type: '2';
title: string;
user_info: UserInfo;
item_info: {} & NoteBase;
comment_info: CommonentInfo;
};
export type MentionComment = {
type: 'mention/comment';
id: string;
type: 'mention/comment' | 'comment/comment';
track_type: '8';
title: string;
item_info: {} & NoteBase;

View File

@@ -1,7 +1,7 @@
import { getApiInfo } from './xhs-api/api.ts';
import { XhsClient as XhsClientBase } from '@kevisual/xhs-core';
import { Mention, CommonentInfo } from './xhs-type/mention.ts';
import { Mention, CommonentInfo, ResponseMession } from './xhs-type/mention.ts';
import { pick } from 'lodash-es';
export type Result<T> = {
code: number; // 0: success
msg?: string;
@@ -44,7 +44,7 @@ export const getSign = async (signInfo: SignInfo, options?: SignOptions): Promis
},
body: JSON.stringify({
uri: uri,
data: data,
data,
a1,
web_session: web_session,
}),
@@ -71,19 +71,21 @@ export class XhsClient extends XhsClientBase {
console.log('url', data.url);
console.log('status', data?.response?.status);
if (data.response) {
console.log('data', data.response.data);
// console.log('data', data.response.data);
}
} else if (msg === 'request') {
console.log('request', data);
const { method, url } = data || {};
const headers = pick(data?.headers || {}, ['Cookie', 'x-s', 'x-t', 'x-s-common']);
// console.log('request', { headers, method, url });
} else if (msg === 'html') {
// console.log('html', response);
}
switch (msg) {
case 'get':
console.log('get', data);
// console.log('get', data);
break;
case 'sign':
console.log('sign', data);
// console.log('sign', data);
break;
}
}
@@ -157,7 +159,7 @@ export class XhsClient extends XhsClientBase {
* @uri /api/sns/web/v1/you/mentions
* @returns
*/
async getMention(num = 20): Promise<Result<Mention>> {
async getMention(num = 20): Promise<Result<ResponseMession>> {
const url = '/api/sns/web/v1/you/mentions';
const response = await this.get(
url,
@@ -184,6 +186,11 @@ export class XhsClient extends XhsClientBase {
const xs = _sign?.['x-s'];
const xt = _sign?.['x-t'];
const b1 = _sign?.['b1'];
const newA1 = _sign?.['a1'];
if (a1 !== newA1) {
this.setCookieMap({ a1: newA1 });
this.printResult('cookie change', a1);
}
if (res && xs) {
headers['x-s'] = xs;
headers['x-t'] = xt;
@@ -214,15 +221,23 @@ export class XhsClient extends XhsClientBase {
* @param comment
* @returns
*/
async postComment(comment: { note_id: string; comment_id: string; content: string }) {
async postComment(comment: { note_id: string; comment_id?: string; content: string; images_info?: any, images?: 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: [], //
};
if (comment.comment_id) {
data['target_comment_id'] = comment.comment_id;
}
if (comment.images_info) {
data['images_info'] = comment.images_info;
}
if (comment.images) {
data['images'] = comment.images;
}
type PostCommentResponse = {
comment: CommonentInfo;
time: number;

View File

@@ -1,5 +1,9 @@
import { app, xhsServices } from '@kevisual/xhs/app.ts';
import { Parse } from '@kevisual/xhs/libs/parse.ts';
import { Mention } from '@kevisual/xhs/libs/xhs-type/mention.ts';
const sleep = (ms: number) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};
app
.route({
path: 'mention',
@@ -7,11 +11,9 @@ app
description: '获取提及列表',
})
.define(async (ctx) => {
//
const client = xhsServices.getClient();
const res = await client.getUnread();
if (res.code === 0) {
const unread_count = res.data.unread_count;
ctx.body = res.data;
} else {
ctx.body = {
@@ -20,6 +22,19 @@ app
}
})
.addTo(app);
app
.route({
path: 'mention',
key: 'postRead',
description: '标记为已读',
})
.define(async (ctx) => {
const type = ctx.query.type || 'mentions';
const client = xhsServices.getClient();
const res = await client.postRead(type);
ctx.body = res.data;
})
.addTo(app);
app
.route({
path: 'mention',
@@ -58,14 +73,19 @@ app
key: 'addComment',
})
.define(async (ctx) => {
const { node_id, comment_id, content } = ctx.query;
const { note_id, comment_id, content } = ctx.query;
const client = xhsServices.getClient();
const res = await client.postComment({
note_id: node_id,
note_id: note_id,
comment_id: comment_id,
content,
});
ctx.body = res.data;
if (res.code === 0) {
ctx.body = res.data;
} else {
console.log('添加评论失败', res.code);
ctx.throw(res.code, '添加评论失败');
}
})
.addTo(app);
app
@@ -84,6 +104,28 @@ app
const num = ctx.query.num;
const client = xhsServices.getClient();
const res = await client.getMention(num);
ctx.body = res.data;
if (res.code === 0) {
const mentionList = res.data.message_list;
const handleMention: any[] = [];
for (const mention of mentionList) {
const mention_id = mention.id;
const note_id = mention.item_info.id;
const xsec_token = mention.item_info.xsec_token;
let comment: any = Parse.getComment(mention);
// console.log('note_id', note_id, 'xsec_token', xsec_token, comment);
handleMention.push({
mention_id,
note_id,
xsec_token,
comment,
mention,
});
}
console.log('获取提及列表成功', res.code, res.data?.message_list?.length);
ctx.body = handleMention;
} else {
console.log('获取提及列表失败', res.code);
ctx.throw(res.code, '获取提及列表失败');
}
})
.addTo(app);

View File

@@ -1,6 +1,6 @@
import { XhsClient } from '@kevisual/xhs/libs/xhs.ts';
import { Sequelize } from 'sequelize';
import { createSequelize } from '@kevisual/xhs/services/xhs-db/db.ts';
// import { createSequelize } from '@kevisual/xhs/services/xhs-db/db.ts';
import path from 'node:path';
import fs from 'node:fs';
@@ -17,7 +17,7 @@ type XhsClientMap = {
client: XhsClient;
key: string;
options: XhsClientOptions;
db: Sequelize;
db?: Sequelize;
};
type XhsServicesOptions = {
root?: string;
@@ -49,16 +49,16 @@ export class XhsServices {
if (!fs.existsSync(storage) || !isNew) {
isNew = true;
}
const db = createSequelize({ storage: storage });
// const db = createSequelize({ storage: storage });
const xhsClientMap = {
client,
key,
options,
db,
// db,
};
if (isNew) {
this.initDb(xhsClientMap);
}
// if (isNew) {
// this.initDb(xhsClientMap);
// }
this.map.set(key, xhsClientMap);
return client;

View File

@@ -1,4 +1,4 @@
import { xhsServices } from '../index.ts';
import { xhsServices, app } from '../index.ts';
import { program } from 'commander';
export { program, xhsServices };
export { program, xhsServices, app };

View File

@@ -7,8 +7,30 @@ program
const client = xhsServices.getClient();
const res = await client.postComment({
note_id: '68136dab0000000007034c46',
content: 'test comment 233',
comment_id: '68136dcf000000000401a8c9',
content: 'test',
comment_id: '681741610000000004014e77',
// images_info: {
// images: [
// {
// file_id: '1040g2h031h28ues73i405ostgpcpgo3mff4lk68',
// metadata: { source: -1 },
// stickers: { version: 2, floating: [] },
// extra_info_json: '{"mimeType":"image/jpeg"}',
// },
// ],
// },
images: ['http://sns-img-qc.xhscdn.com/comment/1040g2h031h28ues73i405ostgpcpgo3mff4lk68']
});
console.log(res);
});
// http://sns-img-qc.xhscdn.com/comment/1040g2h031h28ues73i405ostgpcpgo3mff4lk68
const item_info = {
type: 'note_info',
id: '68136dab0000000007034c46',
image: 'http://ci.xiaohongshu.com/notes_pre_post/1040g3k031gulc4mn3q505pp6prq734o3hmigh70?imageView2/2/w/1080/format/jpg',
image_info: {
url: 'http://ci.xiaohongshu.com/notes_pre_post/1040g3k031gulc4mn3q505pp6prq734o3hmigh70?imageView2/2/w/1080/format/jpg',
width: 1200,
height: 1600,
},
};

View File

@@ -1,10 +1,12 @@
import { xhsServices, program } from '../common.ts';
import { xhsServices, program, app } from '../common.ts';
import util from 'node:util';
import { omit } from 'lodash-es';
const getMentions = async () => {
try {
const client = xhsServices.getClient();
const res = await client.getMention(1);
if (res.code) {
if (res.code === 0) {
const data = res.data || {};
console.log('getMentionNotifications', util.inspect(data, { depth: 10 }));
}
@@ -27,3 +29,20 @@ const getTestMentionNote = async () => {
};
program.command('test-mention').description('get mention note').action(getTestMentionNote);
const queryMention = async () => {
const res = await app.call({
path: 'mention',
key: 'getMention',
payload: {
num: 1,
},
});
if (res.code === 200) {
let data = res.body || [];
// data = data.map((item) => omit(item, 'mention'));
console.log('queryMention', util.inspect(data, { depth: 10 }));
}
};
program.command('query-mention').description('query mention').action(queryMention);