122 lines
4.5 KiB
Python
122 lines
4.5 KiB
Python
import threading
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from fastapi.responses import FileResponse, StreamingResponse
|
|
from sqlalchemy.orm import Session
|
|
|
|
from api.schemas import CleanupRequest, VideoCreate, VideoResponse
|
|
from database.database import SessionLocal, get_db
|
|
from download.download_service import download_video
|
|
from model.video import Video
|
|
from notify.notify_clients import notify_clients
|
|
from stream.stream_service import stream_video_live
|
|
|
|
router = APIRouter(prefix="/videos", tags=["videos"])
|
|
|
|
|
|
@router.post("", response_model=list[VideoResponse])
|
|
async def create_videos(videos_data: list[VideoCreate], db: Session = Depends(get_db)):
|
|
created_ids = []
|
|
profile_ids = set()
|
|
for video_data in reversed(videos_data):
|
|
video_id_match = video_data.youtube_url.split("v=")[-1].split("&")[0]
|
|
Video.delete_by_youtube_id(db, video_id_match)
|
|
data = video_data.model_dump(exclude={"profile_id"})
|
|
video = Video.create_from_dict(db, data, video_data.profile_id)
|
|
created_ids.append(video.id)
|
|
profile_ids.add(video_data.profile_id or 1)
|
|
videos = [Video.get_by_id(db, vid) for vid in created_ids]
|
|
|
|
if profile_ids:
|
|
await notify_clients(list(profile_ids))
|
|
|
|
return [VideoResponse.from_model(v) for v in videos if v]
|
|
|
|
|
|
@router.get("", response_model=list[VideoResponse])
|
|
def get_all_videos(profile_id: Optional[int] = Query(None), db: Session = Depends(get_db)):
|
|
videos = Video.get_all(db, profile_id=profile_id)
|
|
return [VideoResponse.from_model(v) for v in videos]
|
|
|
|
|
|
@router.get("/downloaded", response_model=list[VideoResponse])
|
|
def get_downloaded_videos(profile_id: Optional[int] = Query(None), db: Session = Depends(get_db)):
|
|
videos = Video.get_downloaded(db, profile_id=profile_id)
|
|
return [VideoResponse.from_model(v) for v in videos]
|
|
|
|
|
|
@router.post("/cleanup")
|
|
def cleanup_videos(request: CleanupRequest, db: Session = Depends(get_db)):
|
|
count = Video.delete_not_downloaded(db, request.profile_id, request.exclude_ids or None)
|
|
return {"deleted": count}
|
|
|
|
|
|
@router.post("/{video_id}/download")
|
|
def trigger_download(video_id: int, db: Session = Depends(get_db)):
|
|
video = Video.get_by_id(db, video_id)
|
|
if not video:
|
|
raise HTTPException(status_code=404, detail="Video nicht gefunden")
|
|
if video.file_path:
|
|
return {"status": "already_downloaded"}
|
|
|
|
thread = threading.Thread(target=download_video, args=(video.id, video.youtube_url))
|
|
thread.start()
|
|
return {"status": "download_started"}
|
|
|
|
|
|
@router.get("/{video_id}/stream")
|
|
def stream_video(video_id: int, db: Session = Depends(get_db)):
|
|
video = Video.get_by_id(db, video_id)
|
|
if not video:
|
|
raise HTTPException(status_code=404, detail="Video nicht gefunden")
|
|
|
|
if not video.file_path:
|
|
def stream_and_save():
|
|
output_path = f"/videos/{video_id}.mp4"
|
|
yield from stream_video_live(video_id, video.youtube_url)
|
|
if Path(output_path).exists():
|
|
sdb = SessionLocal()
|
|
try:
|
|
Video.update_file_path(sdb, video_id, output_path)
|
|
finally:
|
|
sdb.close()
|
|
|
|
return StreamingResponse(stream_and_save(), media_type="video/mp4")
|
|
|
|
path = Path(video.file_path)
|
|
if not path.exists():
|
|
raise HTTPException(status_code=404, detail="Videodatei nicht gefunden")
|
|
|
|
return FileResponse(path, media_type="video/mp4")
|
|
|
|
|
|
@router.get("/{video_id}/file")
|
|
def download_file(video_id: int, db: Session = Depends(get_db)):
|
|
video = Video.get_by_id(db, video_id)
|
|
if not video:
|
|
raise HTTPException(status_code=404, detail="Video nicht gefunden")
|
|
if not video.file_path:
|
|
raise HTTPException(status_code=404, detail="Video noch nicht heruntergeladen")
|
|
|
|
path = Path(video.file_path)
|
|
if not path.exists():
|
|
Video.update_file_path(db, video_id, None)
|
|
raise HTTPException(status_code=404, detail="Video noch nicht heruntergeladen")
|
|
|
|
return FileResponse(path, media_type="video/mp4", filename=f"{video.title}.mp4")
|
|
|
|
|
|
@router.delete("/{video_id}/file")
|
|
def delete_server_file(video_id: int, db: Session = Depends(get_db)):
|
|
video = Video.get_by_id(db, video_id)
|
|
if not video:
|
|
raise HTTPException(status_code=404, detail="Video nicht gefunden")
|
|
if video.file_path:
|
|
path = Path(video.file_path)
|
|
if path.exists():
|
|
path.unlink()
|
|
Video.update_file_path(db, video_id, None)
|
|
return {"status": "deleted"}
|