update references to codey.lol -> codey.horse [new domain]
This commit is contained in:
@@ -4,6 +4,7 @@ import regex
|
||||
import aiosqlite as sqlite3
|
||||
from fastapi import FastAPI, HTTPException, Depends
|
||||
from fastapi_throttle import RateLimiter
|
||||
from fastapi.requests import Request
|
||||
from fastapi.responses import JSONResponse
|
||||
from typing import LiteralString, Optional, Union, Iterable
|
||||
from regex import Pattern
|
||||
@@ -128,7 +129,7 @@ class LyricSearch(FastAPI):
|
||||
return JSONResponse(content=[])
|
||||
return JSONResponse(content=typeahead)
|
||||
|
||||
async def lyric_search_handler(self, data: ValidLyricRequest) -> JSONResponse:
|
||||
async def lyric_search_handler(self, data: ValidLyricRequest, request: Request) -> JSONResponse:
|
||||
"""
|
||||
Search for lyrics.
|
||||
|
||||
@@ -317,4 +318,13 @@ class LyricSearch(FastAPI):
|
||||
if not data.extra:
|
||||
result.pop("src")
|
||||
|
||||
# Check if the request is coming from the old domain
|
||||
host = request.headers.get("host", "")
|
||||
if "api.codey.lol" in host:
|
||||
warning_message = "Warning: The API domain is moving to api.codey.horse. Please update your scripts to use the new domain."
|
||||
if "lyrics" in result:
|
||||
result["lyrics"] = f"{warning_message}<br>{result['lyrics']}"
|
||||
elif "lrc" in result:
|
||||
result["lrc"] = f"{warning_message}\n{result['lrc']}"
|
||||
|
||||
return JSONResponse(content=result)
|
||||
|
||||
@@ -357,7 +357,7 @@ class Radio(FastAPI):
|
||||
logging.debug("album_art_handler Exception: %s", str(e))
|
||||
traceback.print_exc()
|
||||
return RedirectResponse(
|
||||
url="https://codey.lol/images/radio_art_default.jpg", status_code=302
|
||||
url="https://codey.horse/images/radio_art_default.jpg", status_code=302
|
||||
)
|
||||
|
||||
async def radio_now_playing(self, request: Request,
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user