Initial commit: Video metadata registration service

- Add FastAPI server for video metadata registration
- PostgreSQL database models for videos, video_streams, audio_streams, subtitle_streams
- Batch registration script for .probe.json files
- RESTful API endpoints for CRUD operations
- Search functionality by title, artist, codec, resolution
This commit is contained in:
accusys
2026-03-11 00:30:31 +08:00
commit b4aa7b96d3
16 changed files with 709 additions and 0 deletions

66
app/api/routes/videos.py Normal file
View File

@@ -0,0 +1,66 @@
import os
from typing import Optional
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from app.database import get_db
from app.models.schemas import VideoSchema, VideoListResponse, RegisterRequest
from app.services.video_register import VideoRegisterService
router = APIRouter(prefix="/videos", tags=["videos"])
@router.post("", response_model=VideoSchema)
def register_video(request: RegisterRequest, db: Session = Depends(get_db)):
if not os.path.exists(request.probe_json_path):
raise HTTPException(status_code=404, detail="Probe JSON file not found")
if not os.path.exists(request.absolute_file_path):
raise HTTPException(status_code=404, detail="Video file not found")
service = VideoRegisterService(db)
video = service.register_video(request.probe_json_path, request.absolute_file_path)
return video
@router.get("/{video_id}", response_model=VideoSchema)
def get_video(video_id: UUID, db: Session = Depends(get_db)):
service = VideoRegisterService(db)
video = service.get_video_by_id(video_id)
if not video:
raise HTTPException(status_code=404, detail="Video not found")
return video
@router.get("", response_model=VideoListResponse)
def search_videos(
title: Optional[str] = Query(None, description="Search by title"),
artist: Optional[str] = Query(None, description="Search by artist"),
codec_name: Optional[str] = Query(None, description="Search by video codec"),
min_width: Optional[int] = Query(None, description="Minimum video width"),
max_width: Optional[int] = Query(None, description="Maximum video width"),
min_height: Optional[int] = Query(None, description="Minimum video height"),
max_height: Optional[int] = Query(None, description="Maximum video height"),
format_name: Optional[str] = Query(None, description="Search by format name"),
skip: int = Query(0, ge=0),
limit: int = Query(20, ge=1, le=100),
db: Session = Depends(get_db),
):
service = VideoRegisterService(db)
total, videos = service.search_videos(
title=title,
artist=artist,
codec_name=codec_name,
min_width=min_width,
max_width=max_width,
min_height=min_height,
max_height=max_height,
format_name=format_name,
skip=skip,
limit=limit,
)
return {"total": total, "videos": videos}