122 lines
4.1 KiB
Python
122 lines
4.1 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, getDb
|
|
from download.download_service import downloadVideo
|
|
from model.video import Video
|
|
from notify.notify_clients import notifyClients
|
|
from stream.stream_service import streamVideoLive
|
|
|
|
router = APIRouter(prefix="/videos", tags=["videos"])
|
|
|
|
|
|
@router.post("", status_code=204)
|
|
async def create(videoData: VideoCreate, db: Session = Depends(getDb)):
|
|
title = videoData.title
|
|
youtuber = videoData.youtuber
|
|
thumbnailUrl = videoData.thumbnailUrl
|
|
youtubeUrl = videoData.youtubeUrl
|
|
profileId = videoData.profileId
|
|
|
|
Video.deleteIfExists(db, youtubeUrl, profileId)
|
|
Video.create(db, title, youtuber, thumbnailUrl, youtubeUrl, profileId)
|
|
await notifyClients(profileId)
|
|
|
|
|
|
@router.get("", response_model=list[VideoResponse])
|
|
def getAll(
|
|
profileId: Optional[int] = Query(None),
|
|
db: Session = Depends(getDb),
|
|
):
|
|
videos = Video.getAll(db, profileId=profileId)
|
|
return [VideoResponse.fromModel(v) for v in videos]
|
|
|
|
|
|
@router.get("/downloaded", response_model=list[VideoResponse])
|
|
def getDownloaded(
|
|
profileId: Optional[int] = Query(None),
|
|
db: Session = Depends(getDb),
|
|
):
|
|
videos = Video.getDownloaded(db, profileId=profileId)
|
|
return [VideoResponse.fromModel(v) for v in videos]
|
|
|
|
|
|
@router.post("/cleanup")
|
|
def cleanup(request: CleanupRequest, db: Session = Depends(getDb)):
|
|
count = Video.deleteNotDownloaded(db, request.profileId, request.excludeIds or None)
|
|
return {"deleted": count}
|
|
|
|
|
|
@router.post("/{videoId}/download")
|
|
def download(videoId: int, db: Session = Depends(getDb)):
|
|
video = Video.getById(db, videoId)
|
|
if not video:
|
|
raise HTTPException(status_code=404, detail="Video nicht gefunden")
|
|
if video.filePath:
|
|
return {"status": "already_downloaded"}
|
|
|
|
thread = threading.Thread(target=downloadVideo, args=(video.id, video.youtubeUrl))
|
|
thread.start()
|
|
return {"status": "download_started"}
|
|
|
|
|
|
@router.get("/{videoId}/stream")
|
|
def stream(videoId: int, db: Session = Depends(getDb)):
|
|
video = Video.getById(db, videoId)
|
|
if not video:
|
|
raise HTTPException(status_code=404, detail="Video nicht gefunden")
|
|
|
|
if not video.filePath:
|
|
def streamAndSave():
|
|
outputPath = f"/videos/{videoId}.mp4"
|
|
yield from streamVideoLive(videoId, video.youtubeUrl)
|
|
if Path(outputPath).exists():
|
|
sdb = SessionLocal()
|
|
try:
|
|
Video.updateFilePath(sdb, videoId, outputPath)
|
|
finally:
|
|
sdb.close()
|
|
|
|
return StreamingResponse(streamAndSave(), media_type="video/mp4")
|
|
|
|
path = Path(video.filePath)
|
|
if not path.exists():
|
|
raise HTTPException(status_code=404, detail="Videodatei nicht gefunden")
|
|
|
|
return FileResponse(path, media_type="video/mp4")
|
|
|
|
|
|
@router.get("/{videoId}/file")
|
|
def getFile(videoId: int, db: Session = Depends(getDb)):
|
|
video = Video.getById(db, videoId)
|
|
if not video:
|
|
raise HTTPException(status_code=404, detail="Video nicht gefunden")
|
|
if not video.filePath:
|
|
raise HTTPException(status_code=404, detail="Video noch nicht heruntergeladen")
|
|
|
|
path = Path(video.filePath)
|
|
if not path.exists():
|
|
Video.updateFilePath(db, videoId, 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("/{videoId}/file")
|
|
def deleteFile(videoId: int, db: Session = Depends(getDb)):
|
|
video = Video.getById(db, videoId)
|
|
if not video:
|
|
raise HTTPException(status_code=404, detail="Video nicht gefunden")
|
|
if video.filePath:
|
|
path = Path(video.filePath)
|
|
if path.exists():
|
|
path.unlink()
|
|
Video.updateFilePath(db, videoId, None)
|
|
return {"status": "deleted"}
|