fix(video-edit): 新增同源vendor端点避免ffmpeg资源404

This commit is contained in:
root committed 2026-02-17 18:00:53 +08:00
1 parent a595adfe83
commit 385132f625
3 files changed
+75 -5

No files matched your search

+71 -1
View File
@@ -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))
+3 -3
View File
@@ -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 限制,同时实现多源超时切换。
+1 -1
View File
@@ -274,7 +274,7 @@
<script src="/static/common/js/pwa.js?v=0.1.1"></script>
<script src="/static/vendor/ffmpeg/ffmpeg.js?v=0.1.0"></script>
<script src="/static/vendor/ffmpeg/ffmpeg-util.js?v=0.1.0"></script>
<script src="/static/public/js/video.js?v=0.3.8"></script>
<script src="/static/public/js/video.js?v=0.3.9"></script>
</body>
</html>