Merge pull request #26 from Jasonzhu1207/fix/insight-social-context-runtime-and-cookie-optional

fix: no-cookie Weibo context + social prompt copy refinements
This commit is contained in:
Jason
2026-04-14 00:12:19 +08:00
committed by GitHub
3 changed files with 70 additions and 17 deletions

View File

@@ -809,7 +809,7 @@ ${topMentionText}
if (!allowSocialContext) return ''
const rawCookie = String(this.config.get('aiInsightWeiboCookie') || '').trim()
if (!rawCookie) return ''
const hasCookie = rawCookie.length > 0
const bindings =
(this.config.get('aiInsightWeiboBindings') as Record<string, { uid?: string; screenName?: string }> | undefined) || {}
@@ -830,7 +830,10 @@ ${topMentionText}
return `[微博 ${time}] ${text}`
})
insightLog('INFO', `已加载 ${lines.length} 条微博公开内容 (uid=${uid})`)
return `近期公开社交平台内容(实验性,来源:微博,最近 ${lines.length} 条):\n${lines.join('\n')}`
const riskHint = hasCookie
? ''
: '\n提示未配置微博 Cookie使用移动端公开接口抓取可能因平台风控导致获取失败或内容较少。'
return `近期公开社交平台内容(来源:微博,最近 ${lines.length} 条):\n${lines.join('\n')}${riskHint}`
} catch (error) {
insightLog('WARN', `拉取微博公开内容失败 (uid=${uid}): ${(error as Error).message}`)
return ''

View File

@@ -7,6 +7,8 @@ const WEIBO_MAX_POSTS = 5
const WEIBO_CACHE_TTL_MS = 30 * 60 * 1000
const WEIBO_USER_AGENT =
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
const WEIBO_MOBILE_USER_AGENT =
'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1'
interface BrowserCookieEntry {
domain?: string
@@ -48,6 +50,18 @@ interface WeiboStatusShowResponse {
retweeted_status?: WeiboWaterFallItem
}
interface MWeiboCard {
mblog?: WeiboWaterFallItem
card_group?: MWeiboCard[]
}
interface MWeiboContainerResponse {
ok?: number
data?: {
cards?: MWeiboCard[]
}
}
export interface WeiboRecentPost {
id: string
createdAt: string
@@ -61,7 +75,7 @@ interface CachedRecentPosts {
posts: WeiboRecentPost[]
}
function requestJson<T>(url: string, options: { cookie: string; referer?: string }): Promise<T> {
function requestJson<T>(url: string, options: { cookie?: string; referer?: string; userAgent?: string }): Promise<T> {
return new Promise((resolve, reject) => {
let urlObj: URL
try {
@@ -71,19 +85,23 @@ function requestJson<T>(url: string, options: { cookie: string; referer?: string
return
}
const headers: Record<string, string> = {
Accept: 'application/json, text/plain, */*',
Referer: options.referer || 'https://weibo.com',
'User-Agent': options.userAgent || WEIBO_USER_AGENT,
'X-Requested-With': 'XMLHttpRequest'
}
if (options.cookie) {
headers.Cookie = options.cookie
}
const req = https.request(
{
hostname: urlObj.hostname,
port: urlObj.port || 443,
path: urlObj.pathname + urlObj.search,
method: 'GET',
headers: {
Accept: 'application/json, text/plain, */*',
Referer: options.referer || 'https://weibo.com',
'User-Agent': WEIBO_USER_AGENT,
'X-Requested-With': 'XMLHttpRequest',
Cookie: options.cookie
}
headers
},
(res) => {
let raw = ''
@@ -232,10 +250,10 @@ class WeiboService {
): Promise<WeiboRecentPost[]> {
const uid = normalizeWeiboUid(uidInput)
const cookie = normalizeWeiboCookieInput(cookieInput)
if (!cookie) return []
const hasCookie = Boolean(cookie)
const count = Math.max(1, Math.min(WEIBO_MAX_POSTS, Math.floor(Number(requestedCount) || 0)))
const cacheKey = buildCacheKey(uid, count, cookie)
const cacheKey = buildCacheKey(uid, count, hasCookie ? cookie : '__no_cookie_mobile__')
const cached = this.recentPostsCache.get(cacheKey)
const now = Date.now()
@@ -243,8 +261,9 @@ class WeiboService {
return cached.posts
}
const timeline = await this.fetchTimeline(uid, cookie)
const rawItems = Array.isArray(timeline.data?.list) ? timeline.data.list : []
const rawItems = hasCookie
? (await this.fetchTimeline(uid, cookie)).data?.list || []
: await this.fetchMobileTimeline(uid)
const posts: WeiboRecentPost[] = []
for (const item of rawItems) {
@@ -254,7 +273,7 @@ class WeiboService {
if (!id) continue
let text = mergeRetweetText(item)
if (item.isLongText) {
if (item.isLongText && hasCookie) {
try {
const detail = await this.fetchDetail(id, cookie)
text = mergeRetweetText(detail)
@@ -298,6 +317,37 @@ class WeiboService {
})
}
private fetchMobileTimeline(uid: string): Promise<WeiboWaterFallItem[]> {
const containerid = `107603${uid}`
return requestJson<MWeiboContainerResponse>(
`https://m.weibo.cn/api/container/getIndex?type=uid&value=${encodeURIComponent(uid)}&containerid=${encodeURIComponent(containerid)}`,
{
referer: `https://m.weibo.cn/u/${encodeURIComponent(uid)}`,
userAgent: WEIBO_MOBILE_USER_AGENT
}
).then((response) => {
if (response.ok !== 1 || !Array.isArray(response.data?.cards)) {
throw new Error('微博时间线获取失败,请稍后重试')
}
const rows: WeiboWaterFallItem[] = []
for (const card of response.data.cards) {
if (card?.mblog) rows.push(card.mblog)
if (Array.isArray(card?.card_group)) {
for (const subCard of card.card_group) {
if (subCard?.mblog) rows.push(subCard.mblog)
}
}
}
if (rows.length === 0) {
throw new Error('该微博账号暂无可读取的近期公开内容')
}
return rows
})
}
private fetchDetail(id: string, cookie: string): Promise<WeiboStatusShowResponse> {
return requestJson<WeiboStatusShowResponse>(
`https://weibo.com/ajax/statuses/show?id=${encodeURIComponent(id)}&isGetLongText=true`,

View File

@@ -3220,7 +3220,7 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
</div>
{!hasWeiboCookieConfigured && (
<span className="form-hint" style={{ marginTop: 8, display: 'block' }}>
Cookie
Cookie
</span>
)}
</div>
@@ -4625,7 +4625,7 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
</button>
<button className="btn btn-primary" onClick={() => { void handleCloseWeiboCookieModal() }} disabled={isSavingWeiboCookie}>
{isSavingWeiboCookie ? '保存中...' : '关闭'}
{isSavingWeiboCookie ? '保存中...' : '关闭并保存'}
</button>
</div>
</div>