first commit
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
import yt_dlp
|
||||
import glob
|
||||
import re
|
||||
import os
|
||||
|
||||
DOWNLOAD_DIR = "downloads"
|
||||
|
||||
def sanitize_filename(name):
|
||||
"""Rimuove caratteri non validi dai nomi dei file"""
|
||||
return re.sub(r'[\\/*?:"<>|]', '', name)
|
||||
|
||||
def download_video(url, mode):
|
||||
# Template che usa il titolo e l'ID
|
||||
template = f"{DOWNLOAD_DIR}/%(title)s - %(id)s.%(ext)s"
|
||||
|
||||
if mode == "audio":
|
||||
opts = {
|
||||
"format": "bestaudio/best",
|
||||
"outtmpl": template,
|
||||
"postprocessors": [{
|
||||
"key": "FFmpegExtractAudio",
|
||||
"preferredcodec": "mp3",
|
||||
"preferredquality": "192",
|
||||
}]
|
||||
}
|
||||
else:
|
||||
opts = {
|
||||
"format": "bestvideo+bestaudio/best",
|
||||
"merge_output_format": "mp4",
|
||||
"outtmpl": template
|
||||
}
|
||||
|
||||
with yt_dlp.YoutubeDL(opts) as ydl:
|
||||
info = ydl.extract_info(url, download=True)
|
||||
|
||||
# Prende il file scaricato e lo rinomina in modo sicuro
|
||||
downloaded_files = glob.glob(f"{DOWNLOAD_DIR}/*{info['id']}*")
|
||||
final_path = downloaded_files[0]
|
||||
safe_path = os.path.join(
|
||||
DOWNLOAD_DIR,
|
||||
sanitize_filename(os.path.basename(final_path))
|
||||
)
|
||||
if safe_path != final_path:
|
||||
os.rename(final_path, safe_path)
|
||||
|
||||
return safe_path
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
from fastapi import FastAPI, Request, Form
|
||||
from fastapi.responses import HTMLResponse, FileResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
import os
|
||||
import uuid
|
||||
|
||||
from app.downloader import download_video
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
templates = Jinja2Templates(directory="app/templates")
|
||||
|
||||
DOWNLOAD_DIR = "downloads"
|
||||
os.makedirs(DOWNLOAD_DIR, exist_ok=True)
|
||||
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def home(request: Request):
|
||||
return templates.TemplateResponse("index.html", {"request": request})
|
||||
|
||||
|
||||
@app.post("/download")
|
||||
async def download(url: str = Form(...), mode: str = Form(...)):
|
||||
path = download_video(url, mode)
|
||||
return {"path": path}
|
||||
|
||||
|
||||
@app.get("/file")
|
||||
async def file(path: str):
|
||||
return FileResponse(path)
|
||||
@@ -0,0 +1,84 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>StreamVault</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-900 text-white flex items-center justify-center h-screen">
|
||||
|
||||
<div class="bg-gray-800 p-10 rounded-2xl shadow-2xl w-96">
|
||||
|
||||
<h1 class="text-3xl font-bold mb-6 text-center">
|
||||
StreamVault
|
||||
</h1>
|
||||
|
||||
<input
|
||||
id="url"
|
||||
placeholder="Paste video URL"
|
||||
class="w-full p-3 rounded bg-gray-700 mb-4"
|
||||
/>
|
||||
|
||||
<select id="mode" class="w-full p-3 rounded bg-gray-700 mb-4">
|
||||
<option value="video">Video (MP4)</option>
|
||||
<option value="audio">Audio (MP3)</option>
|
||||
</select>
|
||||
|
||||
<button
|
||||
id="downloadBtn"
|
||||
class="w-full bg-blue-600 hover:bg-blue-700 p-3 rounded font-semibold"
|
||||
>
|
||||
Download
|
||||
</button>
|
||||
|
||||
<div id="status" class="mt-6 text-center text-sm"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
document.getElementById("downloadBtn").addEventListener("click", async () => {
|
||||
|
||||
const url = document.getElementById("url").value
|
||||
const mode = document.getElementById("mode").value
|
||||
const status = document.getElementById("status")
|
||||
|
||||
if(!url){
|
||||
status.innerHTML = "Insert an URL"
|
||||
return
|
||||
}
|
||||
|
||||
status.innerHTML = "Downloading"
|
||||
|
||||
const form = new FormData()
|
||||
form.append("url", url)
|
||||
form.append("mode", mode)
|
||||
|
||||
try{
|
||||
|
||||
const res = await fetch("/download",{
|
||||
method:"POST",
|
||||
body:form
|
||||
})
|
||||
|
||||
const data = await res.json()
|
||||
|
||||
status.innerHTML =
|
||||
`Done<br>
|
||||
<a href="/file?path=${data.path}" class="text-green-400 underline">
|
||||
Download file
|
||||
</a>`
|
||||
|
||||
}catch(e){
|
||||
|
||||
status.innerHTML = "Done"
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user