feat: resolve shared media assets
All checks were successful
Publish Python Package to Gitea / publish (push) Successful in 20s

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-03 18:43:58 +08:00
parent 21d4907f02
commit eba90fb8b9
6 changed files with 656 additions and 3 deletions

187
tests/test_media_assets.py Normal file
View File

@@ -0,0 +1,187 @@
# -*- coding: utf-8 -*-
"""media_assets 共享媒体资源解析测试。"""
from __future__ import annotations
import platform
import zipfile
from pathlib import Path
from unittest.mock import patch
import pytest
from jiangchang_skill_core import media_assets as ma
def _make_complete_assets(root: Path, *, with_ffmpeg: bool = True, with_ffprobe: bool = True) -> None:
(root / "music" / "calm").mkdir(parents=True)
(root / "fonts").mkdir(parents=True)
(root / "watermark").mkdir(parents=True)
bin_key = ma._platform_bin_key()
bin_dir = root / "bin" / bin_key
bin_dir.mkdir(parents=True)
if with_ffmpeg:
(bin_dir / ma._tool_filename("ffmpeg")).write_bytes(b"ffmpeg")
if with_ffprobe:
(bin_dir / ma._tool_filename("ffprobe")).write_bytes(b"ffprobe")
def test_media_assets_root_env_priority(tmp_path: Path) -> None:
custom = tmp_path / "custom-media"
custom.mkdir()
env = {
"MEDIA_ASSETS_ROOT": str(custom),
"JIANGCHANG_DATA_ROOT": str(tmp_path / "data"),
}
assert ma.resolve_media_assets_root(env=env) == custom
def test_default_media_assets_path(tmp_path: Path) -> None:
env = {"JIANGCHANG_DATA_ROOT": str(tmp_path / "data")}
expected = tmp_path / "data" / "shared" / "media-assets"
assert ma.resolve_media_assets_root(env=env) == expected
def test_complete_assets_skips_download(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
root = tmp_path / "data" / "shared" / "media-assets"
_make_complete_assets(root)
def _fail_download(*args, **kwargs):
raise AssertionError("download should not be called")
monkeypatch.setattr(ma, "_try_download_via_zip", _fail_download)
monkeypatch.setattr(ma, "_try_download_via_git", _fail_download)
status = ma.ensure_media_assets(env={"JIANGCHANG_DATA_ROOT": str(tmp_path / "data")})
assert status.ready is True
assert status.warnings == []
assert status.source == "local"
def test_missing_ffmpeg_warning(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
root = tmp_path / "data" / "shared" / "media-assets"
_make_complete_assets(root, with_ffmpeg=False)
monkeypatch.setattr(ma, "_try_download_via_zip", lambda *a, **k: False)
monkeypatch.setattr(ma, "_try_download_via_git", lambda *a, **k: False)
status = ma.ensure_media_assets(env={"JIANGCHANG_DATA_ROOT": str(tmp_path / "data")})
assert status.ready is False
assert "ffmpeg_missing" in status.warnings
def test_missing_ffprobe_warning(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
root = tmp_path / "data" / "shared" / "media-assets"
_make_complete_assets(root, with_ffprobe=False)
monkeypatch.setattr(ma, "_try_download_via_zip", lambda *a, **k: False)
monkeypatch.setattr(ma, "_try_download_via_git", lambda *a, **k: False)
status = ma.ensure_media_assets(env={"JIANGCHANG_DATA_ROOT": str(tmp_path / "data")})
assert status.ready is False
assert "ffprobe_missing" in status.warnings
def test_pick_background_music_stable_first(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
root = tmp_path / "data" / "shared" / "media-assets"
_make_complete_assets(root)
music = root / "music"
(music / "b-upbeat.mp3").write_bytes(b"mp3")
(music / "calm" / "a-calm.mp3").write_bytes(b"mp3")
(music / "z-last.wav").write_bytes(b"wav")
monkeypatch.setattr(
ma,
"ensure_media_assets",
lambda *a, **k: ma._inspect_media_assets(root, source="local"),
)
picked = ma.pick_background_music(env={"JIANGCHANG_DATA_ROOT": str(tmp_path / "data")})
assert picked == music / "b-upbeat.mp3"
def _build_archive_zip(dest: Path, inner_name: str) -> None:
with zipfile.ZipFile(dest, "w") as zf:
zf.writestr(f"{inner_name}/README.md", "# media-assets\n")
zf.writestr(f"{inner_name}/music/.keep", "")
zf.writestr(f"{inner_name}/fonts/.keep", "")
zf.writestr(f"{inner_name}/watermark/.keep", "")
bin_key = ma._platform_bin_key()
zf.writestr(
f"{inner_name}/bin/{bin_key}/{ma._tool_filename('ffmpeg')}",
b"ffmpeg",
)
zf.writestr(
f"{inner_name}/bin/{bin_key}/{ma._tool_filename('ffprobe')}",
b"ffprobe",
)
def test_zip_wrapper_layout_detected(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
data_root = tmp_path / "data"
shared = data_root / "shared"
target = shared / "media-assets"
archive = tmp_path / "media-assets.zip"
_build_archive_zip(archive, "media-assets-main")
def _fake_download(url: str, dest: Path) -> None:
dest.write_bytes(archive.read_bytes())
monkeypatch.setattr(ma, "_download_zip", _fake_download)
monkeypatch.setattr(ma, "_find_git_executable", lambda: None)
status = ma.ensure_media_assets(env={"JIANGCHANG_DATA_ROOT": str(data_root)})
assert target.is_dir()
assert status.ready is True
assert status.source == "zip"
assert "media_assets_zip_invalid_layout" not in status.warnings
def test_zip_download_failure_returns_warning(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
import urllib.error
def _raise_url_error(url: str, dest: Path) -> None:
raise urllib.error.URLError("network down")
monkeypatch.setattr(ma, "_download_zip", _raise_url_error)
monkeypatch.setattr(ma, "_find_git_executable", lambda: None)
status = ma.ensure_media_assets(env={"JIANGCHANG_DATA_ROOT": str(tmp_path / "data")})
assert status.ready is False
assert "media_assets_zip_download_failed" in status.warnings
assert "git_not_available" in status.warnings
def test_git_not_available_when_zip_fails(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
import urllib.error
monkeypatch.setattr(
ma,
"_download_zip",
lambda url, dest: (_ for _ in ()).throw(urllib.error.URLError("fail")),
)
monkeypatch.setattr(ma, "_find_git_executable", lambda: None)
status = ma.ensure_media_assets(env={"JIANGCHANG_DATA_ROOT": str(tmp_path / "data")})
assert "git_not_available" in status.warnings
def test_media_assets_root_override_no_download(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
custom = tmp_path / "override"
custom.mkdir()
def _fail_download(*args, **kwargs):
raise AssertionError("download should not be called when MEDIA_ASSETS_ROOT is set")
monkeypatch.setattr(ma, "_try_download_via_zip", _fail_download)
status = ma.ensure_media_assets(env={"MEDIA_ASSETS_ROOT": str(custom)})
assert status.root == custom
assert status.exists is True
@pytest.mark.skipif(platform.system().lower() != "windows", reason="Windows default path check")
def test_windows_default_data_root() -> None:
with patch.dict("os.environ", {}, clear=True):
root = ma.resolve_media_assets_root()
assert root == Path(r"D:\jiangchang-data") / "shared" / "media-assets"