dsh-bili-watch 0.2.26 → 0.2.28
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/index.js +9 -2
- package/package.json +1 -1
- package/tools/look.mjs +26 -2
package/index.js
CHANGED
|
@@ -433,7 +433,11 @@ function pickFolderDialog() {
|
|
|
433
433
|
* 缓存自动清理:先按天数删过期文件,再按总量从最旧删到阈值内。
|
|
434
434
|
* 返回被删统计,供面板显示。
|
|
435
435
|
*/
|
|
436
|
-
|
|
436
|
+
let lastCleanAt = 0
|
|
437
|
+
|
|
438
|
+
function autoCleanCache(opts = {}) {
|
|
439
|
+
// T31-P2-6:面板每 8 秒轮询 /status,不许每次都全量 walk 缓存目录
|
|
440
|
+
if (!opts.force && Date.now() - lastCleanAt < 10 * 60 * 1000) return { removed: 0, bytes: 0, skipped: true }
|
|
437
441
|
if (!existsSync(CACHE)) return { removed: 0, bytes: 0 }
|
|
438
442
|
const { days, maxMb } = cacheCfg()
|
|
439
443
|
const cutoff = Date.now() - days * 86400000
|
|
@@ -466,6 +470,7 @@ function autoCleanCache() {
|
|
|
466
470
|
if (total <= limit) break
|
|
467
471
|
}
|
|
468
472
|
}
|
|
473
|
+
lastCleanAt = Date.now()
|
|
469
474
|
return { removed, bytes }
|
|
470
475
|
}
|
|
471
476
|
|
|
@@ -756,7 +761,7 @@ async function lookup({ command, bv, extra = [], badOut = false }) {
|
|
|
756
761
|
function apply(ctx) {
|
|
757
762
|
// 启动时按「天数 + 总量阈值」清一次缓存,不点按钮也不会无限涨
|
|
758
763
|
try {
|
|
759
|
-
const r = autoCleanCache()
|
|
764
|
+
const r = autoCleanCache({ force: true })
|
|
760
765
|
if (r.removed) ctx.logger?.info?.(`[dsh-bili-watch] 自动清理缓存 ${r.removed} 个文件 / ${(r.bytes / 1048576).toFixed(1)} MB`)
|
|
761
766
|
} catch {}
|
|
762
767
|
|
|
@@ -780,6 +785,7 @@ function apply(ctx) {
|
|
|
780
785
|
try {
|
|
781
786
|
if (createUserMessage && uiCfg().autoHint !== false) {
|
|
782
787
|
const hinted = new Map() // message.id → true,同一条消息只提示一次
|
|
788
|
+
const HINT_CAP = 500 // T31-P2-5:常驻 Map 不能无限涨,满了整体清空(只影响重复提示)
|
|
783
789
|
const hint = (msg) => {
|
|
784
790
|
const { ok, text } = textOfUserMessage(msg)
|
|
785
791
|
if (!ok) return null
|
|
@@ -806,6 +812,7 @@ function apply(ctx) {
|
|
|
806
812
|
const extra = hint(msg)
|
|
807
813
|
if (!extra) continue
|
|
808
814
|
hinted.set(msg.id, true)
|
|
815
|
+
if (hinted.size > HINT_CAP) hinted.clear()
|
|
809
816
|
fresh.push(extra)
|
|
810
817
|
}
|
|
811
818
|
if (!fresh.length) return decision
|
package/package.json
CHANGED
package/tools/look.mjs
CHANGED
|
@@ -93,7 +93,17 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
|
|
|
93
93
|
const jitter = (base, spread) => base + Math.floor(Math.random() * spread)
|
|
94
94
|
|
|
95
95
|
async function jget(url, headers = H, timeoutMs = 30000) {
|
|
96
|
-
|
|
96
|
+
// T36-P1-2:只对网络层抖动重试一次(B 站偶发 ECONNRESET);业务 code(-352/-404)不重试
|
|
97
|
+
let r
|
|
98
|
+
for (let attempt = 0; ; attempt++) {
|
|
99
|
+
try {
|
|
100
|
+
r = await fetch(url, { headers, signal: AbortSignal.timeout(timeoutMs) })
|
|
101
|
+
if (!(r.status >= 500) || attempt >= 1) break
|
|
102
|
+
} catch (e) {
|
|
103
|
+
if (attempt >= 1) throw e
|
|
104
|
+
}
|
|
105
|
+
await sleep(300 + Math.floor(Math.random() * 400))
|
|
106
|
+
}
|
|
97
107
|
const t = await r.text()
|
|
98
108
|
if (!r.ok) return { code: -r.status, message: `HTTP ${r.status}` }
|
|
99
109
|
try {
|
|
@@ -1366,6 +1376,18 @@ async function cmdSheet(bv, opts = {}) {
|
|
|
1366
1376
|
mkdirSync(dirname(out), { recursive: true })
|
|
1367
1377
|
execFileSync(bin, ['-y', '-threads', '2', '-i', join(tmp, '%02d.jpg'), '-vf', `scale=640:-1,tile=${cols}x${rows}`, '-frames:v', '1', out], { stdio: 'ignore', timeout: 300000 })
|
|
1368
1378
|
console.log(`拼图: ${out}(${(statSync(out).size / 1024).toFixed(0)} KiB,共 ${picked.length} 帧)`)
|
|
1379
|
+
// T42:九宫格没有时间轴,模型看图不知道「第几格是第几秒」;写一份 manifest 并打一行
|
|
1380
|
+
const stepUsed = Number((/-([0-9]+)s$/.exec(r.dir) || [])[1] || opts.step || 0)
|
|
1381
|
+
const cellSec = (f, i) => {
|
|
1382
|
+
const m = /-([0-9]+)\.jpg$/.exec(f)
|
|
1383
|
+
const n = m ? Number(m[1]) : i + 1
|
|
1384
|
+
return stepUsed > 0 ? Math.max(0, (n - 1) * stepUsed) : null
|
|
1385
|
+
}
|
|
1386
|
+
const cells = picked.map((f, i) => { const sec = cellSec(f, i); return { cell: i + 1, file: basename(f), sec, mmss: sec == null ? '?' : fmtSec(sec) } })
|
|
1387
|
+
try {
|
|
1388
|
+
writeFileSync(out.replace(/\.jpg$/, '.manifest.json'), JSON.stringify({ bv, grid, step: stepUsed || null, cells }, null, 2) + '\n', 'utf8')
|
|
1389
|
+
} catch {}
|
|
1390
|
+
console.log('每格时间:' + cells.map((x) => `#${x.cell}=${x.mmss}`).join(' '))
|
|
1369
1391
|
console.log('读这张图就能过一遍画面;要精确读字用 ocr <BV>。')
|
|
1370
1392
|
}
|
|
1371
1393
|
|
|
@@ -1781,7 +1803,7 @@ async function cmdText(bv, credPath, opts = {}) {
|
|
|
1781
1803
|
// 口播类正常 4–6 字/秒;低于 2 字/秒多半是背景音乐、外语歌或纯画面,
|
|
1782
1804
|
// 这时候转写出来的「字」只是把杂音听成了字,继续往下走 OCR 更靠谱。
|
|
1783
1805
|
const rate = v.dur > 0 ? a.chars / v.dur : 0
|
|
1784
|
-
if (rate >= 2) {
|
|
1806
|
+
if (rate >= 2 && !(a.verify && a.verify.suspect)) {
|
|
1785
1807
|
// T40:ASR 也会把杂音/背景音听成字,主入口同样要过诱饵信号(原先只有字幕分支有)
|
|
1786
1808
|
const asrBait = baitSignals(a.text, v, credibility(v, a.text))
|
|
1787
1809
|
if (asrBait.suspect) {
|
|
@@ -1800,6 +1822,8 @@ async function cmdText(bv, credPath, opts = {}) {
|
|
|
1800
1822
|
printText(a.text, opts, bv)
|
|
1801
1823
|
done()
|
|
1802
1824
|
return
|
|
1825
|
+
} else if (a.verify && a.verify.suspect) {
|
|
1826
|
+
say(`[track] 转写: ⚠ 疑似幻觉(${(a.verify.reasons || []).join(';')}),降级到抽帧/OCR`)
|
|
1803
1827
|
}
|
|
1804
1828
|
say(`[track] 转写: 质量低(${a.chars} 字,${rate.toFixed(1)} 字/秒),继续往下试`)
|
|
1805
1829
|
} else {
|