koishi-plugin-bilibili-notify 3.2.9-alpha.4 → 3.2.9-rc.1
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.d.mts +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +65 -87
- package/lib/index.mjs +65 -87
- package/lib/static/render.js +107 -0
- package/package.json +1 -1
- package/readme.md +2 -0
package/lib/index.d.mts
CHANGED
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -112,6 +112,7 @@ const BAConfigSchema = koishi.Schema.object({
|
|
|
112
112
|
pushImgsInDynamic: koishi.Schema.boolean().default(false).description("是否推送动态中的图片,默认不开启。开启后会单独推送动态中的图片,该功能容易导致QQ风控"),
|
|
113
113
|
live: koishi.Schema.object({}).description("直播推送设置"),
|
|
114
114
|
liveDetectType: koishi.Schema.union([koishi.Schema.const("WS").description("使用WebSocket连接到B站消息服务器进行直播检测,推荐使用"), koishi.Schema.const("API").description("通过轮询API发送请求监测直播状态,此模式理论可无限订阅,但容易产生其他问题,功能没有WS模式全面").experimental()]).role("radio").default("WS").description("直播检测方式,WS为连接到B站消息服务器,API为通过轮询发送请求监测,默认使用WS检测"),
|
|
115
|
+
wordcloud: koishi.Schema.boolean().default(false).description("直播结束后,是否生成本场直播弹幕词云"),
|
|
115
116
|
restartPush: koishi.Schema.boolean().default(true).description("插件重启后,如果订阅的主播正在直播,是否进行一次推送,默认开启"),
|
|
116
117
|
pushTime: koishi.Schema.number().min(0).max(12).step(.5).default(1).description("设定间隔多长时间推送一次直播状态,单位为小时,默认为一小时"),
|
|
117
118
|
customLiveStart: koishi.Schema.string().default("-name开播啦,当前粉丝数:-follower\\n-link").description("自定义开播提示语,-name代表UP昵称,-follower代表当前粉丝数,-link代表直播间链接(如果使用的是QQ官方机器人,请不要使用),\\n为换行。例如-name开播啦,会发送为xxxUP开播啦"),
|
|
@@ -798,56 +799,56 @@ var ComRegister = class {
|
|
|
798
799
|
});
|
|
799
800
|
biliCom.subcommand(".wc").action(async ({ session }) => {
|
|
800
801
|
const words = [
|
|
801
|
-
["
|
|
802
|
-
["
|
|
803
|
-
["
|
|
804
|
-
["
|
|
805
|
-
["
|
|
806
|
-
["
|
|
807
|
-
["
|
|
808
|
-
["
|
|
809
|
-
["
|
|
810
|
-
["
|
|
811
|
-
["
|
|
812
|
-
["
|
|
813
|
-
["
|
|
814
|
-
["
|
|
815
|
-
["
|
|
816
|
-
["
|
|
817
|
-
["
|
|
818
|
-
["
|
|
819
|
-
["
|
|
820
|
-
["
|
|
821
|
-
["
|
|
822
|
-
["
|
|
823
|
-
["
|
|
824
|
-
["
|
|
825
|
-
["
|
|
826
|
-
["
|
|
827
|
-
["
|
|
828
|
-
["
|
|
829
|
-
["
|
|
830
|
-
["
|
|
831
|
-
["
|
|
832
|
-
["
|
|
833
|
-
["
|
|
834
|
-
["
|
|
835
|
-
["
|
|
836
|
-
["
|
|
837
|
-
["
|
|
838
|
-
["
|
|
839
|
-
["
|
|
840
|
-
["
|
|
841
|
-
["
|
|
842
|
-
["
|
|
843
|
-
["
|
|
844
|
-
["
|
|
845
|
-
["
|
|
846
|
-
["
|
|
847
|
-
["
|
|
848
|
-
["
|
|
849
|
-
["
|
|
850
|
-
["
|
|
802
|
+
["弹幕护体", 77],
|
|
803
|
+
["笑死", 30],
|
|
804
|
+
["泪目", 45],
|
|
805
|
+
["加油", 70],
|
|
806
|
+
["???", 80],
|
|
807
|
+
["我可以", 66],
|
|
808
|
+
["无语", 55],
|
|
809
|
+
["梦开始的地方", 1],
|
|
810
|
+
["太真实了", 8],
|
|
811
|
+
["我哭死", 1],
|
|
812
|
+
["人呢", 2],
|
|
813
|
+
["有点意思", 4],
|
|
814
|
+
["妙啊", 4],
|
|
815
|
+
["这波啊", 11],
|
|
816
|
+
["懂了", 6],
|
|
817
|
+
["破防了", 65],
|
|
818
|
+
["蚌埠住了", 92],
|
|
819
|
+
["草", 100],
|
|
820
|
+
["针不戳", 68],
|
|
821
|
+
["yyds", 50],
|
|
822
|
+
["DNA动了", 58],
|
|
823
|
+
["猝不及防", 40],
|
|
824
|
+
["建议加精", 15],
|
|
825
|
+
["保护", 22],
|
|
826
|
+
["害怕", 18],
|
|
827
|
+
["就这?", 99],
|
|
828
|
+
["2333", 20],
|
|
829
|
+
["公开处刑", 35],
|
|
830
|
+
["血压上来了", 45],
|
|
831
|
+
["整不会了", 32],
|
|
832
|
+
["见证历史", 88],
|
|
833
|
+
["下次一定", 65],
|
|
834
|
+
["奥利给", 56],
|
|
835
|
+
["求更新", 18],
|
|
836
|
+
["真实", 20],
|
|
837
|
+
["好活当赏", 25],
|
|
838
|
+
["泪,冲了出来", 68],
|
|
839
|
+
["刻进DNA", 70],
|
|
840
|
+
["我直接好家伙", 55],
|
|
841
|
+
["夺笋啊", 40],
|
|
842
|
+
["歪歪滴艾斯", 1],
|
|
843
|
+
["典中典", 5],
|
|
844
|
+
["麻中麻", 3],
|
|
845
|
+
["绷不住了", 8],
|
|
846
|
+
["逆天", 95],
|
|
847
|
+
["寄", 65],
|
|
848
|
+
["孝", 20],
|
|
849
|
+
["乐", 101],
|
|
850
|
+
["急急急", 3],
|
|
851
|
+
["典", 5]
|
|
851
852
|
];
|
|
852
853
|
await session.send(/* @__PURE__ */ (0, __satorijs_element_jsx_runtime.jsx)("message", { children: koishi.h.image(await this.ctx.gi.generateWordCloudImg(words, "词云测试"), "image/jpg") }));
|
|
853
854
|
});
|
|
@@ -1385,7 +1386,7 @@ var ComRegister = class {
|
|
|
1385
1386
|
masterInfo,
|
|
1386
1387
|
cardStyle
|
|
1387
1388
|
}, uid, liveStartMsg);
|
|
1388
|
-
if (!pushAtTimeTimer) pushAtTimeTimer = this.ctx.setInterval(pushAtTimeFunc, this.config.pushTime * 1e3 * 60 * 60);
|
|
1389
|
+
if (this.config.pushTime !== 0 && !pushAtTimeTimer) pushAtTimeTimer = this.ctx.setInterval(pushAtTimeFunc, this.config.pushTime * 1e3 * 60 * 60);
|
|
1389
1390
|
},
|
|
1390
1391
|
onLiveEnd: async () => {
|
|
1391
1392
|
liveStatus = false;
|
|
@@ -1407,7 +1408,7 @@ var ComRegister = class {
|
|
|
1407
1408
|
}, uid, liveEndMsg);
|
|
1408
1409
|
pushAtTimeTimer();
|
|
1409
1410
|
pushAtTimeTimer = null;
|
|
1410
|
-
await sendDanmakuWordCloud();
|
|
1411
|
+
if (this.config.wordcloud) await sendDanmakuWordCloud();
|
|
1411
1412
|
}
|
|
1412
1413
|
};
|
|
1413
1414
|
await this.ctx.bl.startLiveRoomListener(roomId, handler);
|
|
@@ -1421,7 +1422,7 @@ var ComRegister = class {
|
|
|
1421
1422
|
masterInfo,
|
|
1422
1423
|
cardStyle
|
|
1423
1424
|
}, uid, liveMsg);
|
|
1424
|
-
if (!pushAtTimeTimer) pushAtTimeTimer = this.ctx.setInterval(pushAtTimeFunc, this.config.pushTime * 1e3 * 60 * 60);
|
|
1425
|
+
if (this.config.pushTime !== 0 && !pushAtTimeTimer) pushAtTimeTimer = this.ctx.setInterval(pushAtTimeFunc, this.config.pushTime * 1e3 * 60 * 60);
|
|
1425
1426
|
liveStatus = true;
|
|
1426
1427
|
}
|
|
1427
1428
|
}
|
|
@@ -1827,6 +1828,7 @@ var ComRegister = class {
|
|
|
1827
1828
|
masterAccountGuildId: koishi.Schema.string()
|
|
1828
1829
|
}),
|
|
1829
1830
|
liveDetectType: koishi.Schema.string(),
|
|
1831
|
+
wordcloud: koishi.Schema.boolean(),
|
|
1830
1832
|
restartPush: koishi.Schema.boolean().required(),
|
|
1831
1833
|
pushTime: koishi.Schema.number().required(),
|
|
1832
1834
|
pushImgsInDynamic: koishi.Schema.boolean().required(),
|
|
@@ -84243,6 +84245,7 @@ var require_tar_fs = __commonJS$1({ "node_modules/tar-fs/index.js"(exports) {
|
|
|
84243
84245
|
const now = /* @__PURE__ */ new Date();
|
|
84244
84246
|
const umask = typeof opts.umask === "number" ? ~opts.umask : ~processUmask();
|
|
84245
84247
|
const strict = opts.strict !== false;
|
|
84248
|
+
const validateSymLinks = opts.validateSymlinks !== false;
|
|
84246
84249
|
let map = opts.map || noop;
|
|
84247
84250
|
let dmode = typeof opts.dmode === "number" ? opts.dmode : 0;
|
|
84248
84251
|
let fmode = typeof opts.fmode === "number" ? opts.fmode : 0;
|
|
@@ -84310,7 +84313,7 @@ var require_tar_fs = __commonJS$1({ "node_modules/tar-fs/index.js"(exports) {
|
|
|
84310
84313
|
if (win32$1) return next();
|
|
84311
84314
|
xfs.unlink(name$3, function() {
|
|
84312
84315
|
const dst = path$4.resolve(path$4.dirname(name$3), header.linkname);
|
|
84313
|
-
if (!inCwd(dst)) return next(/* @__PURE__ */ new Error(name$3 + " is not a valid symlink"));
|
|
84316
|
+
if (!inCwd(dst) && validateSymLinks) return next(/* @__PURE__ */ new Error(name$3 + " is not a valid symlink"));
|
|
84314
84317
|
xfs.symlink(header.linkname, name$3, stat);
|
|
84315
84318
|
});
|
|
84316
84319
|
}
|
|
@@ -94391,6 +94394,7 @@ var GenerateImg = class extends koishi.Service {
|
|
|
94391
94394
|
async generateWordCloudImg(words, masterName) {
|
|
94392
94395
|
const fontURL = (0, node_url.pathToFileURL)((0, node_path.resolve)(__dirname, "font/HYZhengYuan-75W.ttf"));
|
|
94393
94396
|
const wordcloudJS = (0, node_url.pathToFileURL)((0, node_path.resolve)(__dirname, "static/wordcloud2.min.js"));
|
|
94397
|
+
const renderFunc = (0, node_url.pathToFileURL)((0, node_path.resolve)(__dirname, "static/render.js"));
|
|
94394
94398
|
const html = `
|
|
94395
94399
|
<!DOCTYPE html>
|
|
94396
94400
|
<html lang="zh-CN">
|
|
@@ -94398,7 +94402,6 @@ var GenerateImg = class extends koishi.Service {
|
|
|
94398
94402
|
<head>
|
|
94399
94403
|
<meta charset="UTF-8">
|
|
94400
94404
|
<title>高清词云展示</title>
|
|
94401
|
-
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@500&display=swap" rel="stylesheet">
|
|
94402
94405
|
<style>
|
|
94403
94406
|
@font-face {
|
|
94404
94407
|
font-family: "Custom Font";
|
|
@@ -94464,6 +94467,7 @@ var GenerateImg = class extends koishi.Service {
|
|
|
94464
94467
|
</div>
|
|
94465
94468
|
|
|
94466
94469
|
<script src="${wordcloudJS}"></script>
|
|
94470
|
+
<script src="${renderFunc}"></script>
|
|
94467
94471
|
<script>
|
|
94468
94472
|
const canvas = document.getElementById('wordCloudCanvas');
|
|
94469
94473
|
const ctx = canvas.getContext('2d');
|
|
@@ -94481,38 +94485,11 @@ var GenerateImg = class extends koishi.Service {
|
|
|
94481
94485
|
|
|
94482
94486
|
const words = ${JSON.stringify(words)}
|
|
94483
94487
|
|
|
94484
|
-
|
|
94485
|
-
|
|
94486
|
-
|
|
94487
|
-
|
|
94488
|
-
|
|
94489
|
-
const maxFontSize = 60;
|
|
94490
|
-
const minFontSize = 14;
|
|
94491
|
-
|
|
94492
|
-
// 用映射函数代替 weightFactor
|
|
94493
|
-
function getWeightFactor(size) {
|
|
94494
|
-
if (maxWeight === minWeight) return maxFontSize; // 防止除0
|
|
94495
|
-
const ratio = (size - minWeight) / (maxWeight - minWeight);
|
|
94496
|
-
return minFontSize + (maxFontSize - minFontSize) * ratio;
|
|
94497
|
-
}
|
|
94498
|
-
|
|
94499
|
-
WordCloud(canvas, {
|
|
94500
|
-
list: words,
|
|
94501
|
-
gridSize: Math.round(8 * (cssWidth / 1024)), // 自动适配大小
|
|
94502
|
-
weightFactor: getWeightFactor,
|
|
94503
|
-
fontFamily: 'Quicksand, sans-serif',
|
|
94504
|
-
color: () => {
|
|
94505
|
-
const colors = ['#007CF0', '#00DFD8', '#7928CA', '#FF0080', '#FF4D4D', '#F9CB28'];
|
|
94506
|
-
return colors[Math.floor(Math.random() * colors.length)];
|
|
94507
|
-
},
|
|
94508
|
-
rotateRatio: 0.5,
|
|
94509
|
-
rotationSteps: 2,
|
|
94510
|
-
backgroundColor: 'transparent',
|
|
94511
|
-
drawOutOfBound: false,
|
|
94512
|
-
origin: [cssWidth / 2, cssHeight / 2], // 居中关键点
|
|
94513
|
-
// 明确告诉 wordcloud2 使用这个宽高(以 CSS 尺寸为准)
|
|
94514
|
-
width: cssWidth,
|
|
94515
|
-
height: cssHeight,
|
|
94488
|
+
renderAutoFitWordCloud(canvas, words, {
|
|
94489
|
+
maxFontSize: 40,
|
|
94490
|
+
minFontSize: 12,
|
|
94491
|
+
densityTarget: 0.3,
|
|
94492
|
+
weightExponent: 0.5
|
|
94516
94493
|
});
|
|
94517
94494
|
</script>
|
|
94518
94495
|
</body>
|
|
@@ -95415,6 +95392,7 @@ var ServerManager = class extends koishi.Service {
|
|
|
95415
95392
|
const cr = this.ctx.plugin(comRegister_default, {
|
|
95416
95393
|
sub: globalConfig.sub,
|
|
95417
95394
|
master: globalConfig.master,
|
|
95395
|
+
wordcloud: globalConfig.wordcloud,
|
|
95418
95396
|
liveDetectType: globalConfig.liveDetectType,
|
|
95419
95397
|
restartPush: globalConfig.restartPush,
|
|
95420
95398
|
pushTime: globalConfig.pushTime,
|
package/lib/index.mjs
CHANGED
|
@@ -114,6 +114,7 @@ const BAConfigSchema = Schema.object({
|
|
|
114
114
|
pushImgsInDynamic: Schema.boolean().default(false).description("是否推送动态中的图片,默认不开启。开启后会单独推送动态中的图片,该功能容易导致QQ风控"),
|
|
115
115
|
live: Schema.object({}).description("直播推送设置"),
|
|
116
116
|
liveDetectType: Schema.union([Schema.const("WS").description("使用WebSocket连接到B站消息服务器进行直播检测,推荐使用"), Schema.const("API").description("通过轮询API发送请求监测直播状态,此模式理论可无限订阅,但容易产生其他问题,功能没有WS模式全面").experimental()]).role("radio").default("WS").description("直播检测方式,WS为连接到B站消息服务器,API为通过轮询发送请求监测,默认使用WS检测"),
|
|
117
|
+
wordcloud: Schema.boolean().default(false).description("直播结束后,是否生成本场直播弹幕词云"),
|
|
117
118
|
restartPush: Schema.boolean().default(true).description("插件重启后,如果订阅的主播正在直播,是否进行一次推送,默认开启"),
|
|
118
119
|
pushTime: Schema.number().min(0).max(12).step(.5).default(1).description("设定间隔多长时间推送一次直播状态,单位为小时,默认为一小时"),
|
|
119
120
|
customLiveStart: Schema.string().default("-name开播啦,当前粉丝数:-follower\\n-link").description("自定义开播提示语,-name代表UP昵称,-follower代表当前粉丝数,-link代表直播间链接(如果使用的是QQ官方机器人,请不要使用),\\n为换行。例如-name开播啦,会发送为xxxUP开播啦"),
|
|
@@ -800,56 +801,56 @@ var ComRegister = class {
|
|
|
800
801
|
});
|
|
801
802
|
biliCom.subcommand(".wc").action(async ({ session }) => {
|
|
802
803
|
const words = [
|
|
803
|
-
["
|
|
804
|
-
["
|
|
805
|
-
["
|
|
806
|
-
["
|
|
807
|
-
["
|
|
808
|
-
["
|
|
809
|
-
["
|
|
810
|
-
["
|
|
811
|
-
["
|
|
812
|
-
["
|
|
813
|
-
["
|
|
814
|
-
["
|
|
815
|
-
["
|
|
816
|
-
["
|
|
817
|
-
["
|
|
818
|
-
["
|
|
819
|
-
["
|
|
820
|
-
["
|
|
821
|
-
["
|
|
822
|
-
["
|
|
823
|
-
["
|
|
824
|
-
["
|
|
825
|
-
["
|
|
826
|
-
["
|
|
827
|
-
["
|
|
828
|
-
["
|
|
829
|
-
["
|
|
830
|
-
["
|
|
831
|
-
["
|
|
832
|
-
["
|
|
833
|
-
["
|
|
834
|
-
["
|
|
835
|
-
["
|
|
836
|
-
["
|
|
837
|
-
["
|
|
838
|
-
["
|
|
839
|
-
["
|
|
840
|
-
["
|
|
841
|
-
["
|
|
842
|
-
["
|
|
843
|
-
["
|
|
844
|
-
["
|
|
845
|
-
["
|
|
846
|
-
["
|
|
847
|
-
["
|
|
848
|
-
["
|
|
849
|
-
["
|
|
850
|
-
["
|
|
851
|
-
["
|
|
852
|
-
["
|
|
804
|
+
["弹幕护体", 77],
|
|
805
|
+
["笑死", 30],
|
|
806
|
+
["泪目", 45],
|
|
807
|
+
["加油", 70],
|
|
808
|
+
["???", 80],
|
|
809
|
+
["我可以", 66],
|
|
810
|
+
["无语", 55],
|
|
811
|
+
["梦开始的地方", 1],
|
|
812
|
+
["太真实了", 8],
|
|
813
|
+
["我哭死", 1],
|
|
814
|
+
["人呢", 2],
|
|
815
|
+
["有点意思", 4],
|
|
816
|
+
["妙啊", 4],
|
|
817
|
+
["这波啊", 11],
|
|
818
|
+
["懂了", 6],
|
|
819
|
+
["破防了", 65],
|
|
820
|
+
["蚌埠住了", 92],
|
|
821
|
+
["草", 100],
|
|
822
|
+
["针不戳", 68],
|
|
823
|
+
["yyds", 50],
|
|
824
|
+
["DNA动了", 58],
|
|
825
|
+
["猝不及防", 40],
|
|
826
|
+
["建议加精", 15],
|
|
827
|
+
["保护", 22],
|
|
828
|
+
["害怕", 18],
|
|
829
|
+
["就这?", 99],
|
|
830
|
+
["2333", 20],
|
|
831
|
+
["公开处刑", 35],
|
|
832
|
+
["血压上来了", 45],
|
|
833
|
+
["整不会了", 32],
|
|
834
|
+
["见证历史", 88],
|
|
835
|
+
["下次一定", 65],
|
|
836
|
+
["奥利给", 56],
|
|
837
|
+
["求更新", 18],
|
|
838
|
+
["真实", 20],
|
|
839
|
+
["好活当赏", 25],
|
|
840
|
+
["泪,冲了出来", 68],
|
|
841
|
+
["刻进DNA", 70],
|
|
842
|
+
["我直接好家伙", 55],
|
|
843
|
+
["夺笋啊", 40],
|
|
844
|
+
["歪歪滴艾斯", 1],
|
|
845
|
+
["典中典", 5],
|
|
846
|
+
["麻中麻", 3],
|
|
847
|
+
["绷不住了", 8],
|
|
848
|
+
["逆天", 95],
|
|
849
|
+
["寄", 65],
|
|
850
|
+
["孝", 20],
|
|
851
|
+
["乐", 101],
|
|
852
|
+
["急急急", 3],
|
|
853
|
+
["典", 5]
|
|
853
854
|
];
|
|
854
855
|
await session.send(/* @__PURE__ */ jsx("message", { children: h.image(await this.ctx.gi.generateWordCloudImg(words, "词云测试"), "image/jpg") }));
|
|
855
856
|
});
|
|
@@ -1387,7 +1388,7 @@ var ComRegister = class {
|
|
|
1387
1388
|
masterInfo,
|
|
1388
1389
|
cardStyle
|
|
1389
1390
|
}, uid, liveStartMsg);
|
|
1390
|
-
if (!pushAtTimeTimer) pushAtTimeTimer = this.ctx.setInterval(pushAtTimeFunc, this.config.pushTime * 1e3 * 60 * 60);
|
|
1391
|
+
if (this.config.pushTime !== 0 && !pushAtTimeTimer) pushAtTimeTimer = this.ctx.setInterval(pushAtTimeFunc, this.config.pushTime * 1e3 * 60 * 60);
|
|
1391
1392
|
},
|
|
1392
1393
|
onLiveEnd: async () => {
|
|
1393
1394
|
liveStatus = false;
|
|
@@ -1409,7 +1410,7 @@ var ComRegister = class {
|
|
|
1409
1410
|
}, uid, liveEndMsg);
|
|
1410
1411
|
pushAtTimeTimer();
|
|
1411
1412
|
pushAtTimeTimer = null;
|
|
1412
|
-
await sendDanmakuWordCloud();
|
|
1413
|
+
if (this.config.wordcloud) await sendDanmakuWordCloud();
|
|
1413
1414
|
}
|
|
1414
1415
|
};
|
|
1415
1416
|
await this.ctx.bl.startLiveRoomListener(roomId, handler);
|
|
@@ -1423,7 +1424,7 @@ var ComRegister = class {
|
|
|
1423
1424
|
masterInfo,
|
|
1424
1425
|
cardStyle
|
|
1425
1426
|
}, uid, liveMsg);
|
|
1426
|
-
if (!pushAtTimeTimer) pushAtTimeTimer = this.ctx.setInterval(pushAtTimeFunc, this.config.pushTime * 1e3 * 60 * 60);
|
|
1427
|
+
if (this.config.pushTime !== 0 && !pushAtTimeTimer) pushAtTimeTimer = this.ctx.setInterval(pushAtTimeFunc, this.config.pushTime * 1e3 * 60 * 60);
|
|
1427
1428
|
liveStatus = true;
|
|
1428
1429
|
}
|
|
1429
1430
|
}
|
|
@@ -1829,6 +1830,7 @@ var ComRegister = class {
|
|
|
1829
1830
|
masterAccountGuildId: Schema.string()
|
|
1830
1831
|
}),
|
|
1831
1832
|
liveDetectType: Schema.string(),
|
|
1833
|
+
wordcloud: Schema.boolean(),
|
|
1832
1834
|
restartPush: Schema.boolean().required(),
|
|
1833
1835
|
pushTime: Schema.number().required(),
|
|
1834
1836
|
pushImgsInDynamic: Schema.boolean().required(),
|
|
@@ -84245,6 +84247,7 @@ var require_tar_fs = __commonJS$1({ "node_modules/tar-fs/index.js"(exports) {
|
|
|
84245
84247
|
const now = /* @__PURE__ */ new Date();
|
|
84246
84248
|
const umask = typeof opts.umask === "number" ? ~opts.umask : ~processUmask();
|
|
84247
84249
|
const strict = opts.strict !== false;
|
|
84250
|
+
const validateSymLinks = opts.validateSymlinks !== false;
|
|
84248
84251
|
let map = opts.map || noop;
|
|
84249
84252
|
let dmode = typeof opts.dmode === "number" ? opts.dmode : 0;
|
|
84250
84253
|
let fmode = typeof opts.fmode === "number" ? opts.fmode : 0;
|
|
@@ -84312,7 +84315,7 @@ var require_tar_fs = __commonJS$1({ "node_modules/tar-fs/index.js"(exports) {
|
|
|
84312
84315
|
if (win32$1) return next();
|
|
84313
84316
|
xfs.unlink(name$3, function() {
|
|
84314
84317
|
const dst = path$3.resolve(path$3.dirname(name$3), header.linkname);
|
|
84315
|
-
if (!inCwd(dst)) return next(/* @__PURE__ */ new Error(name$3 + " is not a valid symlink"));
|
|
84318
|
+
if (!inCwd(dst) && validateSymLinks) return next(/* @__PURE__ */ new Error(name$3 + " is not a valid symlink"));
|
|
84316
84319
|
xfs.symlink(header.linkname, name$3, stat);
|
|
84317
84320
|
});
|
|
84318
84321
|
}
|
|
@@ -94393,6 +94396,7 @@ var GenerateImg = class extends Service {
|
|
|
94393
94396
|
async generateWordCloudImg(words, masterName) {
|
|
94394
94397
|
const fontURL = pathToFileURL(resolve$1(__dirname, "font/HYZhengYuan-75W.ttf"));
|
|
94395
94398
|
const wordcloudJS = pathToFileURL(resolve$1(__dirname, "static/wordcloud2.min.js"));
|
|
94399
|
+
const renderFunc = pathToFileURL(resolve$1(__dirname, "static/render.js"));
|
|
94396
94400
|
const html = `
|
|
94397
94401
|
<!DOCTYPE html>
|
|
94398
94402
|
<html lang="zh-CN">
|
|
@@ -94400,7 +94404,6 @@ var GenerateImg = class extends Service {
|
|
|
94400
94404
|
<head>
|
|
94401
94405
|
<meta charset="UTF-8">
|
|
94402
94406
|
<title>高清词云展示</title>
|
|
94403
|
-
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@500&display=swap" rel="stylesheet">
|
|
94404
94407
|
<style>
|
|
94405
94408
|
@font-face {
|
|
94406
94409
|
font-family: "Custom Font";
|
|
@@ -94466,6 +94469,7 @@ var GenerateImg = class extends Service {
|
|
|
94466
94469
|
</div>
|
|
94467
94470
|
|
|
94468
94471
|
<script src="${wordcloudJS}"></script>
|
|
94472
|
+
<script src="${renderFunc}"></script>
|
|
94469
94473
|
<script>
|
|
94470
94474
|
const canvas = document.getElementById('wordCloudCanvas');
|
|
94471
94475
|
const ctx = canvas.getContext('2d');
|
|
@@ -94483,38 +94487,11 @@ var GenerateImg = class extends Service {
|
|
|
94483
94487
|
|
|
94484
94488
|
const words = ${JSON.stringify(words)}
|
|
94485
94489
|
|
|
94486
|
-
|
|
94487
|
-
|
|
94488
|
-
|
|
94489
|
-
|
|
94490
|
-
|
|
94491
|
-
const maxFontSize = 60;
|
|
94492
|
-
const minFontSize = 14;
|
|
94493
|
-
|
|
94494
|
-
// 用映射函数代替 weightFactor
|
|
94495
|
-
function getWeightFactor(size) {
|
|
94496
|
-
if (maxWeight === minWeight) return maxFontSize; // 防止除0
|
|
94497
|
-
const ratio = (size - minWeight) / (maxWeight - minWeight);
|
|
94498
|
-
return minFontSize + (maxFontSize - minFontSize) * ratio;
|
|
94499
|
-
}
|
|
94500
|
-
|
|
94501
|
-
WordCloud(canvas, {
|
|
94502
|
-
list: words,
|
|
94503
|
-
gridSize: Math.round(8 * (cssWidth / 1024)), // 自动适配大小
|
|
94504
|
-
weightFactor: getWeightFactor,
|
|
94505
|
-
fontFamily: 'Quicksand, sans-serif',
|
|
94506
|
-
color: () => {
|
|
94507
|
-
const colors = ['#007CF0', '#00DFD8', '#7928CA', '#FF0080', '#FF4D4D', '#F9CB28'];
|
|
94508
|
-
return colors[Math.floor(Math.random() * colors.length)];
|
|
94509
|
-
},
|
|
94510
|
-
rotateRatio: 0.5,
|
|
94511
|
-
rotationSteps: 2,
|
|
94512
|
-
backgroundColor: 'transparent',
|
|
94513
|
-
drawOutOfBound: false,
|
|
94514
|
-
origin: [cssWidth / 2, cssHeight / 2], // 居中关键点
|
|
94515
|
-
// 明确告诉 wordcloud2 使用这个宽高(以 CSS 尺寸为准)
|
|
94516
|
-
width: cssWidth,
|
|
94517
|
-
height: cssHeight,
|
|
94490
|
+
renderAutoFitWordCloud(canvas, words, {
|
|
94491
|
+
maxFontSize: 40,
|
|
94492
|
+
minFontSize: 12,
|
|
94493
|
+
densityTarget: 0.3,
|
|
94494
|
+
weightExponent: 0.5
|
|
94518
94495
|
});
|
|
94519
94496
|
</script>
|
|
94520
94497
|
</body>
|
|
@@ -95417,6 +95394,7 @@ var ServerManager = class extends Service {
|
|
|
95417
95394
|
const cr = this.ctx.plugin(comRegister_default, {
|
|
95418
95395
|
sub: globalConfig.sub,
|
|
95419
95396
|
master: globalConfig.master,
|
|
95397
|
+
wordcloud: globalConfig.wordcloud,
|
|
95420
95398
|
liveDetectType: globalConfig.liveDetectType,
|
|
95421
95399
|
restartPush: globalConfig.restartPush,
|
|
95422
95400
|
pushTime: globalConfig.pushTime,
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 自动适配的词云渲染函数,直到填满画布
|
|
3
|
+
* @param {HTMLCanvasElement} canvas - canvas 元素
|
|
4
|
+
* @param {Array<[string, number]>} words - 词数组 [['哈哈', 20], ['666', 10]]
|
|
5
|
+
* @param {Object} options - 选项
|
|
6
|
+
*/
|
|
7
|
+
function renderAutoFitWordCloud(canvas, words, options = {}) {
|
|
8
|
+
const ctx = canvas.getContext("2d");
|
|
9
|
+
const style = getComputedStyle(canvas);
|
|
10
|
+
const cssWidth = parseInt(style.width);
|
|
11
|
+
const cssHeight = parseInt(style.height);
|
|
12
|
+
const ratio = window.devicePixelRatio || 1;
|
|
13
|
+
|
|
14
|
+
// 设置高清分辨率
|
|
15
|
+
canvas.width = cssWidth * ratio;
|
|
16
|
+
canvas.height = cssHeight * ratio;
|
|
17
|
+
ctx.scale(ratio, ratio);
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
fontFamily = 'sans-serif',
|
|
21
|
+
maxFontSize = 72,
|
|
22
|
+
minFontSize = 12,
|
|
23
|
+
densityTarget = 0.25,
|
|
24
|
+
weightExponent = 0.5,
|
|
25
|
+
rotationSteps = 2,
|
|
26
|
+
rotateRatio = 0.4,
|
|
27
|
+
color = () => ['#007CF0', '#00DFD8', '#7928CA', '#FF0080', '#FF4D4D', '#F9CB28'][Math.floor(Math.random() * 6)],
|
|
28
|
+
backgroundColor = 'transparent'
|
|
29
|
+
} = options;
|
|
30
|
+
|
|
31
|
+
const weightFactor = createDynamicWeightFactor(words, cssWidth, cssHeight, {
|
|
32
|
+
maxFontSize,
|
|
33
|
+
minFontSize,
|
|
34
|
+
densityTarget,
|
|
35
|
+
weightExponent
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
WordCloud(canvas, {
|
|
39
|
+
list: words,
|
|
40
|
+
gridSize: Math.max(2, Math.floor(cssWidth / 100)), // 自动调整 gridSize
|
|
41
|
+
weightFactor,
|
|
42
|
+
fontFamily,
|
|
43
|
+
color,
|
|
44
|
+
rotateRatio,
|
|
45
|
+
rotationSteps,
|
|
46
|
+
backgroundColor,
|
|
47
|
+
drawOutOfBound: false,
|
|
48
|
+
origin: [cssWidth / 2, cssHeight / 2],
|
|
49
|
+
width: cssWidth,
|
|
50
|
+
height: cssHeight,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* function createDynamicWeightFactor(words, width, height, {
|
|
55
|
+
maxFontSize = 72,
|
|
56
|
+
minFontSize = 12,
|
|
57
|
+
densityTarget = 0.25
|
|
58
|
+
} = {}) {
|
|
59
|
+
const weights = words.map(w => w[1]);
|
|
60
|
+
const maxWeight = Math.max(...weights);
|
|
61
|
+
const minWeight = Math.min(...weights);
|
|
62
|
+
const range = maxWeight - minWeight || 1;
|
|
63
|
+
|
|
64
|
+
// 移除基于词数的自动缩放
|
|
65
|
+
const realMax = maxFontSize;
|
|
66
|
+
const realMin = minFontSize;
|
|
67
|
+
|
|
68
|
+
// 改为基于画布面积的密度控制
|
|
69
|
+
const areaPerWord = (width * height * densityTarget) / words.length;
|
|
70
|
+
const sizeScale = Math.min(1, Math.sqrt(areaPerWord / 500)); // 500是可调基准值
|
|
71
|
+
|
|
72
|
+
return function weightFactor(weight) {
|
|
73
|
+
const norm = (weight - minWeight) / range;
|
|
74
|
+
// 应用三次方曲线让大小差异更明显
|
|
75
|
+
const sizeRatio = Math.pow(norm, 0.33);
|
|
76
|
+
return realMin + (realMax - realMin) * sizeRatio * sizeScale;
|
|
77
|
+
};
|
|
78
|
+
} */
|
|
79
|
+
|
|
80
|
+
function createDynamicWeightFactor(words, width, height, {
|
|
81
|
+
maxFontSize = 72,
|
|
82
|
+
minFontSize = 12,
|
|
83
|
+
densityTarget = 0.25,
|
|
84
|
+
weightExponent = 0.5 // 新增权重指数参数
|
|
85
|
+
} = {}) {
|
|
86
|
+
const weights = words.map(w => w[1]);
|
|
87
|
+
const maxWeight = Math.max(...weights);
|
|
88
|
+
const minWeight = Math.min(...weights);
|
|
89
|
+
const range = Math.max(1, maxWeight - minWeight); // 确保不为0
|
|
90
|
+
|
|
91
|
+
// 计算权重转换曲线
|
|
92
|
+
const weightCurve = (weight) => {
|
|
93
|
+
const normalized = (weight - minWeight) / range;
|
|
94
|
+
// 使用指数曲线放大差异
|
|
95
|
+
return Math.pow(normalized, weightExponent);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// 计算动态缩放比例(基于画布面积和词数)
|
|
99
|
+
const areaScale = Math.sqrt((width * height * densityTarget) / words.length) / 20;
|
|
100
|
+
const sizeScale = Math.min(1, Math.max(0.3, areaScale)); // 限制在0.3-1之间
|
|
101
|
+
|
|
102
|
+
return function (weight) {
|
|
103
|
+
const curveValue = weightCurve(weight);
|
|
104
|
+
// 应用非线性放大
|
|
105
|
+
return minFontSize + (maxFontSize - minFontSize) * curveValue * sizeScale;
|
|
106
|
+
};
|
|
107
|
+
}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -305,6 +305,8 @@ uid为必填参数,为要推送的UP主的UID,index为可选参数,为要
|
|
|
305
305
|
> - ver 3.2.9-alpha.2 修复:`AxiosError: Request failed with status code 404 xxx at async BiliAPI.checkIfTokenNeedRefresh`、潜在cookie相关bug、弹幕词云bug `Error: 生成图片失败!错误: TimeoutError: Navigation timeout of 30000 ms exceeded`
|
|
306
306
|
> - ver 3.2.9-alpha.3 修复:词云生成空白
|
|
307
307
|
> - ver 3.2.9-alpha.4 修复:弹幕词云bug `Error: 生成图片失败!错误: TimeoutError: Navigation timeout of 30000 ms exceeded`
|
|
308
|
+
> - ver 3.2.9-rc.0 优化:弹幕词云生成效果、选项 `pushTime` 设置为0时可关闭该功能; 新增:选项 `wordcloud` 可选择在直播结束后是否生成弹幕词云
|
|
309
|
+
> - ver 3.2.9-rc.1 优化:弹幕词云生成效果;
|
|
308
310
|
|
|
309
311
|
## 交流群
|
|
310
312
|
|