first commit

This commit is contained in:
enrilinux
2026-03-08 12:54:08 +01:00
parent 9ad5408a5d
commit f94333c2f9
7 changed files with 229 additions and 0 deletions
+46
View File
@@ -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
View File
@@ -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)
+84
View File
@@ -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>