update references to codey.lol -> codey.horse [new domain]

This commit is contained in:
2026-02-21 08:00:38 -05:00
parent d6689b9c38
commit 83285ff08c
6 changed files with 89 additions and 31 deletions

View File

@@ -686,7 +686,10 @@ class RIP(FastAPI):
self, video_id: str, request: Request, user=Depends(get_current_user)
) -> Response:
"""
Download a video file.
Download a video file via streaming.
Streams the video directly from the HLS source through ffmpeg
to the client without buffering the entire file to disk first.
Parameters:
- **video_id** (str): The Tidal video ID.
@@ -694,10 +697,11 @@ class RIP(FastAPI):
- **user**: Current user (dependency).
Returns:
- **Response**: The video file as a streaming response.
- **Response**: Streaming video response.
"""
from fastapi.responses import FileResponse
import os
from fastapi.responses import StreamingResponse
import asyncio
import re
if "trip" not in user.get("roles", []) and "admin" not in user.get("roles", []):
raise HTTPException(status_code=403, detail="Insufficient permissions")
@@ -710,32 +714,76 @@ class RIP(FastAPI):
status_code=400,
)
# Get video metadata for filename
metadata = await self.trip_util.get_video_metadata(vid_id)
# Get video metadata and stream URL concurrently
metadata, stream_url = await asyncio.gather(
self.trip_util.get_video_metadata(vid_id),
self.trip_util.get_video_stream_url(vid_id),
)
if not metadata:
return JSONResponse(
content={"error": "Video not found"},
status_code=404,
)
# Download the video
file_path = await self.trip_util.download_video(vid_id)
if not file_path or not os.path.exists(file_path):
if not stream_url:
return JSONResponse(
content={"error": "Failed to download video"},
content={"error": "Video stream not available"},
status_code=500,
)
# Generate a nice filename
# Build a safe filename
artist = metadata.get("artist", "Unknown")
title = metadata.get("title", f"video_{vid_id}")
# Sanitize filename
safe_filename = f"{artist} - {title}.mp4".replace("/", "-").replace("\\", "-")
safe_filename = re.sub(r'[<>:"|?*\x00-\x1F]', '', f"{artist} - {title}.mp4")
safe_filename = safe_filename.replace("/", "-").replace("\\", "-")
return FileResponse(
path=file_path,
filename=safe_filename,
async def stream_video():
"""Stream ffmpeg output directly to client."""
cmd = [
"ffmpeg",
"-nostdin",
"-hide_banner",
"-loglevel", "error",
"-analyzeduration", "10M",
"-probesize", "10M",
"-i", stream_url,
"-c:v", "copy",
"-c:a", "aac",
"-b:a", "256k",
"-af", "aresample=async=1:first_pts=0",
"-movflags", "frag_keyframe+empty_moov+faststart",
"-f", "mp4",
"pipe:1",
]
proc = await asyncio.create_subprocess_exec(
*cmd,
stdin=asyncio.subprocess.DEVNULL,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
try:
while True:
chunk = await proc.stdout.read(256 * 1024) # 256KB chunks
if not chunk:
break
yield chunk
finally:
if proc.returncode is None:
try:
proc.kill()
except Exception:
pass
await proc.wait()
return StreamingResponse(
stream_video(),
media_type="video/mp4",
headers={
"Content-Disposition": f'attachment; filename="{safe_filename}"',
},
)
async def video_bulk_fetch_handler(