first commit
This commit is contained in:
@@ -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
@@ -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"]
|
||||
@@ -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>
|
||||
@@ -0,0 +1,11 @@
|
||||
services:
|
||||
|
||||
streamvault:
|
||||
|
||||
build: .
|
||||
|
||||
ports:
|
||||
- "8087:8000"
|
||||
|
||||
volumes:
|
||||
- ./downloads:/app/downloads
|
||||
@@ -0,0 +1,5 @@
|
||||
fastapi
|
||||
uvicorn
|
||||
jinja2
|
||||
python-multipart
|
||||
yt-dlp
|
||||
Reference in New Issue
Block a user