fix(worker): 素材下载storage_key为空时fallback到file_url,兼容存量数据 #485

Merged
auto-approve-bot merged 1 commits from fix/download-asset-storage-key-fallback into develop 2026-07-17 20:08:26 +08:00
4 changed files with 45 additions and 11 deletions
@@ -367,11 +367,14 @@ class RenderAdapter:
seen_asset_ids: set[str] = set()
# 批量查询素材的 storage_keyOSS 存储路径)
# 兼容存量数据:storage_key 为空时 fallback 到 file_url
clip_asset_ids = [c.asset_id for c in clips if c.asset_id]
asset_storage_map: dict[str, str] = {}
if clip_asset_ids:
assets = self._db.query(AssetModel).filter(AssetModel.id.in_(clip_asset_ids)).all()
asset_storage_map = {a.id: a.storage_key for a in assets if a.storage_key}
asset_storage_map = {
a.id: (a.storage_key or a.file_url or "") for a in assets if a.storage_key or a.file_url
}
for clip in clips:
asset_id = clip.asset_id
@@ -468,8 +471,9 @@ class RenderAdapter:
from packages.adapters.sqlalchemy_impl.models import AssetModel
model = self._db.query(AssetModel).filter(AssetModel.id == asset_id).first()
if model and model.storage_key:
storage_key = model.storage_key
if model and (model.storage_key or model.file_url):
# 兼容存量数据:storage_key 为空时 fallback 到 file_url
storage_key = model.storage_key or model.file_url
logger.info("[plan_id=%s] [BGM] 从素材库下载: asset_id=%s", plan_id, asset_id)
ok = download_asset(storage_key, bgm_file)
if ok and bgm_file.exists() and bgm_file.stat().st_size > 0:
@@ -473,13 +473,16 @@ def render_edit_plan(self, plan_id: str) -> dict:
failed_clip_ids: list[str] = []
# 预先批量查询所有素材的 storage_key
# 兼容存量数据:storage_key 为空时 fallback 到 file_url
from packages.adapters.sqlalchemy_impl.models import AssetModel
clip_asset_ids = [c.asset_id for c in clips if c.asset_id]
asset_storage_map: dict[str, str] = {}
if clip_asset_ids:
assets = db.query(AssetModel).filter(AssetModel.id.in_(clip_asset_ids)).all()
asset_storage_map = {a.id: a.storage_key for a in assets if a.storage_key}
asset_storage_map = {
a.id: (a.storage_key or a.file_url or "") for a in assets if a.storage_key or a.file_url
}
for clip in clips:
if not clip.asset_id:
+3 -2
View File
@@ -537,8 +537,9 @@ def _prepare_bgm_track(
session = SessionLocal()
try:
model = session.query(AssetModel).filter(AssetModel.id == asset_id).first()
if model and model.storage_key:
storage_key = model.storage_key
if model and (model.storage_key or model.file_url):
# 兼容存量数据:storage_key 为空时 fallback 到 file_url
storage_key = model.storage_key or model.file_url
logger.info("[task_id=%s] [BGM] 从素材库下载: asset_id=%s", task_id, asset_id)
ok = download_asset(storage_key, bgm_file)
if ok and bgm_file.exists() and bgm_file.stat().st_size > 0:
+31 -5
View File
@@ -670,20 +670,46 @@ class TestDownloadAssets:
assert "c2" in rendered_ids
@patch("video_processing.render_adapter.download_asset")
def test_asset_without_storage_key_skipped(self, mock_download, tmp_path):
"""素材在assets表中无storage_key时跳过下载,标记为失败"""
# 构造返回 asset 但 storage_key 为空
def test_asset_without_storage_key_fallback_to_file_url(self, mock_download, tmp_path):
"""storage_key为空但file_url有值时,fallback到file_url下载成功"""
mock_download.return_value = True
mock_db = MagicMock()
mock_query = MagicMock()
mock_asset = MagicMock()
mock_asset.id = "asset_no_url"
mock_asset.id = "asset_fallback"
mock_asset.storage_key = ""
mock_asset.file_url = "videos/test_fallback.mp4"
mock_query.all.return_value = [mock_asset]
mock_query.filter.return_value = mock_query
mock_db.query.return_value = mock_query
adapter = RenderAdapter(mock_db)
clips = [_make_clip("c1", order=0, asset_id="asset_no_url")]
clips = [_make_clip("c1", order=0, asset_id="asset_fallback")]
asset_path_map, rendered_ids, failed_ids = adapter._download_assets(clips, tmp_path)
assert len(asset_path_map) == 1
assert "c1" in rendered_ids
mock_download.assert_called_once()
# 验证用的是file_url的值
call_args = mock_download.call_args
assert call_args[0][0] == "videos/test_fallback.mp4"
@patch("video_processing.render_adapter.download_asset")
def test_asset_without_storage_key_and_file_url_skipped(self, mock_download, tmp_path):
"""storage_key和file_url都为空时跳过下载,标记为失败。"""
mock_db = MagicMock()
mock_query = MagicMock()
mock_asset = MagicMock()
mock_asset.id = "asset_no_key"
mock_asset.storage_key = ""
mock_asset.file_url = ""
mock_query.all.return_value = [mock_asset]
mock_query.filter.return_value = mock_query
mock_db.query.return_value = mock_query
adapter = RenderAdapter(mock_db)
clips = [_make_clip("c1", order=0, asset_id="asset_no_key")]
asset_path_map, rendered_ids, failed_ids = adapter._download_assets(clips, tmp_path)