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
+36
View File
@@ -0,0 +1,36 @@
name: Build and Push Docker Image
on:
push:
branches:
- main
jobs:
build-and-push:
runs-on: self-hosted
steps:
# --- Installa Node.js nel contesto del workflow ---
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
# --- Checkout del repository (richiede Node) ---
- name: Checkout repository
uses: actions/checkout@v3
# --- Login al Gitea Container Registry ---
- name: Login to Gitea Container Registry
run: |
echo "${{ secrets.REGISTRY_TOKEN }}" | docker login gitea.enrilinux.ovh -u "${{ secrets.REGISTRY_USER }}" --password-stdin
# --- Build della Docker image della tua app ---
- name: Build Docker image
run: |
docker build -t gitea.enrilinux.ovh/${{ secrets.REGISTRY_USER }}/streamvault:latest .
# --- Push della Docker image al registry ---
- name: Push Docker image
run: |
docker push gitea.enrilinux.ovh/${{ secrets.REGISTRY_USER }}/streamvault:latest
+17
View File
@@ -0,0 +1,17 @@
FROM python:3.11
WORKDIR /app
RUN apt-get update && apt-get install -y ffmpeg
COPY requirements.txt .
RUN pip install -r requirements.txt
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y nodejs
COPY app ./app
RUN mkdir downloads
CMD ["uvicorn","app.main:app","--host","0.0.0.0","--port","8000"]
+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>
+11
View File
@@ -0,0 +1,11 @@
services:
streamvault:
build: .
ports:
- "8087:8000"
volumes:
- ./downloads:/app/downloads
+5
View File
@@ -0,0 +1,5 @@
fastapi
uvicorn
jinja2
python-multipart
yt-dlp