initial commmit

A video player controller for the video player node
This commit is contained in:
Media
2026-06-14 14:34:34 -05:00
commit fc27feaea1
6 changed files with 1164 additions and 0 deletions
+253
View File
@@ -0,0 +1,253 @@
from flask import Flask, render_template_string, request, redirect, url_for, flash
import os
from controller_core import enqueue_download
app = Flask(__name__)
app.secret_key = os.environ.get("FLASK_SECRET_KEY", "dev-secret")
HTML_FORM = """
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>YouTube Playlist Submit</title>
<!-- Make it behave on mobile -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<style>
:root {
color-scheme: dark;
}
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
margin: 0;
padding: 0;
background: #020617;
color: #e5e7eb;
}
.page-wrapper {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 1.25rem;
}
.card {
width: 100%;
max-width: 520px;
background: rgba(15, 23, 42, 0.98);
padding: 1.75rem 1.5rem 1.4rem;
border-radius: 1rem;
box-shadow: 0 18px 45px rgba(0, 0, 0, 0.7);
border: 1px solid rgba(148, 163, 184, 0.35);
}
h2 {
margin: 0 0 0.4rem;
font-size: 1.35rem;
}
.subtitle {
margin: 0 0 1.1rem;
font-size: 0.95rem;
color: #9ca3af;
}
.flash {
margin-bottom: 0.75rem;
padding: 0.55rem 0.75rem;
border-radius: 0.6rem;
background: rgba(30, 64, 175, 0.35);
border: 1px solid rgba(129, 140, 248, 0.7);
font-size: 0.9rem;
}
.form-group {
margin-bottom: 0.85rem;
}
label {
display: block;
margin-bottom: 0.3rem;
font-size: 0.92rem;
}
input,
textarea {
width: 100%;
box-sizing: border-box;
padding: 0.7rem 0.85rem;
border-radius: 0.65rem;
border: 1px solid #4b5563;
background: #020617;
color: #e5e7eb;
font-size: 1rem;
}
input::placeholder,
textarea::placeholder {
color: #6b7280;
}
input:focus,
textarea:focus {
outline: 2px solid #38bdf8;
outline-offset: 2px;
border-color: #38bdf8;
}
textarea {
min-height: 3.2rem;
resize: vertical;
}
button {
width: 100%;
padding: 0.8rem 1.5rem;
border-radius: 999px;
border: none;
background: linear-gradient(135deg, #38bdf8, #6366f1);
color: #fff;
font-weight: 600;
font-size: 1rem;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
margin-top: 0.2rem;
}
button:active {
transform: scale(0.98);
}
.helper {
margin-top: 0.9rem;
font-size: 0.8rem;
color: #9ca3af;
}
@media (max-width: 480px) {
.page-wrapper {
padding: 1rem;
}
.card {
padding: 1.4rem 1.1rem 1.2rem;
border-radius: 0.9rem;
}
h2 {
font-size: 1.2rem;
}
input,
textarea {
font-size: 1.02rem;
}
button {
font-size: 1.02rem;
}
}
</style>
</head>
<body>
<div class="page-wrapper">
<div class="card">
<h2>Submit YouTube Playlist</h2>
<p class="subtitle">
Paste a playlist link below. It’ll be queued for download and assigned to the next free slot.
</p>
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for m in messages %}
<div class="flash">{{ m }}</div>
{% endfor %}
{% endif %}
{% endwith %}
<form method="post" action="{{ url_for('submit') }}">
<div class="form-group">
<label for="url">YouTube URL</label>
<input
type="url"
id="url"
name="url"
required
placeholder="https://www.youtube.com/playlist?list=..."
>
</div>
<div class="form-group">
<label for="submitter">Your name (optional)</label>
<input
type="text"
id="submitter"
name="submitter"
placeholder="Simon Peter"
>
</div>
<div class="form-group">
<label for="note">Note (optional)</label>
<textarea
id="note"
name="note"
rows="3"
placeholder="Service, event, etc."
></textarea>
</div>
<button type="submit">Submit Playlist</button>
</form>
<p class="helper">
Playlists are kept for roughly 48 hours after they’re downloaded.
</p>
</div>
</div>
</body>
</html>
"""
@app.route("/", methods=["GET"])
def index():
return render_template_string(HTML_FORM)
@app.route("/submit", methods=["POST"])
def submit():
url = request.form.get("url", "").strip()
submitter = request.form.get("submitter", "").strip() or None
note = request.form.get("note", "").strip() or None
if not url.startswith("http"):
flash("Invalid URL.")
return redirect(url_for("index"))
result = enqueue_download(url, submitter, note)
if result.get("status") == "queue_full":
secs = result.get("oldest_expires_in_seconds", 0)
hours = max(1, secs // 3600)
flash(f"Queue is full. Oldest playlist expires in about {hours} hour(s).")
else:
slot = result.get("slot")
msg = f"Playlist queued in slot {slot}."
if result.get("reused_slot"):
msg += " (Existing slot – only new videos will be added.)"
else:
msg += " It will start downloading shortly."
flash(msg)
return redirect(url_for("index"))
if __name__ == "__main__":
app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 7531)))