dsh-foxy-weibo 0.2.3 → 0.2.4
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/client.js +7 -5
- package/lib/index.js +9 -2
- package/lib/settings.js +1 -1
- package/lib/weibo.js +61 -30
- package/package.json +2 -1
package/lib/client.js
CHANGED
|
@@ -224,7 +224,8 @@ window.__ModuleLoader__.load({
|
|
|
224
224
|
? '正在运行,请稍候'
|
|
225
225
|
: result.skipped === 'no-target'
|
|
226
226
|
? '未开始:请先填写监控账号 UID'
|
|
227
|
-
:
|
|
227
|
+
: `运行完成:博文 ${result.posts || 0} 篇、评论 ${result.comments || 0} 条,` +
|
|
228
|
+
`处理 ${result.checked || 0} 条,回复 ${result.replied || 0} 条` +
|
|
228
229
|
(result.previewed ? `,预览 ${result.previewed} 条` : '') +
|
|
229
230
|
`,跳过 ${result.skipped || 0} 条`,
|
|
230
231
|
)
|
|
@@ -246,7 +247,8 @@ window.__ModuleLoader__.load({
|
|
|
246
247
|
? '未开始:请先填写监控账号 UID'
|
|
247
248
|
: result.skipped === 'busy'
|
|
248
249
|
? '正在运行,请稍候'
|
|
249
|
-
:
|
|
250
|
+
: `检查完成:博文 ${result.posts || 0} 篇、评论 ${result.comments || 0} 条,` +
|
|
251
|
+
`待处理 ${result.checked || 0} 条,预览 ${result.previewed || 0} 条,跳过 ${result.skipped || 0} 条` +
|
|
250
252
|
(result.errors ? `,失败 ${result.errors} 条` : ''),
|
|
251
253
|
)
|
|
252
254
|
} catch (e) { setError(e.message) } finally { setBusy('') }
|
|
@@ -268,7 +270,7 @@ window.__ModuleLoader__.load({
|
|
|
268
270
|
? `已立即回复 ${result.replied} 条,可在下方日志查看`
|
|
269
271
|
: result.skipped === 'no-target'
|
|
270
272
|
? '未开始:请先填写监控账号 UID'
|
|
271
|
-
:
|
|
273
|
+
: `已浏览 ${result.posts || 0} 篇博文、${result.comments || 0} 条评论,但没有可立即回复的新评论(可能已处理或模型选择跳过)`,
|
|
272
274
|
)
|
|
273
275
|
} catch (e) { setError(e.message) } finally { setBusy('') }
|
|
274
276
|
}
|
|
@@ -337,8 +339,8 @@ window.__ModuleLoader__.load({
|
|
|
337
339
|
h('option', { value: 'off' }, '仅检查,不回复'),
|
|
338
340
|
h('option', { value: 'auto' }, '自动回复'),
|
|
339
341
|
)),
|
|
340
|
-
h(Field, { label: '
|
|
341
|
-
h('input', { type: 'number', min: 1, max:
|
|
342
|
+
h(Field, { label: '浏览范围(博文条数)', hint: '按时间倒序检查;1–100,填 100 即尽量浏览全部' },
|
|
343
|
+
h('input', { type: 'number', min: 1, max: 100, value: settings.maxPostsPerRun, onChange: (e) => setField('maxPostsPerRun', e.target.value) })),
|
|
342
344
|
h(Field, { label: '每日回复上限', hint: '0–10,同时限制评论' },
|
|
343
345
|
h('input', { type: 'number', min: 0, max: 10, value: settings.maxCommentsPerDay, onChange: (e) => setField('maxCommentsPerDay', e.target.value) })),
|
|
344
346
|
),
|
package/lib/index.js
CHANGED
|
@@ -171,6 +171,8 @@ async function scanOwnComments(ctx, config, state, log, force = false, options =
|
|
|
171
171
|
previewed: 0,
|
|
172
172
|
skipped: 0,
|
|
173
173
|
errors: 0,
|
|
174
|
+
posts: 0,
|
|
175
|
+
comments: 0,
|
|
174
176
|
items: [],
|
|
175
177
|
}
|
|
176
178
|
const targetUid = String(config.targetUid || '').trim()
|
|
@@ -189,12 +191,16 @@ async function scanOwnComments(ctx, config, state, log, force = false, options =
|
|
|
189
191
|
} else {
|
|
190
192
|
return { ...result, errors: 1, error: '请先扫码登录微博账号' }
|
|
191
193
|
}
|
|
192
|
-
const maxPosts = Math.max(1, Math.min(
|
|
194
|
+
const maxPosts = Math.max(1, Math.min(100, Number(config.maxPostsPerRun) || 5))
|
|
193
195
|
const maxReplies = Math.max(1, Math.min(8, Number(options.maxReplies ?? config.maxCommentsPerDay) || 1))
|
|
194
196
|
const ignoreQuota = forceReply
|
|
195
197
|
let posts = []
|
|
196
198
|
try {
|
|
197
|
-
posts = await fetchTimeline(targetUid, config
|
|
199
|
+
posts = await fetchTimeline(targetUid, config, {
|
|
200
|
+
maxPosts,
|
|
201
|
+
maxPages: Math.ceil(maxPosts / 10) + 1,
|
|
202
|
+
})
|
|
203
|
+
result.posts = posts.length
|
|
198
204
|
} catch (error) {
|
|
199
205
|
return { ...result, errors: 1, error: error?.message || String(error) }
|
|
200
206
|
}
|
|
@@ -209,6 +215,7 @@ async function scanOwnComments(ctx, config, state, log, force = false, options =
|
|
|
209
215
|
log(`[foxy-weibo] 读取评论失败 ${post.id}:${error?.message || error}`)
|
|
210
216
|
continue
|
|
211
217
|
}
|
|
218
|
+
result.comments += comments.length
|
|
212
219
|
for (const comment of comments) {
|
|
213
220
|
if (targetCid && String(comment.cid) !== targetCid) continue
|
|
214
221
|
if (canReply && result.replied >= maxReplies) break
|
package/lib/settings.js
CHANGED
|
@@ -97,7 +97,7 @@ function clampNumber(key, value, fallback) {
|
|
|
97
97
|
const n = Number(value)
|
|
98
98
|
if (!Number.isFinite(n)) return fallback
|
|
99
99
|
if (key === 'intervalMinutes') return Math.max(5, Math.min(24 * 60, Math.round(n)))
|
|
100
|
-
if (key === 'maxPostsPerRun') return Math.max(1, Math.min(
|
|
100
|
+
if (key === 'maxPostsPerRun') return Math.max(1, Math.min(100, Math.round(n)))
|
|
101
101
|
if (key === 'maxCommentsPerDay') return Math.max(0, Math.min(10, Math.round(n)))
|
|
102
102
|
return n
|
|
103
103
|
}
|
package/lib/weibo.js
CHANGED
|
@@ -100,11 +100,11 @@ export function normalizePost(raw) {
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
async function fetchWebTimeline(uid, config = {}) {
|
|
103
|
+
async function fetchWebTimeline(uid, config = {}, page = 1) {
|
|
104
104
|
const target = String(uid || '').trim()
|
|
105
105
|
const url =
|
|
106
106
|
`https://weibo.com/ajax/statuses/mymblog?uid=${encodeURIComponent(target)}` +
|
|
107
|
-
`&page
|
|
107
|
+
`&page=${Math.max(1, page)}&feature=0`
|
|
108
108
|
const response = await fetch(url, { headers: headersFor(config, false) })
|
|
109
109
|
if (!response.ok) throw new WeiboError(`读取微博失败:HTTP ${response.status}`, 'HTTP')
|
|
110
110
|
const text = await response.text()
|
|
@@ -122,39 +122,70 @@ async function fetchWebTimeline(uid, config = {}) {
|
|
|
122
122
|
return list.map(normalizePost).filter((post) => post.id && post.text)
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
function uniquePosts(posts) {
|
|
126
|
+
const seen = new Set()
|
|
127
|
+
const out = []
|
|
128
|
+
for (const post of posts) {
|
|
129
|
+
const key = post.id || post.mid
|
|
130
|
+
if (!key || seen.has(key)) continue
|
|
131
|
+
seen.add(key)
|
|
132
|
+
out.push(post)
|
|
133
|
+
}
|
|
134
|
+
return out
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export async function fetchTimeline(uid, config = {}, options = {}) {
|
|
126
138
|
const target = String(uid || '').trim()
|
|
127
139
|
if (!/^\d{5,20}$/.test(target)) throw new WeiboError('微博 UID 格式不正确', 'BAD_UID')
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
140
|
+
const maxPosts = Math.max(1, Math.min(100, Number(options.maxPosts) || 20))
|
|
141
|
+
const maxPages = Math.max(1, Math.min(20, Number(options.maxPages) || Math.ceil(maxPosts / 10) + 1))
|
|
142
|
+
const collected = []
|
|
143
|
+
|
|
144
|
+
for (let page = 1; page <= maxPages && collected.length < maxPosts; page += 1) {
|
|
145
|
+
const url =
|
|
146
|
+
`https://m.weibo.cn/api/container/getIndex?type=uid&value=${encodeURIComponent(target)}` +
|
|
147
|
+
`&containerid=107603${encodeURIComponent(target)}&page=${page}`
|
|
148
|
+
try {
|
|
149
|
+
const response = await fetch(url, { headers: headersFor(config, true) })
|
|
150
|
+
if (!response.ok) throw new WeiboError(`读取微博失败:HTTP ${response.status}`, 'HTTP')
|
|
151
|
+
const json = await readJson(response)
|
|
152
|
+
const cards = Array.isArray(json?.data?.cards) ? json.data.cards : []
|
|
153
|
+
const posts = uniquePosts(
|
|
154
|
+
cards
|
|
155
|
+
.filter((card) => card?.mblog)
|
|
156
|
+
.map((card) => normalizePost(card.mblog))
|
|
157
|
+
.filter((post) => post.id && post.text),
|
|
158
|
+
)
|
|
159
|
+
if (!posts.length) break
|
|
160
|
+
collected.push(...posts)
|
|
161
|
+
if (posts.length < 10) break
|
|
162
|
+
} catch (error) {
|
|
163
|
+
if (config.cookie) {
|
|
164
|
+
try {
|
|
165
|
+
const posts = uniquePosts(await fetchWebTimeline(target, config, page))
|
|
166
|
+
if (!posts.length) break
|
|
167
|
+
collected.push(...posts)
|
|
168
|
+
if (posts.length < 10) break
|
|
169
|
+
continue
|
|
170
|
+
} catch (webError) {
|
|
171
|
+
if (collected.length) break
|
|
172
|
+
throw new WeiboError(
|
|
173
|
+
`${error.message};备用接口也失败:${webError.message}`,
|
|
174
|
+
'FETCH_FAILED',
|
|
175
|
+
webError.detail,
|
|
176
|
+
)
|
|
177
|
+
}
|
|
150
178
|
}
|
|
179
|
+
if (collected.length) break
|
|
180
|
+
throw new WeiboError(
|
|
181
|
+
`${error.message};微博接口可能要求登录 Cookie(设置 → Foxy-weibo → 微博 Cookie)`,
|
|
182
|
+
'LOGIN_REQUIRED',
|
|
183
|
+
error.detail,
|
|
184
|
+
)
|
|
151
185
|
}
|
|
152
|
-
throw new WeiboError(
|
|
153
|
-
`${error.message};微博接口可能要求登录 Cookie(设置 → Foxy-weibo → 微博 Cookie)`,
|
|
154
|
-
'LOGIN_REQUIRED',
|
|
155
|
-
error.detail,
|
|
156
|
-
)
|
|
157
186
|
}
|
|
187
|
+
|
|
188
|
+
return uniquePosts(collected).slice(0, maxPosts)
|
|
158
189
|
}
|
|
159
190
|
|
|
160
191
|
function normalizeComment(raw) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-foxy-weibo",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
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",
|
|
@@ -49,3 +49,4 @@
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
|