koishi-plugin-share-links-analysis 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +18 -13
- package/lib/parsers/xiaohongshu.d.ts +1 -0
- package/lib/parsers/xiaohongshu.js +9 -6
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -76,12 +76,6 @@ function apply(ctx, config) {
|
|
|
76
76
|
ctx.on('ready', async () => {
|
|
77
77
|
logger.info('插件已启动,执行一次初始的小红书 Cookie 刷新...');
|
|
78
78
|
await (0, xiaohongshu_1.refreshXhsCookie)(ctx, config);
|
|
79
|
-
// 设置一个定时器,每隔 12 小时刷新一次 Cookie
|
|
80
|
-
// 24 * 60 * 60 * 1000 = 24小时
|
|
81
|
-
// 12 * 60 * 60 * 1000 = 12小时
|
|
82
|
-
ctx.setInterval(async () => {
|
|
83
|
-
await (0, xiaohongshu_1.refreshXhsCookie)(ctx, config);
|
|
84
|
-
}, 24 * 60 * 60 * 1000);
|
|
85
79
|
});
|
|
86
80
|
ctx.middleware(async (session, next) => {
|
|
87
81
|
if (!session.content || !session.channelId)
|
|
@@ -120,28 +114,38 @@ function apply(ctx, config) {
|
|
|
120
114
|
}
|
|
121
115
|
});
|
|
122
116
|
}
|
|
117
|
+
function escapeHtml(str) {
|
|
118
|
+
if (!str)
|
|
119
|
+
return '';
|
|
120
|
+
return str.replace(/&/g, '&')
|
|
121
|
+
.replace(/</g, '<')
|
|
122
|
+
.replace(/>/g, '>')
|
|
123
|
+
.replace(/"/g, '"')
|
|
124
|
+
.replace(/'/g, ''');
|
|
125
|
+
}
|
|
123
126
|
async function sendResult(session, config, result, logger) {
|
|
124
127
|
let message = config.format;
|
|
125
|
-
|
|
126
|
-
message = message.replace(/{
|
|
127
|
-
message = message.replace(/{
|
|
128
|
-
message = message.replace(/{
|
|
128
|
+
// 对所有文本内容进行 HTML 转义
|
|
129
|
+
message = message.replace(/{title}/g, escapeHtml(result.title || ''));
|
|
130
|
+
message = message.replace(/{authorName}/g, escapeHtml(result.authorName || ''));
|
|
131
|
+
message = message.replace(/{description}/g, escapeHtml(result.description ? result.description : ''));
|
|
132
|
+
message = message.replace(/{sourceUrl}/g, escapeHtml(result.sourceUrl || ''));
|
|
129
133
|
message = message.replace(/{cover}/g, result.coverUrl ? koishi_1.h.image(result.coverUrl).toString() : '');
|
|
130
134
|
const imagesText = result.images ? result.images.map(img => koishi_1.h.image(img).toString()).join('\n') : '';
|
|
131
135
|
message = message.replace(/{images}/g, imagesText);
|
|
132
|
-
message = message.replace(/{stats}/g, result.stats || '');
|
|
136
|
+
message = message.replace(/{stats}/g, escapeHtml(result.stats || ''));
|
|
133
137
|
// 【修复】只要 videoUrl 存在就处理,仅当 duration 明确超长时才替换为提示
|
|
134
138
|
if (result.videoUrl) {
|
|
135
139
|
// 仅当 duration 是有效数字且超长时,才显示提示
|
|
136
140
|
if (typeof result.duration === 'number' && result.duration > config.Maximumduration * 60) {
|
|
137
|
-
const tip = config.Maximumduration_tip || '';
|
|
141
|
+
const tip = escapeHtml(config.Maximumduration_tip || '');
|
|
138
142
|
message = message.replace(/{video}/g, tip);
|
|
139
143
|
message = message.replace(/{videoUrl}/g, '');
|
|
140
144
|
}
|
|
141
145
|
else {
|
|
142
146
|
// 正常发送视频和链接
|
|
143
147
|
message = message.replace(/{video}/g, koishi_1.h.video(result.videoUrl).toString());
|
|
144
|
-
message = message.replace(/{videoUrl}/g, result.videoUrl);
|
|
148
|
+
message = message.replace(/{videoUrl}/g, escapeHtml(result.videoUrl));
|
|
145
149
|
if (config.logLevel === 'link_only' || config.logLevel === 'full') {
|
|
146
150
|
logger.info(`视频直链 (${result.platform}): ${result.videoUrl}`);
|
|
147
151
|
}
|
|
@@ -152,6 +156,7 @@ async function sendResult(session, config, result, logger) {
|
|
|
152
156
|
message = message.replace(/{video}/g, '');
|
|
153
157
|
message = message.replace(/{videoUrl}/g, '');
|
|
154
158
|
}
|
|
159
|
+
// 过滤空行,保留含有 < 的行(如图片、视频标签)
|
|
155
160
|
const cleanMessage = message.split('\n').filter(line => line.trim() !== '' || line.includes('<')).join('\n');
|
|
156
161
|
if (cleanMessage) {
|
|
157
162
|
await session.send(koishi_1.h.quote(session.messageId) + cleanMessage);
|
|
@@ -26,6 +26,7 @@ function match(content) {
|
|
|
26
26
|
/**
|
|
27
27
|
* 使用 Puppeteer 刷新小红书 Cookie 并存入数据库
|
|
28
28
|
* @param ctx - Koishi Context
|
|
29
|
+
* @param config
|
|
29
30
|
*/
|
|
30
31
|
async function refreshXhsCookie(ctx, config) {
|
|
31
32
|
const logger = ctx.logger('share-links-analysis:xiaohongshu');
|
|
@@ -51,7 +52,7 @@ async function refreshXhsCookie(ctx, config) {
|
|
|
51
52
|
}
|
|
52
53
|
const initialCookies = await page.cookies();
|
|
53
54
|
logger.info(`步骤 1 完成, 获取到 ${initialCookies.length} 个初始 Cookie。`);
|
|
54
|
-
// --- 步骤 2: 访问 /explore 页面,触发反爬虫验证,获取安全 Cookie
|
|
55
|
+
// --- 步骤 2: 访问 /explore 页面,触发反爬虫验证,获取安全 Cookie ---
|
|
55
56
|
logger.info('步骤 2/2: 访问 /explore 页面以触发并获取安全 Cookie...');
|
|
56
57
|
try {
|
|
57
58
|
await page.goto('https://www.xiaohongshu.com/explore', {
|
|
@@ -68,16 +69,18 @@ async function refreshXhsCookie(ctx, config) {
|
|
|
68
69
|
return false;
|
|
69
70
|
}
|
|
70
71
|
const hasWebSession = finalCookies.some((c) => c.name === 'web_session');
|
|
71
|
-
const hasAcwTc = finalCookies.some((c) => c.name === 'acw_tc');
|
|
72
72
|
const hasABRequestId = finalCookies.some((c) => c.name === 'abRequestId');
|
|
73
73
|
logger.info(`步骤 2 完成, 共获取到 ${finalCookies.length} 个最终 Cookie。`);
|
|
74
74
|
logger.info(`- 是否包含 'web_session': ${hasWebSession ? '是' : '否'}`);
|
|
75
|
-
logger.info(`- 是否包含 'acw_tc': ${hasAcwTc ? '是' : '否'}`);
|
|
76
75
|
logger.info(`- 是否包含 'abRequestId': ${hasABRequestId ? '是' : '否'}`);
|
|
77
|
-
if (!hasWebSession || !
|
|
78
|
-
logger.warn('关键 Cookie
|
|
76
|
+
if (!hasWebSession || !hasABRequestId) {
|
|
77
|
+
logger.warn('关键 Cookie 缺失,本次刷新可能不完整。将放弃刷新。');
|
|
78
|
+
return false;
|
|
79
79
|
}
|
|
80
|
-
|
|
80
|
+
// 在这里过滤掉 acw_tc
|
|
81
|
+
const filteredCookies = finalCookies.filter((c) => c.name !== 'acw_tc');
|
|
82
|
+
// 使用过滤后的 cookie 数组来生成字符串
|
|
83
|
+
const cookieString = filteredCookies.map((c) => `${c.name}=${c.value}`).join('; ');
|
|
81
84
|
await ctx.database.upsert('sla_cookie_cache', [{ platform: platformId, cookie: cookieString }]);
|
|
82
85
|
logger.info('成功执行两步刷新策略并缓存了小红书 Cookie!');
|
|
83
86
|
return true;
|