yz-yuki-plugin 2.0.3-4 → 2.0.3-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/CHANGELOG.md CHANGED
@@ -1,4 +1,6 @@
1
1
  # 2.0.3
2
+ * 优化获取完整文章动态
3
+ * fix addBiliSub
2
4
  * 优化提示信息
3
5
 
4
6
  # 2.0.2
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  # 🌰一、安装插件
12
12
 
13
13
  ## 选择安装方式
14
- 按照网络情况以及使用的bot框架是`Yunzai-Next`还是`Yunzai-V3:`,选择对应的安装方式。
14
+ 按照网络情况以及使用的bot框架是`Yunzai-Next`还是`Yunzai-V3`,选择对应的安装方式。
15
15
 
16
16
  ### ***(一)Yunzai-Next***
17
17
  > 选择其中一种方式安装插件:
@@ -134,7 +134,7 @@ https://m.weibo.cn/u/7643376782 # 7643376782 为崩坏星穹铁道博主uid
134
134
 
135
135
  # 🌈 三、功能列表
136
136
 
137
- 请使用 `优纪帮助`或 `yuki帮助` 获取完整帮助
137
+ 请使用 `#优纪帮助`或 `/yuki帮助` 获取完整帮助
138
138
 
139
139
  - [x] B站动态
140
140
  - [x] 微博动态
@@ -17,12 +17,22 @@ export declare class BiliQuery {
17
17
  */
18
18
  static parseRichTextNodes: (nodes: any[] | string | any) => any;
19
19
  /**获取完整B站文章内容
20
- * @param postId - 文章ID
21
- * @returns {Json}完整的B站文章内容json数据
20
+ * @param postUrl - 文章链接: https://www.bilibili.com/read/cvxxxx 或者 https://www.bilibili.com/opus/xxxx
21
+ * @returns {Json} 完整的B站文章内容json数据
22
22
  */
23
- static getFullArticleContent(postUrl: string): Promise<any>;
24
- /**解析完整文章内容 */
25
- static praseFullArticleContent(content: string): string;
23
+ static getFullArticleContent(postUrl: string): Promise<{
24
+ readInfo: any;
25
+ articleType: string;
26
+ }>;
27
+ /**解析旧版完整文章内容 */
28
+ static praseFullOldTypeArticleContent(content: string): string;
29
+ /**解析新版完整文章内容
30
+ * @param paragraphs - MODULE_TYPE_CONTENT 类型文章的段落数组
31
+ */
32
+ static praseFullNewTypeArticleContent: (paragraphs: any[] | any) => {
33
+ content: string;
34
+ img: any[];
35
+ };
26
36
  static formatUrl(url: string): string;
27
37
  /**
28
38
  * 生成动态消息文字内容
@@ -86,16 +86,31 @@ class BiliQuery {
86
86
  pics = desc?.pics;
87
87
  pics = pics.map((item) => { return { url: item?.url, width: item?.width, height: item?.height }; }) || [];
88
88
  formatData.data.title = desc?.title;
89
+ // 文章内容过长,则尝试获取全文
89
90
  if ((desc?.summary?.text)?.length >= 480) {
90
- const readInfo = await this.getFullArticleContent(this.formatUrl(desc?.jump_url));
91
- formatData.data.content = this.praseFullArticleContent(readInfo?.content);
92
- formatData.data.pics = [];
93
- if (!(formatData.data.content)) {
94
- formatData.data.content = this.parseRichTextNodes(desc?.summary?.rich_text_nodes || desc?.summary?.text) || "";
95
- formatData.data.pics = pics;
91
+ const { readInfo, articleType } = await this.getFullArticleContent(this.formatUrl(desc?.jump_url));
92
+ // 文章链接类型为 cv(旧类型) 或者 opus(新类型)
93
+ if (articleType === "cv") {
94
+ formatData.data.content = this.praseFullOldTypeArticleContent(readInfo?.content);
95
+ if (String(formatData.data.content).length < 100) {
96
+ formatData.data.content = this.parseRichTextNodes(desc?.summary?.rich_text_nodes || desc?.summary?.text) || "";
97
+ formatData.data.pics = pics;
98
+ }
99
+ else {
100
+ formatData.data.pics = [];
101
+ }
102
+ }
103
+ else if (articleType === "opus") {
104
+ const { content, img } = this.praseFullNewTypeArticleContent(readInfo?.paragraphs);
105
+ formatData.data.content = content;
106
+ formatData.data.pics = (img && img.length > 0) ? img : pics;
107
+ if (content && content.length < 100) {
108
+ formatData.data.content = this.parseRichTextNodes(desc?.summary?.rich_text_nodes || desc?.summary?.text);
109
+ }
96
110
  }
97
111
  else {
98
- formatData.data.pics = [];
112
+ formatData.data.content = this.parseRichTextNodes(desc?.summary?.rich_text_nodes || desc?.summary?.text) || "";
113
+ formatData.data.pics = pics;
99
114
  }
100
115
  }
101
116
  else {
@@ -106,7 +121,7 @@ class BiliQuery {
106
121
  else if (majorType === "MAJOR_TYPE_ARTICLE") {
107
122
  desc = data?.modules?.module_dynamic?.major?.article || {};
108
123
  pics = desc?.covers;
109
- pics = pics.map((item) => { return { url: item }; }) || [];
124
+ pics = pics.map((item) => ({ url: item }));
110
125
  formatData.data.title = desc?.title;
111
126
  formatData.data.content = this.parseRichTextNodes(desc?.desc);
112
127
  }
@@ -210,8 +225,8 @@ class BiliQuery {
210
225
  }
211
226
  };
212
227
  /**获取完整B站文章内容
213
- * @param postId - 文章ID
214
- * @returns {Json}完整的B站文章内容json数据
228
+ * @param postUrl - 文章链接: https://www.bilibili.com/read/cvxxxx 或者 https://www.bilibili.com/opus/xxxx
229
+ * @returns {Json} 完整的B站文章内容json数据
215
230
  */
216
231
  static async getFullArticleContent(postUrl) {
217
232
  const Cookie = await readSyncCookie();
@@ -221,11 +236,24 @@ class BiliQuery {
221
236
  responseType: 'text'
222
237
  });
223
238
  const text = response.data;
224
- const match = text.match(/"readInfo":([\s\S]+?),"readViewInfo":/);
225
- if (match) {
226
- const full_json_text = match[1];
227
- const readInfo = JSON.parse(full_json_text);
228
- return readInfo;
239
+ let match, readInfo, articleType;
240
+ if (/^https:\/\/www.bilibili.com\/read\/cv/.test(postUrl)) {
241
+ match = String(text).match(/"readInfo":([\s\S]+?),"readViewInfo":/);
242
+ if (match) {
243
+ const full_json_text = match[1];
244
+ readInfo = JSON.parse(full_json_text);
245
+ articleType = 'cv';
246
+ return { readInfo, articleType };
247
+ }
248
+ }
249
+ else if (/^https:\/\/www.bilibili.com\/opus\//.test(postUrl)) {
250
+ match = String(text).match(/"module_content":([\s\S]+?),\s*"module_type":"MODULE_TYPE_CONTENT"/);
251
+ if (match) {
252
+ const full_json_text = match[1];
253
+ readInfo = JSON.parse(full_json_text);
254
+ articleType = 'opus';
255
+ return { readInfo, articleType };
256
+ }
229
257
  }
230
258
  }
231
259
  catch (err) {
@@ -233,8 +261,8 @@ class BiliQuery {
233
261
  return null;
234
262
  }
235
263
  }
236
- /**解析完整文章内容 */
237
- static praseFullArticleContent(content) {
264
+ /**解析旧版完整文章内容 */
265
+ static praseFullOldTypeArticleContent(content) {
238
266
  content = String(content).replace(/\n/g, '<br>');
239
267
  // 使用正则表达式匹配 <img> 标签的 data-src 属性
240
268
  const imgTagRegex = /<img[^>]*data-src="([^"]*)"[^>]*>/g;
@@ -245,6 +273,73 @@ class BiliQuery {
245
273
  });
246
274
  return content;
247
275
  }
276
+ /**解析新版完整文章内容
277
+ * @param paragraphs - MODULE_TYPE_CONTENT 类型文章的段落数组
278
+ */
279
+ static praseFullNewTypeArticleContent = (paragraphs) => {
280
+ if (Array.isArray(paragraphs)) {
281
+ // 筛选出正文和图片
282
+ paragraphs = paragraphs.filter(paragraph => paragraph.para_type === 1 || paragraph.para_type === 2);
283
+ let content = "";
284
+ let img = [];
285
+ paragraphs.forEach((item) => {
286
+ switch (item.para_type) {
287
+ case 1:
288
+ // 处理正文
289
+ content += item.text.nodes.map((node) => {
290
+ let nodeType = node.type;
291
+ if (nodeType === 'TEXT_NODE_TYPE_RICH') {
292
+ let richType = node?.rich?.type;
293
+ switch (richType) {
294
+ case 'RICH_TEXT_NODE_TYPE_TOPIC':
295
+ // 确保链接以 https:// 开头
296
+ let jumpUrl = node?.rich?.jump_url;
297
+ if (jumpUrl && !jumpUrl.startsWith('http://') && !jumpUrl.startsWith('https://')) {
298
+ jumpUrl = `https://${jumpUrl}`;
299
+ }
300
+ return `<span class="bili-rich-text-module topic" href="${jumpUrl}">${node?.rich?.text}</span>`;
301
+ case 'RICH_TEXT_NODE_TYPE_TEXT':
302
+ // 正文将 \n 替换为 <br> 以实现换行
303
+ return node?.rich?.text.replace(/\n/g, '<br>');
304
+ case 'RICH_TEXT_NODE_TYPE_AT':
305
+ // 处理 @ 类型,使用官方的HTML标签写法
306
+ return `<span data-module="desc" data-type="at" data-oid="${node?.rich?.rid}" class="bili-rich-text-module at">${node?.rich?.text}</span>`;
307
+ case 'RICH_TEXT_NODE_TYPE_LOTTERY':
308
+ // 处理互动抽奖类型,使用官方的HTML标签写法
309
+ return `<span data-module="desc" data-type="lottery" data-oid="${node?.rich?.rid}" class="bili-rich-text-module lottery">${node?.rich?.text}</span>`;
310
+ case 'RICH_TEXT_NODE_TYPE_WEB':
311
+ // 处理 RICH_TEXT_NODE_TYPE_WEB 类型,直接拼接 text 属性
312
+ return node?.rich?.text;
313
+ case 'RICH_TEXT_NODE_TYPE_EMOJI':
314
+ // 处理表情类型,使用 img 标签显示表情
315
+ const emoji = node?.rich?.emoji;
316
+ return `<img src="${emoji?.icon_url}" alt="${emoji?.text}" title="${emoji?.text}" style="vertical-align: middle; width: ${emoji?.size}em; height: ${emoji?.size}em;">`;
317
+ case 'RICH_TEXT_NODE_TYPE_GOODS':
318
+ // 处理商品推广类型,使用官方的HTML标签写法
319
+ const goods_url = node?.rich?.jump_url;
320
+ return `<span data-module="desc" data-type="goods" data-url="${goods_url}" data-oid="${node?.rich?.rid}" class="bili-rich-text-module goods ${node?.rich?.icon_name}">&ZeroWidthSpace;${node?.rich?.text}</span>`;
321
+ default:
322
+ return node;
323
+ }
324
+ }
325
+ else if (nodeType === "TEXT_NODE_TYPE_WORD") {
326
+ return `${node?.word?.words}<br>`;
327
+ }
328
+ }).join('');
329
+ break;
330
+ case 2:
331
+ // 处理图片
332
+ img = img.concat(item?.pic?.pics.map((item) => { return { url: item?.url, width: item?.width, height: item?.height }; }) || []);
333
+ break;
334
+ }
335
+ });
336
+ return { content, img };
337
+ }
338
+ else {
339
+ // 未知类型,返回null
340
+ return null;
341
+ }
342
+ };
248
343
  // 处理斜杠开头的链接
249
344
  static formatUrl(url) {
250
345
  return 0 == url.indexOf('//') ? `https:${url}` : url;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yz-yuki-plugin",
3
- "version": "2.0.3-4",
3
+ "version": "2.0.3-5",
4
4
  "description": "优纪插件,yunzaijs 关于 微博推送、B站推送 等功能的拓展插件",
5
5
  "author": "snowtafir",
6
6
  "type": "module",