-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
64 lines (54 loc) · 2.19 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
from yt_dlp import YoutubeDL
from fastapi import FastAPI, BackgroundTasks
from fastapi.staticfiles import StaticFiles
from starlette.responses import FileResponse
from starlette.middleware.cors import CORSMiddleware
from tempfile import TemporaryDirectory
from copy import deepcopy
from os import path, environ
app = FastAPI()
# If we're in development, allow CORS to let Vite dev server communicate.
# If we're in production, we don't need it as the static frontend is hosted
# by this server and all requests are same-origin
if environ.get("PYTHON_ENV") != "production":
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["Content-Disposition"],
)
DEFAULT_OPTIONS = {
"format": "best",
"postprocessors": [
{
"key": "FFmpegExtractAudio",
"preferredcodec": "mp3",
}
],
"outtmpl": "%(title)s.%(ext)s",
}
@app.get("/download")
def download(url: str, background_tasks: BackgroundTasks):
tempdir = TemporaryDirectory()
# when this request is done, clean up the temporary directory and audio track
background_tasks.add_task(cleanup_tempdir, tempdir)
options = deepcopy(DEFAULT_OPTIONS)
options["paths"] = {"home": tempdir.name}
with YoutubeDL(options) as downloader:
downloader.download(url)
info_dict = downloader.extract_info(url, download=False)
filepath = downloader.prepare_filename(info_dict).replace("mp4", "mp3")
response = FileResponse(filepath, media_type="audio/mpeg")
response.headers["Content-Disposition"] = (
f"attachment; filename={path.basename(filepath)}"
)
return response
# this env var is set in the production Dockerfile, which handles building the React
# frontend and placing the static files in the appropriate directory. For development,
# use the separate Vite dev server for hot module reloading.
if environ.get("PYTHON_ENV") == "production":
app.mount("/", StaticFiles(directory="./frontend/dist", html=True), name="static")
def cleanup_tempdir(tempdir: TemporaryDirectory[str]) -> None:
tempdir.cleanup()