fix(media): image_legacy渲染+下载覆盖+WA raw_json URL回退

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
浅念
2026-08-13 14:02:42 +08:00
parent 9e4a5ee536
commit 2154d050e5
3 changed files with 164 additions and 30 deletions
+20 -11
View File
@@ -394,11 +394,13 @@ def _pick_message_image_url(
) -> str | None:
"""Pick the best downloadable http(s) URL for a message media row.
For ``image`` messages, prefer the thumbnail (``file_th_url``): thumbnails
are small, fast to fetch, and exactly what the chat timeline renders, so
localizing the thumbnail is sufficient for display and easy on disk + bandwidth.
Falls back to ``file_url`` then ``file_hd_url`` when no http(s) thumbnail is
available.
For ``image`` / ``image_legacy`` messages, prefer the thumbnail
(``file_th_url``): thumbnails are small, fast to fetch, and exactly what the
chat timeline renders, so localizing the thumbnail is sufficient for display
and easy on disk + bandwidth. Falls back to ``file_url`` then ``file_hd_url``
when no http(s) thumbnail is available. ``image_legacy`` (smoke.db 26 rows
with valid ``wx.oss.yunkecn.com`` URLs) is treated exactly like ``image``
here so the legacy WeChat type-3-via-OSS rows are localized.
For every other media type (``video`` / ``file``), prefer ``file_url`` (the
original), then ``file_hd_url``, then ``file_th_url``.
@@ -406,7 +408,7 @@ def _pick_message_image_url(
Returns ``None`` when no candidate is an http(s) URL (e.g. type-3 opaque ids
or relative filenames). Only ``http://`` / ``https://`` URLs are downloadable.
"""
if type_ == "image":
if type_ in ("image", "image_legacy"):
order = (file_th_url, file_url, file_hd_url)
else:
order = (file_url, file_hd_url, file_th_url)
@@ -428,12 +430,15 @@ async def download_message_images(
Iterates ``message`` rows that carry an http(s) URL on any of
``file_url`` / ``file_th_url`` / ``file_hd_url``, have ``type`` in
('image', 'video', 'file'), are on the wechat / whatsapp channel, and do
NOT yet carry a ``media_hash``. For each: pick the best available URL
(image: thumbnail-first; other: original-first — see
('image', 'image_legacy', 'video', 'file'), are on the wechat / whatsapp
channel, and do NOT yet carry a ``media_hash``. For each: pick the best
available URL (image: thumbnail-first; other: original-first — see
:func:`_pick_message_image_url`), fetch bytes (:func:`download_url`),
store content-addressed (:meth:`ObjectStore.put_by_hash`, sha256 dedup),
upsert a ``Media`` row, and write ``media_hash`` back onto the message.
``image_legacy`` rows are stored as ``media_type='image'`` (normalized via
:func:`media_type_from_message`) so the legacy WeChat type-3-via-OSS rows
(smoke.db 26 rows with valid ``wx.oss.yunkecn.com`` URLs) are covered.
Returns ``(attempted, localized)``. Resilient: a per-row download/store
failure is logged and counted as attempted-but-not-localized; no exception
@@ -462,7 +467,7 @@ async def download_message_images(
)
.where(Message.media_hash.is_(None))
.where(Message.channel.in_(("wechat", "whatsapp")))
.where(Message.type.in_(("image", "video", "file")))
.where(Message.type.in_(("image", "image_legacy", "video", "file")))
.where(
sa.or_(
Message.file_url.like("http%"),
@@ -500,11 +505,15 @@ async def download_message_images(
continue
ext = _ext_from_url(url)
sha256_hex, path = await store.put_by_hash(data, ext=ext)
# Normalize ``image_legacy`` to ``image`` on the stored Media row so
# the legacy WeChat type-3-via-OSS rows land in the same bucket as
# type-2 images (matches ``media_type_from_message``).
media_type = "image" if type_ == "image_legacy" else type_
await upsert_media(
session,
media_hash=sha256_hex,
channel=channel or "wechat",
media_type=type_,
media_type=media_type,
original_url=file_url,
original_th_url=file_th_url,
original_hd_url=file_hd_url,