@@ -1964,6 +1964,33 @@ const upgradeTencentHttps = (u) => {
19641964 return raw
19651965}
19661966
1967+ const normalizeHex32 = (value) => {
1968+ const raw = String(value ?? '').trim()
1969+ if (!raw) return ''
1970+ const hex = raw.replace(/[^0-9a-fA-F]/g, '').toLowerCase()
1971+ return hex.length >= 32 ? hex.slice(0, 32) : ''
1972+ }
1973+
1974+ const mediaSizeKey = (m) => {
1975+ const t = String(m?.type ?? '')
1976+ const w = String(m?.size?.width || m?.size?.w || '').trim()
1977+ const h = String(m?.size?.height || m?.size?.h || '').trim()
1978+ const total = String(m?.size?.totalSize || m?.size?.total_size || m?.size?.total || '').trim()
1979+ return `${t}:${w}:${h}:${total}`
1980+ }
1981+
1982+ const mediaSizeGroupIndex = (post, m, idx) => {
1983+ const list = Array.isArray(post?.media) ? post.media : []
1984+ const key = mediaSizeKey(m)
1985+ const i0 = Number(idx) || 0
1986+ if (!key || i0 <= 0) return i0
1987+ let count = 0
1988+ for (let i = 0; i < i0; i++) {
1989+ if (mediaSizeKey(list[i]) === key) count++
1990+ }
1991+ return count
1992+ }
1993+
19671994const getSnsMediaUrl = (post, m, idx, rawUrl) => {
19681995 const raw = upgradeTencentHttps(String(rawUrl || '').trim())
19691996 if (!raw) return ''
@@ -1980,12 +2007,37 @@ const getSnsMediaUrl = (post, m, idx, rawUrl) => {
19802007 const host = new URL(raw).hostname.toLowerCase()
19812008 if (host.endsWith('.qpic.cn') || host.endsWith('.qlogo.cn') || host.endsWith('.tc.qq.com')) {
19822009 const acc = String(selectedAccount.value || '').trim()
1983- // Match WeFlow's image pipeline: use a stable URL + key/token and let the
1984- // backend handle cache-first remote fetch/decrypt. Avoid attaching legacy
1985- // local-match metadata to the main image path so browser caching can reuse
1986- // the same request URL for list + preview.
2010+ const ct = String(post?.createTime || '').trim()
2011+ const w = String(m?.size?.width || m?.size?.w || '').trim()
2012+ const h = String(m?.size?.height || m?.size?.h || '').trim()
2013+ const ts = String(m?.size?.totalSize || m?.size?.total_size || m?.size?.total || '').trim()
2014+ const sizeIdx = mediaSizeGroupIndex(post, m, idx)
2015+ let md5 = normalizeHex32(m?.urlAttrs?.md5 || m?.thumbAttrs?.md5 || m?.urlAttrs?.MD5 || m?.thumbAttrs?.MD5)
2016+ if (!md5) {
2017+ const match = /[?&]md5=([0-9a-fA-F]{16,32})/.exec(raw)
2018+ if (match?.[1]) md5 = normalizeHex32(match[1])
2019+ }
2020+
19872021 const parts = new URLSearchParams()
19882022 if (acc) parts.set('account', acc)
2023+ if (ct) parts.set('create_time', ct)
2024+ if (w) parts.set('width', w)
2025+ if (h) parts.set('height', h)
2026+ if (/^\d+$/.test(ts)) parts.set('total_size', ts)
2027+ parts.set('idx', String(Number(sizeIdx) || 0))
2028+
2029+ const pid = String(post?.id || post?.tid || '').trim()
2030+ if (pid) parts.set('post_id', pid)
2031+
2032+ const mid = String(m?.id || '').trim()
2033+ if (mid) parts.set('media_id', mid)
2034+
2035+ const postType = String(post?.type || '1').trim()
2036+ if (postType) parts.set('post_type', postType)
2037+
2038+ const mediaType = String(m?.type || '2').trim()
2039+ if (mediaType) parts.set('media_type', mediaType)
2040+
19892041 const token = String(m?.token || m?.urlAttrs?.token || m?.thumbAttrs?.token || '').trim()
19902042 if (token) parts.set('token', token)
19912043
@@ -1995,8 +2047,9 @@ const getSnsMediaUrl = (post, m, idx, rawUrl) => {
19952047 parts.set('use_cache', snsUseCache.value ? '1' : '0')
19962048 // When cache is disabled, bust browser caching so backend really downloads+decrypts each time.
19972049 if (!snsUseCache.value) parts.set('_t', String(Date.now()))
1998- // Bump this when changing the WeFlow-aligned image pipeline to avoid stale browser caches.
1999- parts.set('v', '10')
2050+ if (md5) parts.set('md5', md5)
2051+ // 修改后端媒体匹配逻辑时递增版本号,避免浏览器复用旧的错误缓存。
2052+ parts.set('v', '11')
20002053 parts.set('url', raw)
20012054 return `${apiBase}/sns/media?${parts.toString()}`
20022055 }
0 commit comments