会员积分改版V4 | 修复历史素材云兼容BUG | build app/admin

This commit is contained in:
2026-08-11 10:27:06 +08:00
parent 392b9f4117
commit ba32d6f55e
8 changed files with 810 additions and 804 deletions
@@ -64,20 +64,20 @@ class DownloadedAsset(NamedTuple):
def _max_bytes(asset_type: str) -> int:
return VP_V3_VIDEO_MAX_BYTES if asset_type == UploadResourceTypeEnum.VIDEO.value else VP_V3_IMAGE_MAX_BYTES
return VP_V3_VIDEO_MAX_BYTES if asset_type == UploadResourceTypeEnum.F_VIDEO.value else VP_V3_IMAGE_MAX_BYTES
def _allowed_mime_set(asset_type: str) -> set[str]:
return VIDEO_MIME_ALLOWED if asset_type == UploadResourceTypeEnum.VIDEO.value else IMAGE_MIME_ALLOWED
return VIDEO_MIME_ALLOWED if asset_type == UploadResourceTypeEnum.F_VIDEO.value else IMAGE_MIME_ALLOWED
def _safe_ext(filename: str, asset_type: str) -> str:
ext = (os.path.splitext(filename or "")[1].lower().lstrip(".") or "").strip()
allowed = VIDEO_EXT_ALLOWED if asset_type == UploadResourceTypeEnum.VIDEO.value else IMAGE_EXT_ALLOWED
allowed = VIDEO_EXT_ALLOWED if asset_type == UploadResourceTypeEnum.F_VIDEO.value else IMAGE_EXT_ALLOWED
if ext and ext in allowed:
return ext
# fallback
return "mp4" if asset_type == UploadResourceTypeEnum.VIDEO.value else "png"
return "mp4" if asset_type == UploadResourceTypeEnum.F_VIDEO.value else "png"
def _get_ffprobe_bin() -> str:
@@ -150,7 +150,7 @@ def _build_destination(*, api_key_id: str, asset_type: str, original_filename: s
month = f"{now.month:02d}"
day = f"{now.day:02d}"
sub_type = "videos" if asset_type == UploadResourceTypeEnum.VIDEO.value else "images"
sub_type = "videos" if asset_type == UploadResourceTypeEnum.F_VIDEO.value else "images"
rel_dir = Path("api") / "private_portrait_virtual" / sub_type / year / month / day
filename = f"vp_v3_{safe_uuid}.{ext}"
@@ -198,7 +198,7 @@ def _guess_ext_from_mime(mime: str | None, asset_type: str) -> str | None:
if not mime:
return None
# 按 asset_type 优先匹配
allowed_exts = VIDEO_EXT_ALLOWED if asset_type == UploadResourceTypeEnum.VIDEO.value else IMAGE_EXT_ALLOWED
allowed_exts = VIDEO_EXT_ALLOWED if asset_type == UploadResourceTypeEnum.F_VIDEO.value else IMAGE_EXT_ALLOWED
guesses = mimetypes.guess_all_extensions(mime.strip().lower()) or []
for g in guesses:
ext = g.lower().lstrip(".")
@@ -232,7 +232,7 @@ async def upload_asset_file(
- 落盘到 /uploads/images|videos/vp_v3/{api_key_id_short}/{yyyy}/{mm}/{dd}/
- 返回 url + 虚拟 resource_idhash 形式)
"""
if asset_type not in {UploadResourceTypeEnum.IMAGE.value, UploadResourceTypeEnum.VIDEO.value}:
if asset_type not in {UploadResourceTypeEnum.F_IMAGE.value, UploadResourceTypeEnum.F_VIDEO.value}:
raise HTTPException(status_code=400, detail="虚拟素材上传仅支持图片或视频")
max_size = _max_bytes(asset_type)
@@ -317,7 +317,7 @@ async def download_url_to_local(
- 下载一半失败 → 清理临时文件,不留下半截
- 视频可选探测 ffprobe,失败不抛错(调用方自行用 payload.video_duration
"""
if asset_type not in {UploadResourceTypeEnum.IMAGE.value, UploadResourceTypeEnum.VIDEO.value}:
if asset_type not in {UploadResourceTypeEnum.F_IMAGE.value, UploadResourceTypeEnum.F_VIDEO.value}:
raise HTTPException(status_code=400, detail="虚拟素材仅支持图片或视频")
# URL 合法性
@@ -465,7 +465,7 @@ async def download_url_to_local(
# --- 第二步:视频可选 ffprobe 探测时长 ---
duration: float | None = None
if asset_type == UploadResourceTypeEnum.VIDEO.value:
if asset_type == UploadResourceTypeEnum.F_VIDEO.value:
duration = _probe_duration_optional(Path(temp_path))
# --- 第三步:落到最终目录(与 _build_destination 一致的目录结构/权限) ---
@@ -483,7 +483,7 @@ async def download_url_to_local(
if not mime:
mime, _ = mimetypes.guess_type(final_filename)
if not mime:
mime = "image/png" if asset_type == UploadResourceTypeEnum.IMAGE.value else "video/mp4"
mime = "image/png" if asset_type == UploadResourceTypeEnum.F_IMAGE.value else "video/mp4"
suggested_name: str | None = None
try: