dsh-foxy-weibo 0.2.1 → 0.2.3
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 +3 -3
- package/cordis.patch.yml +1 -1
- package/lib/client.js +24 -12
- package/lib/index.js +23 -9
- package/lib/settings.js +5 -3
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Foxy 的微博子插件:按 foxy3 预设关注微博账号、阅读博文、
|
|
|
6
6
|
|
|
7
7
|
## 功能
|
|
8
8
|
|
|
9
|
-
-
|
|
9
|
+
- **博文评论回复**:检查指定的监控账号 UID,读取其新博文下的评论,只回复未处理的他人评论;登录账号是机器人自己,监控账号通常是主人账号;
|
|
10
10
|
- 可设置每日检查时间(`HH:MM`,最多 6 个),例如 `08:30, 20:00`;
|
|
11
11
|
- 回复前按 foxy3 预设判断 `skip / comment`,不设最少字数,最多 80 字;
|
|
12
12
|
- 旧模式保留:关注一个或多个微博 UID,定时读取时间线并评论;
|
|
@@ -47,7 +47,7 @@ Cookie 只保存在本机 `~/.dsh/foxy-weibo/settings.json`,不会回传给前
|
|
|
47
47
|
|
|
48
48
|
### 自己的 UID / 关注 UID
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
`监控账号 UID` 是要检查博文评论的目标账号(通常是主人账号);`当前账号` 是扫码登录的机器人账号,两者可以不同。
|
|
51
51
|
|
|
52
52
|
`关注 UID` 是旧模式使用,多个 UID 用逗号分隔,最多 20 个。UID 是微博用户主页 URL 里的数字 ID,例如 `https://weibo.com/u/1234567890`。
|
|
53
53
|
|
|
@@ -63,7 +63,7 @@ Cookie 只保存在本机 `~/.dsh/foxy-weibo/settings.json`,不会回传给前
|
|
|
63
63
|
|
|
64
64
|
## 建议顺序
|
|
65
65
|
|
|
66
|
-
1.
|
|
66
|
+
1. 扫码登录,填监控账号 UID,`enabled: true`、`replyMode: off`;
|
|
67
67
|
2. 设置每日检查时间,或先点「立即运行」,看日志和「调试」里的模型决策;
|
|
68
68
|
3. 确认判断正常后,再开启 `replyMode: auto`,每日上限先设为 1;
|
|
69
69
|
4. 「立即检查」只判断不发布,用来预览回复;「立即回复」会真实发布一条,适合测试;
|
package/cordis.patch.yml
CHANGED
package/lib/client.js
CHANGED
|
@@ -213,13 +213,17 @@ window.__ModuleLoader__.load({
|
|
|
213
213
|
const data = await request('/run', { method: 'POST', body: '{}' })
|
|
214
214
|
setStatus(data.status)
|
|
215
215
|
const result = data.result || {}
|
|
216
|
+
if (result.error) {
|
|
217
|
+
setError(`检查失败:${result.error}`)
|
|
218
|
+
return
|
|
219
|
+
}
|
|
216
220
|
setNotice(
|
|
217
221
|
result.skipped === 'disabled'
|
|
218
222
|
? '未开始:自动浏览已关闭'
|
|
219
223
|
: result.skipped === 'busy'
|
|
220
224
|
? '正在运行,请稍候'
|
|
221
|
-
: result.skipped === 'no-
|
|
222
|
-
? '
|
|
225
|
+
: result.skipped === 'no-target'
|
|
226
|
+
? '未开始:请先填写监控账号 UID'
|
|
223
227
|
: `运行完成:检查 ${result.checked || 0} 条,回复 ${result.replied || 0} 条` +
|
|
224
228
|
(result.previewed ? `,预览 ${result.previewed} 条` : '') +
|
|
225
229
|
`,跳过 ${result.skipped || 0} 条`,
|
|
@@ -233,9 +237,13 @@ window.__ModuleLoader__.load({
|
|
|
233
237
|
const data = await request('/check-now', { method: 'POST', body: '{}' })
|
|
234
238
|
setStatus(data.status)
|
|
235
239
|
const result = data.result || {}
|
|
240
|
+
if (result.error) {
|
|
241
|
+
setError(`检查失败:${result.error}`)
|
|
242
|
+
return
|
|
243
|
+
}
|
|
236
244
|
setNotice(
|
|
237
|
-
result.skipped === 'no-
|
|
238
|
-
? '
|
|
245
|
+
result.skipped === 'no-target'
|
|
246
|
+
? '未开始:请先填写监控账号 UID'
|
|
239
247
|
: result.skipped === 'busy'
|
|
240
248
|
? '正在运行,请稍候'
|
|
241
249
|
: `检查完成:检查 ${result.checked || 0} 条评论,预览 ${result.previewed || 0} 条,跳过 ${result.skipped || 0} 条` +
|
|
@@ -251,11 +259,15 @@ window.__ModuleLoader__.load({
|
|
|
251
259
|
const data = await request('/reply-now', { method: 'POST', body: '{}' })
|
|
252
260
|
setStatus(data.status)
|
|
253
261
|
const result = data.result || {}
|
|
262
|
+
if (result.error) {
|
|
263
|
+
setError(`回复失败:${result.error}`)
|
|
264
|
+
return
|
|
265
|
+
}
|
|
254
266
|
setNotice(
|
|
255
267
|
result.replied > 0
|
|
256
268
|
? `已立即回复 ${result.replied} 条,可在下方日志查看`
|
|
257
|
-
: result.skipped === 'no-
|
|
258
|
-
? '
|
|
269
|
+
: result.skipped === 'no-target'
|
|
270
|
+
? '未开始:请先填写监控账号 UID'
|
|
259
271
|
: '没有可立即回复的评论(可能已处理或模型选择跳过)',
|
|
260
272
|
)
|
|
261
273
|
} catch (e) { setError(e.message) } finally { setBusy('') }
|
|
@@ -272,7 +284,7 @@ window.__ModuleLoader__.load({
|
|
|
272
284
|
h('div', { className: 'fw-head' },
|
|
273
285
|
h('div', null,
|
|
274
286
|
h('p', { className: 'fw-eyebrow' }, 'FOXY EXTENSION'),
|
|
275
|
-
h('h1', null, '
|
|
287
|
+
h('h1', null, '微博评论'),
|
|
276
288
|
h('p', null, 'Foxy 按 foxy3 预设关注微博账号,阅读、判断、评论并写入记忆。'),
|
|
277
289
|
),
|
|
278
290
|
h('span', { className: 'fw-badge' }, settings.enabled ? '自动浏览已开启' : '自动浏览已关闭'),
|
|
@@ -284,8 +296,8 @@ window.__ModuleLoader__.load({
|
|
|
284
296
|
h(Field, { label: '当前账号', hint: '扫码成功后自动显示' },
|
|
285
297
|
h('input', { value: settings.accountName ? `${settings.accountName}(${settings.accountUid || '?'})` : settings.cookieSet ? '已登录' : '未登录', readOnly: true }),
|
|
286
298
|
),
|
|
287
|
-
h(Field, { label: '
|
|
288
|
-
h('input', { value: settings.
|
|
299
|
+
h(Field, { label: '监控账号 UID', hint: '要检查博文评论的目标账号;不是登录的机器人账号' },
|
|
300
|
+
h('input', { value: settings.targetUid || '', placeholder: '例如 1234567890', onChange: (e) => setField('targetUid', e.target.value) })),
|
|
289
301
|
),
|
|
290
302
|
h('div', { className: 'fw-actions' },
|
|
291
303
|
h('button', { className: 'fw-btn primary', disabled: !!busy, onClick: startLogin }, busy === 'login' ? '获取二维码…' : qr ? '刷新二维码' : '扫码登录'),
|
|
@@ -314,9 +326,9 @@ window.__ModuleLoader__.load({
|
|
|
314
326
|
),
|
|
315
327
|
|
|
316
328
|
h('section', { className: 'fw-card' },
|
|
317
|
-
h(SectionHead, { title: '
|
|
329
|
+
h(SectionHead, { title: '博文评论回复', description: '每日按设定时间检查目标账号的新博文,并回复其评论区中尚未处理的他人评论。' }),
|
|
318
330
|
h(Toggle, { checked: settings.enabled, onChange: (v) => setField('enabled', v), label: '启用自动检查', hint: '关闭后定时任务不运行,仍可使用「立即运行」。' }),
|
|
319
|
-
h(Toggle, { checked: settings.replyOwnPosts, onChange: (v) => setField('replyOwnPosts', v), label: '
|
|
331
|
+
h(Toggle, { checked: settings.replyOwnPosts, onChange: (v) => setField('replyOwnPosts', v), label: '仅监控目标账号的博文', hint: '关闭后回到旧模式,浏览关注账号的时间线并评论博文。' }),
|
|
320
332
|
h('div', { className: 'fw-grid' },
|
|
321
333
|
h(Field, { label: '每日检查时间', hint: 'HH:MM,多个用逗号分隔,最多 6 个,例如 08:30, 20:00' },
|
|
322
334
|
h('input', { value: scheduleText, placeholder: '20:00', onChange: (e) => setScheduleText(e.target.value) })),
|
|
@@ -331,7 +343,7 @@ window.__ModuleLoader__.load({
|
|
|
331
343
|
h('input', { type: 'number', min: 0, max: 10, value: settings.maxCommentsPerDay, onChange: (e) => setField('maxCommentsPerDay', e.target.value) })),
|
|
332
344
|
),
|
|
333
345
|
h('div', { className: 'fw-grid' },
|
|
334
|
-
h(Field, { label: '时间线轮询(旧模式备用)', hint: '
|
|
346
|
+
h(Field, { label: '时间线轮询(旧模式备用)', hint: '关闭“仅监控目标账号的博文”时使用,分钟' },
|
|
335
347
|
h('input', { type: 'number', min: 5, max: 1440, value: settings.intervalMinutes, onChange: (e) => setField('intervalMinutes', e.target.value) })),
|
|
336
348
|
h(Field, { label: '旧模式评论模式', hint: '浏览他人博文时是否发一级评论' },
|
|
337
349
|
h('select', { value: settings.commentMode, onChange: (e) => setField('commentMode', e.target.value) },
|
package/lib/index.js
CHANGED
|
@@ -164,11 +164,6 @@ async function scanOwnComments(ctx, config, state, log, force = false, options =
|
|
|
164
164
|
const forceReply = options.forceReply === true
|
|
165
165
|
const canReply = !previewOnly && (forceReply || config.replyMode === 'auto')
|
|
166
166
|
const targetCid = String(options.cid || '').trim()
|
|
167
|
-
const selfUid = String(config.selfUid || config.accountUid || '').trim()
|
|
168
|
-
if (!selfUid) return { skipped: 'no-self' }
|
|
169
|
-
const maxPosts = Math.max(1, Math.min(20, Number(config.maxPostsPerRun) || 5))
|
|
170
|
-
const maxReplies = Math.max(1, Math.min(8, Number(options.maxReplies ?? config.maxCommentsPerDay) || 1))
|
|
171
|
-
const ignoreQuota = forceReply
|
|
172
167
|
const result = {
|
|
173
168
|
mode: options.mode || 'own-comments',
|
|
174
169
|
checked: 0,
|
|
@@ -178,9 +173,28 @@ async function scanOwnComments(ctx, config, state, log, force = false, options =
|
|
|
178
173
|
errors: 0,
|
|
179
174
|
items: [],
|
|
180
175
|
}
|
|
176
|
+
const targetUid = String(config.targetUid || '').trim()
|
|
177
|
+
if (!targetUid) return { skipped: 'no-target' }
|
|
178
|
+
let loginUid = String(config.accountUid || '').trim()
|
|
179
|
+
if (config.cookie) {
|
|
180
|
+
const account = await fetchAccount(config.cookie)
|
|
181
|
+
if (!account.uid) {
|
|
182
|
+
return {
|
|
183
|
+
...result,
|
|
184
|
+
errors: 1,
|
|
185
|
+
error: '微博登录态无效,请重新扫码登录后再检查',
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (!loginUid) loginUid = account.uid
|
|
189
|
+
} else {
|
|
190
|
+
return { ...result, errors: 1, error: '请先扫码登录微博账号' }
|
|
191
|
+
}
|
|
192
|
+
const maxPosts = Math.max(1, Math.min(20, Number(config.maxPostsPerRun) || 5))
|
|
193
|
+
const maxReplies = Math.max(1, Math.min(8, Number(options.maxReplies ?? config.maxCommentsPerDay) || 1))
|
|
194
|
+
const ignoreQuota = forceReply
|
|
181
195
|
let posts = []
|
|
182
196
|
try {
|
|
183
|
-
posts = await fetchTimeline(
|
|
197
|
+
posts = await fetchTimeline(targetUid, config)
|
|
184
198
|
} catch (error) {
|
|
185
199
|
return { ...result, errors: 1, error: error?.message || String(error) }
|
|
186
200
|
}
|
|
@@ -199,7 +213,7 @@ async function scanOwnComments(ctx, config, state, log, force = false, options =
|
|
|
199
213
|
if (targetCid && String(comment.cid) !== targetCid) continue
|
|
200
214
|
if (canReply && result.replied >= maxReplies) break
|
|
201
215
|
if (!comment.cid || state.commentSeen[comment.cid]) continue
|
|
202
|
-
if (String(comment.author?.uid || '') ===
|
|
216
|
+
if (loginUid && String(comment.author?.uid || '') === loginUid) {
|
|
203
217
|
state.commentSeen[comment.cid] = { at: Date.now(), status: 'self' }
|
|
204
218
|
continue
|
|
205
219
|
}
|
|
@@ -529,7 +543,8 @@ export function apply(ctx, rawConfig = {}) {
|
|
|
529
543
|
enabled: config.enabled === true,
|
|
530
544
|
running,
|
|
531
545
|
mode: config.replyOwnPosts === false ? 'timeline' : 'own-comments',
|
|
532
|
-
|
|
546
|
+
targetUid: config.targetUid || '',
|
|
547
|
+
loginUid: config.accountUid || '',
|
|
533
548
|
scheduleTimes: config.scheduleTimes,
|
|
534
549
|
nextRunAt,
|
|
535
550
|
replyMode: config.replyMode,
|
|
@@ -631,7 +646,6 @@ export function apply(ctx, rawConfig = {}) {
|
|
|
631
646
|
config.cookie = result.cookie
|
|
632
647
|
config.accountName = result.account?.screenName || ''
|
|
633
648
|
config.accountUid = result.account?.uid || ''
|
|
634
|
-
if (!config.selfUid && result.account?.uid) config.selfUid = result.account.uid
|
|
635
649
|
saveSettings(config)
|
|
636
650
|
}
|
|
637
651
|
return json({ ok: true, ...result, settings: publicSettings(config), status: status() })
|
package/lib/settings.js
CHANGED
|
@@ -5,7 +5,7 @@ import { dirname, join } from 'node:path'
|
|
|
5
5
|
export const DEFAULTS = {
|
|
6
6
|
enabled: false,
|
|
7
7
|
cookie: '',
|
|
8
|
-
|
|
8
|
+
targetUid: '',
|
|
9
9
|
targetUids: [],
|
|
10
10
|
replyOwnPosts: true,
|
|
11
11
|
replyMode: 'off', // off | auto
|
|
@@ -26,7 +26,7 @@ export const DEFAULTS = {
|
|
|
26
26
|
|
|
27
27
|
export const SETTING_KEYS = [
|
|
28
28
|
'enabled',
|
|
29
|
-
'
|
|
29
|
+
'targetUid',
|
|
30
30
|
'targetUids',
|
|
31
31
|
'replyOwnPosts',
|
|
32
32
|
'replyMode',
|
|
@@ -45,7 +45,7 @@ export const SETTING_KEYS = [
|
|
|
45
45
|
]
|
|
46
46
|
|
|
47
47
|
const TEXT_KEYS = new Set([
|
|
48
|
-
'
|
|
48
|
+
'targetUid',
|
|
49
49
|
'commentMode',
|
|
50
50
|
'replyMode',
|
|
51
51
|
'memoryPresetId',
|
|
@@ -137,6 +137,8 @@ export function loadSettings(base = {}) {
|
|
|
137
137
|
if (existsSync(settingsPath())) {
|
|
138
138
|
const parsed = JSON.parse(readFileSync(settingsPath(), 'utf8'))
|
|
139
139
|
next = normalizePatch(next, parsed)
|
|
140
|
+
// 0.2.x used selfUid for the monitored account; migrate it once.
|
|
141
|
+
if (!next.targetUid && typeof parsed.selfUid === 'string') next.targetUid = parsed.selfUid.trim()
|
|
140
142
|
if (typeof parsed.cookie === 'string') next.cookie = parsed.cookie
|
|
141
143
|
if (typeof parsed.llmApiKey === 'string') next.llmApiKey = parsed.llmApiKey
|
|
142
144
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-foxy-weibo",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Foxy's Weibo transport for DeepSeek Harness: follow users, read posts, comment, reply, and remember events.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -48,3 +48,4 @@
|
|
|
48
48
|
"test": "node test/test-weibo.cjs && node test/test-client.cjs"
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
+
|