diff --git a/app/api/v1/public_api/video.py b/app/api/v1/public_api/video.py
index 0a3976a..f79d617 100644
--- a/app/api/v1/public_api/video.py
+++ b/app/api/v1/public_api/video.py
@@ -5,8 +5,9 @@ import uuid
from typing import Optional, List, Dict, Any
import orjson
+import httpx
from fastapi import APIRouter, Depends, HTTPException, Query, Request
-from fastapi.responses import StreamingResponse
+from fastapi.responses import StreamingResponse, Response
from pydantic import BaseModel, Field
from app.core.auth import verify_public_key
@@ -21,6 +22,8 @@ router = APIRouter()
VIDEO_SESSION_TTL = 600
_VIDEO_SESSIONS: dict[str, dict] = {}
_VIDEO_SESSIONS_LOCK = asyncio.Lock()
+_VENDOR_CACHE: dict[str, bytes] = {}
+_VENDOR_LOCK = asyncio.Lock()
_VIDEO_RATIO_MAP = {
"1280x720": "16:9",
@@ -35,6 +38,28 @@ _VIDEO_RATIO_MAP = {
"1:1": "1:1",
}
+_FFMPEG_VENDOR_SOURCES = {
+ "ffmpeg-core.js": [
+ "https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.6/dist/umd/ffmpeg-core.js",
+ "https://unpkg.com/@ffmpeg/core@0.12.6/dist/umd/ffmpeg-core.js",
+ ],
+ "ffmpeg-core.wasm": [
+ "https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.6/dist/umd/ffmpeg-core.wasm",
+ "https://unpkg.com/@ffmpeg/core@0.12.6/dist/umd/ffmpeg-core.wasm",
+ ],
+ # 某些版本没有 worker 文件,允许返回 404 由前端自动降级。
+ "ffmpeg-core.worker.js": [
+ "https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.6/dist/umd/ffmpeg-core.worker.js",
+ "https://unpkg.com/@ffmpeg/core@0.12.6/dist/umd/ffmpeg-core.worker.js",
+ ],
+}
+
+_VENDOR_CONTENT_TYPE = {
+ "ffmpeg-core.js": "application/javascript; charset=utf-8",
+ "ffmpeg-core.worker.js": "application/javascript; charset=utf-8",
+ "ffmpeg-core.wasm": "application/wasm",
+}
+
def _extract_parent_post_id_from_url(url: str) -> str:
text = str(url or "").strip()
@@ -390,6 +415,51 @@ async def public_video_stop(data: VideoStopRequest):
return {"status": "success", "removed": removed}
+@router.get("/video/vendor/{filename}")
+async def public_video_vendor(filename: str):
+ filename = str(filename or "").strip()
+ if filename not in _FFMPEG_VENDOR_SOURCES:
+ raise HTTPException(status_code=404, detail="vendor asset not found")
+
+ async with _VENDOR_LOCK:
+ cached = _VENDOR_CACHE.get(filename)
+ if cached:
+ return Response(
+ content=cached,
+ media_type=_VENDOR_CONTENT_TYPE.get(filename, "application/octet-stream"),
+ headers={"Cache-Control": "public, max-age=86400"},
+ )
+
+ timeout = httpx.Timeout(connect=8.0, read=60.0, write=30.0, pool=8.0)
+ last_error = None
+ async with httpx.AsyncClient(timeout=timeout) as client:
+ for url in _FFMPEG_VENDOR_SOURCES[filename]:
+ try:
+ resp = await client.get(url, follow_redirects=True)
+ if resp.status_code == 200 and resp.content:
+ content = bytes(resp.content)
+ async with _VENDOR_LOCK:
+ _VENDOR_CACHE[filename] = content
+ logger.info(
+ f"Video vendor proxy loaded: {filename} <- {url} ({len(content)} bytes)"
+ )
+ return Response(
+ content=content,
+ media_type=_VENDOR_CONTENT_TYPE.get(
+ filename, "application/octet-stream"
+ ),
+ headers={"Cache-Control": "public, max-age=86400"},
+ )
+ last_error = f"status={resp.status_code}"
+ except Exception as e:
+ last_error = str(e)
+
+ raise HTTPException(
+ status_code=502,
+ detail=f"vendor fetch failed: {filename}, error={last_error or 'unknown'}",
+ )
+
+
@router.get("/video/cache/list", dependencies=[Depends(verify_public_key)])
async def public_video_cache_list(page: int = 1, page_size: int = 100):
page = max(1, int(page or 1))
diff --git a/app/static/public/js/video.js b/app/static/public/js/video.js
index ae317fa..376348f 100644
--- a/app/static/public/js/video.js
+++ b/app/static/public/js/video.js
@@ -637,13 +637,13 @@
try {
const candidates = {
coreURL: [
- '/static/vendor/ffmpeg/ffmpeg-core.js',
+ '/v1/public/video/vendor/ffmpeg-core.js',
],
wasmURL: [
- '/static/vendor/ffmpeg/ffmpeg-core.wasm',
+ '/v1/public/video/vendor/ffmpeg-core.wasm',
],
workerURL: [
- '/static/vendor/ffmpeg/ffmpeg-core.worker.js',
+ '/v1/public/video/vendor/ffmpeg-core.worker.js',
],
};
// 统一转为同源 blob URL,避免跨域 Worker 限制,同时实现多源超时切换。
diff --git a/app/static/public/pages/video.html b/app/static/public/pages/video.html
index 5dab45f..b41f6d6 100644
--- a/app/static/public/pages/video.html
+++ b/app/static/public/pages/video.html
@@ -274,7 +274,7 @@
-
+