""" Asset endpoints - media file registration and metadata. """ from typing import Optional from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query from api.deps import get_asset from api.schema import AssetCreate, AssetResponse, AssetUpdate from core.storage import BUCKET_IN, list_objects router = APIRouter(prefix="/assets", tags=["assets"]) # Supported media extensions VIDEO_EXTS = {".mp4", ".mkv", ".avi", ".mov", ".webm", ".flv", ".wmv", ".m4v"} AUDIO_EXTS = {".mp3", ".wav", ".flac", ".aac", ".ogg", ".m4a"} MEDIA_EXTS = VIDEO_EXTS | AUDIO_EXTS @router.post("/", response_model=AssetResponse, status_code=201) def create_asset(data: AssetCreate): """Register a media file as an asset.""" from mpr.media_assets.models import MediaAsset asset = MediaAsset.objects.create( filename=data.filename or data.file_path.split("/")[-1], file_path=data.file_path, file_size=data.file_size, ) return asset @router.get("/", response_model=list[AssetResponse]) def list_assets( status: Optional[str] = Query(None, description="Filter by status"), limit: int = Query(50, ge=1, le=100), offset: int = Query(0, ge=0), ): """List assets with optional filtering.""" from mpr.media_assets.models import MediaAsset qs = MediaAsset.objects.all() if status: qs = qs.filter(status=status) return list(qs[offset : offset + limit]) @router.get("/{asset_id}", response_model=AssetResponse) def get_asset_detail(asset_id: UUID, asset=Depends(get_asset)): """Get asset details.""" return asset @router.patch("/{asset_id}", response_model=AssetResponse) def update_asset(asset_id: UUID, data: AssetUpdate, asset=Depends(get_asset)): """Update asset metadata (comments, tags).""" update_fields = [] if data.comments is not None: asset.comments = data.comments update_fields.append("comments") if data.tags is not None: asset.tags = data.tags update_fields.append("tags") if update_fields: asset.save(update_fields=update_fields) return asset @router.delete("/{asset_id}", status_code=204) def delete_asset(asset_id: UUID, asset=Depends(get_asset)): """Delete an asset.""" asset.delete() @router.post("/scan", response_model=dict) def scan_media_folder(): """ Scan the S3 media-in bucket for new video/audio files and register them as assets. """ from mpr.media_assets.models import MediaAsset # List objects from S3 bucket objects = list_objects(BUCKET_IN, extensions=MEDIA_EXTS) # Get existing filenames to avoid duplicates existing_filenames = set(MediaAsset.objects.values_list("filename", flat=True)) registered_files = [] skipped_files = [] for obj in objects: if obj["filename"] in existing_filenames: skipped_files.append(obj["filename"]) continue try: MediaAsset.objects.create( filename=obj["filename"], file_path=obj["key"], file_size=obj["size"], ) registered_files.append(obj["filename"]) except Exception as e: print(f"Error registering {obj['filename']}: {e}") return { "found": len(objects), "registered": len(registered_files), "skipped": len(skipped_files), "files": registered_files, }