Spaces:
Running
Running
Download app/api/media.py from basyx/MediaRouter: direct link, hf CLI and curl.
- Browser
- Download file 4.76 kB
-
https://huggingface.co/spaces/basyx/MediaRouter/resolve/main/app/api/media.py
- Command line
-
hf download hf://spaces/basyx/MediaRouter/app/api/media.py
-
curl -L -o media.py https://huggingface.co/spaces/basyx/MediaRouter/resolve/main/app/api/media.py
4.76 kB
| from __future__ import annotations | |
| from collections.abc import AsyncIterator | |
| from pathlib import Path | |
| import aiofiles | |
| from fastapi import APIRouter, Query, Request | |
| from fastapi.responses import StreamingResponse | |
| from app.core.exceptions import NotFoundError | |
| from app.core.response import SuccessResponse | |
| from app.security.assets import CanonicalAssetNotFoundError | |
| from app.services.media_service import MediaProcessor, Operation | |
| from app.services.media_url_signer import MediaURLSigner | |
| router = APIRouter(tags=["media"]) | |
| def get_processor(request: Request) -> MediaProcessor: | |
| return request.app.state.container.processor | |
| async def execute_operation(request: Request, name: str, operation: Operation) -> SuccessResponse: | |
| request.state.operation = name | |
| processor = get_processor(request) | |
| resolved = await processor.resolver.resolve(request) | |
| return await processor.run(resolved, name, operation) | |
| async def inspect_media(request: Request) -> SuccessResponse: | |
| """Inspect uploaded or remotely referenced media without transforming it. | |
| Accepts the same multipart, JSON URL/Base64, n8n binary, and raw-body | |
| inputs as processing endpoints. The shared resolver and FFprobe validation | |
| keep this endpoint's behavior consistent with the processing pipeline. | |
| """ | |
| request.state.operation = "media.inspect" | |
| processor = get_processor(request) | |
| resolved = await processor.resolver.resolve(request) | |
| return await processor.probe(resolved) | |
| async def stream_file(path: Path) -> AsyncIterator[bytes]: | |
| async with aiofiles.open(path, "rb") as media: | |
| while chunk := await media.read(1024 * 1024): | |
| yield chunk | |
| def _download_headers(path: Path, request_id: str) -> dict[str, str]: | |
| return { | |
| "Content-Disposition": f'attachment; filename="{path.name}"', | |
| "Content-Length": str(path.stat().st_size), | |
| "X-Request-ID": request_id, | |
| "X-Content-Type-Options": "nosniff", | |
| # Media links are capabilities or workspace-scoped resources. Avoid | |
| # intermediary/browser cache retention beyond their authorization. | |
| "Cache-Control": "private, no-store", | |
| } | |
| async def download_media(request: Request, request_id: str, filename: str) -> StreamingResponse: | |
| request.state.operation = "media.download" | |
| container = request.app.state.container | |
| # The filesystem locator is not an authorization token. In authenticated | |
| # deployments an output must have been issued by the pipeline to the | |
| # caller's authoritative workspace before it can be downloaded. | |
| if container.settings.auth_enabled: | |
| context = getattr(request.state, "auth", None) | |
| if context is None or not context.workspace_id: | |
| raise NotFoundError("Output file not found") | |
| try: | |
| asset = await container.assets.get_owned( | |
| workspace_id=context.workspace_id, | |
| request_id=request_id, | |
| filename=filename, | |
| ) | |
| path = container.cleanup.resolve_download(request_id, asset.filename) | |
| await container.assets.verify_file(asset, path) | |
| except CanonicalAssetNotFoundError as exc: | |
| raise NotFoundError("Output file not found") from exc | |
| else: | |
| path = container.cleanup.resolve_download(request_id, filename) | |
| media_type = container.validator.infer_mime(path) | |
| return StreamingResponse( | |
| stream_file(path), media_type=media_type, headers=_download_headers(path, request_id) | |
| ) | |
| async def download_signed_media( | |
| request: Request, | |
| request_id: str, | |
| filename: str, | |
| expires: int = Query(..., ge=1), | |
| signature: str = Query(..., min_length=16), | |
| ) -> StreamingResponse: | |
| """Serve a published file using a time-limited HMAC URL. | |
| This endpoint intentionally does not require an Authorization header. | |
| Possession of a valid, unexpired signature is the capability. The | |
| signature is bound to the exact request ID and filename. | |
| """ | |
| request.state.operation = "media.signed_download" | |
| container = request.app.state.container | |
| signer = MediaURLSigner(container.settings) | |
| if not signer.verify(request_id, filename, expires, signature): | |
| raise NotFoundError("Output file not found") | |
| path = container.cleanup.resolve_download(request_id, filename) | |
| media_type = container.validator.infer_mime(path) | |
| return StreamingResponse( | |
| stream_file(path), media_type=media_type, headers=_download_headers(path, request_id) | |
| ) | |