dsh-foxy-weibo 0.2.0 → 0.2.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/README.md +1 -1
- package/lib/client.js +36 -0
- package/lib/index.js +67 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -66,7 +66,7 @@ Cookie 只保存在本机 `~/.dsh/foxy-weibo/settings.json`,不会回传给前
|
|
|
66
66
|
1. 扫码登录,填自己的微博 UID,`enabled: true`、`replyMode: off`;
|
|
67
67
|
2. 设置每日检查时间,或先点「立即运行」,看日志和「调试」里的模型决策;
|
|
68
68
|
3. 确认判断正常后,再开启 `replyMode: auto`,每日上限先设为 1;
|
|
69
|
-
4.
|
|
69
|
+
4. 「立即检查」只判断不发布,用来预览回复;「立即回复」会真实发布一条,适合测试;
|
|
70
70
|
5. 微博评论有账号风控,不要高频、不要对陌生人全自动回复。
|
|
71
71
|
|
|
72
72
|
## 记忆事件
|
package/lib/client.js
CHANGED
|
@@ -227,6 +227,40 @@ window.__ModuleLoader__.load({
|
|
|
227
227
|
} catch (e) { setError(e.message) } finally { setBusy('') }
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
+
const checkNow = async () => {
|
|
231
|
+
setBusy('check'); setError(''); setNotice('')
|
|
232
|
+
try {
|
|
233
|
+
const data = await request('/check-now', { method: 'POST', body: '{}' })
|
|
234
|
+
setStatus(data.status)
|
|
235
|
+
const result = data.result || {}
|
|
236
|
+
setNotice(
|
|
237
|
+
result.skipped === 'no-self'
|
|
238
|
+
? '未开始:请先扫码登录或填写自己的微博 UID'
|
|
239
|
+
: result.skipped === 'busy'
|
|
240
|
+
? '正在运行,请稍候'
|
|
241
|
+
: `检查完成:检查 ${result.checked || 0} 条评论,预览 ${result.previewed || 0} 条,跳过 ${result.skipped || 0} 条` +
|
|
242
|
+
(result.errors ? `,失败 ${result.errors} 条` : ''),
|
|
243
|
+
)
|
|
244
|
+
} catch (e) { setError(e.message) } finally { setBusy('') }
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const replyNow = async () => {
|
|
248
|
+
if (!window.confirm('立即回复会真实发布到微博,确定继续?')) return
|
|
249
|
+
setBusy('reply'); setError(''); setNotice('')
|
|
250
|
+
try {
|
|
251
|
+
const data = await request('/reply-now', { method: 'POST', body: '{}' })
|
|
252
|
+
setStatus(data.status)
|
|
253
|
+
const result = data.result || {}
|
|
254
|
+
setNotice(
|
|
255
|
+
result.replied > 0
|
|
256
|
+
? `已立即回复 ${result.replied} 条,可在下方日志查看`
|
|
257
|
+
: result.skipped === 'no-self'
|
|
258
|
+
? '未开始:请先扫码登录或填写自己的微博 UID'
|
|
259
|
+
: '没有可立即回复的评论(可能已处理或模型选择跳过)',
|
|
260
|
+
)
|
|
261
|
+
} catch (e) { setError(e.message) } finally { setBusy('') }
|
|
262
|
+
}
|
|
263
|
+
|
|
230
264
|
if (!settings) return h('div', { className: 'fw-page' }, h('p', { className: 'fw-muted' }, error || '正在读取微博设置…'))
|
|
231
265
|
|
|
232
266
|
const recent = Array.isArray(status?.recent) ? status.recent : []
|
|
@@ -311,6 +345,8 @@ window.__ModuleLoader__.load({
|
|
|
311
345
|
h(Toggle, { checked: settings.debug, onChange: (v) => setField('debug', v), label: '记录调试日志', hint: '保存模型输出与记忆写入结果,便于排查。' }),
|
|
312
346
|
h('div', { className: 'fw-actions' },
|
|
313
347
|
h('button', { className: 'fw-btn primary', disabled: !!busy, onClick: runNow }, busy === 'run' ? '正在运行…' : '立即运行'),
|
|
348
|
+
h('button', { className: 'fw-btn', disabled: !!busy, onClick: checkNow }, busy === 'check' ? '检查中…' : '立即检查'),
|
|
349
|
+
h('button', { className: 'fw-btn', disabled: !!busy, onClick: replyNow }, busy === 'reply' ? '回复中…' : '立即回复'),
|
|
314
350
|
h('button', { className: 'fw-btn', disabled: !!busy, onClick: save }, busy === 'save' ? '保存中…' : '保存设置'),
|
|
315
351
|
),
|
|
316
352
|
h('div', { className: 'fw-stats' },
|
package/lib/index.js
CHANGED
|
@@ -11,6 +11,8 @@ export const inject = ['connection']
|
|
|
11
11
|
export const STATUS_ROUTE = '/api/dsh-foxy-weibo/status'
|
|
12
12
|
export const SETTINGS_ROUTE = '/api/dsh-foxy-weibo/settings'
|
|
13
13
|
export const RUN_ROUTE = '/api/dsh-foxy-weibo/run'
|
|
14
|
+
export const CHECK_NOW_ROUTE = '/api/dsh-foxy-weibo/check-now'
|
|
15
|
+
export const REPLY_NOW_ROUTE = '/api/dsh-foxy-weibo/reply-now'
|
|
14
16
|
export const LOGIN_START_ROUTE = '/api/dsh-foxy-weibo/login/start'
|
|
15
17
|
export const LOGIN_POLL_ROUTE = '/api/dsh-foxy-weibo/login/poll'
|
|
16
18
|
export const LOGOUT_ROUTE = '/api/dsh-foxy-weibo/logout'
|
|
@@ -156,15 +158,19 @@ async function rememberReply(ctx, config, state, post, comment, replyText) {
|
|
|
156
158
|
}
|
|
157
159
|
}
|
|
158
160
|
|
|
159
|
-
async function scanOwnComments(ctx, config, state, log, force = false) {
|
|
161
|
+
async function scanOwnComments(ctx, config, state, log, force = false, options = {}) {
|
|
160
162
|
if (!config.enabled && !force) return { skipped: 'disabled' }
|
|
161
|
-
const
|
|
163
|
+
const previewOnly = options.previewOnly === true
|
|
164
|
+
const forceReply = options.forceReply === true
|
|
165
|
+
const canReply = !previewOnly && (forceReply || config.replyMode === 'auto')
|
|
166
|
+
const targetCid = String(options.cid || '').trim()
|
|
162
167
|
const selfUid = String(config.selfUid || config.accountUid || '').trim()
|
|
163
168
|
if (!selfUid) return { skipped: 'no-self' }
|
|
164
169
|
const maxPosts = Math.max(1, Math.min(20, Number(config.maxPostsPerRun) || 5))
|
|
165
|
-
const maxReplies = Math.max(1, Math.min(8, Number(config.maxCommentsPerDay) || 1))
|
|
170
|
+
const maxReplies = Math.max(1, Math.min(8, Number(options.maxReplies ?? config.maxCommentsPerDay) || 1))
|
|
171
|
+
const ignoreQuota = forceReply
|
|
166
172
|
const result = {
|
|
167
|
-
mode: 'own-comments',
|
|
173
|
+
mode: options.mode || 'own-comments',
|
|
168
174
|
checked: 0,
|
|
169
175
|
replied: 0,
|
|
170
176
|
previewed: 0,
|
|
@@ -190,6 +196,7 @@ async function scanOwnComments(ctx, config, state, log, force = false) {
|
|
|
190
196
|
continue
|
|
191
197
|
}
|
|
192
198
|
for (const comment of comments) {
|
|
199
|
+
if (targetCid && String(comment.cid) !== targetCid) continue
|
|
193
200
|
if (canReply && result.replied >= maxReplies) break
|
|
194
201
|
if (!comment.cid || state.commentSeen[comment.cid]) continue
|
|
195
202
|
if (String(comment.author?.uid || '') === selfUid) {
|
|
@@ -197,7 +204,7 @@ async function scanOwnComments(ctx, config, state, log, force = false) {
|
|
|
197
204
|
continue
|
|
198
205
|
}
|
|
199
206
|
const limit = Math.max(0, Number(config.maxCommentsPerDay) || 0)
|
|
200
|
-
if (canReply && commentCount(state) >= limit) break
|
|
207
|
+
if (canReply && !ignoreQuota && commentCount(state) >= limit) break
|
|
201
208
|
result.checked += 1
|
|
202
209
|
let entry
|
|
203
210
|
try {
|
|
@@ -474,6 +481,50 @@ export function apply(ctx, rawConfig = {}) {
|
|
|
474
481
|
}
|
|
475
482
|
}
|
|
476
483
|
|
|
484
|
+
const checkNow = async () => {
|
|
485
|
+
if (running) return { skipped: 'busy' }
|
|
486
|
+
running = true
|
|
487
|
+
try {
|
|
488
|
+
log('[foxy-weibo] 开始立即检查')
|
|
489
|
+
const result = await scanOwnComments(ctx, config, state, log, true, {
|
|
490
|
+
previewOnly: true,
|
|
491
|
+
mode: 'own-comments-check',
|
|
492
|
+
})
|
|
493
|
+
saveState(state)
|
|
494
|
+
log(`[foxy-weibo] 立即检查结束 ${JSON.stringify(result)}`)
|
|
495
|
+
return result
|
|
496
|
+
} catch (error) {
|
|
497
|
+
saveState(state)
|
|
498
|
+
ctx.logger?.warn?.(`[foxy-weibo] check failed: ${error?.message || error}`)
|
|
499
|
+
return { error: String(error?.message || error) }
|
|
500
|
+
} finally {
|
|
501
|
+
running = false
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const replyNow = async (cid = '') => {
|
|
506
|
+
if (running) return { skipped: 'busy' }
|
|
507
|
+
running = true
|
|
508
|
+
try {
|
|
509
|
+
log(`[foxy-weibo] 开始立即回复${cid ? ` cid=${cid}` : ''}`)
|
|
510
|
+
const result = await scanOwnComments(ctx, config, state, log, true, {
|
|
511
|
+
forceReply: true,
|
|
512
|
+
maxReplies: 1,
|
|
513
|
+
cid,
|
|
514
|
+
mode: 'own-comments-reply-now',
|
|
515
|
+
})
|
|
516
|
+
saveState(state)
|
|
517
|
+
log(`[foxy-weibo] 立即回复结束 ${JSON.stringify(result)}`)
|
|
518
|
+
return result
|
|
519
|
+
} catch (error) {
|
|
520
|
+
saveState(state)
|
|
521
|
+
ctx.logger?.warn?.(`[foxy-weibo] reply-now failed: ${error?.message || error}`)
|
|
522
|
+
return { error: String(error?.message || error) }
|
|
523
|
+
} finally {
|
|
524
|
+
running = false
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
477
528
|
const status = () => ({
|
|
478
529
|
enabled: config.enabled === true,
|
|
479
530
|
running,
|
|
@@ -598,6 +649,17 @@ export function apply(ctx, rawConfig = {}) {
|
|
|
598
649
|
const result = await run('manual', true)
|
|
599
650
|
return json({ ok: true, result, status: status() })
|
|
600
651
|
})
|
|
652
|
+
|
|
653
|
+
route(CHECK_NOW_ROUTE, ['POST'], async () => {
|
|
654
|
+
const result = await checkNow()
|
|
655
|
+
return json({ ok: true, result, status: status() })
|
|
656
|
+
})
|
|
657
|
+
|
|
658
|
+
route(REPLY_NOW_ROUTE, ['POST'], async (request) => {
|
|
659
|
+
const body = await readJsonBody(request)
|
|
660
|
+
const result = await replyNow(body?.cid)
|
|
661
|
+
return json({ ok: true, result, status: status() })
|
|
662
|
+
})
|
|
601
663
|
})
|
|
602
664
|
|
|
603
665
|
log(
|
package/package.json
CHANGED