koishi-plugin-rocom 1.0.9 → 1.0.11
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/activities-service.d.ts +72 -0
- package/lib/activities-service.js +293 -0
- package/lib/client.d.ts +34 -1
- package/lib/client.js +98 -8
- package/lib/commands/account.js +44 -0
- package/lib/commands/community.d.ts +12 -0
- package/lib/commands/community.js +323 -0
- package/lib/commands/egg.js +12 -4
- package/lib/commands/merchant.js +21 -5
- package/lib/commands/query.js +0 -17
- package/lib/commands/tools.d.ts +2 -0
- package/lib/commands/tools.js +164 -0
- package/lib/egg-service.d.ts +12 -0
- package/lib/egg-service.js +76 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +5300 -144
- package/lib/render-templates/activities/index.html +77 -0
- package/lib/render-templates/activities/style.css +434 -0
- package/lib/render.js +14 -5
- package/lib/send-image.d.ts +1 -0
- package/lib/send-image.js +13 -1
- package/lib/subscription-send.js +2 -1
- package/lib/types.d.ts +2 -0
- package/package.json +1 -1
- package/readme.md +4 -9
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=1600, initial-scale=1">
|
|
6
|
+
<title>{{title}}</title>
|
|
7
|
+
<link rel="stylesheet" href="{{_res_path}}render-templates/activities/style.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="activity-calendar-page">
|
|
11
|
+
<div class="calendar-header">
|
|
12
|
+
<div class="super-title">ROCOM WORLD</div>
|
|
13
|
+
<div class="title-wrap">
|
|
14
|
+
<div class="bg-word">CALENDAR</div>
|
|
15
|
+
<div class="main-title">
|
|
16
|
+
<div class="title-mark"></div>
|
|
17
|
+
<h1>{{title}}</h1>
|
|
18
|
+
<div class="dot-line"><span></span><span></span><span></span><span></span></div>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="subtitle">{{subtitle}}</div>
|
|
21
|
+
</div>
|
|
22
|
+
<img class="header-logo" src="{{_res_path}}img/logo.cVSpb3sL.png" alt="">
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div class="axis-area">
|
|
26
|
+
<div class="axis-line-horizontal"></div>
|
|
27
|
+
{{each axis_dates d}}
|
|
28
|
+
<div class="axis-marker" style="left: {{d.left_pct}}%;">
|
|
29
|
+
<div class="axis-flag">{{d.label}}<i></i></div>
|
|
30
|
+
<div class="axis-line-vertical"></div>
|
|
31
|
+
</div>
|
|
32
|
+
{{/each}}
|
|
33
|
+
{{if now_line}}
|
|
34
|
+
<div class="axis-marker now-marker" style="left: {{now_line.left_pct}}%;">
|
|
35
|
+
<div class="axis-flag now-flag">{{now_line.label}}<i></i></div>
|
|
36
|
+
<div class="axis-line-vertical now-vertical"></div>
|
|
37
|
+
</div>
|
|
38
|
+
{{/if}}
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div class="gantt-area">
|
|
42
|
+
{{if empty}}
|
|
43
|
+
<div class="empty-state">暂无进行中的活动。</div>
|
|
44
|
+
{{else}}
|
|
45
|
+
{{each lanes lane}}
|
|
46
|
+
<div class="gantt-row">
|
|
47
|
+
{{each lane act}}
|
|
48
|
+
<div class="gantt-bar-wrapper" style="left: {{act.left_pct}}%; width: {{act.width_pct}}%;">
|
|
49
|
+
<div class="gantt-bar theme-{{act.theme}}">
|
|
50
|
+
{{if act.cover}}
|
|
51
|
+
<div class="bar-cover-wrap"><img class="bar-cover" src="{{act.cover}}" alt=""></div>
|
|
52
|
+
{{/if}}
|
|
53
|
+
<div class="bar-tag {{act.statusClass}}">{{act.statusText}}</div>
|
|
54
|
+
<div class="bar-content">
|
|
55
|
+
<div class="bar-bracket">[ {{act.desc}} ]</div>
|
|
56
|
+
<div class="bar-name">{{act.name}}</div>
|
|
57
|
+
<div class="bar-time">{{act.time_label}}</div>
|
|
58
|
+
<div class="bar-rewards">{{act.rewards_text}}</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
{{/each}}
|
|
63
|
+
</div>
|
|
64
|
+
{{/each}}
|
|
65
|
+
{{/if}}
|
|
66
|
+
{{if now_line}}
|
|
67
|
+
<div class="gantt-now-line" style="left: {{now_line.left_pct}}%;"></div>
|
|
68
|
+
{{/if}}
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<div class="footer">
|
|
72
|
+
<span>{{commandHint}}</span>
|
|
73
|
+
<span>{{copyright}}</span>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</body>
|
|
77
|
+
</html>
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
@font-face {
|
|
2
|
+
font-family: "RocomWenHei";
|
|
3
|
+
src: url("../../ttf/HYWenHei-85W-1.ttf") format("truetype");
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
* {
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
body {
|
|
11
|
+
margin: 0;
|
|
12
|
+
color: #21190f;
|
|
13
|
+
background: #f7efe0;
|
|
14
|
+
font-family: "RocomWenHei", "Microsoft YaHei", sans-serif;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.activity-calendar-page {
|
|
18
|
+
position: relative;
|
|
19
|
+
width: 100%;
|
|
20
|
+
min-height: 900px;
|
|
21
|
+
padding: 34px 38px 30px;
|
|
22
|
+
background:
|
|
23
|
+
linear-gradient(180deg, rgba(255, 247, 226, .90), rgba(255, 231, 188, .86)),
|
|
24
|
+
url("../../img/bg.C8CUoi7I.jpg") center top / cover;
|
|
25
|
+
overflow: hidden;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.activity-calendar-page::before {
|
|
29
|
+
content: "";
|
|
30
|
+
position: absolute;
|
|
31
|
+
inset: 0;
|
|
32
|
+
background: radial-gradient(circle at 12% 0, rgba(255, 255, 255, .58), transparent 30%),
|
|
33
|
+
linear-gradient(90deg, rgba(94, 54, 18, .10), transparent 40%, rgba(94, 54, 18, .08));
|
|
34
|
+
pointer-events: none;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.calendar-header,
|
|
38
|
+
.axis-area,
|
|
39
|
+
.gantt-area,
|
|
40
|
+
.footer {
|
|
41
|
+
position: relative;
|
|
42
|
+
z-index: 1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.calendar-header {
|
|
46
|
+
min-height: 178px;
|
|
47
|
+
padding: 16px 28px;
|
|
48
|
+
border-radius: 28px;
|
|
49
|
+
background: linear-gradient(135deg, rgba(255, 246, 207, .95), rgba(255, 208, 107, .90));
|
|
50
|
+
border: 4px solid rgba(126, 75, 26, .20);
|
|
51
|
+
box-shadow: 0 18px 38px rgba(72, 43, 17, .18);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.super-title {
|
|
55
|
+
font-size: 18px;
|
|
56
|
+
color: rgba(102, 63, 26, .60);
|
|
57
|
+
letter-spacing: 3px;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.title-wrap {
|
|
61
|
+
position: relative;
|
|
62
|
+
margin-top: 8px;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.bg-word {
|
|
66
|
+
position: absolute;
|
|
67
|
+
top: -28px;
|
|
68
|
+
left: -8px;
|
|
69
|
+
color: rgba(111, 77, 42, .10);
|
|
70
|
+
font-size: 112px;
|
|
71
|
+
letter-spacing: 16px;
|
|
72
|
+
line-height: 1;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.main-title {
|
|
76
|
+
position: relative;
|
|
77
|
+
display: flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
gap: 18px;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.title-mark {
|
|
83
|
+
width: 42px;
|
|
84
|
+
height: 42px;
|
|
85
|
+
background: #ffca42;
|
|
86
|
+
border: 5px solid #5e3a18;
|
|
87
|
+
box-shadow: 4px 4px 0 rgba(75, 42, 16, .22);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
h1 {
|
|
91
|
+
margin: 0;
|
|
92
|
+
color: #4f2d0f;
|
|
93
|
+
font-size: 54px;
|
|
94
|
+
letter-spacing: 4px;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.subtitle {
|
|
98
|
+
position: relative;
|
|
99
|
+
margin-top: 12px;
|
|
100
|
+
color: rgba(80, 48, 20, .72);
|
|
101
|
+
font-size: 24px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.dot-line {
|
|
105
|
+
display: flex;
|
|
106
|
+
gap: 8px;
|
|
107
|
+
margin-left: 18px;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.dot-line span {
|
|
111
|
+
width: 10px;
|
|
112
|
+
height: 10px;
|
|
113
|
+
border-radius: 50%;
|
|
114
|
+
background: rgba(94, 54, 18, .32);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.header-logo {
|
|
118
|
+
position: absolute;
|
|
119
|
+
right: 34px;
|
|
120
|
+
top: 28px;
|
|
121
|
+
width: 300px;
|
|
122
|
+
max-height: 120px;
|
|
123
|
+
object-fit: contain;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.axis-area {
|
|
127
|
+
z-index: 4;
|
|
128
|
+
height: 72px;
|
|
129
|
+
margin-top: 30px;
|
|
130
|
+
pointer-events: none;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.axis-line-horizontal {
|
|
134
|
+
position: absolute;
|
|
135
|
+
left: 0;
|
|
136
|
+
right: 0;
|
|
137
|
+
top: 36px;
|
|
138
|
+
height: 3px;
|
|
139
|
+
background: rgba(83, 53, 28, .18);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.axis-marker {
|
|
143
|
+
position: absolute;
|
|
144
|
+
top: 0;
|
|
145
|
+
width: 80px;
|
|
146
|
+
transform: translateX(-40px);
|
|
147
|
+
text-align: center;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.axis-flag {
|
|
151
|
+
position: relative;
|
|
152
|
+
display: inline-block;
|
|
153
|
+
padding: 5px 10px;
|
|
154
|
+
background: #ffca42;
|
|
155
|
+
color: #3f260f;
|
|
156
|
+
font-size: 18px;
|
|
157
|
+
box-shadow: 3px 3px 0 rgba(68, 39, 14, .18);
|
|
158
|
+
white-space: nowrap;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.axis-flag i {
|
|
162
|
+
position: absolute;
|
|
163
|
+
left: 50%;
|
|
164
|
+
bottom: -8px;
|
|
165
|
+
width: 0;
|
|
166
|
+
height: 0;
|
|
167
|
+
transform: translateX(-50%);
|
|
168
|
+
border-left: 8px solid transparent;
|
|
169
|
+
border-right: 8px solid transparent;
|
|
170
|
+
border-top: 8px solid #ffca42;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.axis-line-vertical {
|
|
174
|
+
position: absolute;
|
|
175
|
+
left: 50%;
|
|
176
|
+
top: 42px;
|
|
177
|
+
width: 2px;
|
|
178
|
+
height: 900px;
|
|
179
|
+
background: rgba(83, 53, 28, .08);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.now-marker {
|
|
183
|
+
z-index: 10;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.now-flag {
|
|
187
|
+
color: #fff7dc;
|
|
188
|
+
background: #cc5530;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.now-flag i {
|
|
192
|
+
border-top-color: #cc5530;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.now-vertical {
|
|
196
|
+
width: 3px;
|
|
197
|
+
height: 38px;
|
|
198
|
+
background: transparent;
|
|
199
|
+
border-left: 3px dashed rgba(204, 85, 48, .78);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.gantt-area {
|
|
203
|
+
z-index: 2;
|
|
204
|
+
position: relative;
|
|
205
|
+
margin-top: 8px;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.gantt-now-line {
|
|
209
|
+
position: absolute;
|
|
210
|
+
top: -38px;
|
|
211
|
+
bottom: 0;
|
|
212
|
+
width: 0;
|
|
213
|
+
transform: translateX(-1.5px);
|
|
214
|
+
border-left: 3px dashed rgba(204, 85, 48, .82);
|
|
215
|
+
z-index: 30;
|
|
216
|
+
pointer-events: none;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.gantt-row {
|
|
220
|
+
position: relative;
|
|
221
|
+
height: 112px;
|
|
222
|
+
margin-bottom: 14px;
|
|
223
|
+
border-bottom: 2px dashed rgba(83, 53, 28, .14);
|
|
224
|
+
background: repeating-linear-gradient(-45deg, rgba(255,255,255,.30), rgba(255,255,255,.30) 12px, rgba(255,231,188,.28) 12px, rgba(255,231,188,.28) 24px);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.gantt-bar-wrapper {
|
|
228
|
+
position: absolute;
|
|
229
|
+
height: 100%;
|
|
230
|
+
min-width: 270px;
|
|
231
|
+
container-type: inline-size;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.gantt-bar {
|
|
235
|
+
position: relative;
|
|
236
|
+
height: 100%;
|
|
237
|
+
overflow: hidden;
|
|
238
|
+
display: flex;
|
|
239
|
+
align-items: center;
|
|
240
|
+
justify-content: flex-end;
|
|
241
|
+
padding: 10px 18px 10px 104px;
|
|
242
|
+
border-left: 8px solid rgba(255, 218, 92, .90);
|
|
243
|
+
box-shadow: 0 8px 18px rgba(69, 38, 12, .25);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.theme-gold {
|
|
247
|
+
background: linear-gradient(90deg, rgba(118, 77, 37, .92), rgba(211, 143, 46, .95));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.theme-green {
|
|
251
|
+
background: linear-gradient(90deg, rgba(69, 93, 50, .92), rgba(135, 166, 65, .95));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.theme-brown {
|
|
255
|
+
background: linear-gradient(90deg, rgba(80, 63, 47, .94), rgba(151, 102, 58, .95));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.bar-cover-wrap {
|
|
259
|
+
position: absolute;
|
|
260
|
+
inset: 0 auto 0 0;
|
|
261
|
+
width: 58%;
|
|
262
|
+
max-width: 620px;
|
|
263
|
+
-webkit-mask-image: linear-gradient(to right, #000 55%, transparent 100%);
|
|
264
|
+
mask-image: linear-gradient(to right, #000 55%, transparent 100%);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.bar-cover {
|
|
268
|
+
width: 100%;
|
|
269
|
+
height: 100%;
|
|
270
|
+
object-fit: cover;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.bar-tag {
|
|
274
|
+
position: absolute;
|
|
275
|
+
left: 16px;
|
|
276
|
+
top: 50%;
|
|
277
|
+
transform: translateY(-50%);
|
|
278
|
+
max-width: 76px;
|
|
279
|
+
padding: 5px 10px;
|
|
280
|
+
border-radius: 999px;
|
|
281
|
+
color: #fff8dc;
|
|
282
|
+
background: rgba(65, 39, 17, .70);
|
|
283
|
+
overflow: hidden;
|
|
284
|
+
text-overflow: ellipsis;
|
|
285
|
+
white-space: nowrap;
|
|
286
|
+
font-size: 14px;
|
|
287
|
+
z-index: 2;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.bar-tag.active {
|
|
291
|
+
background: #d46926;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.bar-tag.upcoming {
|
|
295
|
+
background: #57894a;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.bar-tag.ended {
|
|
299
|
+
background: #7c746b;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.bar-tag.permanent {
|
|
303
|
+
background: #a35f24;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.bar-content {
|
|
307
|
+
position: relative;
|
|
308
|
+
z-index: 2;
|
|
309
|
+
width: 100%;
|
|
310
|
+
min-width: 0;
|
|
311
|
+
max-width: 100%;
|
|
312
|
+
text-align: right;
|
|
313
|
+
color: #fff8dc;
|
|
314
|
+
text-shadow: 0 2px 4px rgba(47, 25, 8, .55);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.bar-bracket {
|
|
318
|
+
overflow: hidden;
|
|
319
|
+
text-overflow: ellipsis;
|
|
320
|
+
white-space: nowrap;
|
|
321
|
+
font-size: 11px;
|
|
322
|
+
letter-spacing: 1px;
|
|
323
|
+
opacity: .90;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.bar-name {
|
|
327
|
+
margin-top: 3px;
|
|
328
|
+
overflow: hidden;
|
|
329
|
+
display: -webkit-box;
|
|
330
|
+
overflow-wrap: anywhere;
|
|
331
|
+
-webkit-box-orient: vertical;
|
|
332
|
+
-webkit-line-clamp: 2;
|
|
333
|
+
font-size: 20px;
|
|
334
|
+
line-height: 1.1;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.bar-time,
|
|
338
|
+
.bar-rewards {
|
|
339
|
+
display: block;
|
|
340
|
+
margin-top: 5px;
|
|
341
|
+
padding: 3px 9px;
|
|
342
|
+
background: rgba(42, 26, 10, .54);
|
|
343
|
+
overflow: hidden;
|
|
344
|
+
overflow-wrap: anywhere;
|
|
345
|
+
font-size: 11px;
|
|
346
|
+
line-height: 1.25;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.bar-rewards {
|
|
350
|
+
max-width: 100%;
|
|
351
|
+
display: -webkit-box;
|
|
352
|
+
-webkit-box-orient: vertical;
|
|
353
|
+
-webkit-line-clamp: 2;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.empty-state {
|
|
357
|
+
min-height: 260px;
|
|
358
|
+
display: flex;
|
|
359
|
+
align-items: center;
|
|
360
|
+
justify-content: center;
|
|
361
|
+
border: 2px dashed rgba(83, 53, 28, .20);
|
|
362
|
+
background: rgba(255, 255, 255, .36);
|
|
363
|
+
color: rgba(80, 48, 20, .72);
|
|
364
|
+
font-size: 32px;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
@container (max-width: 420px) {
|
|
368
|
+
.gantt-bar {
|
|
369
|
+
padding-left: 88px;
|
|
370
|
+
padding-right: 12px;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.bar-tag {
|
|
374
|
+
left: 10px;
|
|
375
|
+
max-width: 66px;
|
|
376
|
+
padding: 4px 8px;
|
|
377
|
+
font-size: 12px;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.bar-bracket {
|
|
381
|
+
display: none;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.bar-name {
|
|
385
|
+
font-size: 17px;
|
|
386
|
+
line-height: 1.12;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.bar-time,
|
|
390
|
+
.bar-rewards {
|
|
391
|
+
margin-top: 4px;
|
|
392
|
+
padding: 2px 6px;
|
|
393
|
+
font-size: 10px;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
@container (max-width: 320px) {
|
|
398
|
+
.gantt-bar {
|
|
399
|
+
align-items: stretch;
|
|
400
|
+
padding: 8px 10px 8px 72px;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.bar-tag {
|
|
404
|
+
left: 8px;
|
|
405
|
+
max-width: 56px;
|
|
406
|
+
font-size: 11px;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.bar-content {
|
|
410
|
+
display: flex;
|
|
411
|
+
min-height: 0;
|
|
412
|
+
flex-direction: column;
|
|
413
|
+
justify-content: center;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.bar-name {
|
|
417
|
+
font-size: 15px;
|
|
418
|
+
-webkit-line-clamp: 2;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.bar-rewards {
|
|
422
|
+
display: none;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.footer {
|
|
427
|
+
display: flex;
|
|
428
|
+
justify-content: space-between;
|
|
429
|
+
margin-top: 22px;
|
|
430
|
+
padding-top: 16px;
|
|
431
|
+
border-top: 2px solid rgba(83, 53, 28, .16);
|
|
432
|
+
color: rgba(71, 43, 20, .72);
|
|
433
|
+
font-size: 18px;
|
|
434
|
+
}
|
package/lib/render.js
CHANGED
|
@@ -47,6 +47,13 @@ const logger = new koishi_1.Logger('rocom-render');
|
|
|
47
47
|
const TEMPLATE_CAPTURE_PADDING = {
|
|
48
48
|
package: { left: 0, right: 0, top: 0, bottom: 0 },
|
|
49
49
|
};
|
|
50
|
+
const TEMPLATE_VIEWPORTS = {
|
|
51
|
+
activities: { width: 1600, height: 1200, deviceScaleFactor: 2 },
|
|
52
|
+
};
|
|
53
|
+
const DEFAULT_SCREENSHOT_OPTIONS = {
|
|
54
|
+
type: 'jpeg',
|
|
55
|
+
quality: 82,
|
|
56
|
+
};
|
|
50
57
|
function toDirectoryFileUrl(dirPath) {
|
|
51
58
|
const href = (0, node_url_1.pathToFileURL)(dirPath).href;
|
|
52
59
|
return href.endsWith('/') ? href : `${href}/`;
|
|
@@ -119,7 +126,8 @@ class Renderer {
|
|
|
119
126
|
try {
|
|
120
127
|
await page.setCacheEnabled(false);
|
|
121
128
|
node_fs_1.default.writeFileSync(tempHtmlPath, html, 'utf-8');
|
|
122
|
-
|
|
129
|
+
const initialViewport = TEMPLATE_VIEWPORTS[templateName] || { width: 1280, height: 768, deviceScaleFactor: 2 };
|
|
130
|
+
await page.setViewport(initialViewport);
|
|
123
131
|
try {
|
|
124
132
|
await page.goto((0, node_url_1.pathToFileURL)(tempHtmlPath).href, {
|
|
125
133
|
waitUntil: 'networkidle0',
|
|
@@ -172,6 +180,7 @@ class Renderer {
|
|
|
172
180
|
'.home-page',
|
|
173
181
|
'.pet-panel-page',
|
|
174
182
|
'.pet-detail-page',
|
|
183
|
+
'.activity-calendar-page',
|
|
175
184
|
];
|
|
176
185
|
let target = null;
|
|
177
186
|
for (const selector of selectors) {
|
|
@@ -199,7 +208,7 @@ class Renderer {
|
|
|
199
208
|
await page.setViewport({
|
|
200
209
|
width: Math.max(Math.ceil(elementMetrics.x + elementMetrics.width + capturePadding.right) + 8, 200),
|
|
201
210
|
height: Math.max(Math.ceil(elementMetrics.y + elementMetrics.height + capturePadding.bottom) + 8, 200),
|
|
202
|
-
deviceScaleFactor:
|
|
211
|
+
deviceScaleFactor: initialViewport.deviceScaleFactor,
|
|
203
212
|
});
|
|
204
213
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
205
214
|
const hasOverflow = elementMetrics.width > box.width + 0.5 ||
|
|
@@ -210,7 +219,7 @@ class Renderer {
|
|
|
210
219
|
const clipWidth = elementMetrics.width + capturePadding.left + capturePadding.right;
|
|
211
220
|
const clipHeight = elementMetrics.height + capturePadding.top + capturePadding.bottom;
|
|
212
221
|
const screenshot = await page.screenshot({
|
|
213
|
-
|
|
222
|
+
...DEFAULT_SCREENSHOT_OPTIONS,
|
|
214
223
|
clip: {
|
|
215
224
|
x: clipX,
|
|
216
225
|
y: clipY,
|
|
@@ -221,10 +230,10 @@ class Renderer {
|
|
|
221
230
|
return Buffer.isBuffer(screenshot) ? screenshot : Buffer.from(screenshot);
|
|
222
231
|
}
|
|
223
232
|
}
|
|
224
|
-
const screenshot = await target.screenshot(
|
|
233
|
+
const screenshot = await target.screenshot(DEFAULT_SCREENSHOT_OPTIONS);
|
|
225
234
|
return Buffer.isBuffer(screenshot) ? screenshot : Buffer.from(screenshot);
|
|
226
235
|
}
|
|
227
|
-
const screenshot = await page.screenshot({ fullPage: true });
|
|
236
|
+
const screenshot = await page.screenshot({ ...DEFAULT_SCREENSHOT_OPTIONS, fullPage: true });
|
|
228
237
|
return Buffer.isBuffer(screenshot) ? screenshot : Buffer.from(screenshot);
|
|
229
238
|
}
|
|
230
239
|
finally {
|
package/lib/send-image.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { PluginConfig } from './types';
|
|
2
|
+
export declare function detectImageMime(image: Buffer): string;
|
|
2
3
|
export declare function compressPngImage(image: Buffer, config: Pick<PluginConfig, 'imageCompressionEnabled' | 'imageCompressionMinBytes' | 'imageCompressionLevel'>): Buffer;
|
|
3
4
|
export declare function sendImageWithFallback(session: any, image: Buffer | null, fallbackText: string, scene: string, compressionConfig?: Pick<PluginConfig, 'imageCompressionEnabled' | 'imageCompressionMinBytes' | 'imageCompressionLevel'>): Promise<void>;
|
package/lib/send-image.js
CHANGED
|
@@ -3,12 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.detectImageMime = detectImageMime;
|
|
6
7
|
exports.compressPngImage = compressPngImage;
|
|
7
8
|
exports.sendImageWithFallback = sendImageWithFallback;
|
|
8
9
|
const koishi_1 = require("koishi");
|
|
9
10
|
const node_zlib_1 = __importDefault(require("node:zlib"));
|
|
10
11
|
const logger = new koishi_1.Logger('rocom-send');
|
|
11
12
|
const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
|
13
|
+
const JPEG_SIGNATURE = Buffer.from([0xff, 0xd8, 0xff]);
|
|
12
14
|
function formatSessionContext(session) {
|
|
13
15
|
if (!session)
|
|
14
16
|
return 'session=<null>';
|
|
@@ -48,6 +50,16 @@ function pngChunk(type, data) {
|
|
|
48
50
|
function isPng(buffer) {
|
|
49
51
|
return buffer.length > PNG_SIGNATURE.length && buffer.subarray(0, PNG_SIGNATURE.length).equals(PNG_SIGNATURE);
|
|
50
52
|
}
|
|
53
|
+
function isJpeg(buffer) {
|
|
54
|
+
return buffer.length > JPEG_SIGNATURE.length && buffer.subarray(0, JPEG_SIGNATURE.length).equals(JPEG_SIGNATURE);
|
|
55
|
+
}
|
|
56
|
+
function detectImageMime(image) {
|
|
57
|
+
if (isPng(image))
|
|
58
|
+
return 'image/png';
|
|
59
|
+
if (isJpeg(image))
|
|
60
|
+
return 'image/jpeg';
|
|
61
|
+
return 'image/png';
|
|
62
|
+
}
|
|
51
63
|
function compressPngImage(image, config) {
|
|
52
64
|
if (!config.imageCompressionEnabled)
|
|
53
65
|
return image;
|
|
@@ -118,7 +130,7 @@ async function sendImageWithFallback(session, image, fallbackText, scene, compre
|
|
|
118
130
|
logger.info(`[${scene}] compressed image ${image.length}B -> ${outputImage.length}B | ${ctxInfo}`);
|
|
119
131
|
}
|
|
120
132
|
try {
|
|
121
|
-
const result = await session.send(koishi_1.h.image(outputImage,
|
|
133
|
+
const result = await session.send(koishi_1.h.image(outputImage, detectImageMime(outputImage)));
|
|
122
134
|
if (!hasSendResult(result)) {
|
|
123
135
|
logger.warn(`[${scene}] image send returned empty result | size=${outputImage.length}B | ${ctxInfo}`);
|
|
124
136
|
}
|
package/lib/subscription-send.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.sendScheduledMessage = sendScheduledMessage;
|
|
4
4
|
exports.sendScheduledImageWithFallback = sendScheduledImageWithFallback;
|
|
5
5
|
const koishi_1 = require("koishi");
|
|
6
|
+
const send_image_1 = require("./send-image");
|
|
6
7
|
const logger = new koishi_1.Logger('rocom-subscription-send');
|
|
7
8
|
function findBot(ctx, platform = '') {
|
|
8
9
|
if (!ctx.bots?.length)
|
|
@@ -52,7 +53,7 @@ async function sendScheduledImageWithFallback(ctx, target, image, fallbackText,
|
|
|
52
53
|
if (!image) {
|
|
53
54
|
return sendScheduledMessage(ctx, target, `${prefix}${fallbackText}`);
|
|
54
55
|
}
|
|
55
|
-
const imageSegment = koishi_1.h.image(image,
|
|
56
|
+
const imageSegment = koishi_1.h.image(image, (0, send_image_1.detectImageMime)(image));
|
|
56
57
|
const content = mentionAll ? `${prefix}${imageSegment}` : imageSegment;
|
|
57
58
|
const sent = await sendScheduledMessage(ctx, target, content);
|
|
58
59
|
if (sent)
|
package/lib/types.d.ts
CHANGED
|
@@ -13,7 +13,9 @@ export interface PluginConfig {
|
|
|
13
13
|
merchantSubscriptionEnabled: boolean;
|
|
14
14
|
merchantSubscriptionItems: string[];
|
|
15
15
|
merchantPrivateSubscriptionEnabled: boolean;
|
|
16
|
+
merchantCheckMode: 'interval' | 'times';
|
|
16
17
|
merchantCheckInterval: number;
|
|
18
|
+
merchantCheckTimes: string[];
|
|
17
19
|
homeSubscriptionEnabled: boolean;
|
|
18
20
|
homeSubscriptionIntervalMinutes: number;
|
|
19
21
|
imageCompressionEnabled: boolean;
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -9,12 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
sk-ba042e079cf9ccb30e72b3d5af458f45
|
|
14
|
-
sk-c7952558b84a176b76d0215760732330
|
|
15
|
-
sk-b3d96323b2b045282c52f81ca43fcad8
|
|
16
|
-
sk-5c14c1e5da063037d02c15e50285dd04
|
|
17
|
-
|
|
12
|
+
APIkey获取请访问:[洛克魔法书](https://rocom.shallow.ink/)
|
|
18
13
|
---
|
|
19
14
|
|
|
20
15
|
</div>
|
|
@@ -38,7 +33,7 @@ Koishi 版洛克王国数据查询插件。插件基于 WeGame / 后端接口提
|
|
|
38
33
|
- `puppeteer`
|
|
39
34
|
- `rocom`
|
|
40
35
|
|
|
41
|
-
|
|
36
|
+
如果图片渲染失败,插件会尽量回落为文字结果;但档案、战绩、背包、阵容、交换大厅、远行商人、活动日历和查蛋配种等功能推荐配合 Puppeteer 使用。
|
|
42
37
|
|
|
43
38
|
| 功能 | 示例图片 | 功能 | 示例图片 |
|
|
44
39
|
| -------- | -------------------------------------------------- | -------- | -------------------------------------------------- |
|
|
@@ -64,13 +59,13 @@ Koishi 版洛克王国数据查询插件。插件基于 WeGame / 后端接口提
|
|
|
64
59
|
| `merchantPrivateSubscriptionEnabled` | `true` | 是否允许私聊订阅远行商人推送 |
|
|
65
60
|
| `homeSubscriptionEnabled` | `true` | 是否启用家园菜园和灵感订阅推送 |
|
|
66
61
|
| `homeSubscriptionIntervalMinutes` | `5` | 家园订阅检查间隔,单位分钟 |
|
|
67
|
-
| `imageCompressionEnabled` | `true` |
|
|
62
|
+
| `imageCompressionEnabled` | `true` | 是否对 PNG 图片启用无损压缩 |
|
|
68
63
|
| `imageCompressionMinBytes` | `262144` | 触发压缩的最小图片大小,单位字节 |
|
|
69
64
|
| `imageCompressionLevel` | `9` | PNG zlib 压缩等级,范围 `0-9`,数值越大通常越小但更耗时 |
|
|
70
65
|
|
|
71
66
|
### 图片压缩设置
|
|
72
67
|
|
|
73
|
-
|
|
68
|
+
后台配置页中有单独的“图片压缩设置”分组。Puppeteer 渲染图默认以 JPEG 发送,用于降低图片体积;仍以 PNG 进入发送链路的图片会按该设置对 IDAT 数据做无损重压缩,不会改变图片尺寸、画质或透明度。若压缩失败,或压缩后文件没有变小,会自动发送原图。
|
|
74
69
|
|
|
75
70
|
## 快速开始
|
|
76
71
|
|