From 2cccc1b1d11fdedd2d3f9d6efb124fee27b5da89 Mon Sep 17 00:00:00 2001 From: Xiaoxia AI Date: Tue, 23 Jun 2026 11:44:10 +0800 Subject: [PATCH] fix(upload): support mov assets and large web uploads --- apps/worker/worker_app/core/asset_types.py | 7 +++++++ apps/worker/worker_app/tasks/ingest.py | 7 +++---- infra/docker/nginx-production.conf | 3 +++ tests/unit/test_release_scripts.py | 2 ++ tests/unit/test_worker_ingest.py | 19 +++++++++++++++++++ 5 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 apps/worker/worker_app/core/asset_types.py create mode 100644 tests/unit/test_worker_ingest.py diff --git a/apps/worker/worker_app/core/asset_types.py b/apps/worker/worker_app/core/asset_types.py new file mode 100644 index 000000000..f798848d5 --- /dev/null +++ b/apps/worker/worker_app/core/asset_types.py @@ -0,0 +1,7 @@ +def infer_mime_type_from_storage_key(storage_key: str) -> str: + lower_filename = storage_key.rsplit("/", 1)[-1].lower() + if lower_filename.endswith(".mov"): + return "video/quicktime" + if lower_filename.endswith((".mp4", ".m4v", ".avi", ".mkv", ".webm")): + return "video/mp4" + return "image/jpeg" diff --git a/apps/worker/worker_app/tasks/ingest.py b/apps/worker/worker_app/tasks/ingest.py index cfdd5e6b2..fc5d6df33 100644 --- a/apps/worker/worker_app/tasks/ingest.py +++ b/apps/worker/worker_app/tasks/ingest.py @@ -8,6 +8,7 @@ from packages.adapters.sqlalchemy_impl import ( SQLAlchemyIngestJobRepository, ) from packages.domain import Asset, IngestJobStatus +from worker_app.core.asset_types import infer_mime_type_from_storage_key @celery_app.task(name="worker.ingest_asset") @@ -37,7 +38,8 @@ def ingest_asset(job_id: str) -> dict: job_repo.update(job) # Mock metadata extraction (in real implementation: use ffprobe, Pillow, etc.) - mime_type = "video/mp4" if job.storage_key.endswith(".mp4") else "image/jpeg" + filename = job.storage_key.split("/")[-1] + mime_type = infer_mime_type_from_storage_key(job.storage_key) metadata = { "duration": 10.5, "width": 1920, @@ -45,9 +47,6 @@ def ingest_asset(job_id: str) -> dict: "size_bytes": 1024000, } - # Extract filename from storage_key - filename = job.storage_key.split("/")[-1] - # Create Asset asset = Asset.create( workspace_id=job.workspace_id, diff --git a/infra/docker/nginx-production.conf b/infra/docker/nginx-production.conf index efeae1500..696f5a536 100644 --- a/infra/docker/nginx-production.conf +++ b/infra/docker/nginx-production.conf @@ -16,6 +16,9 @@ server { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 300s; + proxy_send_timeout 300s; + proxy_request_buffering off; } location / { diff --git a/tests/unit/test_release_scripts.py b/tests/unit/test_release_scripts.py index 0497da50c..a40630d31 100644 --- a/tests/unit/test_release_scripts.py +++ b/tests/unit/test_release_scripts.py @@ -70,6 +70,8 @@ def test_production_nginx_static_upstream_requires_web_recreate(): assert "proxy_pass http://xiaoxia-api-production:8000/api/;" in config assert "client_max_body_size 100m;" in config + assert "proxy_read_timeout 300s;" in config + assert "proxy_request_buffering off;" in config assert "--force-recreate web" in script diff --git a/tests/unit/test_worker_ingest.py b/tests/unit/test_worker_ingest.py new file mode 100644 index 000000000..a40a495a5 --- /dev/null +++ b/tests/unit/test_worker_ingest.py @@ -0,0 +1,19 @@ +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "apps" / "worker")) + +from worker_app.core.asset_types import infer_mime_type_from_storage_key + + +def test_infer_mime_type_treats_mov_as_video(): + assert infer_mime_type_from_storage_key("uploads/abc/DBLQ7915.MOV") == "video/quicktime" + + +def test_infer_mime_type_treats_common_video_extensions_as_video(): + for filename in ["clip.mp4", "clip.m4v", "clip.avi", "clip.mkv", "clip.webm"]: + assert infer_mime_type_from_storage_key(f"uploads/abc/{filename}") == "video/mp4" + + +def test_infer_mime_type_keeps_unknown_files_as_image_placeholder(): + assert infer_mime_type_from_storage_key("uploads/abc/photo.jpg") == "image/jpeg"