Files
yt2mp3/server/py/fastapi_server/main.py
2026-01-19 21:42:34 +00:00

124 lines
4.1 KiB
Python

# src/main.py
from fastapi import FastAPI, HTTPException, status, Request
from fastapi.responses import JSONResponse, PlainTextResponse
import os
import bcrypt
import asyncio
import logging
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
from . import db_setup as db # Import the entire db_setup module
from .user_mgmt import *
from .media_mgmt import *
app = FastAPI(
title="YT2MP3 API",
description="Simple API to download YouTube videos as MP3.",
version="1.0.0",
license_info="MIT",
lifespan=db.lifespan
)
# Global error handler
@app.exception_handler(Exception)
async def global_exception_handler(request, exc):
logger.exception(f"An unexpected error occurred: {exc}")
return JSONResponse(content={"error": "Internal Server Error"}, status_code=500)
# Health check endpoint
@app.get("/health", status_code=status.HTTP_200_OK)
async def health_check():
return {"status": "ok"}
#
# User-related endpoints
#
@app.get("/me")
async def me_endpoint(req: Request):
query = dict(req.query_params)
if "id" not in query.keys(): raise HTTPException(400, "Give ID")
user = await fetch_user_info(query["id"],"id")
if user is None: raise HTTPException(404, "User not found")
else:
return user
@app.post("/login")
async def login_endpoint(req: Request):
body = await req.json()
needed_keys = ("email","password")
for key in needed_keys:
if body.get(key) is None:
raise HTTPException(400, "Missing args")
login_obj = login_user(body["email"], body["password"])
if login_obj is None:
raise HTTPException(401, "Incorrect login")
else:
return login_obj
@app.post("/register")
async def register_endpoint(req: Request):
body = await req.json()
for key in ("email","password", "first_name", "last_name"):
if body.get(key) is None:
raise HTTPException(400, "Missing args")
# check if user exists.
if await fetch_user_info(body["email"],"email") is not None:
raise HTTPException(403, "User already exists")
create_user(body["fist_name"], body["last_name"], body["email"], body["password"])
return PlainTextResponse("User registered")
@app.put("/edit_user")
async def edit_endpoint(req: Request):
body:dict = await req.json()
if "user_id" not in body.keys(): raise HTTPException(400, "Provide user ID")
params = body
params.pop("user_id")
edit_user(body["user_id"], params)
return PlainTextResponse("User edited")
#
# Track-specific endpoints
#
@app.post("/convert")
async def begin_conversion(req: Request):
body:dict = await req.json()
video_url = body.get("video_url")
user_id = body.get("user_id")
quality = body.get("kbps")
if (video_url is None): raise HTTPException(400, "Please provide an URL on body")
if (user_id is None): raise HTTPException(401, "No User ID")
# User folder is DOWNLOAD_FOLDER/<userid>
USER_FOLDER = os.path.join(DOWNLOAD_FOLDER, str(user_id))
if not os.path.exists(USER_FOLDER): os.mkdir(USER_FOLDER)
try:
file = await asyncio.to_thread(download_audio, video_url, USER_FOLDER, quality)
final_file = await asyncio.to_thread(set_metadata_and_rename, file, body.get("song"), body.get("artist"), body.get("album"))
file_name = final_file.split("/")[-1]
print("File served: " + final_file)
asyncio.create_task(delay_delete_file(final_file))
return { "file" : file_name }
except KeyError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Missing parameter: {e}")
except DownloadError as e:
logger.exception(f"Download error: {e}")
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to download video")
except Exception as e:
logger.exception(f"Error during media conversion: {e}")
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to convert media")