refactor: 移除废弃的 ffmpeg 本地拼接遗留逻辑

This commit is contained in:
XianYuDaXian committed 2026-03-10 06:55:24 +08:00
1 parent 84f365dba3
commit 15cde1b80a
9 files changed
+1 -184

No files matched your search

+1 -76
View File
@@ -5,9 +5,8 @@ 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, Response
from fastapi.responses import StreamingResponse
from pydantic import BaseModel, Field
from app.core.auth import verify_public_key
@@ -23,8 +22,6 @@ 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",
@@ -39,28 +36,6 @@ _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 _public_video_error_payload(exc: Exception) -> dict:
"""统一 public video 错误文案,避免透传工具层异常。"""
@@ -521,56 +496,6 @@ 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)
if filename == "ffmpeg-core.worker.js":
raise HTTPException(
status_code=404,
detail="optional worker asset not found",
)
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))
-2
View File
@@ -1,2 +0,0 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FFmpegWASM=t():e.FFmpegWASM=t()}(self,(()=>(()=>{"use strict";const e="https://unpkg.com/@ffmpeg/core@0.12.6/dist/umd/ffmpeg-core.js";var t;!function(e){e.LOAD="LOAD",e.EXEC="EXEC",e.WRITE_FILE="WRITE_FILE",e.READ_FILE="READ_FILE",e.DELETE_FILE="DELETE_FILE",e.RENAME="RENAME",e.CREATE_DIR="CREATE_DIR",e.LIST_DIR="LIST_DIR",e.DELETE_DIR="DELETE_DIR",e.ERROR="ERROR",e.DOWNLOAD="DOWNLOAD",e.PROGRESS="PROGRESS",e.LOG="LOG",e.MOUNT="MOUNT",e.UNMOUNT="UNMOUNT"}(t||(t={}));const r=new Error("unknown message type"),a=new Error("ffmpeg is not loaded, call `await ffmpeg.load()` first"),s=(new Error("called FFmpeg.terminate()"),new Error("failed to import ffmpeg-core.js"));let o;return self.onmessage=async({data:{id:n,type:E,data:c}})=>{const i=[];let p;try{if(E!==t.LOAD&&!o)throw a;switch(E){case t.LOAD:p=await(async({coreURL:r,wasmURL:a,workerURL:n})=>{const E=!o;try{r||(r=e),importScripts(r)}catch{if(r||(r=e.replace("/umd/","/esm/")),self.createFFmpegCore=(await import(r)).default,!self.createFFmpegCore)throw s}const c=r,i=a||r.replace(/.js$/g,".wasm"),p=n||r.replace(/.js$/g,".worker.js");return o=await self.createFFmpegCore({mainScriptUrlOrBlob:`${c}#${btoa(JSON.stringify({wasmURL:i,workerURL:p}))}`}),o.setLogger((e=>self.postMessage({type:t.LOG,data:e}))),o.setProgress((e=>self.postMessage({type:t.PROGRESS,data:e}))),E})(c);break;case t.EXEC:p=(({args:e,timeout:t=-1})=>{o.setTimeout(t),o.exec(...e);const r=o.ret;return o.reset(),r})(c);break;case t.WRITE_FILE:p=(({path:e,data:t})=>(o.FS.writeFile(e,t),!0))(c);break;case t.READ_FILE:p=(({path:e,encoding:t})=>o.FS.readFile(e,{encoding:t}))(c);break;case t.DELETE_FILE:p=(({path:e})=>(o.FS.unlink(e),!0))(c);break;case t.RENAME:p=(({oldPath:e,newPath:t})=>(o.FS.rename(e,t),!0))(c);break;case t.CREATE_DIR:p=(({path:e})=>(o.FS.mkdir(e),!0))(c);break;case t.LIST_DIR:p=(({path:e})=>{const t=o.FS.readdir(e),r=[];for(const a of t){const t=o.FS.stat(`${e}/${a}`),s=o.FS.isDir(t.mode);r.push({name:a,isDir:s})}return r})(c);break;case t.DELETE_DIR:p=(({path:e})=>(o.FS.rmdir(e),!0))(c);break;case t.MOUNT:p=(({fsType:e,options:t,mountPoint:r})=>{const a=e,s=o.FS.filesystems[a];return!!s&&(o.FS.mount(s,t,r),!0)})(c);break;case t.UNMOUNT:p=(({mountPoint:e})=>(o.FS.unmount(e),!0))(c);break;default:throw r}}catch(e){return void self.postMessage({id:n,type:t.ERROR,data:e.toString()})}p instanceof Uint8Array&&i.push(p.buffer),self.postMessage({id:n,type:E,data:p},i)},{}})()));
//# sourceMappingURL=814.ffmpeg.js.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"814.ffmpeg.js","mappings":"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","sources":["webpack://FFmpegWASM/webpack/universalModuleDefinition","webpack://FFmpegWASM/./dist/esm/const.js","webpack://FFmpegWASM/./dist/esm/errors.js","webpack://FFmpegWASM/./dist/esm/worker.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"FFmpegWASM\"] = factory();\n\telse\n\t\troot[\"FFmpegWASM\"] = factory();\n})(self, () => {\nreturn ","export const MIME_TYPE_JAVASCRIPT = \"text/javascript\";\nexport const MIME_TYPE_WASM = \"application/wasm\";\nexport const CORE_VERSION = \"0.12.6\";\nexport const CORE_URL = `https://unpkg.com/@ffmpeg/core@${CORE_VERSION}/dist/umd/ffmpeg-core.js`;\nexport var FFMessageType;\n(function (FFMessageType) {\n FFMessageType[\"LOAD\"] = \"LOAD\";\n FFMessageType[\"EXEC\"] = \"EXEC\";\n FFMessageType[\"WRITE_FILE\"] = \"WRITE_FILE\";\n FFMessageType[\"READ_FILE\"] = \"READ_FILE\";\n FFMessageType[\"DELETE_FILE\"] = \"DELETE_FILE\";\n FFMessageType[\"RENAME\"] = \"RENAME\";\n FFMessageType[\"CREATE_DIR\"] = \"CREATE_DIR\";\n FFMessageType[\"LIST_DIR\"] = \"LIST_DIR\";\n FFMessageType[\"DELETE_DIR\"] = \"DELETE_DIR\";\n FFMessageType[\"ERROR\"] = \"ERROR\";\n FFMessageType[\"DOWNLOAD\"] = \"DOWNLOAD\";\n FFMessageType[\"PROGRESS\"] = \"PROGRESS\";\n FFMessageType[\"LOG\"] = \"LOG\";\n FFMessageType[\"MOUNT\"] = \"MOUNT\";\n FFMessageType[\"UNMOUNT\"] = \"UNMOUNT\";\n})(FFMessageType || (FFMessageType = {}));\n","export const ERROR_UNKNOWN_MESSAGE_TYPE = new Error(\"unknown message type\");\nexport const ERROR_NOT_LOADED = new Error(\"ffmpeg is not loaded, call `await ffmpeg.load()` first\");\nexport const ERROR_TERMINATED = new Error(\"called FFmpeg.terminate()\");\nexport const ERROR_IMPORT_FAILURE = new Error(\"failed to import ffmpeg-core.js\");\n","/// <reference no-default-lib=\"true\" />\n/// <reference lLine truncated
-21
View File
@@ -1,21 +0,0 @@
var createFFmpegCore = (() => {
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
return (
function(createFFmpegCore = {}) {
var Module=typeof createFFmpegCore!="undefined"?createFFmpegCore:{};var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});const NULL=0;const SIZE_I32=Uint32Array.BYTES_PER_ELEMENT;const DEFAULT_ARGS=["./ffmpeg","-nostdin","-y"];Module["NULL"]=NULL;Module["SIZE_I32"]=SIZE_I32;Module["DEFAULT_ARGS"]=DEFAULT_ARGS;Module["ret"]=-1;Module["timeout"]=-1;Module["logger"]=()=>{};Module["progress"]=()=>{};function stringToPtr(str){const len=Module["lengthBytesUTF8"](str)+1;const ptr=Module["_malloc"](len);Module["stringToUTF8"](str,ptr,len);return ptr}function stringsToPtr(strs){const len=strs.length;const ptr=Module["_malloc"](len*SIZE_I32);for(let i=0;i<len;i++){Module["setValue"](ptr+SIZE_I32*i,stringToPtr(strs[i]),"i32")}return ptr}function print(message){Module["logger"]({type:"stdout",message:message})}function printErr(message){if(!message.startsWith("Aborted(native code called abort())"))Module["logger"]({type:"stderr",message:message})}function exec(..._args){const args=[...Module["DEFAULT_ARGS"],..._args];try{Module["_ffmpeg"](args.length,stringsToPtr(args))}catch(e){if(!e.message.startsWith("Aborted")){throw e}}return Module["ret"]}function setLogger(logger){Module["logger"]=logger}function setTimeout(timeout){Module["timeout"]=timeout}function setProgress(handler){Module["progress"]=handler}function receiveProgress(progress,time){Module["progress"]({progress:progress,time:time})}function reset(){Module["ret"]=-1;Module["timeout"]=-1}function _locateFile(path,prefix){const mainScriptUrlOrBlob=Module["mainScriptUrlOrBlob"];if(mainScriptUrlOrBlob){const{wasmURL:wasmURL,workerURL:workerURL}=JSON.parse(atob(mainScriptUrlOrBlob.slice(mainScriptUrlOrBlob.lastIndexOf("#")+1)));if(path.endsWith(".wasm"))return wasmURL;if(path.endsWith(".worker.js"))return workerURL}return prefix+path}Module["stringToPtr"]=stringToPtr;Module["stringsToPtr"]=stringsToPtr;Module["print"]=print;Module["printErr"]=printErr;Module["locateFile"]=_locateFile;Module["exec"]=exec;Module["setLogger"]=setLogger;Module["setTimeout"]=setTimeout;Module["setProgress"]=setProgress;Module["reset"]=reset;Module["receiveProgress"]=receiveProgress;var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");if(ENVIRONMENT_IS_WORKER){scriptDirectory=nodePath.dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=(filename,binary)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)onerror(err);else onload(binary?data.buffer:data)})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow};Module["inspect"]=()=>"[Emscripten Module object]"}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=title=>document.title=title}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"]Line truncated
return createFFmpegCore.ready
}
);
})();
if (typeof exports === 'object' && typeof module === 'object')
module.exports = createFFmpegCore;
else if (typeof define === 'function' && define['amd'])
define([], function() { return createFFmpegCore; });
else if (typeof exports === 'object')
exports["createFFmpegCore"] = createFFmpegCore;
Binary file not shown.
-1
View File
@@ -1 +0,0 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FFmpegUtil=t():e.FFmpegUtil=t()}(self,(()=>(()=>{"use strict";var e={591:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.HeaderContentLength=void 0,t.HeaderContentLength="Content-Length"},431:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ERROR_INCOMPLETED_DOWNLOAD=t.ERROR_RESPONSE_BODY_READER=void 0,t.ERROR_RESPONSE_BODY_READER=new Error("failed to get response body reader"),t.ERROR_INCOMPLETED_DOWNLOAD=new Error("failed to complete download")},915:function(e,t,o){var r=this&&this.__awaiter||function(e,t,o,r){return new(o||(o=Promise))((function(n,i){function d(e){try{l(r.next(e))}catch(e){i(e)}}function a(e){try{l(r.throw(e))}catch(e){i(e)}}function l(e){var t;e.done?n(e.value):(t=e.value,t instanceof o?t:new o((function(e){e(t)}))).then(d,a)}l((r=r.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.toBlobURL=t.downloadWithProgress=t.importScript=t.fetchFile=void 0;const n=o(431),i=o(591);t.fetchFile=e=>r(void 0,void 0,void 0,(function*(){let t;if("string"==typeof e)t=/data:_data\/([a-zA-Z]*);base64,([^"]*)/.test(e)?atob(e.split(",")[1]).split("").map((e=>e.charCodeAt(0))):yield(yield fetch(e)).arrayBuffer();else if(e instanceof URL)t=yield(yield fetch(e)).arrayBuffer();else{if(!(e instanceof File||e instanceof Blob))return new Uint8Array;t=yield(o=e,new Promise(((e,t)=>{const r=new FileReader;r.onload=()=>{const{result:t}=r;t instanceof ArrayBuffer?e(new Uint8Array(t)):e(new Uint8Array)},r.onerror=e=>{var o,r;t(Error(`File could not be read! Code=${(null===(r=null===(o=null==e?void 0:e.target)||void 0===o?void 0:o.error)||void 0===r?void 0:r.code)||-1}`))},r.readAsArrayBuffer(o)})))}var o;return new Uint8Array(t)})),t.importScript=e=>r(void 0,void 0,void 0,(function*(){return new Promise((t=>{const o=document.createElement("script"),r=()=>{o.removeEventListener("load",r),t()};o.src=e,o.type="text/javascript",o.addEventListener("load",r),document.getElementsByTagName("head")[0].appendChild(o)}))})),t.downloadWithProgress=(e,t)=>r(void 0,void 0,void 0,(function*(){var o;const r=yield fetch(e);let d;try{const a=parseInt(r.headers.get(i.HeaderContentLength)||"-1"),l=null===(o=r.body)||void 0===o?void 0:o.getReader();if(!l)throw n.ERROR_RESPONSE_BODY_READER;const c=[];let s=0;for(;;){const{done:o,value:r}=yield l.read(),i=r?r.length:0;if(o){if(-1!=a&&a!==s)throw n.ERROR_INCOMPLETED_DOWNLOAD;t&&t({url:e,total:a,received:s,delta:i,done:o});break}c.push(r),s+=i,t&&t({url:e,total:a,received:s,delta:i,done:o})}const f=new Uint8Array(s);let u=0;for(const e of c)f.set(e,u),u+=e.length;d=f.buffer}catch(o){console.log("failed to send download progress event: ",o),d=yield r.arrayBuffer(),t&&t({url:e,total:d.byteLength,received:d.byteLength,delta:0,done:!0})}return d})),t.toBlobURL=(e,o,n=!1,i)=>r(void 0,void 0,void 0,(function*(){const r=n?yield(0,t.downloadWithProgress)(e,i):yield(yield fetch(e)).arrayBuffer(),d=new Blob([r],{type:o});return URL.createObjectURL(d)}))}},t={};return function o(r){var n=t[r];if(void 0!==n)return n.exports;var i=t[r]={exports:{}};return e[r].call(i.exports,i,i.exports,o),i.exports}(915)})()));
-2
View File
@@ -1,2 +0,0 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FFmpegWASM=t():e.FFmpegWASM=t()}(self,(()=>(()=>{"use strict";var e={m:{},d:(t,s)=>{for(var r in s)e.o(s,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:s[r]})},u:e=>e+".ffmpeg.js"};e.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),e.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),e.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var t;e.g.importScripts&&(t=e.g.location+"");var s=e.g.document;if(!t&&s&&(s.currentScript&&(t=s.currentScript.src),!t)){var r=s.getElementsByTagName("script");if(r.length)for(var a=r.length-1;a>-1&&!t;)t=r[a--].src}if(!t)throw new Error("Automatic publicPath is not supported in this browser");t=t.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),e.p=t})(),e.b=document.baseURI||self.location.href;var t,s={};e.r(s),e.d(s,{FFmpeg:()=>i}),function(e){e.LOAD="LOAD",e.EXEC="EXEC",e.WRITE_FILE="WRITE_FILE",e.READ_FILE="READ_FILE",e.DELETE_FILE="DELETE_FILE",e.RENAME="RENAME",e.CREATE_DIR="CREATE_DIR",e.LIST_DIR="LIST_DIR",e.DELETE_DIR="DELETE_DIR",e.ERROR="ERROR",e.DOWNLOAD="DOWNLOAD",e.PROGRESS="PROGRESS",e.LOG="LOG",e.MOUNT="MOUNT",e.UNMOUNT="UNMOUNT"}(t||(t={}));const r=(()=>{let e=0;return()=>e++})(),a=(new Error("unknown message type"),new Error("ffmpeg is not loaded, call `await ffmpeg.load()` first")),o=new Error("called FFmpeg.terminate()");new Error("failed to import ffmpeg-core.js");class i{#e=null;#t={};#s={};#r=[];#a=[];loaded=!1;#o=()=>{this.#e&&(this.#e.onmessage=({data:{id:e,type:s,data:r}})=>{switch(s){case t.LOAD:this.loaded=!0,this.#t[e](r);break;case t.MOUNT:case t.UNMOUNT:case t.EXEC:case t.WRITE_FILE:case t.READ_FILE:case t.DELETE_FILE:case t.RENAME:case t.CREATE_DIR:case t.LIST_DIR:case t.DELETE_DIR:this.#t[e](r);break;case t.LOG:this.#r.forEach((e=>e(r)));break;case t.PROGRESS:this.#a.forEach((e=>e(r)));break;case t.ERROR:this.#s[e](r)}delete this.#t[e],delete this.#s[e]})};#i=({type:e,data:t},s=[],o)=>this.#e?new Promise(((a,i)=>{const n=r();this.#e&&this.#e.postMessage({id:n,type:e,data:t},s),this.#t[n]=a,this.#s[n]=i,o?.addEventListener("abort",(()=>{i(new DOMException(`Message # ${n} was aborted`,"AbortError"))}),{once:!0})})):Promise.reject(a);on(e,t){"log"===e?this.#r.push(t):"progress"===e&&this.#a.push(t)}off(e,t){"log"===e?this.#r=this.#r.filter((e=>e!==t)):"progress"===e&&(this.#a=this.#a.filter((e=>e!==t)))}load=({classWorkerURL:s,...r}={},{signal:a}={})=>(this.#e||(this.#e=s?new Worker(new URL(s,"file:///home/jeromewu/ffmpeg.wasm/packages/ffmpeg/dist/esm/classes.js"),{type:"module"}):new Worker(new URL(e.p+e.u(814),e.b),{type:void 0}),this.#o()),this.#i({type:t.LOAD,data:r},void 0,a));exec=(e,s=-1,{signal:r}={})=>this.#i({type:t.EXEC,data:{args:e,timeout:s}},void 0,r);terminate=()=>{const e=Object.keys(this.#s);for(const t of e)this.#s[t](o),delete this.#s[t],delete this.#t[t];this.#e&&(this.#e.terminate(),this.#e=null,this.loaded=!1)};writeFile=(e,s,{signal:r}={})=>{const a=[];return s instanceof Uint8Array&&a.push(s.buffer),this.#i({type:t.WRITE_FILE,data:{path:e,data:s}},a,r)};mount=(e,s,r)=>this.#i({type:t.MOUNT,data:{fsType:e,options:s,mountPoint:r}},[]);unmount=e=>this.#i({type:t.UNMOUNT,data:{mountPoint:e}},[]);readFile=(e,s="binary",{signal:r}={})=>this.#i({type:t.READ_FILE,data:{path:e,encoding:s}},void 0,r);deleteFile=(e,{signal:s}={})=>this.#i({type:t.DELETE_FILE,data:{path:e}},void 0,s);rename=(e,s,{signal:r}={})=>this.#i({type:t.RENAME,data:{oldPath:e,newPath:s}},void 0,r);createDir=(e,{signal:s}={})=>this.#i({type:t.CREATE_DIR,data:{path:e}},void 0,s);listDir=(e,{signal:s}={})=>this.#i({type:t.LIST_DIR,data:{path:e}},void 0,s);deleteDir=(e,{signal:s}={})=>this.#i({type:t.DELETE_DIR,data:{path:e}},void 0,s)}return s})()));
//# sourceMappingURL=ffmpeg.js.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"ffmpeg.js","mappings":"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","sources":["webpack://FFmpegWASM/webpack/universalModuleDefinition","webpack://FFmpegWASM/webpack/bootstrap","webpack://FFmpegWASM/webpack/runtime/define property getters","webpack://FFmpegWASM/webpack/runtime/get javascript chunk filename","webpack://FFmpegWASM/webpack/runtime/global","webpack://FFmpegWASM/webpack/runtime/hasOwnProperty shorthand","webpack://FFmpegWASM/webpacLine truncated
-80
View File
@@ -10,11 +10,8 @@ import os
import platform
import sys
from pathlib import Path
from typing import Dict, List
import asyncio
from dotenv import load_dotenv
import httpx
BASE_DIR = Path(__file__).resolve().parent
APP_DIR = BASE_DIR / "app"
@@ -55,82 +52,6 @@ setup_logging(
)
FFMPEG_VENDOR_DIR = APP_DIR / "static" / "vendor" / "ffmpeg"
FFMPEG_VENDOR_ASSETS: Dict[str, List[str]] = {
"ffmpeg.js": [
"https://cdn.jsdelivr.net/npm/@ffmpeg/ffmpeg@0.12.10/dist/umd/ffmpeg.js",
"https://unpkg.com/@ffmpeg/ffmpeg@0.12.10/dist/umd/ffmpeg.js",
],
"814.ffmpeg.js": [
"https://cdn.jsdelivr.net/npm/@ffmpeg/ffmpeg@0.12.10/dist/umd/814.ffmpeg.js",
"https://unpkg.com/@ffmpeg/ffmpeg@0.12.10/dist/umd/814.ffmpeg.js",
],
"ffmpeg.js.map": [
"https://cdn.jsdelivr.net/npm/@ffmpeg/ffmpeg@0.12.10/dist/umd/ffmpeg.js.map",
"https://unpkg.com/@ffmpeg/ffmpeg@0.12.10/dist/umd/ffmpeg.js.map",
],
"814.ffmpeg.js.map": [
"https://cdn.jsdelivr.net/npm/@ffmpeg/ffmpeg@0.12.10/dist/umd/814.ffmpeg.js.map",
"https://unpkg.com/@ffmpeg/ffmpeg@0.12.10/dist/umd/814.ffmpeg.js.map",
],
"ffmpeg-util.js": [
"https://cdn.jsdelivr.net/npm/@ffmpeg/util@0.12.1/dist/umd/index.js",
"https://unpkg.com/@ffmpeg/util@0.12.1/dist/umd/index.js",
],
"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",
],
}
async def _download_first_success(
client: httpx.AsyncClient, filename: str, urls: List[str], target_path: Path
) -> bool:
for url in urls:
try:
resp = await client.get(url, follow_redirects=True)
if resp.status_code == 200 and resp.content:
target_path.write_bytes(resp.content)
logger.info(
f"FFmpeg vendor downloaded: {filename} <- {url} ({len(resp.content)} bytes)"
)
return True
logger.warning(
f"FFmpeg vendor candidate failed: {filename} <- {url} status={resp.status_code}"
)
except Exception as e:
logger.warning(f"FFmpeg vendor download error: {filename} <- {url}, error={e}")
return False
async def ensure_ffmpeg_vendor_assets() -> None:
"""启动时预热 ffmpeg 前端依赖到本地静态目录,避免浏览器跨域/CORS 问题。"""
FFMPEG_VENDOR_DIR.mkdir(parents=True, exist_ok=True)
timeout = httpx.Timeout(connect=8.0, read=30.0, write=30.0, pool=8.0)
async with httpx.AsyncClient(timeout=timeout) as client:
tasks = []
pending_names: list[str] = []
for filename, urls in FFMPEG_VENDOR_ASSETS.items():
target = FFMPEG_VENDOR_DIR / filename
if target.exists() and target.stat().st_size > 0:
logger.info(f"FFmpeg vendor exists: {filename}")
continue
pending_names.append(filename)
tasks.append(_download_first_success(client, filename, urls, target))
if not tasks:
return
results = await asyncio.gather(*tasks, return_exceptions=False)
failed = [name for name, ok in zip(pending_names, results) if not ok]
if failed:
logger.warning(f"FFmpeg vendor partial ready, failed={failed}")
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期管理"""
@@ -147,7 +68,6 @@ async def lifespan(app: FastAPI):
logger.info("Starting Grok2API...")
logger.info(f"Platform: {platform.system()} {platform.release()}")
logger.info(f"Python: {sys.version.split()[0]}")
await ensure_ffmpeg_vendor_assets()
# 4. 启动 Token 刷新调度器
refresh_enabled = get_config("token.auto_refresh", True)