yz-yuki-plugin 2.0.3-4 → 2.0.3-6

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,7 @@
1
1
  # 2.0.3
2
+ * 优化截图、静态资源引入方式
3
+ * 优化获取完整文章动态
4
+ * fix addBiliSub
2
5
  * 优化提示信息
3
6
 
4
7
  # 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] 微博动态
@@ -1,16 +1,17 @@
1
1
  import React from 'react';
2
2
  import LogoText from './LogoText.js';
3
- import { createRequire } from 'react-puppeteer';
3
+ import { _paths } from '../../utils/paths.js';
4
+ import path from 'path';
4
5
 
5
6
  // Account
6
7
  // up账户组件
7
- const require = createRequire(import.meta.url);
8
- const bilibililogo = require('./../../../resources/img/icon/dynamic/bilibili.svg');
9
- const weibilogo = require('./../../../resources/img/icon/dynamic/weibo.svg');
8
+ const Bilibililogo = path.join(_paths.pluginResources, 'img/icon/dynamic/bilibili.svg');
9
+ const Weibilogo = path.join(_paths.pluginResources, 'img/icon/dynamic/weibo.svg');
10
+ const AccountCss = path.join(_paths.pluginResources, 'css/dynamic/Account.css');
10
11
  const Account = ({ data }) => {
11
12
  const renderLogo = (logoSrc, className) => (React.createElement("img", { src: logoSrc, className: className, alt: "logo" }));
12
13
  return (React.createElement(React.Fragment, null,
13
- React.createElement("link", { rel: "stylesheet", href: require("./../../../resources/css/dynamic/Account.css") }),
14
+ React.createElement("link", { rel: "stylesheet", href: AccountCss }),
14
15
  React.createElement("div", { className: "account" },
15
16
  React.createElement("div", { className: "avatar-container" },
16
17
  React.createElement("img", { src: data.face, alt: "\u5934\u50CF", className: "avatar" }),
@@ -19,8 +20,8 @@ const Account = ({ data }) => {
19
20
  React.createElement("div", { className: "nickname" }, data.name || ""),
20
21
  React.createElement("div", { className: "timestamp" }, data.pubTs || ""))),
21
22
  React.createElement("div", { className: "logo-container" },
22
- data.appName === 'bilibili' && renderLogo(bilibililogo, 'bilibili-logo'),
23
- data.appName === 'weibo' && renderLogo(weibilogo, 'weibo-logo'),
23
+ data.appName === 'bilibili' && renderLogo(Bilibililogo, 'bilibili-logo'),
24
+ data.appName === 'weibo' && renderLogo(Weibilogo, 'weibo-logo'),
24
25
  React.createElement(LogoText, { data: data })))));
25
26
  };
26
27
  var Account$1 = Account;
@@ -1,8 +1,11 @@
1
1
  import React from 'react';
2
- import { createRequire } from 'react-puppeteer';
2
+ import { _paths } from '../../utils/paths.js';
3
+ import path from 'path';
3
4
 
4
5
  // DynamicContent.tsx
5
- const require = createRequire(import.meta.url);
6
+ const ContentBoxGrid4Css = path.join(_paths.pluginResources, 'css/dynamic/Content.box.grid.4.css');
7
+ const ContentBoxGrid9Css = path.join(_paths.pluginResources, 'css/dynamic/Content.box.grid.9.css');
8
+ const ContentCss = path.join(_paths.pluginResources, 'css/dynamic/Content.css');
6
9
  const Content = ({ data }) => {
7
10
  const picItems = data.pics && (React.createElement("div", { className: 'pic-content' }, data.pics.map((item, index) => {
8
11
  if (item) {
@@ -11,8 +14,8 @@ const Content = ({ data }) => {
11
14
  }
12
15
  return null;
13
16
  })));
14
- const boxGrid_4 = React.createElement("link", { key: "0", rel: "stylesheet", href: require('./../../../resources/css/dynamic/Content.box.grid.4.css') });
15
- const boxGrid_9 = React.createElement("link", { key: "0", rel: "stylesheet", href: require('./../../../resources/css/dynamic/Content.box.grid.9.css') });
17
+ const boxGrid_4 = React.createElement("link", { key: "0", rel: "stylesheet", href: ContentBoxGrid4Css });
18
+ const boxGrid_9 = React.createElement("link", { key: "0", rel: "stylesheet", href: ContentBoxGrid9Css });
16
19
  /**动态宫格样式 */
17
20
  function getBoxGridStyle(pics) {
18
21
  if (!Array.isArray(pics) || pics.length === 0) {
@@ -66,7 +69,7 @@ const Content = ({ data }) => {
66
69
  return null;
67
70
  }
68
71
  const boxGrid = data.boxGrid && (data.pics && getBoxGridStyle(data.pics));
69
- const contentCss = React.createElement("link", { rel: "stylesheet", href: require('./../../../resources/css/dynamic/Content.css') });
72
+ const contentCss = React.createElement("link", { rel: "stylesheet", href: ContentCss });
70
73
  switch (data.type) {
71
74
  case 'DYNAMIC_TYPE_LIVE_RCMD':
72
75
  return (React.createElement(React.Fragment, null,
@@ -1,16 +1,18 @@
1
1
  import React from 'react';
2
2
  import { ConfigController, BOT_NAME } from 'yunzai';
3
3
  import Config from '../../utils/config.js';
4
- import { createRequire } from 'react-puppeteer';
4
+ import { _paths } from '../../utils/paths.js';
5
+ import path from 'path';
5
6
 
6
7
  // Footer.tsx
7
8
  const botVersion = ConfigController.package?.version;
8
- const require = createRequire(import.meta.url);
9
- const bilibililogo = require('./../../../resources/img/icon/dynamic/bilibili.svg');
10
- const weibilogo = require('./../../../resources/img/icon/dynamic/weibo.svg');
9
+ const yukiPluginVersion = Config.getPackageJsonKey('version', path.join(_paths.pluginPath, 'package.json'));
10
+ const bilibililogo = path.join(_paths.pluginResources, 'img/icon/dynamic/bilibili.svg');
11
+ const weibilogo = path.join(_paths.pluginResources, 'img/icon/dynamic/weibo.svg');
12
+ const FooterCss = path.join(_paths.pluginResources, 'css/dynamic/Footer.css');
11
13
  const Footer = ({ data }) => {
12
14
  return (React.createElement(React.Fragment, null,
13
- React.createElement("link", { rel: "stylesheet", href: require('./../../../resources/css/dynamic/Footer.css') }),
15
+ React.createElement("link", { rel: "stylesheet", href: FooterCss }),
14
16
  React.createElement("div", { className: "footer" },
15
17
  React.createElement("div", { className: "footer-text-container" },
16
18
  data.appName === 'bilibili' && (React.createElement("svg", { className: 'w-32 h-10 bili-logo-0', style: { width: '8rem', height: '2.5rem' } },
@@ -29,7 +31,7 @@ const Footer = ({ data }) => {
29
31
  " & ",
30
32
  React.createElement("span", { className: "yuki-plugin-text-title" }, "yuki-plugin"),
31
33
  "-v",
32
- React.createElement("span", { className: "italic" }, `${Config.getLatestVersion()}`))),
34
+ React.createElement("span", { className: "italic" }, yukiPluginVersion))),
33
35
  React.createElement("img", { src: data.urlImgData, alt: "\u4E8C\u7EF4\u7801", className: "qr-code" }))));
34
36
  };
35
37
  var Footer$1 = Footer;
@@ -1,13 +1,14 @@
1
1
  import React from 'react';
2
2
  import Account from './Account.js';
3
3
  import Content from './Content.js';
4
- import { createRequire } from 'react-puppeteer';
4
+ import { _paths } from '../../utils/paths.js';
5
+ import path from 'path';
5
6
 
6
7
  // ForwardContent
7
8
  // 转发动态内容组件
8
- const require = createRequire(import.meta.url);
9
+ const ForwardContentCss = path.join(_paths.pluginResources, 'css/dynamic/ForwardContent.css');
9
10
  const ForwardContent = ({ data }) => (React.createElement(React.Fragment, null,
10
- React.createElement("link", { rel: "stylesheet", href: require("./../../../resources/css/dynamic/ForwardContent.css") }),
11
+ React.createElement("link", { rel: "stylesheet", href: ForwardContentCss }),
11
12
  React.createElement("div", { className: "orig" },
12
13
  React.createElement("div", { className: "orig-container", id: "orig-container" },
13
14
  React.createElement(Account, { data: data }),
@@ -1,11 +1,12 @@
1
1
  import React from 'react';
2
- import { createRequire } from 'react-puppeteer';
2
+ import { _paths } from '../../utils/paths.js';
3
+ import path from 'path';
3
4
 
4
5
  // LogoText
5
6
  // Logo 文本组件
6
- const require = createRequire(import.meta.url);
7
+ const LogoTextCss = path.join(_paths.pluginResources, 'css/dynamic/LogoText.css');
7
8
  const LogoText = ({ data }) => (React.createElement(React.Fragment, null,
8
- React.createElement("link", { rel: "stylesheet", href: require('./../../../resources/css/dynamic/LogoText.css') }),
9
+ React.createElement("link", { rel: "stylesheet", href: LogoTextCss }),
9
10
  data.appName === 'bilibili' && (React.createElement("div", { className: "bilibili-logo-text" }, data.category)),
10
11
  data.appName === 'weibo' && (React.createElement("div", { className: "weibo-logo-text" }, data.category))));
11
12
 
@@ -3,13 +3,14 @@ import Account from './Account.js';
3
3
  import Content from './Content.js';
4
4
  import ForwardContent from './ForwardContent.js';
5
5
  import Footer from './Footer.js';
6
- import { createRequire } from 'react-puppeteer';
6
+ import { _paths } from '../../utils/paths.js';
7
+ import path from 'path';
7
8
 
8
9
  // MainPage.tsx
9
- const require = createRequire(import.meta.url);
10
+ const MainPageCss = path.join(_paths.pluginResources, 'css/dynamic/MainPage.css');
10
11
  function App({ data }) {
11
12
  return (React.createElement(React.Fragment, null,
12
- React.createElement("link", { rel: "stylesheet", href: `${require('./../../../resources/css/dynamic/MainPage.css')}` }),
13
+ React.createElement("link", { rel: "stylesheet", href: MainPageCss }),
13
14
  React.createElement("div", { className: "outside-border" },
14
15
  React.createElement("div", { className: "container" },
15
16
  React.createElement(Account, { data: data }),
@@ -1,24 +1,27 @@
1
1
  import React from 'react';
2
2
  import { BOT_NAME, ConfigController } from 'yunzai';
3
3
  import Config from '../../utils/config.js';
4
- import { createRequire } from 'react-puppeteer';
4
+ import { _paths } from '../../utils/paths.js';
5
+ import path from 'path';
5
6
 
6
7
  //help.tsx
7
8
  const botVersion = ConfigController.package?.version;
8
- const require = createRequire(import.meta.url);
9
+ const yukiPluginVersion = Config.getPackageJsonKey('version', path.join(_paths.pluginPath, 'package.json'));
10
+ const HelpCss = path.join(_paths.pluginResources, 'css/help/help.css');
11
+ const iconPath = (iconName) => path.join(_paths.pluginResources, `img/icon/puplic/${iconName}.png`);
9
12
  function App({ data }) {
10
13
  return (React.createElement(React.Fragment, null,
11
- React.createElement("link", { rel: "stylesheet", href: require('./../../../resources/css/help/help.css') }),
14
+ React.createElement("link", { rel: "stylesheet", href: HelpCss }),
12
15
  React.createElement("div", { className: "container", id: "container" },
13
16
  React.createElement("div", { className: "head_box" },
14
17
  React.createElement("div", { className: "id_text" }, "Yuki-Plugin"),
15
18
  React.createElement("h2", { className: "day_text" },
16
19
  "\u4F7F\u7528\u8BF4\u660E-v",
17
- Config.getLatestVersion())),
20
+ yukiPluginVersion)),
18
21
  data.map((val, index) => (React.createElement("div", { className: "data_box", key: index },
19
22
  React.createElement("div", { className: "tab_lable" }, val.group),
20
23
  React.createElement("div", { className: "list" }, val.list.map((item, itemIndex) => (React.createElement("div", { className: "item", key: itemIndex },
21
- React.createElement("img", { className: "icon", src: require(`./../../../resources/img/icon/puplic/${item.icon}.png`), alt: item.title }),
24
+ React.createElement("img", { className: "icon", src: iconPath(item.icon), alt: item.title }),
22
25
  React.createElement("div", { className: "title" },
23
26
  React.createElement("div", { className: "text" }, item.title),
24
27
  React.createElement("div", { className: "dec" }, item.desc))))))))),
@@ -28,7 +31,7 @@ function App({ data }) {
28
31
  " & ",
29
32
  React.createElement("span", { className: "yuki-plugin-text-title" }, "yuki-plugin"),
30
33
  "-v",
31
- React.createElement("span", { className: "italic" }, `${Config.getLatestVersion()}`)))));
34
+ React.createElement("span", { className: "italic" }, yukiPluginVersion)))));
32
35
  }
33
36
 
34
37
  export { App as default };
@@ -1,11 +1,12 @@
1
1
  import React from 'react';
2
- import { createRequire } from 'react-puppeteer';
2
+ import { _paths } from '../../utils/paths.js';
3
+ import path from 'path';
3
4
 
4
5
  // QrcodeLoginPage.tsx
5
- const require = createRequire(import.meta.url);
6
+ const LoginQrcodeCss = path.join(_paths.pluginResources, 'css/loginQrcode/Page.css');
6
7
  function App({ data }) {
7
8
  return (React.createElement(React.Fragment, null,
8
- React.createElement("link", { rel: "stylesheet", href: require("./../../../resources/css/loginQrcode/Page.css") }),
9
+ React.createElement("link", { rel: "stylesheet", href: LoginQrcodeCss }),
9
10
  React.createElement("div", { className: 'container w-96 max-h-96 m-auto text-lg p-5' },
10
11
  React.createElement("div", { className: "txt-0 text-center mt-3 mb-3 p-1 text-blue-500" },
11
12
  "Created By yuki-plugin",
@@ -1,13 +1,15 @@
1
1
  import React from 'react';
2
2
  import { BOT_NAME, ConfigController } from 'yunzai';
3
3
  import Config from '../../utils/config.js';
4
- import { createRequire } from 'react-puppeteer';
4
+ import { _paths } from '../../utils/paths.js';
5
+ import path from 'path';
5
6
 
6
7
  const botVersion = ConfigController.package?.version;
7
- const require = createRequire(import.meta.url);
8
+ const yukiPluginVersion = Config.getPackageJsonKey('version', path.join(_paths.pluginPath, 'package.json'));
9
+ const VersionCss = path.join(_paths.pluginResources, 'css/version/version.css');
8
10
  function App({ data }) {
9
11
  return (React.createElement(React.Fragment, null,
10
- React.createElement("link", { rel: "stylesheet", href: require("./../../../resources/css/version/version.css") }),
12
+ React.createElement("link", { rel: "stylesheet", href: VersionCss }),
11
13
  React.createElement("div", { className: "container", id: "container" },
12
14
  data.map((item, idx) => (React.createElement("div", { key: idx, className: "version-card" },
13
15
  React.createElement("div", { className: "title" },
@@ -21,7 +23,7 @@ function App({ data }) {
21
23
  " & ",
22
24
  React.createElement("span", { className: "yuki-plugin-text-title" }, "yuki-plugin"),
23
25
  "-v",
24
- React.createElement("span", { className: "italic" }, `${Config.getLatestVersion()}`)))));
26
+ React.createElement("span", { className: "italic" }, yukiPluginVersion)))));
25
27
  }
26
28
 
27
29
  export { App as default };
package/lib/index.js CHANGED
@@ -1,10 +1,13 @@
1
1
  import chalk from 'chalk';
2
2
  import { applicationOptions, setBotTask, useEvent } from 'yunzai';
3
3
  import Config from './utils/config.js';
4
+ import path from 'path';
5
+ import { _paths } from './utils/paths.js';
4
6
  import * as index$1 from './apps/index.js';
5
7
  import { BiliTask } from './models/bilibili/bilibili.task.js';
6
8
  import { WeiboTask } from './models/weibo/weibo.task.js';
7
9
 
10
+ const yukiPluginVersion = Config.getPackageJsonKey('version', path.join(_paths.pluginPath, 'package.json'));
8
11
  let biliConfigData = Config.getConfigData("config", "bilibili", "config");
9
12
  let weiboConfigData = Config.getConfigData("config", "weibo", "config");
10
13
  /** B站动态任务 函数 */
@@ -35,7 +38,7 @@ var index = () => {
35
38
  }
36
39
  }
37
40
  logger.info(chalk.rgb(0, 190, 255)(`-----------------------------------------`));
38
- logger.info(chalk.rgb(255, 225, 255)(`优纪插件 ${Config.getLatestVersion()} 初始化~`));
41
+ logger.info(chalk.rgb(255, 225, 255)(`优纪插件 ${yukiPluginVersion} 初始化~`));
39
42
  logger.info(chalk.rgb(255, 245, 255)(`作者:snowtafir`));
40
43
  logger.info(chalk.rgb(255, 225, 255)(`仓库地址:`));
41
44
  logger.info(chalk.rgb(255, 245, 255)(`https://github.com/snowtafir/yuki-plugin`));
@@ -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;
@@ -3,7 +3,6 @@ import chokidar from "chokidar";
3
3
  * Config 类用于管理配置文件的读取和监听
4
4
  */
5
5
  declare class Config {
6
- readonly packageJsonPath: string;
7
6
  readonly defaultConfigPath: string;
8
7
  readonly userConfigPath: string;
9
8
  defaultConfig: Record<string, any>;
@@ -64,8 +63,11 @@ declare class Config {
64
63
  * @param value 配置项的值
65
64
  */
66
65
  updateConfigItem(appDir: string, functionName: string, key: string, value: any): void;
67
- /** 读取package.json文件,获取最新版本号*/
68
- getLatestVersion(): string | null;
66
+ /** 读取package.json文件,获取指定key的值
67
+ * @param keyName 要获取的key名称
68
+ * @param path package.json文件路径
69
+ */
70
+ getPackageJsonKey(keyName: string, path: string): string | null;
69
71
  }
70
72
  declare const _default: Config;
71
73
  export default _default;
@@ -9,14 +9,12 @@ import { _paths } from './paths.js';
9
9
  * Config 类用于管理配置文件的读取和监听
10
10
  */
11
11
  class Config {
12
- packageJsonPath;
13
12
  defaultConfigPath;
14
13
  userConfigPath;
15
14
  defaultConfig;
16
15
  userConfig;
17
16
  watcher;
18
17
  constructor() {
19
- this.packageJsonPath = path.join(_paths.pluginPath, 'package.json');
20
18
  /** 默认设置 */
21
19
  this.defaultConfigPath = path.join(_paths.pluginPath, 'defaultConfig');
22
20
  this.defaultConfig = {};
@@ -160,15 +158,24 @@ class Config {
160
158
  config[key] = value; // 更新配置项
161
159
  this.saveConfig("config", appDir, functionName, config); // 保存更新后的配置
162
160
  }
163
- /** 读取package.json文件,获取最新版本号*/
164
- getLatestVersion() {
165
- const content = fs.readFileSync(this.packageJsonPath, 'utf-8');
166
- const packageJson = JSON.parse(content);
167
- const match = packageJson.version;
168
- if (match) {
169
- return match;
161
+ /** 读取package.json文件,获取指定key的值
162
+ * @param keyName 要获取的key名称
163
+ * @param path package.json文件路径
164
+ */
165
+ getPackageJsonKey(keyName, path) {
166
+ try {
167
+ const content = fs.readFileSync(path, 'utf-8');
168
+ const packageJson = JSON.parse(content);
169
+ const match = packageJson[keyName];
170
+ if (match) {
171
+ return match;
172
+ }
173
+ else {
174
+ return null;
175
+ }
170
176
  }
171
- else {
177
+ catch (error) {
178
+ logger.error(`getPackageJsonKey error: ${error}`);
172
179
  return null;
173
180
  }
174
181
  }
@@ -1,8 +1,9 @@
1
1
  import { Picture, ComponentCreateOpsionType } from 'react-puppeteer';
2
2
  import { ScreenshotOptions } from '@/utils/puppeteer.render';
3
3
  export declare class Image extends Picture {
4
+ private yukiPuppeteerRender;
4
5
  /**
5
- * 初始化运行Puppeteer
6
+ * 整合截图方法
6
7
  */
7
8
  constructor();
8
9
  /**
@@ -1,21 +1,21 @@
1
1
  import React from 'react';
2
- import { Component, Picture, Puppeteer } from 'react-puppeteer';
2
+ import { Picture } from 'react-puppeteer';
3
3
  import { YukiPuppeteerRender } from './puppeteer.render.js';
4
4
  import * as index from '../components/index.js';
5
5
 
6
- // 初始化 组件渲染对象
7
- const com = new Component();
8
- const yukiPuppeteerRender = new YukiPuppeteerRender();
9
6
  class Image extends Picture {
7
+ yukiPuppeteerRender;
10
8
  /**
11
- * 初始化运行Puppeteer
9
+ * 整合截图方法
12
10
  */
13
11
  constructor() {
14
12
  // 继承实例
15
13
  super();
16
- // start
17
- this.Pup = new Puppeteer();
14
+ // 组件渲染对象
15
+ this.Com;
16
+ // start puppeteer
18
17
  this.Pup.start();
18
+ this.yukiPuppeteerRender = new YukiPuppeteerRender(this.Pup);
19
19
  }
20
20
  /**
21
21
  * @param uid 唯一标识符
@@ -27,7 +27,7 @@ class Image extends Picture {
27
27
  */
28
28
  async renderPage(uid, page, props = {}, ScreenshotOptions, ComponentCreateOpsion) {
29
29
  const Page = index[page];
30
- return yukiPuppeteerRender.yukiScreenshot(com.compile({
30
+ return this.yukiPuppeteerRender.yukiScreenshot(this.Com.compile({
31
31
  join_dir: page,
32
32
  html_name: `${uid}.html`,
33
33
  html_body: React.createElement(Page, { ...props }),
@@ -16,7 +16,9 @@ export type ScreenshotOptions = {
16
16
  modelName?: string;
17
17
  saveHtmlfile?: boolean;
18
18
  };
19
- export declare class YukiPuppeteerRender extends Puppeteer {
19
+ export declare class YukiPuppeteerRender {
20
+ private puppeteerInstance;
21
+ constructor(puppeteerInstance: Puppeteer);
20
22
  /**
21
23
  * 截图并返回buffer
22
24
  * @param htmlPath 绝对路径
@@ -1,10 +1,12 @@
1
- import { Puppeteer } from 'react-puppeteer';
2
1
  import fs__default from 'fs';
3
2
  import path from 'path';
4
3
  import { _paths } from './paths.js';
5
4
 
6
- // 该文件是 yuki-plugin 插件的截图类,继承了 Puppeteer 类,重写了 screenshot 方法,实现了截图的额外功能。
7
- class YukiPuppeteerRender extends Puppeteer {
5
+ class YukiPuppeteerRender {
6
+ puppeteerInstance;
7
+ constructor(puppeteerInstance) {
8
+ this.puppeteerInstance = puppeteerInstance;
9
+ }
8
10
  /**
9
11
  * 截图并返回buffer
10
12
  * @param htmlPath 绝对路径
@@ -21,12 +23,12 @@ class YukiPuppeteerRender extends Puppeteer {
21
23
  * @returns {false | {img: buffer[]}}
22
24
  */
23
25
  async yukiScreenshot(htmlPath, Options) {
24
- if (!(await this.isStart()))
26
+ if (!(await this.puppeteerInstance.isStart()))
25
27
  return false;
26
28
  let name = Options?.modelName ?? 'yuki-plugin';
27
29
  let pageHeight = Options?.pageSplitHeight ?? 8000; // 分割图片高度,默认 8000
28
30
  try {
29
- const page = await this.browser?.newPage().catch(err => {
31
+ const page = await this.puppeteerInstance.browser?.newPage().catch(err => {
30
32
  logger.error(err);
31
33
  });
32
34
  if (!page)
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-6",
4
4
  "description": "优纪插件,yunzaijs 关于 微博推送、B站推送 等功能的拓展插件",
5
5
  "author": "snowtafir",
6
6
  "type": "module",
@@ -30,13 +30,13 @@
30
30
  "md5": "^2.3.0",
31
31
  "moment": "^2.30.1",
32
32
  "node-fetch": "^3.3.2",
33
- "puppeteer": "^22.15.0",
33
+ "puppeteer": "^23.3.0",
34
34
  "qrcode": "^1.5.4",
35
35
  "react": "^18.3.1",
36
36
  "react-dom": "^18.3.1",
37
- "react-puppeteer": "^1.0.3",
37
+ "react-puppeteer": "^1.0.7-rc.0",
38
38
  "redis": "^4.7.0",
39
- "yaml": "^2.5.0",
39
+ "yaml": "^2.5.1",
40
40
  "yarn": "^1.19.1"
41
41
  },
42
42
  "devDependencies": {
@@ -72,11 +72,11 @@
72
72
  "node-fetch": "^3.3.2",
73
73
  "nodemon": "^3.1.4",
74
74
  "prettier": "^3.3.3",
75
- "puppeteer": "^22.15.0",
75
+ "puppeteer": "^23.3.0",
76
76
  "qrcode": "^1.5.4",
77
77
  "react": "^18.3.1",
78
78
  "react-dom": "^18.3.1",
79
- "react-puppeteer": "1.0.3",
79
+ "react-puppeteer": "^1.0.7-rc.0",
80
80
  "redis": "^4.7.0",
81
81
  "rollup": "^4.20.0",
82
82
  "rollup-plugin-auto-external": "^2.0.0",
@@ -87,8 +87,8 @@
87
87
  "ts-node": "^10.9.2",
88
88
  "tsx": "^4.19.0",
89
89
  "typescript": "^5.5.4",
90
- "yunzai": "^1.1.3",
91
- "yunzai-mys": "^1.0.5"
90
+ "yunzai": "^1.1.4",
91
+ "yunzai-mys": "^1.0.6"
92
92
  },
93
93
  "files": [
94
94
  "public",