fix: 修复语音首播并完善消息解析与会话兼容性

(cherry picked from commit 214090192f5dfc91cdec0269bad434d3e22394d8)
This commit is contained in:
电摇小子
2026-08-03 10:04:45 +08:00
committed by Wxw-Gu
parent ee7dc11e92
commit b4f909a597
18 changed files with 846 additions and 206 deletions
+55
View File
@@ -0,0 +1,55 @@
export type StickerFailureCode =
| 'link_expired'
| 'authentication_required'
| 'access_denied'
| 'resource_removed'
| 'rate_limited'
| 'http_error'
export interface StickerHttpFailure {
code: StickerFailureCode
message: string
}
export function classifyStickerHttpFailure(
statusCode: number,
url: string,
now = Date.now()
): StickerHttpFailure {
if (statusCode === 401) {
return { code: 'authentication_required', message: '表情链接需要微信授权' }
}
if (statusCode === 403) {
const expiresAt = readExpiryTimestamp(url)
if (expiresAt !== undefined && expiresAt <= now) {
return { code: 'link_expired', message: '表情链接已过期' }
}
return { code: 'access_denied', message: '表情链接已失效或需要微信授权' }
}
if (statusCode === 404 || statusCode === 410) {
return { code: 'resource_removed', message: '表情资源已删除或失效' }
}
if (statusCode === 429) {
return { code: 'rate_limited', message: '表情下载请求过于频繁' }
}
return { code: 'http_error', message: `表情包下载失败: HTTP ${statusCode}` }
}
function readExpiryTimestamp(value: string): number | undefined {
try {
const url = new URL(value)
for (const key of ['expire', 'expires', 'expiry', 'deadline']) {
const raw = url.searchParams.get(key)
if (!raw) continue
const numeric = Number(raw)
if (Number.isFinite(numeric) && numeric > 0) {
return numeric > 10_000_000_000 ? numeric : numeric * 1000
}
const parsed = Date.parse(raw)
if (Number.isFinite(parsed)) return parsed
}
} catch {
// Invalid URLs have no trustworthy expiry metadata.
}
return undefined
}
+17 -1
View File
@@ -6,6 +6,8 @@ export interface Contact {
avatar?: string
wechatNickname?: string
remark?: string
isFolded?: boolean
isMuted?: boolean
}
export interface Message {
@@ -53,6 +55,19 @@ type ShareContent = {
appname?: string
typeVal?: string
}
export type ForwardedMessageItem = {
messageType: number
sender?: string
sentAt?: string
text: string
nested?: ForwardedMessageItem[]
}
type ForwardBundleContent = {
type: 'forwardBundle'
title: string
description?: string
items: ForwardedMessageItem[]
}
type MiniProgramContent = {
type: 'miniProgram'
title: string
@@ -119,7 +134,7 @@ type SystemContent = {
recallTime?: number
}
}
type UnknownContent = { type: 'unknown'; raw: string }
type UnknownContent = { type: 'unknown'; raw: string; messageType?: string | number }
export type ParsedContent =
| TextContent
@@ -127,6 +142,7 @@ export type ParsedContent =
| LocationContent
| CardContent
| ShareContent
| ForwardBundleContent
| MiniProgramContent
| RedPacketContent
| VoipContent