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
@@ -17,7 +17,10 @@ Mirrors ``test_recording_downloader.py``:
set excludes the failing msg_id from later batches) and returns
``(attempted=1, localized=0)`` with no exception escaping.
* Filter: a text message with an http URL (e.g. a documentation link) is
NOT selected (only ``type IN ('image','video','file')`` rows are eligible).
NOT selected (only ``type IN ('image','image_legacy','video','file')`` rows
are eligible).
* ``image_legacy`` coverage: legacy WeChat type-3 rows whose ``file_url``
carries a valid OSS URL ARE selected and stored as ``media_type='image'``.
"""
from __future__ import annotations
@@ -340,8 +343,9 @@ async def test_resilient_on_failure_and_no_infinite_loop(tmp_path):
async def test_text_message_with_url_is_not_selected(tmp_path):
"""A text message whose text happens to be a URL is NOT selected.
The candidate filter requires ``type IN ('image','video','file')``; a
text message is skipped even if its columns somehow carry an http URL.
The candidate filter requires ``type IN ('image','image_legacy','video',
'file')``; a text message is skipped even if its columns somehow carry an
http URL.
"""
store = ObjectStore(tmp_path)
engine = await _make_engine()
@@ -373,3 +377,73 @@ async def test_text_message_with_url_is_not_selected(tmp_path):
finally:
await client.aclose()
await engine.dispose()
@respx.mock
async def test_image_legacy_is_selected_and_normalized_to_image(tmp_path):
"""``type='image_legacy'`` rows ARE selected (smoke.db 26 rows).
The candidate filter includes ``image_legacy`` so the legacy WeChat type-3
rows whose ``file_url`` carries a valid ``wx.oss.yunkecn.com`` OSS URL get
localized. The thumbnail-first preference applies (same as ``image``), and
the stored ``Media.media_type`` is NORMALIZED to ``'image'`` so the legacy
bucket lands in the same bin as type-2 images.
"""
store = ObjectStore(tmp_path)
engine = await _make_engine()
SessionLocal = async_sessionmaker(engine, expire_on_commit=False)
thumb_blob = b"\xff\xd8\xff\xe0legacy-thumb-jpg"
thumb_route = respx.get(OSS_THUMB).mock(
return_value=httpx.Response(200, content=thumb_blob)
)
full_route = respx.get(OSS_FULL).mock(return_value=httpx.Response(200, content=b"full"))
client = _primed_client()
try:
async with SessionLocal() as session:
session.add(
Message(
msg_id="m-legacy",
channel="wechat",
type="image_legacy",
type_raw=3,
file_url=OSS_FULL,
file_th_url=OSS_THUMB,
file_hd_url=OSS_HD,
)
)
await session.commit()
async with SessionLocal() as session:
attempted, localized = await download_message_images(
client, store, session
)
await session.commit()
assert (attempted, localized) == (1, 1)
# Thumbnail-first preference applies to image_legacy exactly as for image.
assert thumb_route.called
assert not full_route.called
expected_sha = hashlib.sha256(thumb_blob).hexdigest()
async with SessionLocal() as session:
msg = (
await session.execute(
sa.select(Message).where(Message.msg_id == "m-legacy")
)
).scalar_one()
assert msg.media_hash == expected_sha
media = (
await session.execute(
sa.select(Media).where(Media.media_hash == expected_sha)
)
).scalar_one()
# Normalized: image_legacy -> image on the stored Media row.
assert media.media_type == "image"
assert media.mime_type == "image/jpeg"
assert media.original_url == OSS_FULL
finally:
await client.aclose()
await engine.dispose()