fix(video-edit): 新增同源vendor端点避免ffmpeg资源404
This commit is contained in:
1 parent
a595adfe83
commit
385132f625
3 files changed
+75
-5
No files matched your search
@@ -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))
|
||||
|
||||
@@ -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 限制,同时实现多源超时切换。
|
||||
|
||||
@@ -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>
|
||||
Reference in new issue
Block a user