koishi-plugin-dwrgbwiki 2.1.2 → 2.2.0
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/codex.js +44 -56
- package/index.js +100 -59
- package/notice.js +20 -17
- package/package.json +1 -1
- package/readme.md +6 -13
package/codex.js
CHANGED
|
@@ -36,26 +36,26 @@ async function fetchText(url, timeout) {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
async function fetchUrl(url, timeout) {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
let res = await doFetch()
|
|
50
|
-
if (res.status === 567 || res.status === 429 || res.status === 503) {
|
|
51
|
-
await new Promise(r => setTimeout(r, 3000))
|
|
52
|
-
res = await doFetch()
|
|
53
|
-
}
|
|
54
|
-
if (!res.ok) throw new Error('HTTP ' + res.status)
|
|
55
|
-
return await res.text()
|
|
56
|
-
} finally {
|
|
57
|
-
clearTimeout(timer)
|
|
39
|
+
const headers = {
|
|
40
|
+
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36',
|
|
41
|
+
'Accept-Language': 'zh-CN,zh;q=0.9',
|
|
42
|
+
}
|
|
43
|
+
const doFetch = () => {
|
|
44
|
+
const ctrl = new AbortController()
|
|
45
|
+
const timer = setTimeout(() => ctrl.abort(), timeout)
|
|
46
|
+
const p = fetch(url, { signal: ctrl.signal, headers })
|
|
47
|
+
p.finally(() => clearTimeout(timer))
|
|
48
|
+
return p
|
|
58
49
|
}
|
|
50
|
+
let res = await doFetch()
|
|
51
|
+
const RETRY_WAIT = [3000, 8000]
|
|
52
|
+
for (const wait of RETRY_WAIT) {
|
|
53
|
+
if (res.status !== 567 && res.status !== 429 && res.status !== 503) break
|
|
54
|
+
await new Promise(r => setTimeout(r, wait))
|
|
55
|
+
res = await doFetch()
|
|
56
|
+
}
|
|
57
|
+
if (!res.ok) throw new Error('HTTP ' + res.status)
|
|
58
|
+
return await res.text()
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
async function fetchCategoryMembers(category, config) {
|
|
@@ -74,6 +74,14 @@ async function fetchCategoryMembers(category, config) {
|
|
|
74
74
|
return titles
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
async function searchPages(query, config) {
|
|
78
|
+
const q = String(query || '').trim().replace(/[“”"]/g, '')
|
|
79
|
+
if (!q) return []
|
|
80
|
+
const url = API_BASE + '/api.php?action=query&list=search&srsearch=' + encodeURIComponent(q) + '&srlimit=5&format=json&formatversion=2'
|
|
81
|
+
const data = await fetchRaw(url, config.timeout || 15000)
|
|
82
|
+
return (data.query && data.query.search) || []
|
|
83
|
+
}
|
|
84
|
+
|
|
77
85
|
function buildRoleHtml(category, titles, config) {
|
|
78
86
|
const width = config.width || 1300
|
|
79
87
|
const total = titles.length
|
|
@@ -116,49 +124,28 @@ body { background:#0d1117; color:#c9d1d9; font-family:-apple-system,BlinkMacSyst
|
|
|
116
124
|
async function resolveTitle(title, config) {
|
|
117
125
|
const q = String(title || '').trim()
|
|
118
126
|
if (!q) throw new Error('请输入页面名')
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (!triedQuotes && !/[“”"]/.test(q)) {
|
|
127
|
-
triedQuotes = true
|
|
128
|
-
current = '“' + q + '”'
|
|
129
|
-
continue
|
|
130
|
-
}
|
|
131
|
-
throw new Error('页面不存在:' + current)
|
|
132
|
-
}
|
|
127
|
+
const hasQuote = /[“”"]/.test(q)
|
|
128
|
+
const candidates = hasQuote ? [q] : [q, '“' + q + '”']
|
|
129
|
+
const url = API_BASE + '/api.php?action=query&redirects=1&prop=info&titles=' + encodeURIComponent(candidates.join('|')) + '&format=json&formatversion=2'
|
|
130
|
+
const data = await fetchRaw(url, config.timeout || 15000)
|
|
131
|
+
const pages = (data.query && data.query.pages) || []
|
|
132
|
+
const page = pages.find(p => !p.missing && p.title)
|
|
133
|
+
if (page) return page.title
|
|
133
134
|
throw new Error('页面不存在:' + q)
|
|
134
135
|
}
|
|
135
136
|
|
|
136
137
|
async function fetchWikitext(title, config) {
|
|
137
138
|
const q = String(title || '').trim()
|
|
138
139
|
if (!q) throw new Error('请输入要查询的名称')
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (
|
|
147
|
-
|
|
148
|
-
triedQuotes = true
|
|
149
|
-
current = '“' + q + '”'
|
|
150
|
-
continue
|
|
151
|
-
}
|
|
152
|
-
throw new Error('页面不存在:' + current)
|
|
153
|
-
}
|
|
154
|
-
if (!page.revisions || !page.revisions.length) throw new Error('页面「' + current + '」无内容')
|
|
155
|
-
const content = page.revisions[0].content
|
|
156
|
-
const rd = content.match(/^\s*#(?:重定向|REDIRECT)\s*\[\[([^\]]+)\]\]/)
|
|
157
|
-
if (rd && rd[1] && rd[1] !== current) {
|
|
158
|
-
current = rd[1].split('|')[0].trim()
|
|
159
|
-
continue
|
|
160
|
-
}
|
|
161
|
-
return { title: page.title, content }
|
|
140
|
+
const hasQuote = /[“”"]/.test(q)
|
|
141
|
+
const candidates = hasQuote ? [q] : [q, '“' + q + '”']
|
|
142
|
+
const url = API_BASE + '/api.php?action=query&prop=revisions&rvprop=content&redirects=1&format=json&formatversion=2&titles=' + encodeURIComponent(candidates.join('|'))
|
|
143
|
+
const data = await fetchRaw(url, config.timeout || 15000)
|
|
144
|
+
const pages = (data.query && data.query.pages) || []
|
|
145
|
+
const found = pages.find(p => !p.missing)
|
|
146
|
+
if (found) {
|
|
147
|
+
if (found.revisions && found.revisions.length) return { title: found.title, content: found.revisions[0].content }
|
|
148
|
+
throw new Error('页面「' + found.title + '」无内容')
|
|
162
149
|
}
|
|
163
150
|
throw new Error('页面不存在:' + q)
|
|
164
151
|
}
|
|
@@ -510,6 +497,7 @@ module.exports = {
|
|
|
510
497
|
fetchWikitext,
|
|
511
498
|
resolveTitle,
|
|
512
499
|
fetchCategoryMembers,
|
|
500
|
+
searchPages,
|
|
513
501
|
buildRoleHtml,
|
|
514
502
|
parseTemplates,
|
|
515
503
|
mergeParams,
|
package/index.js
CHANGED
|
@@ -117,36 +117,20 @@ module.exports = {
|
|
|
117
117
|
width: Schema.number().min(400).max(4000)
|
|
118
118
|
.description('图片宽度(px),其他指令未单独设置时使用该值')
|
|
119
119
|
.default(1300),
|
|
120
|
-
|
|
121
|
-
.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
.
|
|
129
|
-
|
|
130
|
-
.
|
|
131
|
-
.default(0),
|
|
120
|
+
commandWidths: Schema.array(Schema.object({
|
|
121
|
+
command: Schema.union(['胜率', '地图', '模仿者', '赛事', '勋章', '基础数据', '抽卡', '图鉴', 'WIKI'])
|
|
122
|
+
.required()
|
|
123
|
+
.description('指令名称'),
|
|
124
|
+
width: Schema.number().min(0).max(4000)
|
|
125
|
+
.description('该指令图片宽度(px),0=使用默认宽度')
|
|
126
|
+
.default(0),
|
|
127
|
+
}))
|
|
128
|
+
.role('table')
|
|
129
|
+
.description('各指令图片宽度设置(px),以表格形式通过「添加项目」新增;0=使用默认宽度')
|
|
130
|
+
.default([]),
|
|
132
131
|
matchMerge: Schema.union(['team', 'player', 'all', 'none'])
|
|
133
132
|
.description('赛事指令默认合并模式:team=合并队伍前身,player=合并选手多个id,all=两者都合并,none=完全不合并')
|
|
134
133
|
.default('team'),
|
|
135
|
-
badgeWidth: Schema.number().min(0).max(4000)
|
|
136
|
-
.description('勋章指令图片宽度(px),0=使用默认宽度')
|
|
137
|
-
.default(0),
|
|
138
|
-
basicWidth: Schema.number().min(0).max(4000)
|
|
139
|
-
.description('基础数据指令图片宽度(px),0=使用默认宽度')
|
|
140
|
-
.default(0),
|
|
141
|
-
gachaWidth: Schema.number().min(0).max(4000)
|
|
142
|
-
.description('抽卡指令图片宽度(px),0=使用默认宽度')
|
|
143
|
-
.default(0),
|
|
144
|
-
codexWidth: Schema.number().min(0).max(4000)
|
|
145
|
-
.description('图鉴指令图片宽度(px),0=使用默认宽度')
|
|
146
|
-
.default(0),
|
|
147
|
-
wikiWidth: Schema.number().min(400).max(4000)
|
|
148
|
-
.description('WIKI页面指令截图宽度(px)')
|
|
149
|
-
.default(1300),
|
|
150
134
|
wikiMaxHeight: Schema.number().min(200).max(12000)
|
|
151
135
|
.description('WIKI页面指令截图最大高度(px)')
|
|
152
136
|
.default(5000),
|
|
@@ -210,12 +194,16 @@ module.exports = {
|
|
|
210
194
|
noticePlatform: Schema.string()
|
|
211
195
|
.description('公告推送的平台(如 qq),留空禁用公告推送')
|
|
212
196
|
.default('qq'),
|
|
213
|
-
|
|
214
|
-
.
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
.
|
|
218
|
-
|
|
197
|
+
noticeTargets: Schema.array(Schema.object({
|
|
198
|
+
type: Schema.union(['channel', 'private'])
|
|
199
|
+
.description('目标类型:channel=群/频道,private=私聊')
|
|
200
|
+
.default('channel'),
|
|
201
|
+
id: Schema.string().required()
|
|
202
|
+
.description('群/频道 id(channel 类型)或用户 id(private 类型)'),
|
|
203
|
+
}))
|
|
204
|
+
.role('table')
|
|
205
|
+
.description('公告推送目标列表,以表格形式通过「添加项目」新增推送目标(每行一个目标),可添加多个,群/频道与私聊可同时推送')
|
|
206
|
+
.default([]),
|
|
219
207
|
noticeInterval: Schema.number().min(1).max(1440)
|
|
220
208
|
.description('公告检查间隔(分钟)')
|
|
221
209
|
.default(10),
|
|
@@ -233,10 +221,10 @@ module.exports = {
|
|
|
233
221
|
key: Schema.string().required()
|
|
234
222
|
.description('模板参数名'),
|
|
235
223
|
label: Schema.string()
|
|
236
|
-
.description('
|
|
237
|
-
.default(''),
|
|
224
|
+
.description('显示名,留空则显示参数名'),
|
|
238
225
|
}))
|
|
239
|
-
.
|
|
226
|
+
.role('table')
|
|
227
|
+
.description('要解析展示的参数,以表格形式通过「添加项目」新增(每行一个参数);新增时默认只填 key,label 可留空或按需填写')
|
|
240
228
|
.default([]),
|
|
241
229
|
image: Schema.string()
|
|
242
230
|
.description('配图文件名模板(用 {{参数名}} 占位,如 {{角色}}{{品质}}品质时装_{{名称}}.png),留空不显示图片')
|
|
@@ -253,17 +241,17 @@ module.exports = {
|
|
|
253
241
|
templates: ['单时装', '商城信息'],
|
|
254
242
|
image: '{{角色}}{{品质}}品质时装_{{名称}}.png',
|
|
255
243
|
fields: [
|
|
256
|
-
{ key: '名称'
|
|
257
|
-
{ key: '角色'
|
|
258
|
-
{ key: '品质'
|
|
259
|
-
{ key: '获取方式'
|
|
260
|
-
{ key: '价格'
|
|
261
|
-
{ key: '上架时间'
|
|
262
|
-
{ key: '下架时间'
|
|
263
|
-
{ key: '具体描述'
|
|
264
|
-
{ key: '备注'
|
|
265
|
-
{ key: '限时限定'
|
|
266
|
-
{ key: '英文名称'
|
|
244
|
+
{ key: '名称' },
|
|
245
|
+
{ key: '角色' },
|
|
246
|
+
{ key: '品质' },
|
|
247
|
+
{ key: '获取方式' },
|
|
248
|
+
{ key: '价格' },
|
|
249
|
+
{ key: '上架时间' },
|
|
250
|
+
{ key: '下架时间' },
|
|
251
|
+
{ key: '具体描述' },
|
|
252
|
+
{ key: '备注' },
|
|
253
|
+
{ key: '限时限定' },
|
|
254
|
+
{ key: '英文名称' },
|
|
267
255
|
],
|
|
268
256
|
},
|
|
269
257
|
]),
|
|
@@ -704,7 +692,25 @@ function logCmd(ctx, session, name, args, extra) {
|
|
|
704
692
|
} catch (e) { /* 日志失败不影响主流程 */ }
|
|
705
693
|
}
|
|
706
694
|
|
|
695
|
+
// 指令宽度表:旧配置键 -> 表格中的指令名(commandWidths)
|
|
696
|
+
const WIDTH_COMMANDS = {
|
|
697
|
+
winrateWidth: '胜率',
|
|
698
|
+
mapWidth: '地图',
|
|
699
|
+
mimicWidth: '模仿者',
|
|
700
|
+
matchWidth: '赛事',
|
|
701
|
+
badgeWidth: '勋章',
|
|
702
|
+
basicWidth: '基础数据',
|
|
703
|
+
gachaWidth: '抽卡',
|
|
704
|
+
codexWidth: '图鉴',
|
|
705
|
+
wikiWidth: 'WIKI',
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// 读取指令图片宽度:优先 commandWidths 表格,其次回退旧版独立配置键,最后使用默认宽度
|
|
707
709
|
function cmdWidth(config, key) {
|
|
710
|
+
const command = WIDTH_COMMANDS[key]
|
|
711
|
+
const list = Array.isArray(config.commandWidths) ? config.commandWidths : []
|
|
712
|
+
const row = command && list.find(t => t && t.command === command)
|
|
713
|
+
if (row && row.width > 0) return row.width
|
|
708
714
|
const v = config[key]
|
|
709
715
|
return (v && v > 0) ? v : (config.width || 1300)
|
|
710
716
|
}
|
|
@@ -879,7 +885,20 @@ async function codexImage(ctx, config, rest) {
|
|
|
879
885
|
return [h.image(image, 'image/png')]
|
|
880
886
|
} catch (e) {
|
|
881
887
|
ctx.logger('dwrgbwiki').warn(e)
|
|
882
|
-
|
|
888
|
+
const msg = e && e.message ? e.message : String(e)
|
|
889
|
+
if (String(msg).includes('页面不存在')) {
|
|
890
|
+
await new Promise(r => setTimeout(r, 2000))
|
|
891
|
+
try {
|
|
892
|
+
const results = await codex.searchPages(q, config)
|
|
893
|
+
if (results.length) {
|
|
894
|
+
const list = results.slice(0, 5).map(r => ' ' + r.title).join('\n')
|
|
895
|
+
return '未找到「' + q + '」相关页面,为你找到:\n' + list + '\n可尝试:图鉴 ' + sub.name + ' <上面的名称>'
|
|
896
|
+
}
|
|
897
|
+
} catch (e2) {
|
|
898
|
+
ctx.logger('dwrgbwiki').warn(e2)
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
return errorImage(ctx, config, '图鉴查询失败:' + msg, '图鉴', codexWidth(sub, config))
|
|
883
902
|
}
|
|
884
903
|
}
|
|
885
904
|
|
|
@@ -962,7 +981,7 @@ async function wikiPageImage(ctx, config, wikiStore, userId, name) {
|
|
|
962
981
|
} catch (e) {
|
|
963
982
|
ctx.logger('dwrgbwiki').warn('WIKI页面解析标题失败,按原样截图: ' + (e && e.message ? e.message : e))
|
|
964
983
|
}
|
|
965
|
-
const width = config
|
|
984
|
+
const width = cmdWidth(config, 'wikiWidth')
|
|
966
985
|
const maxHeight = config.wikiMaxHeight || 5000
|
|
967
986
|
const image = await wiki.screenshot(ctx, target, {
|
|
968
987
|
width,
|
|
@@ -1322,21 +1341,43 @@ async function fetchNotice(url, timeout) {
|
|
|
1322
1341
|
}
|
|
1323
1342
|
}
|
|
1324
1343
|
|
|
1344
|
+
// 汇总公告推送目标列表(noticeTargets:多目标,群/频道与私聊可混用)
|
|
1345
|
+
function buildNoticeTargets(config) {
|
|
1346
|
+
const list = Array.isArray(config.noticeTargets) ? config.noticeTargets : []
|
|
1347
|
+
const targets = []
|
|
1348
|
+
const seen = new Set()
|
|
1349
|
+
for (const t of list) {
|
|
1350
|
+
const id = String(t && t.id ? t.id : '').trim()
|
|
1351
|
+
if (!id) continue
|
|
1352
|
+
const type = t.type === 'private' ? 'private' : 'channel'
|
|
1353
|
+
const key = type + ':' + id
|
|
1354
|
+
if (seen.has(key)) continue
|
|
1355
|
+
seen.add(key)
|
|
1356
|
+
targets.push({ type, id })
|
|
1357
|
+
}
|
|
1358
|
+
return targets
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
// 推送到全部目标,任一目标成功即视为成功(其余目标失败仅记录日志)
|
|
1325
1362
|
async function sendNoticeMessage(ctx, config, content, logger) {
|
|
1326
|
-
|
|
1363
|
+
const targets = buildNoticeTargets(config)
|
|
1364
|
+
if (!config.noticePlatform || !targets.length) return false
|
|
1327
1365
|
const bot = ctx.bots && ctx.bots.find(b => b.platform === config.noticePlatform && b.status === 1)
|
|
1328
1366
|
if (!bot) return false
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1367
|
+
let ok = false
|
|
1368
|
+
for (const t of targets) {
|
|
1369
|
+
try {
|
|
1370
|
+
if (t.type === 'private') {
|
|
1371
|
+
await bot.sendPrivateMessage(t.id, content)
|
|
1372
|
+
} else {
|
|
1373
|
+
await bot.sendMessage(t.id, content)
|
|
1374
|
+
}
|
|
1375
|
+
ok = true
|
|
1376
|
+
} catch (e) {
|
|
1377
|
+
logger.warn('公告推送失败(' + t.type + ':' + t.id + '): ' + (e && e.message ? e.message : e))
|
|
1334
1378
|
}
|
|
1335
|
-
return true
|
|
1336
|
-
} catch (e) {
|
|
1337
|
-
logger.warn('公告推送失败: ' + (e && e.message ? e.message : e))
|
|
1338
|
-
return false
|
|
1339
1379
|
}
|
|
1380
|
+
return ok
|
|
1340
1381
|
}
|
|
1341
1382
|
|
|
1342
1383
|
// 公告渲染为图片推送;失败(无 puppeteer / 渲染出错)返回 false,由调用方回退文本
|
package/notice.js
CHANGED
|
@@ -216,7 +216,10 @@ function buildNoticeHtml(parsed, config, changed) {
|
|
|
216
216
|
const width = config.width || 1300
|
|
217
217
|
const sourceName = config.sourceName || '官方'
|
|
218
218
|
const title = parsed.title || '更新公告'
|
|
219
|
-
|
|
219
|
+
// 增量推送(changed 非空)时,引言(第 1 个板块前的“致诸位尊敬的访客”等段落)未变动则不渲染,
|
|
220
|
+
// 避免每次推送都把固定引言带进图里;完整渲染(changed 为空)时始终展示
|
|
221
|
+
const showIntro = !changed || changed.intro
|
|
222
|
+
const introLines = showIntro ? parsed.intro.split('\n').map(l => l.trim()).filter(Boolean) : []
|
|
220
223
|
const introHtml = introLines.length
|
|
221
224
|
? '<div class="intro' + (changed ? ' update' : '') + '">' + introLines.map(l => inlineHtml(l)).join('<br>') + '</div>'
|
|
222
225
|
: ''
|
|
@@ -240,38 +243,38 @@ body { font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Microsoft YaHei'
|
|
|
240
243
|
.hero { text-align:center; padding:26px 24px 22px; border-radius:18px; margin-bottom:18px;
|
|
241
244
|
background:linear-gradient(135deg, #667eea 0%, #764ba2 55%, #a4508b 100%); box-shadow:0 8px 28px rgba(0,0,0,.4); position:relative; overflow:hidden; }
|
|
242
245
|
.hero::after { content:''; position:absolute; inset:0; background:radial-gradient(600px 200px at 80% -20%, rgba(255,255,255,.18), transparent 60%); }
|
|
243
|
-
.badge { display:inline-flex; align-items:center; gap:6px; font-size:
|
|
246
|
+
.badge { display:inline-flex; align-items:center; gap:6px; font-size:25px; font-weight:700; color:#ffd76d;
|
|
244
247
|
background:rgba(0,0,0,.28); border:1px solid rgba(255,215,109,.4); border-radius:999px; padding:4px 14px; margin-bottom:12px; letter-spacing:1px; }
|
|
245
|
-
.title { font-size:
|
|
246
|
-
.sub { font-size:
|
|
248
|
+
.title { font-size:35px; font-weight:800; color:#fff; letter-spacing:2px; text-shadow:0 2px 10px rgba(0,0,0,.35); }
|
|
249
|
+
.sub { font-size:25px; color:rgba(255,255,255,.8); margin-top:8px; letter-spacing:.5px; }
|
|
247
250
|
.intro { background:rgba(22,27,34,.82); border:1px solid rgba(255,255,255,.1); border-left:4px solid #ffd76d;
|
|
248
|
-
border-radius:14px; padding:16px 20px; margin-bottom:16px; line-height:1.9; font-size:
|
|
251
|
+
border-radius:14px; padding:16px 20px; margin-bottom:16px; line-height:1.9; font-size:25px; color:#c9d1d9; }
|
|
249
252
|
.section { background:rgba(22,27,34,.78); border:1px solid rgba(255,255,255,.09); border-radius:16px; padding:18px 20px; margin-bottom:16px; }
|
|
250
|
-
.s-head { display:flex; align-items:center; gap:12px; font-size:
|
|
253
|
+
.s-head { display:flex; align-items:center; gap:12px; font-size:25px; font-weight:800; color:#ffd76d; letter-spacing:1px;
|
|
251
254
|
padding-bottom:12px; margin-bottom:12px; border-bottom:1px solid rgba(255,255,255,.08); }
|
|
252
255
|
.s-num { flex-shrink:0; width:34px; height:34px; border-radius:10px; display:flex; align-items:center; justify-content:center;
|
|
253
|
-
font-size:
|
|
254
|
-
.s-sub { font-size:
|
|
255
|
-
.s-h3 { font-size:
|
|
256
|
-
.row { display:flex; gap:10px; margin-bottom:10px; line-height:1.85; font-size:
|
|
256
|
+
font-size:25px; font-weight:800; color:#fff; background:linear-gradient(135deg,#667eea,#764ba2); box-shadow:0 3px 10px rgba(102,126,234,.35); }
|
|
257
|
+
.s-sub { font-size:25px; font-weight:700; color:#79c0ff; margin:2px 0 10px; padding-left:10px; border-left:3px solid #58a6ff; line-height:1.6; }
|
|
258
|
+
.s-h3 { font-size:25px; font-weight:700; color:#56d4dd; margin:12px 0 8px; padding-left:10px; border-left:3px solid #56d4dd; line-height:1.6; }
|
|
259
|
+
.row { display:flex; gap:10px; margin-bottom:10px; line-height:1.85; font-size:25px; color:#c9d1d9; }
|
|
257
260
|
.row:last-child { margin-bottom:0; }
|
|
258
261
|
.dot { flex-shrink:0; width:7px; height:7px; border-radius:50%; margin-top:10px; background:linear-gradient(135deg,#ffd76d,#ff8c00); box-shadow:0 0 6px rgba(255,180,60,.6); }
|
|
259
262
|
.row-text { flex:1; }
|
|
260
263
|
.row.changed { background:rgba(255,215,109,.08); border:1px solid rgba(255,215,109,.28); border-radius:8px; padding:6px 10px; margin-left:-6px; margin-right:-6px; }
|
|
261
264
|
.row.changed .dot { background:#3fb950; box-shadow:0 0 6px rgba(63,185,80,.6); }
|
|
262
265
|
.kw { color:#ffd76d; font-weight:700; }
|
|
263
|
-
.tag-new { flex-shrink:0; font-size:
|
|
266
|
+
.tag-new { flex-shrink:0; font-size:25px; font-weight:700; color:#0d1117; background:linear-gradient(135deg,#3fb950,#2ea043); border-radius:999px; padding:2px 10px; letter-spacing:.5px; }
|
|
264
267
|
.tbl { margin:10px 0 14px; }
|
|
265
268
|
.tbl.changed { border:1px solid rgba(255,215,109,.35); border-radius:12px; padding:10px 12px; background:rgba(255,215,109,.05); }
|
|
266
269
|
.intro.update { border-left-color:#3fb950; }
|
|
267
|
-
.tbl-title { font-size:
|
|
270
|
+
.tbl-title { font-size:25px; font-weight:800; color:#fff; margin-bottom:8px; letter-spacing:.5px; }
|
|
268
271
|
.tbl table { width:100%; border-collapse:collapse; border-radius:10px; overflow:hidden; }
|
|
269
|
-
.tbl th { background:linear-gradient(135deg,#667eea,#764ba2); color:#fff; font-size:
|
|
270
|
-
.tbl td { padding:8px 14px; font-size:
|
|
272
|
+
.tbl th { background:linear-gradient(135deg,#667eea,#764ba2); color:#fff; font-size:25px; font-weight:700; padding:8px 14px; text-align:center; }
|
|
273
|
+
.tbl td { padding:8px 14px; font-size:25px; text-align:center; color:#e6edf3; border-top:1px solid rgba(255,255,255,.07); background:rgba(255,255,255,.02); }
|
|
271
274
|
.end-card { background:rgba(248,81,73,.08); border:1px solid rgba(248,81,73,.35); border-radius:16px; padding:18px 20px; margin-top:4px; }
|
|
272
|
-
.end-title { font-size:
|
|
273
|
-
.end-body { line-height:1.9; font-size:
|
|
274
|
-
.foot { text-align:center; color:#8b949e; font-size:
|
|
275
|
+
.end-title { font-size:25px; font-weight:800; color:#ff7b72; margin-bottom:10px; letter-spacing:.5px; }
|
|
276
|
+
.end-body { line-height:1.9; font-size:25px; color:#c9d1d9; }
|
|
277
|
+
.foot { text-align:center; color:#8b949e; font-size:25px; margin-top:16px; opacity:.75; letter-spacing:.5px; }
|
|
275
278
|
</style>
|
|
276
279
|
</head>
|
|
277
280
|
<body>
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -115,7 +115,7 @@ WIKI页面 <页面名>
|
|
|
115
115
|
| `图鉴 时装 招风旗` | 查询时装「招风旗」并生成图片卡片 |
|
|
116
116
|
|
|
117
117
|
- 数据来自第五人格 BWIKI(`wiki.biligame.com/dwrg`),通过 `query&prop=revisions` 获取页面 wikitext 后按模板解析
|
|
118
|
-
-
|
|
118
|
+
- 二级指令、模板名(前缀匹配,可多个)、解析字段、配图文件名模板与输出宽度均可在插件配置「图鉴二级指令配置」中自定义增减;字段以表格形式通过「添加项目」新增(每行一个参数),新增时默认只填 `key`,`label` 留空则显示参数名
|
|
119
119
|
- 配图文件名模板用 `{{参数名}}` 占位,如 `{{角色}}{{品质}}品质时装_{{名称}}.png`,插件会按该文件名在 wiki 上查找图片并显示在卡片左侧(找不到则不显示);参数值会自动清洗 wiki 语法(`[[链接]]`、`[[File:..]]`、`<br>` 等)
|
|
120
120
|
- 每个二级指令可单独设置 `width`(输出图片宽度,0=使用默认宽度),卡片为左侧图片、右侧字段表格的版式
|
|
121
121
|
- **时装专属**:`图鉴 时装 <名称>` 会额外读取 `/WIKI/时装稀有度/` 的 `latest_price.csv`(最新价格),在卡片底部显示该时装的**占有率**(含数据更新日期,占有率为动态数据);当品质为「稀世」时额外显示**单金价格**与**多金价格**
|
|
@@ -270,20 +270,12 @@ WIKI页面 <页面名>
|
|
|
270
270
|
| `showBadge` | 显示勋章分数据 | `true` |
|
|
271
271
|
| `badgeDays` | 勋章日增长率天数 | `7` |
|
|
272
272
|
| `width` | 图片宽度(px),其他指令未单独设置时使用该值 | `1300` |
|
|
273
|
-
| `
|
|
274
|
-
| `mapWidth` | 地图指令图片宽度(px),0=使用默认宽度 | `0` |
|
|
275
|
-
| `mimicWidth` | 模仿者指令图片宽度(px),0=使用默认宽度 | `0` |
|
|
276
|
-
| `badgeWidth` | 勋章指令图片宽度(px),0=使用默认宽度 | `0` |
|
|
277
|
-
| `basicWidth` | 基础数据指令图片宽度(px),0=使用默认宽度 | `0` |
|
|
278
|
-
| `gachaWidth` | 抽卡/探索/资源指令图片宽度(px),0=使用默认宽度 | `0` |
|
|
279
|
-
| `codexWidth` | 图鉴指令图片宽度(px),0=使用默认宽度 | `0` |
|
|
273
|
+
| `commandWidths` | 各指令图片宽度表(表格形式,每行:指令名 + 宽度,0=使用默认宽度),可配置胜率/地图/模仿者/赛事/勋章/基础数据/抽卡/图鉴/WIKI | 空 |
|
|
280
274
|
| `codexCommands` | 图鉴二级指令配置(名称/说明/模板名/解析字段,可增减) | 预置「时装」 |
|
|
281
|
-
| `wikiWidth` | WIKI页面指令截图宽度(px) | `1300` |
|
|
282
275
|
| `wikiMaxHeight` | WIKI页面指令截图最大高度(px) | `5000` |
|
|
283
276
|
| `wikiDailyLimit` | WIKI页面指令每日使用次数上限 | `5` |
|
|
284
277
|
| `cangtouDefaultMode` | 藏头指令默认模式 | `谐音` |
|
|
285
278
|
| `cangtouDefaultType` | 藏头指令默认物品类型 | `所有` |
|
|
286
|
-
| `matchWidth` | 赛事指令图片宽度(px),0=使用默认宽度 | `0` |
|
|
287
279
|
| `matchMerge` | 赛事指令默认合并模式(team/player/all/none) | `team` |
|
|
288
280
|
| `gachaDailyLimit` | 抽卡/探索每日次数上限 | `2` |
|
|
289
281
|
| `gachaDefaultJinghua` | 抽卡-精华 默认卡池编号 | 空 |
|
|
@@ -301,8 +293,7 @@ WIKI页面 <页面名>
|
|
|
301
293
|
| `feedbackUserId` | 接收反馈的账号 id | 空 |
|
|
302
294
|
| `noticeEnable` | 启用网易公告变动监听 | `false` |
|
|
303
295
|
| `noticePlatform` | 公告推送的平台(如 `qq`),留空禁用公告推送 | `qq` |
|
|
304
|
-
| `
|
|
305
|
-
| `noticeChannelId` | 公告推送目标:群/频道 id 或用户 id | 空 |
|
|
296
|
+
| `noticeTargets` | 公告推送目标列表,以表格形式通过「添加项目」新增(每行一个目标:类型 channel=群/频道 或 private=私聊、目标 id),可添加多个,群/频道与私聊可同时推送 | 空 |
|
|
306
297
|
| `noticeInterval` | 公告检查间隔(分钟) | `10` |
|
|
307
298
|
|
|
308
299
|
数据源两个镜像:`https://website.homeworkkun.top` 与 `https://web.homeworkkun.top`,可直接在配置中切换。
|
|
@@ -320,7 +311,9 @@ WIKI页面 <页面名>
|
|
|
320
311
|
- 正式服:`https://h55.update.netease.com/h55_notice_version2.txt`
|
|
321
312
|
- 共研服:`https://h55.update.netease.com/h55_notice_gongyan_version2.txt`
|
|
322
313
|
|
|
323
|
-
每次内容变动(以内容哈希判断)时,通过 `noticePlatform` 平台的机器人推送到 `
|
|
314
|
+
每次内容变动(以内容哈希判断)时,通过 `noticePlatform` 平台的机器人推送到 `noticeTargets` 列表中的全部目标(每条目标可单独指定 `channel` 群/频道或 `private` 私聊,可同时推送)。推送内容为「公告标题」+ 正文摘要(去除 HTML 标签与颜色代码,截断 500 字)。首次启动只记录基线,不推送。
|
|
315
|
+
|
|
316
|
+
变更推送优先渲染为图片(仅包含发生变化的部分):当「致诸位尊敬的访客」等引言段落没有变动时,不再将其渲染进图中,避免每次推送都带上固定引言;若引言本身有变动则会正常展示。图片渲染失败时自动回退为纯文本摘要推送。
|
|
324
317
|
|
|
325
318
|
## 图片内容
|
|
326
319
|
|