shoehorning graphql, step functions and lamdas. aws deployment scripts
This commit is contained in:
@@ -9,45 +9,26 @@ from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
|
||||
from api.deps import get_asset
|
||||
from api.schemas 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.
|
||||
|
||||
The file must exist on disk. A probe task will be queued
|
||||
to extract metadata asynchronously.
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
"""Register a media file as an asset."""
|
||||
from mpr.media_assets.models import MediaAsset
|
||||
|
||||
# Validate file exists
|
||||
path = Path(data.file_path)
|
||||
if not path.exists():
|
||||
raise HTTPException(status_code=400, detail="File not found")
|
||||
|
||||
# Store path relative to media root
|
||||
import os
|
||||
|
||||
media_root = Path(os.environ.get("MEDIA_IN", "/app/media/in"))
|
||||
try:
|
||||
rel_path = str(path.relative_to(media_root))
|
||||
except ValueError:
|
||||
rel_path = path.name
|
||||
|
||||
# Create asset
|
||||
asset = MediaAsset.objects.create(
|
||||
filename=data.filename or path.name,
|
||||
file_path=rel_path,
|
||||
file_size=path.stat().st_size,
|
||||
filename=data.filename or data.file_path.split("/")[-1],
|
||||
file_path=data.file_path,
|
||||
file_size=data.file_size,
|
||||
)
|
||||
|
||||
# TODO: Queue probe task via gRPC/Celery
|
||||
|
||||
return asset
|
||||
|
||||
|
||||
@@ -61,10 +42,8 @@ def list_assets(
|
||||
from mpr.media_assets.models import MediaAsset
|
||||
|
||||
qs = MediaAsset.objects.all()
|
||||
|
||||
if status:
|
||||
qs = qs.filter(status=status)
|
||||
|
||||
return list(qs[offset : offset + limit])
|
||||
|
||||
|
||||
@@ -102,62 +81,36 @@ def delete_asset(asset_id: UUID, asset=Depends(get_asset)):
|
||||
@router.post("/scan", response_model=dict)
|
||||
def scan_media_folder():
|
||||
"""
|
||||
Scan the media folder for new video/audio files and register them as assets.
|
||||
|
||||
Returns a summary of files found and registered.
|
||||
Scan the S3 media-in bucket for new video/audio files and register them as assets.
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from mpr.media_assets.models import MediaAsset
|
||||
|
||||
# Get media input folder from environment
|
||||
media_root = os.environ.get("MEDIA_IN", "/app/media/in")
|
||||
media_path = Path(media_root)
|
||||
|
||||
if not media_path.exists():
|
||||
raise HTTPException(
|
||||
status_code=500, detail=f"Media folder not found: {media_root}"
|
||||
)
|
||||
|
||||
# Supported video/audio extensions
|
||||
video_exts = {".mp4", ".mkv", ".avi", ".mov", ".webm", ".flv", ".wmv", ".m4v"}
|
||||
audio_exts = {".mp3", ".wav", ".flac", ".aac", ".ogg", ".m4a"}
|
||||
supported_exts = video_exts | audio_exts
|
||||
# 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))
|
||||
|
||||
# Scan for media files
|
||||
found_files = []
|
||||
registered_files = []
|
||||
skipped_files = []
|
||||
|
||||
for file_path in media_path.rglob("*"):
|
||||
if file_path.is_file() and file_path.suffix.lower() in supported_exts:
|
||||
found_files.append(str(file_path))
|
||||
for obj in objects:
|
||||
if obj["filename"] in existing_filenames:
|
||||
skipped_files.append(obj["filename"])
|
||||
continue
|
||||
|
||||
# Skip if already registered
|
||||
if file_path.name in existing_filenames:
|
||||
skipped_files.append(file_path.name)
|
||||
continue
|
||||
|
||||
# Register new asset with path relative to media root
|
||||
rel_path = str(file_path.relative_to(media_path))
|
||||
try:
|
||||
asset = MediaAsset.objects.create(
|
||||
filename=file_path.name,
|
||||
file_path=rel_path,
|
||||
file_size=file_path.stat().st_size,
|
||||
)
|
||||
registered_files.append(file_path.name)
|
||||
|
||||
# TODO: Queue probe task to extract metadata
|
||||
except Exception as e:
|
||||
print(f"Error registering {file_path.name}: {e}")
|
||||
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(found_files),
|
||||
"found": len(objects),
|
||||
"registered": len(registered_files),
|
||||
"skipped": len(skipped_files),
|
||||
"files": registered_files,
|
||||
|
||||
Reference in New Issue
Block a user