added html frontend

This commit is contained in:
TylerCG 2025-06-22 17:33:43 -04:00
parent 3b5621142c
commit 333cb01229
3 changed files with 197 additions and 7 deletions

54
.gitignore vendored Normal file
View File

@ -0,0 +1,54 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# Virtual environments
.venv/
env/
venv/
# VSCode settings
.vscode/
# macOS and Linux system files
.DS_Store
Thumbs.db
# Docker-related
*.log
*.pid
*.tar
*.sock
# Ignore test output or temporary files
*.tmp
*.bak
*.swp
# Python artifacts
*.egg-info/
*.egg
dist/
build/
# PyInstaller
*.spec
# Coverage reports
htmlcov/
.coverage
.cache
nosetests.xml
coverage.xml
*.cover
# MyPy
.mypy_cache/
# Presets and data you dont want in Git
presets/
data/
# Frontend build output (optional if using React)
frontend/build/

View File

@ -1,6 +1,7 @@
from fastapi import FastAPI, UploadFile, File, Form, HTTPException from fastapi import FastAPI, UploadFile, File, Form, HTTPException
from fastapi.responses import FileResponse from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
import yaml import yaml
import os import os
import subprocess import subprocess
@ -9,14 +10,21 @@ from utils import parse_yaml_config, get_presets_dir
app = FastAPI() app = FastAPI()
# Allow CORS (frontend access) # CORS setup for frontend use
app.add_middleware( app.add_middleware(
CORSMiddleware, CORSMiddleware,
allow_origins=["*"], allow_origins=["*"], # For dev; restrict for production
allow_methods=["*"], allow_methods=["*"],
allow_headers=["*"], allow_headers=["*"],
) )
# Serve static files (e.g., HTML GUI)
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/")
def read_root():
return FileResponse("static/index.html")
@app.post("/upload-config/") @app.post("/upload-config/")
async def upload_config(file: UploadFile = File(...)): async def upload_config(file: UploadFile = File(...)):
config_data = yaml.safe_load(await file.read()) config_data = yaml.safe_load(await file.read())
@ -26,16 +34,24 @@ async def upload_config(file: UploadFile = File(...)):
async def transcode(yaml_config: dict): async def transcode(yaml_config: dict):
try: try:
ffmpeg_cmd = parse_yaml_config(yaml_config) ffmpeg_cmd = parse_yaml_config(yaml_config)
subprocess.run(ffmpeg_cmd, check=True) process = subprocess.run(ffmpeg_cmd, check=True, capture_output=True, text=True)
return {"status": "success", "cmd": ffmpeg_cmd} return {
except Exception as e: "status": "success",
raise HTTPException(status_code=500, detail=str(e)) "cmd": ffmpeg_cmd,
"output": process.stdout,
"error": process.stderr
}
except subprocess.CalledProcessError as e:
raise HTTPException(status_code=500, detail=e.stderr or str(e))
@app.get("/browse/") @app.get("/browse/")
def browse(path: str = "/data"): def browse(path: str = "/data"):
if not os.path.exists(path): if not os.path.exists(path):
raise HTTPException(status_code=404, detail="Path not found") raise HTTPException(status_code=404, detail="Path not found")
entries = [{"name": f, "is_dir": os.path.isdir(os.path.join(path, f))} for f in os.listdir(path)] entries = [{
"name": f,
"is_dir": os.path.isdir(os.path.join(path, f))
} for f in os.listdir(path)]
return {"path": path, "entries": entries} return {"path": path, "entries": entries}
@app.post("/save-preset/") @app.post("/save-preset/")

120
backend/static/index.html Normal file
View File

@ -0,0 +1,120 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>FFmpeg Transcoder</title>
<style>
body {
font-family: Arial, sans-serif;
background: #1e1e1e;
color: #fff;
padding: 2rem;
}
h1 {
color: #4fc3f7;
}
label, input, select, textarea, button {
display: block;
margin: 1rem 0;
width: 100%;
}
input, select, textarea {
padding: 0.5rem;
background: #333;
color: #fff;
border: 1px solid #555;
border-radius: 4px;
}
button {
background: #4fc3f7;
color: #000;
padding: 0.7rem;
font-weight: bold;
cursor: pointer;
border: none;
border-radius: 4px;
}
#log {
background: #222;
padding: 1rem;
margin-top: 1rem;
height: 200px;
overflow-y: auto;
}
</style>
</head>
<body>
<h1>FFmpeg Web Transcoder</h1>
<form id="upload-form">
<label for="yamlFile">Upload YAML Config:</label>
<input type="file" id="yamlFile" name="yamlFile" accept=".yml, .yaml" required />
<button type="submit">Upload & Transcode</button>
</form>
<label for="presetSelect">Or Select a Preset:</label>
<select id="presetSelect">
<option disabled selected>Loading presets...</option>
</select>
<button onclick="loadPreset()">Load Preset</button>
<label for="fileBrowser">Select Input File:</label>
<input type="text" id="inputFile" placeholder="/data/input.mp4" />
<button onclick="startTranscode()">Start Transcoding</button>
<div id="log"></div>
<script>
const presetSelect = document.getElementById('presetSelect');
async function fetchPresets() {
const res = await fetch('http://localhost:8000/list-presets/');
const data = await res.json();
presetSelect.innerHTML = data.presets.map(p => `<option value="${p}">${p}</option>`).join('');
}
async function loadPreset() {
const preset = presetSelect.value;
const res = await fetch(`http://localhost:8000/preset/${preset}`);
const text = await res.text();
alert(`Loaded Preset: \n\n${text}`);
}
document.getElementById('upload-form').addEventListener('submit', async (e) => {
e.preventDefault();
const fileInput = document.getElementById('yamlFile');
const formData = new FormData();
formData.append('file', fileInput.files[0]);
const res = await fetch('http://localhost:8000/upload-config/', {
method: 'POST',
body: formData
});
const result = await res.json();
document.getElementById('log').innerText = JSON.stringify(result, null, 2);
});
async function startTranscode() {
const inputPath = document.getElementById('inputFile').value;
const preset = presetSelect.value;
const presetRes = await fetch(`http://localhost:8000/preset/${preset}`);
const yamlText = await presetRes.text();
const yamlObj = jsyaml.load(yamlText);
yamlObj.input_file = inputPath;
const res = await fetch('http://localhost:8000/transcode/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(yamlObj)
});
const result = await res.json();
document.getElementById('log').innerText = JSON.stringify(result, null, 2);
}
window.onload = fetchPresets;
</script>
<script src="https://cdn.jsdelivr.net/npm/js-yaml@4.1.0/dist/js-yaml.min.js"></script>
</body>
</html>