Files
iptv-manager-service/app/routers/playlist.py
Stefano a42d4c30a6
All checks were successful
AWS Deploy on Push / build (push) Successful in 5m18s
Started (incomplete) implementation of stream verification scheduler and endpoints
2025-06-17 17:12:39 -05:00

157 lines
4.7 KiB
Python

import logging
from enum import Enum
from typing import Optional
from uuid import uuid4
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, status
from pydantic import BaseModel
from sqlalchemy.orm import Session
from app.auth.dependencies import get_current_user
from app.iptv.stream_manager import StreamManager
from app.models.auth import CognitoUser
from app.utils.database import get_db_session
router = APIRouter(prefix="/playlist", tags=["playlist"])
logger = logging.getLogger(__name__)
# In-memory store for validation processes
validation_processes: dict[str, dict] = {}
class ProcessStatus(str, Enum):
PENDING = "pending"
IN_PROGRESS = "in_progress"
COMPLETED = "completed"
FAILED = "failed"
class StreamValidationRequest(BaseModel):
"""Request model for stream validation endpoint"""
channel_id: Optional[str] = None
class ValidatedStream(BaseModel):
"""Model for a validated working stream"""
channel_id: str
stream_url: str
class ValidationProcessResponse(BaseModel):
"""Response model for validation process initiation"""
process_id: str
status: ProcessStatus
message: str
class ValidationResultResponse(BaseModel):
"""Response model for validation results"""
process_id: str
status: ProcessStatus
working_streams: Optional[list[ValidatedStream]] = None
error: Optional[str] = None
def run_stream_validation(process_id: str, channel_id: Optional[str], db: Session):
"""Background task to validate streams"""
try:
validation_processes[process_id]["status"] = ProcessStatus.IN_PROGRESS
manager = StreamManager(db)
if channel_id:
stream_url = manager.validate_and_select_stream(channel_id)
if stream_url:
validation_processes[process_id]["result"] = {
"working_streams": [
ValidatedStream(channel_id=channel_id, stream_url=stream_url)
]
}
else:
validation_processes[process_id]["error"] = (
f"No working streams found for channel {channel_id}"
)
else:
# TODO: Implement validation for all channels
validation_processes[process_id]["error"] = (
"Validation of all channels not yet implemented"
)
validation_processes[process_id]["status"] = ProcessStatus.COMPLETED
except Exception as e:
logger.error(f"Error validating streams: {str(e)}")
validation_processes[process_id]["status"] = ProcessStatus.FAILED
validation_processes[process_id]["error"] = str(e)
@router.post(
"/validate-streams",
summary="Start stream validation process",
response_model=ValidationProcessResponse,
status_code=status.HTTP_202_ACCEPTED,
responses={202: {"description": "Validation process started successfully"}},
)
async def start_stream_validation(
request: StreamValidationRequest,
background_tasks: BackgroundTasks,
user: CognitoUser = Depends(get_current_user),
db: Session = Depends(get_db_session),
):
"""
Start asynchronous validation of streams.
- Returns immediately with a process ID
- Use GET /validate-streams/{process_id} to check status
"""
process_id = str(uuid4())
validation_processes[process_id] = {
"status": ProcessStatus.PENDING,
"channel_id": request.channel_id,
}
background_tasks.add_task(run_stream_validation, process_id, request.channel_id, db)
return {
"process_id": process_id,
"status": ProcessStatus.PENDING,
"message": "Validation process started",
}
@router.get(
"/validate-streams/{process_id}",
summary="Check validation process status",
response_model=ValidationResultResponse,
responses={
200: {"description": "Process status and results"},
404: {"description": "Process not found"},
},
)
async def get_validation_status(
process_id: str, user: CognitoUser = Depends(get_current_user)
):
"""
Check status of a stream validation process.
Returns current status and results if completed.
"""
if process_id not in validation_processes:
raise HTTPException(status_code=404, detail="Process not found")
process = validation_processes[process_id]
response = {"process_id": process_id, "status": process["status"]}
if process["status"] == ProcessStatus.COMPLETED:
if "error" in process:
response["error"] = process["error"]
else:
response["working_streams"] = process["result"]["working_streams"]
elif process["status"] == ProcessStatus.FAILED:
response["error"] = process["error"]
return response